DS3231高精度时钟模块,IIC,C51 8051单片机I2C 测试程序 【开源】

实物图

原理图



效果图

程序烧录:

/***************************************************************************** 
*文件名称:main.c
*版    本:Keil uVision4
*控 制 器:STC89C52RC/12M
功能:显示时间到串口

*说    明:
1,DS3231实时时钟模块测试程序 
2,1T的单片机用不了
3,晶振12M
4,串口波特率2400

编译结果:
Rebuild target ‘Demo_DS3231‘
compiling main.c...
linking...
*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
    SEGMENT: ?PR?_UART_SENDBYTE?MAIN
Program Size: data=61.2 xdata=0 code=2059
creating hex file from "Demo_DS3231"...
"Demo_DS3231" - 0 Error(s), 1 Warning(s).

*****************************************************************************/

#include <reg52.h>
#include <stdio.h>
#include "intrins.h"

//#define  Effective                  0x01
//#define  Ineffectiveness            0x00
#define  DS3231WriteAddress         0xd0
#define  DS3231ReadAddress          0xd1
//#define  DS3231_SecondRegister      0x00
#define  DS3231_TimeFirstRegister   0x00
#define  DS3231_MinuteRegister      0x01
#define  DS3231_HourRegister        0x02
#define  DS3231_WeekRegister        0x03
#define  DS3231_DayRegister         0x04
#define  DS3231_MonthRegister       0x05
#define  DS3231_YearRegister        0x06
#define  DS3231_InterruptRegister   0x0e
#define  DS3231_AlarmRegister       0x0f
#define  DS3231_ResetSCL()     DS3231_scl = 0   
#define  DS3231_SetSCL()       DS3231_scl = 1
#define  DS3231_ResetSDA()     DS3231_sda = 0
#define  DS3231_SetSDA()       DS3231_sda = 1
#define  DS3231_ReadPinSDA()   DS3231_sda
#define Time0_TH0  0xec	        //定义计数器0计数寄存器装载的高8位值
#define Time0_TL0  0x78	        //定义计数器0计数寄存器装载的低8位值

//--------------------------秒-分-时-星期-日-月-年
unsigned int   SetTime[] = {12,12,12,1,1,1,15};
unsigned int   CurrentT[7];
bit            Flag_Collect = 0;         //定义采集扫描标志变量
unsigned char	 SweepInterval_Collect;	   //定义采集扫描时间累加变量
sbit    DS3231_scl = P2^1;  //DS3231 clock 
sbit    DS3231_sda = P2^0;  //DS3231 data 

void DS3231_Delay(void) {    //DS3231通信速率延时,延时5微秒  12T单片机@12M
	unsigned char Number = 8;
	while (Number--)    {
        _nop_();
        _nop_();
    } 
}

void DS3231_DelayForWrite(void){  //DS3231写字节延时,延时5毫秒 12T单片机@12M
	unsigned int Number = 2500;
	while (Number--){
			_nop_();
      _nop_();
			_nop_();
			_nop_();
			_nop_();
    } 
}

void DS3231_Start(void) { //模拟DS3231通信开始信号,SCL=1期间,在SDA上产生一个下降沿
	DS3231_SetSDA();
	DS3231_SetSCL();DS3231_Delay(); 
	DS3231_ResetSDA();DS3231_Delay(); 
} 

void DS3231_Stop(void) //模拟DS3231通信结束信号,SCL=1期间,在SDA上产生一个上升沿
{   
	DS3231_ResetSDA();DS3231_Delay();
	DS3231_ResetSDA();DS3231_Delay();	 
	DS3231_SetSCL();DS3231_Delay();
	DS3231_SetSCL();DS3231_Delay();
	DS3231_SetSDA();DS3231_Delay();
} 

unsigned char DS3231_WriteByte(unsigned char SendByte){ //向DS3231设备写一字节数据及8为二进制数据,高位在前 
	unsigned char i=8;
	DS3231_ResetSCL();	 
	for(i=0; i<8; i++)	{ 
		if(SendByte&0x80) {DS3231_SetSDA();}
		else {DS3231_ResetSDA();}
		DS3231_ResetSCL();DS3231_Delay();				   
		DS3231_SetSCL(); DS3231_Delay(); 
		SendByte=SendByte<<1;
		DS3231_ResetSCL();DS3231_Delay(); 
	}
	DS3231_SetSDA();DS3231_Delay();
	DS3231_ResetSCL();DS3231_Delay();
	DS3231_SetSCL();DS3231_Delay();
	i = DS3231_ReadPinSDA();DS3231_Delay();
	DS3231_ResetSCL();DS3231_Delay();
	return i;		 
} 

unsigned char DS3231_ReceiveByte(unsigned char Response) { //接收DS3231发送的数据
	unsigned char i=8; 
	unsigned char ReceiveByte=0;
	DS3231_SetSDA();DS3231_Delay();
	DS3231_ResetSCL();DS3231_Delay();	 
	for(i=0; i<8; i++){ 
		DS3231_SetSCL();DS3231_Delay();
		ReceiveByte = ReceiveByte << 1;       
		ReceiveByte=ReceiveByte|(unsigned char)DS3231_ReadPinSDA(); 
		DS3231_ResetSCL();DS3231_Delay(); 
	}
	if(Response) DS3231_SetSDA();
	else DS3231_ResetSDA();
	DS3231_Delay();
	DS3231_SetSCL();DS3231_Delay();
	DS3231_ResetSCL();DS3231_Delay();
	DS3231_SetSDA();DS3231_Delay(); 
	return ReceiveByte; 
}                                                               

unsigned char DS3231_ReadOneByteFromE2PROM(unsigned char DataAddress) {//读指定地址E2PROM中的数据
	unsigned char ReadData;
	DS3231_Start();                       //DS3231芯片IIC通信开始信号
	DS3231_WriteByte(DS3231WriteAddress); //写入芯片IIC写地址
	DS3231_WriteByte(DataAddress);        //写入状态寄存器地址
	DS3231_Start();                       //DS3231芯片IIC通信开始信号
	DS3231_WriteByte(DS3231ReadAddress);  //写入芯片IIC读地址
	ReadData = DS3231_ReceiveByte(0x01);
	DS3231_Stop();                         //DS3231芯片IIC通信停止信号
	return ReadData; 	 
}

void DS3231_Initialization(){            //初始化时钟芯片DS3231,先选择要写入的寄存器,在写入需要设置的指令
	DS3231_Start();											 	 //IIC通信起始信号
	DS3231_WriteByte(DS3231WriteAddress);  //写入芯片IIC写地址
	DS3231_WriteByte(DS3231_HourRegister); //选择时寄存器为写入地址
	DS3231_WriteByte(0x00);                //写入指令,时钟范围为0-23,即24小时制式
	DS3231_Stop(); 

	DS3231_Start();														 //IIC通信起始信号
	DS3231_WriteByte(DS3231WriteAddress);      //写入芯片IIC写地址
	DS3231_WriteByte(DS3231_InterruptRegister);//选择中断寄存器为写入地址	  
	DS3231_WriteByte(0x04);                    //中断寄存器初始化,关闭方波信号,关闭闹钟中断
	DS3231_WriteByte(0x00);                    //状态寄存器初始化,失效32KHz信号输出,不匹配闹钟
	DS3231_Stop(); 
}

void DS3231_SetTime(unsigned int *Pointer){ //向DS3231写入设置时间信息
	unsigned char Number = 0x00;
  unsigned char TransitionData = 0x00;
	DS3231_Start();                             //DS3231芯片IIC通信开始信号
	DS3231_WriteByte(DS3231WriteAddress);       //写入芯片IIC写地址
	DS3231_WriteByte(DS3231_TimeFirstRegister); //写入时间寄存器首地址
  for(Number=0; Number<7; Number++)  {
    TransitionData = *Pointer++;
    DS3231_WriteByte((TransitionData/10)*16+TransitionData%10);   //向DS3231写入设置时间信息
  }
  DS3231_Stop();                                   //DS3231芯片IIC通信停止信号
	DS3231_DelayForWrite();
}

void DS3231_ReadTime(unsigned int *Pointer){       //从DS3231中读出当前时间
	unsigned char Number  = 7;
  unsigned char Time    = 0x00;
	DS3231_Start();                                  //DS3231芯片IIC通信开始信号
	DS3231_WriteByte(DS3231WriteAddress);            //写入芯片IIC写地址
	DS3231_WriteByte(DS3231_AlarmRegister);          //写入闹钟寄存器首地址
	DS3231_WriteByte(0x00);                          //关闭闹钟中断标志位
	DS3231_Stop();                                   //DS3231芯片IIC通信停止信号

	DS3231_Start();                                  //DS3231芯片IIC通信开始信号
	DS3231_WriteByte(DS3231WriteAddress);            //写入芯片IIC写地址
	DS3231_WriteByte(DS3231_TimeFirstRegister);      //写入时间寄存器首地址
	DS3231_Start();                                  //DS3231芯片IIC通信开始信号
	DS3231_WriteByte(DS3231ReadAddress);             //写入芯片IIC读地址
  for(Number=0; Number<6; Number++) {
		Time = DS3231_ReceiveByte(0x00);
    *Pointer++ = (Time/16*10+Time%16);    
  }
	Time = DS3231_ReceiveByte(0x01);
	*Pointer++ = (Time/16*10+Time%16); 
  DS3231_Stop();                                 //DS3231芯片IIC通信停止信号
}

void Time0_Initialization(void){//[email protected] 
		TMOD=0x21;        //T0,工作方式1
		TH0=Time0_TH0;    //装载定时器0寄存器高8位值
		TL0=Time0_TL0;    //装载定时器0寄存器低8位值
		TR0=1;            //开启T0定时器
		ET0=1;            //允许T0定时器中断
		EA=1;             //开启总中断允许
}

void UART_Initialization(void){  //[email protected]
		SCON = 0x50;       //选择串口工作方式1,打开接收允许
		TMOD = 0x21;       //定时器1工作在方式2,定时器0工作在方式1
		TH1  = 0xe6;       //实现波特率2400(系统时钟12MHZ)
		TCON = 0x40;       //定时器1开始计数
		PCON = 0x80;       //波特率倍频
		RI   = 0x00;			 //清接收标志
		TI   = 0x01;			 //清发送标志
		TR1  = 0x01;       //启动定时器T1
}

void UART_SendByte(unsigned char SendByte){
    SBUF = SendByte; //输出字符
    while(!TI);		   //判断是否发完
    TI=0;			       //清TI
}

void main(){                                             //定时采集DS3231时钟芯片时间信息,通过RS232串口打印
	unsigned char State_Timing;
	unsigned int  Value_Contrast;
	UART_Initialization();
	State_Timing = DS3231_ReadOneByteFromE2PROM(DS3231_AlarmRegister);//判断是否校时
	if(State_Timing & 0x80){                                 //判断芯片是否有掉电
		DS3231_Initialization();                               //初始化时间时钟芯片DS3231
		DS3231_SetTime(SetTime);
	}

	DS3231_ReadTime(CurrentT);                               //掉电检测操作,电源短路或者供电系统电量彻底消耗掉才有效 每次上电读取一次当前时间信息
	if(CurrentT[6] == 0x00){                                 //年份信息为0x00,芯片时间需要初始化
		DS3231_Initialization();                               //初始化时间时钟芯片DS3231
		DS3231_SetTime(SetTime);                               
	}
	Time0_Initialization();	          //定时器初始化

	while(1){
		while(Flag_Collect){           // 中断控制
			EA = 0;                      //关闭总中断
			DS3231_ReadTime(CurrentT);   //读取当前时间信息
			if(Value_Contrast != CurrentT[0]){
				Value_Contrast = CurrentT[0];
				printf("Week=%d\r\n",CurrentT[3]);
				printf("Data=20%d/%d/%d\r\n",CurrentT[6],CurrentT[5],CurrentT[4]);
				printf("Time=%d:%d:%d\r\n",CurrentT[2],CurrentT[1],CurrentT[0]);
				printf("\r\n");
			}			  							  
			Flag_Collect = 0;           
			EA = 1;
		}
	}
}

void Time0_Handle(void) interrupt 1 using 3 {
	TR0 = 0;                            //关闭T0定时器   
	TH0 = Time0_TH0;                    //重新装载定时器0寄存器高8位值
	TL0 = Time0_TL0;                    //重新装载定时器0寄存器低8位值
	TR0 = 1;                            //开启T0定时器
	if(SweepInterval_Collect >= 0x3c){     //大约0.3s采集一次时钟信息
		Flag_Collect = 1;                   //采集扫描标志变量置位
		SweepInterval_Collect = 0;          //采集扫描时间变量清零
	}
	else	{SweepInterval_Collect++;}			//采集扫描时间累加
}
时间: 2024-10-18 22:10:47

DS3231高精度时钟模块,IIC,C51 8051单片机I2C 测试程序 【开源】的相关文章

点阵大屏语音感应时计&mdash;&mdash;DS3231高精度时钟模块

DS3231高精度时钟模块倒是又便宜又好用,SDA/SCL两个IO口就能搞定基本功能,不过在使用闹铃中断输出的时候遇到了问题,那就是闹铃中断只会输出一次,之后始终保持低电平. 这个问题数据手册上没有明说,在网上搜索了很久,一点信息都没有找到,只好自己折腾. 经过反复尝试,最终确认DS3231的闹铃中断输出正确使用方式如下: 首先是初始化,设定闹铃时间和允许中断输出 void DS3231_Init_Alarm2()    {        I2C_Start();         I2C_Put

基于STM8的IIC协议--实例篇--时钟模块(DS3231)读取

1. 综述 由上篇博客可知道IIC协议如何用代码实现,本篇博客就不涉及协议内容,只讲解如何使用. 本次的实验传感为:DS3231(时钟模块),对于时钟模块的具体信息我也就不多介绍大家可以自行度娘,具体功能无非就是在单片机中起到一个获取时间的作用.然后该模块是可以由IIC协议去驱动的,再加上所要的操作也是比较简单,适合部分刚接触IIC协议而找不但传感练手的一个模块. 2. 明确任务顺序 个人习惯,在每驱动一个新传感的时候,我会将我要完成的传感分为几个任务点.接下来我就展示以下我在写DS3231模块

张高兴的 Windows 10 IoT 开发笔记:RTC 时钟模块 DS3231

原文:张高兴的 Windows 10 IoT 开发笔记:RTC 时钟模块 DS3231 GitHub:https://github.com/ZhangGaoxing/windows-iot-demo/tree/master/DS3231 注意:不包含闹钟设置

6轴速度计/陀螺仪MPU6050模块 IIC程序C代码

资料下载 http://pan.baidu.com/s/15QGGG 产品参数 名称:MPU-6050模块(三轴陀螺仪+三轴加速度) 使用芯片:MPU-6050 供电电源:3-5V(内部低压差稳压) 通信方式:标准IIC通信协议 芯片内置16bit AD转换器,16位数据输出 陀螺仪范围::±250 500 1000 2000  °/s 加速度范围:±2±4±8±16g 采用沉金PCB,机器焊接工艺保证质量 引脚间距2.54mm MPU-6000为全球首例整合性6轴运动处理组件,相较于多组件方案

(转)FPGA异步时序和多时钟模块

http://bbs.ednchina.com/BLOG_ARTICLE_3019907.HTM   第六章   时钟域 有一个有趣的现象,众多数字设计特别是与FPGA设计相关的教科书都特别强调整个设计最好采用唯一的时钟域.换句话说,只有一个独立的网络可以驱动一个设计中所有触发器的时钟端口.虽然这样可以简化时序分析以及减少很多与多时钟域有关的问题,但是由于FPG**外各种系统限制,只使用一个时钟常常又不现实.FPGA时常需要在两个不同时钟频率系统之间交换数据,在系统之间通过多I/O接口接收和发送

一种基于PTP 协议的局域网高精度时钟同步方法(转)

原文地址 http://www.dzsc.com/data/html/2011-1-17/88338.html 1 引言 在分布式系统中, 常常需要一个全局时间, 用来确定系统中各种事件发生的先后.协调各种消息的传输等,以控制和监视系统的状态.这就需要将系统中各个部件的局部时间统一,进行时钟同步.随着分布式仿真系统和试验系统在网络上的广泛应用,如何在网络上提供可靠的时钟服务成为一项重要课题.并且由于系统速度上的要求,同步的精度也成为一项重要指标. PTP(Precision Time Proto

为什么单片机需要时钟系统,时钟信号在单片机中扮演怎样的角色?

1.单片机内部需要储存器.累加器,这些都需要逻辑门电路.比如锁存器就是一个D触发器,而触发器的置1.清0.置数的功能都需要跳变沿.D触发器就是上升沿后存入数据,而这个上升沿就得外部提供脉冲,这就是脉冲信号 ,而这个脉冲信号就是我们稳定的时钟信号. 2.单片机运行需要时钟支持-–就像计算机的CPU一样,如果没有时钟电路来产生时钟驱动单片机,那单片机就不能执行程序.单片机可以看成是在时钟驱动下的时序逻辑电路. 以MCS–51单片机为例:MCS–51单片机为12个机器周期执行一条指令,也就是说单片机运

linux中C语言获取高精度时钟gettimeofday函数

前言:    在开发中,很多时候需要知道各个函数或者是某些设备对命令的操作用时,因此需要用到 gettimeofday 来获取当前时钟. 一,函数说明 #include  int gettimeofday(struct timeval *tv, struct timezone *tz); 注意: 1.精确级别,微妙级别        2.受系统时间修改影响        3.返回的秒数是从1970年1月1日0时0分0秒开始 其参数tv是保存获取时间结果的结构体,参数tz用于保存时区结果: 结构体

8051单片机软件精确延时研究(一)

前言 最近自学51单片机,编程中如流水灯等非精确延时多用软件延时实现,写了几个类似DelayX10us(unsigned char x)的函数方便调用,函数内部的语句多是用官方延时程序再自己套一个for或者do..while循环改造而成,像这样: //非精确延时10*Xus//@12.000MHz 12T模式 void DelayX10us(unsigned char x) { unsigned char i; for (; x > 0; x--) { _nop_(); i = 2; while