采用stc15单片机做的主控芯片,仅供参考
制作出来的ds3132时钟实物图:
电路原理图:
pcb文件:工程文件可到本帖附件中下载
51单片机源程序如下:
- //#include <reg52.h>
- #include "stc15f104w.h"
- #include "I2C.h"
- #include "Led_can.h"
-
- typedef unsigned int u16; //16位无符号整型数
- typedef unsigned char u8; //8位无符号整型数
- #define E2PROM_WriteAddress 0xAE //器件写地址
- #define DS3231_WriteAddress 0xD0 //器件写地址
- #define DS3231_ReadAddress 0xD1 //器件读地址
- #define DS3231_SECOND 0x00 //秒
- #define DS3231_MINUTE 0x01 //分
- #define DS3231_HOUR 0x02 //时
- #define DS3231_WEEK 0x03 //星期
- #define DS3231_DAY 0x04 //日
- #define DS3231_MONTH 0x05 //月
- #define DS3231_YEAR 0x06 //年
- //闹铃1
- //#define DS3231_SALARM1ECOND 0x07 //秒
- //#define DS3231_ALARM1MINUTE 0x08 //分
- //#define DS3231_ALARM1HOUR 0x09 //时
- //#define DS3231_ALARM1WEEK 0x0A //星期/日
- //闹铃2
- //#define DS3231_ALARM2MINUTE 0x0b //分
- //#define DS3231_ALARM2HOUR 0x0c //时
- //#define DS3231_ALARM2WEEK 0x0d //星期/日
- #define DS3231_CONTROL 0x0e //控制寄存器
- #define DS3231_STATUS 0x0f //状态寄存器
- #define BSY 2 //忙
- #define OSF 7 //振荡器停止标志
- #define DS3231_XTAL 0x10 //晶体老化寄存器
- #define DS3231_TEMPERATUREH 0x11 //温度寄存器高字节(8位)
- #define DS3231_TEMPERATUREL 0x12 //温度寄存器低字节(高2位)
- sbit BP = P1^5; //秒数码管驱动
- sbit KEY1 = P1^5; //按键输入引脚
- u8 Time[18]; //时钟数值缓冲区
- bit BiaoJi=0; //读实时时钟标记
- bit BianJi_c=0; //长按键标记
- bit BianJi_d=0; //短按键标记
- u8 BianJi=0; //编辑模式标记
- u8 L_u[4]={2,3,4,5};//数码管显示第几时钟缓冲区
- u8 ling=0; //数码管首位是否显示零标记
- bit WenDu = 0; //温度转换标记
- void ConfigTimer0(u8 ms); //配置并启动T0,ms-T0定时时间
- void write_byte(u8 addr, u8 write_data);//DS3231_写一个字节数据到时钟芯片
- u8 read_byte(u8 random_addr); //DS3231_读一个字节数据到时钟芯片
- void write_byte_E2( u8 write_data); //E2PROM-写一个字节数据到时钟芯片
- u8 read_byte_E2(); //E2PROM-读一个字节数据到时钟芯片
- u8 BCD2HEX(u8 val); //BCD转换为Byte
- u8 HEX2BCD(u8 val); //B码转换为BCD码
- void anjian(); //按钮扫描 需在定时中断中调用
- void Anjian_d(u8 addr, u8 map); //短按键处理—子程序
- void main()
- {
- u8 map;
- u16 wend;
-
- EA = 1; //开总中断
- Led_cu(); //数码管初始化
- ConfigTimer0(5); //配置T0定时
- ling=read_byte_E2(); //E2PROM读出数据—数码管首位是否显示零标记
- //初始化实时时钟,小时采用24小时制
- write_byte(DS3231_CONTROL, 0x1C); //控制寄存器 DS3231_CONTROL
- write_byte(DS3231_STATUS, 0x00); //状态寄存器 DS3231_STATUS
- //write_byte(DS3231_SECOND,HEX2BCD(30)); //修改秒
- //write_byte(DS3231_MINUTE,HEX2BCD(30)); //修改分
- //write_byte(DS3231_HOUR,HEX2BCD(16)); //修改时
- //write_byte(DS3231_DAY,HEX2BCD(1)); //修改日
- //write_byte(DS3231_MONTH,HEX2BCD(12)); //修改月
- //write_byte(DS3231_YEAR,HEX2BCD(17)); //修改年
-
- while(1)
- { //读取时钟芯片并写进数码管显示缓冲区======================
- if(BiaoJi == 1)
- { BiaoJi = 0;
-
- map=read_byte(DS3231_SECOND); //读秒
- map=BCD2HEX(map);
- Time[0]=map%10;
- Time[1]=map/10%10;
- map=read_byte(DS3231_MINUTE); //读分
- map=BCD2HEX(map);
- Time[2]=map%10;
- Time[3]=map/10%10;
- map=read_byte(DS3231_HOUR)&0x3f; //读小时 24小时制
- map=BCD2HEX(map);
- Time[4]=map%10 ;
- Time[5]=map/10%10 ;
-
- //map=read_byte(DS3231_WEEK ); //读星期
- //Time[6]=map
- //map=read_byte(DS3231_DAY); //读日
- //map=BCD2HEX(map);
- //Time[8]=map%10
- //Time[9]=map/10%10
- //map=read_byte(DS3231_MONTH); //读月
- //map=BCD2HEX(map);
- //Time[10]=map%10
- //Time[11]=map/10%10
- //map=read_byte(DS3231_YEAR); //读年
- //map=BCD2HEX(map);
- //Time[12]=map%10
- //Time[13]=map/10%10
-
- if((ling==0) && (Time[L_u[3]]==0)) //判断数码管首位零是否显示
- Led_buff[3] = 0xff;
- else
- Led_buff[3] = Led_Char[ Time[L_u[3]]];
- Led_buff[2] = Led_Char[ Time[L_u[2]]];
- Led_buff[1] = Led_Char[ Time[L_u[1]]];
- Led_buff[0] = Led_Char[ Time[L_u[0]]];
-
- }
- //读取温度并写进数码管显示缓冲区======================
- if(WenDu == 1)
- { WenDu = 0;
- //零上温度转换
- map=read_byte(DS3231_TEMPERATUREH); //温度高字节—整数位
- if((map&0x80)==0) //判断首字节为1即为 零下温度
- { Led_buff[0] = 0xa7;
- Time[16]=map%10 ;
- Time[17]=map/10%10;
- map=read_byte(DS3231_TEMPERATUREL); //温度低字节—小数位
- map=(map>>6)*25; //由于分辨率为0.25 所以扩大25倍便于显示
- Time[14]=map%10;
- Time[15]=map/10%10;
- }
- else //零下温度转换—零下是以2的补码形式存储的
- { Led_buff[0] = 0xa6;
- wend=map; //单字节转换双字节
- wend=wend<<2; //移出两位放温度的低位
- map=read_byte(DS3231_TEMPERATUREL); //读温度低字节
- map=map>>6; //由于2位放在头两位上,移到低位
- wend=wend+map; //组成10位的2进制的温度编码
- wend=(~wend)+1; //负数是以2的补码形式存储的,转为原码
- wend=wend&0x03ff;//10位的2进制的温度编码,截去无用位
- map= wend&0x0003;//分离低两位,作为小数位
- map= map*25; //由于分辨率为0.25 所以扩大25倍便于显示
- Time[14]=map%10;
- Time[15]=map/10%10;
- wend=wend>>2; //整数位处理
- Time[16]=wend%10;
- Time[17]=wend/10%10;
- }
-
- if((ling==0) && (Time[L_u[17]]==0)) //判断数码管首位零是否显示
- Led_buff[3] = 0xff;
- else
- Led_buff[3] = Led_Char[ Time[17]]; //整数位显示两位
- Led_buff[2] = Led_Char[ Time[16]];
- Led_buff[1] = Led_Char[ Time[15]]; //小数位显示一位
-
- write_byte(DS3231_CONTROL, 0x3C); //温度强制转换—准备下次读取
- }
- //长按键处理
- if(BianJi_c==1)
- { BianJi_c=0;
- KEY1=1;
- BianJi++;
- if(BianJi==1) //进入温度显示
- { WenDu = 1; }
- if(BianJi==2) //进入首位数码管修改位
- { Led_buff[3] = Led_Char[ Time[L_u[3]]];
- Led_buff[2] = 0xbf;
- Led_buff[1] = 0xbf;
- Led_buff[0] = 0xbf;
- }
- if(BianJi==3) //进入第二位数码管修改位
- { Led_buff[3] = 0xbf;
- Led_buff[2] = Led_Char[ Time[L_u[2]]];
- if(Time[L_u[3]]==2 && Time[L_u[2]]>3) //若为24小时制 首位为2则压缩次位的修改范围
- { Time[L_u[2]]=3;
- Anjian_d(L_u[2],3);
- }
- }
- if(BianJi==4) //进入第三位数码管修改位
- { Led_buff[2] = 0xbf;
- Led_buff[1] = Led_Char[ Time[L_u[1]]];
- }
- if(BianJi==5) //进入第四位数码管修改位
- { Led_buff[1] = 0xbf;
- Led_buff[0] = Led_Char[ Time[L_u[0]]];
- }
- if(BianJi==6) //进入数码管首位零是否显示,修改选项 显示零:ON 不显示零:OFF
- { if(ling==0)
- { Led_buff[3] = 0xff;
- Led_buff[2] = 0xC0;
- Led_buff[1] = 0x8E;
- Led_buff[0] = 0x8E;
- }
- else
- { Led_buff[3] = 0xff;
- Led_buff[2] = 0xff;
- Led_buff[1] = 0xC0;
- Led_buff[0] = 0xc8;
- }
- }
- if(BianJi==7) //退出编辑模式
- { BianJi=0; }
-
- }
- //短按键处理
- if(BianJi_d==1)
- { BianJi_d=0;
- if(BianJi==1) //退出编辑模式
- { BianJi=0; }
- if(BianJi==2) //首位数码管修改位
- { Anjian_d(L_u[3],2);}
- if(BianJi==3) //第二位数码管修改位
- { if(Time[L_u[3]]==2 )
- { Anjian_d(L_u[2],3); }
- else
- { Anjian_d(L_u[2],9); }
-
- }
- if(BianJi==4) //第三位数码管修改位
- { Anjian_d(L_u[1],5); }
- if(BianJi==5) //第四位数码管修改位
- { Anjian_d(L_u[0],9); }
- if(BianJi==6) //进入数码管首位零是否显示,修改选项 显示零:ON 不显示零:OFF
- {
- if(ling==0)
- { ling = 1;
- Led_buff[3] = 0xff;
- Led_buff[2] = 0xff;
- Led_buff[1] = 0xC0;
- Led_buff[0] = 0xc8;
- write_byte_E2(ling);
- }
- else
- { ling = 0;
- Led_buff[3] = 0xff;
- Led_buff[2] = 0xC0;
- Led_buff[1] = 0x8E ;
- Led_buff[0] = 0x8E;
- write_byte_E2(ling);
- }
- }
-
- }
- }
- }
- //短按键处理
- void Anjian_d(u8 addr, u8 map)
- {
- u8 i;
- Time[addr]++; //时间变量
- if(Time[addr]>map) //时间变量最大值
- Time[addr]=0;
- if((addr%2)==0) //计算传入值时十位或个位 0:各位 1:十位
- i = Time[addr+1]*10+Time[addr]; //十位个位组成数值待写入DS3231
- else
- i = Time[addr]*10+Time[addr-1]; //十位个位组成数值待写入DS3231
- Led_buff[5-BianJi] = Led_Char[ Time[addr]]; //修改的值显示到数码管上
- write_byte(addr/2,HEX2BCD(i)); //写入DS3231
-
- }
- /* 配置并启动T0,ms-T0定时时间 */
- void ConfigTimer0(u8 ms)
- {
- unsigned long tmp; //临时变量
-
- tmp = 12000000 / 12; //定时器计数频率
- tmp = (tmp * ms) / 1000; //计算所需的计数值
- tmp = 65536 - tmp; //计算定时器重载值
- TMOD &= 0xF0; //清零T0的控制位
- TH0 = (u8)(tmp>>8); //定时器重载值拆分为高低字节
- TL0 = (u8)tmp;
- ET0 = 1; //使能T0中断
- TR0 = 1; //启动T0
- }
- //中断定义为5毫秒
- void InterruptTimer0() interrupt 1
- {
- static u8 Di;
- //非编辑模式进入
- if(BianJi==0)
- {
- Di++;
- if(Di==100)
- {BP=1;} //秒显示赋值 0.5秒
- if(Di==200)
- {
- Di=0;
- BiaoJi=1; //一秒一次读DS3231时间,并写入数码管缓冲区的标记
- BP=0; //秒显示赋值 0.5秒
- }
- }
- //编辑模式(1)进入
- if(BianJi==1)
- { Di++;
- if(Di==200)
- { Di=0; WenDu = 1;} //一秒一次读DS3231温度,并写入数码管缓冲区的标记
- }
-
- Led_can(); //数码管刷新
- anjian(); //按键扫描
- WDT_CONTR=0x37; //看门狗刷新 8.4S
- }
- //E2PROM-写一个字节数据到时钟芯片
- void write_byte_E2( u8 write_data)
- {
- I2CStart(); //产生总线起始信号
- I2CWrite(E2PROM_WriteAddress); //<<<<I2C总线写操作 E2PROM-器件码
- I2CWrite(0); // E2PROM-存储空间高八位地址
- I2CWrite(1); // E2PROM-存储空间低八位地址
- I2CWrite(write_data); // 写数据
- I2CStop(); //产生总线停止信号
-
- }
- //E2PROM-读一个字节数据到时钟芯片
- u8 read_byte_E2()
- {
- char temp;
- I2CStart(); //产生总线起始信号
- I2CWrite(E2PROM_WriteAddress); //<<<<I2C总线写操作 E2PROM-器件码
- I2CWrite(0); // E2PROM-存储空间高八位地址
- I2CWrite(1); // E2PROM-存储空间低八位地址
- I2CStart(); //产生总线起始信号
- I2CWrite(E2PROM_WriteAddress|1); //从写 E2PROM-器件码
- temp = I2CReadNAK(); // 读数据-发送非应答信号,不读了
- I2CStop(); //产生总线停止信号
- return(temp);
- }
- //DS3231_写一个字节数据到时钟芯片
- void write_byte(u8 addr, u8 write_data)
- {
- I2CStart(); //产生总线起始信号
- I2CWrite(DS3231_WriteAddress); //<<<<I2C总线写操作
- I2CWrite(addr); //<<<<I2C总线写操作
- I2CWrite(write_data); //<<<<I2C总线写操作
- I2CStop(); //产生总线停止信号
-
- }
- //DS3231_读一个字节数据到时钟芯片
- u8 read_byte(u8 random_addr)
- {
- char temp;
- I2CStart(); //产生总线起始信号
- I2CWrite(DS3231_WriteAddress); //<<<<I2C总线写操作 器件码
- I2CWrite(random_addr); //<<<<存储空间地址
- I2CStart(); //产生总线起始信号
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
实时时钟.rar
(145.56 KB, 下载次数: 369)
|