这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界» 论坛首页» DIY与开源设计» 电子DIY» 使用高精度RTC时钟芯片DS3231制作LED数码管电子钟

共18条 1/2 1 2 跳转至

使用高精度RTC时钟芯片DS3231制作LED数码管电子钟

工程师
2021-04-10 23:20:32 打赏

在开发板移植STC98C52+两块74HC573用DS1320驱动码数管电子钟,用洞洞做, 玩过DS1302钟知道,DS1302要精度很高晶振,但是受外界温度影响还是有很大误差。网上很难找到用DS3231数码管电子钟例子,以前我在淘宝购DS3231模板一直在空,总想找源植入改变DS1320驱动码数管电子钟,现在终于找到了!

STC98C52+74HC573+74HC138或STC98C52+74HC245+74HC138驱动数码管,数码管显示很好、方便,象DS3231这样精准不必要加什么样GPS或红外了。改一下STC98C52+两块74HC573用DS1320驱动数码管电子钟,把DS1320移掉,两块74HC573,留一换一,试一下,成功显示了。

制作出来的实物图(前后图)如下:

image.png

image.png


源码如下:

#include

#include

#define uchar unsigned char

#define uint unsigned int

sbit SDA=P3^7; //DS3231模拟I2C数据传送位SDA

sbit SCL=P3^6; //DS3231模拟I2C时钟控制位SCL


sbit key1=P1^0; //设置键

sbit key4=P3^1; //闹钟设置

sbit key2=P1^4; //加加

sbit key3=P1^7; //减减

sbit SPK=P2^0; //蜂鸣器


sbit IA=P2^7;//行控制线A //138

sbit IB=P2^6;//行控制线B

sbit IC=P2^5;//行控制线C


bit ack; //应答标志位


#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位)



uchar code dis_code[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //时间

uchar data dis_buf[8];

uchar data dis_digit;

uchar line;

uchar wss,key1n,key2n,key3n,tcont,miao,miao1;

uchar temp,sec,min,hou,da,mon,yea,wee,alhou,almin;

//秒 分 时 日 月 年 星期 闹时 闹分


void scan(uchar Value)

{

switch(Value)

{

case 0: IA=0;IB=0;IC=0;break;

case 1: IA=1;IB=0;IC=0;break;

case 2: IA=0;IB=1;IC=0;break;

case 3: IA=1;IB=1;IC=0;break;

case 4: IA=0;IB=0;IC=1;break;

case 5: IA=1;IB=0;IC=1;break;

case 6: IA=0;IB=1;IC=1;break;

case 7: IA=1;IB=1;IC=1;break;

// break;

}

}


uchar BCD2HEX(uchar val) //BCD转换为Byte

{

return ((val>>4)*10)+(val&0x0f);

}


uchar HEX2BCD(uchar val) //B码转换为BCD码

{

return (((val%100)/10)<<4)|(val%10);

}


void delayus(uint us)

{

while (--us);

}


void Start_I2C()

{

SDA=1; //发送起始条件的数据信号

delayus(4);

SCL=1;

delayus(4); //起始条件建立时间大于4.7us,延时

SDA=0; //发送起始信号

delayus(4); // 起始条件锁定时间大于4μs

SCL=0; //钳住I2C总线,准备发送或接收数据

delayus(4);

}


void Stop_I2C()

{

SDA=0; //发送结束条件的数据信号

delayus(4); //发送结束条件的时钟信号

SCL=1; //结束条件建立时间大于4us

delayus(4);

SDA=1; //发送I2C总线结束信号

delayus(4);

}


void SendByte(uchar c)

{

uchar BitCnt;

for(BitCnt=0;BitCnt<8;BitCnt++) //要传送的数据长度为8位

{

if((c<

SDA=1; //判断发送位

else

SDA=0;

delayus(4);

SCL=1; //置时钟线为高,通知被控器开始接收数据位

delayus(4); //保证时钟高电平周期大于4μs

SCL=0;

}

delayus(4);

SDA=1; //8位发送完后释放数据线,准备接收应答位

delayus(4);

SCL=1;

delayus(4);

if(SDA==1)

ack=0;

else

ack=1; //判断是否接收到应答信号

SCL=0;

delayus(4);

}


uchar RcvByte()

{

uchar retc;

uchar BitCnt;

retc=0;

SDA=1; //置数据线为输入方式

for(BitCnt=0;BitCnt<8;BitCnt++)

{

delayus(4);

SCL=0; //置时钟线为低,准备接收数据位

delayus(4); //时钟低电平周期大于4.7μs

SCL=1; //置时钟线为高使数据线上数据有效

delayus(4);

retc=retc<<1;

if(SDA==1)

retc=retc+1; //读数据位,接收的数据位放入retc中

delayus(4);

}

SCL=0;

delayus(4);

return(retc);

}


void Ack_I2C(bit a)

{

if(a==0)

SDA=0; //在此发出应答或非应答信号

else

SDA=1;

delayus(4);

SCL=1;

delayus(4); //时钟低电平周期大于4μs

SCL=0; //清时钟线,钳住I2C总线以便继续接收

delayus(4);

}


uchar write_byte(uchar addr, uchar write_data)

{

Start_I2C();

SendByte(DS3231_WriteAddress);

if (ack == 0)

return 0;

SendByte(addr);

if (ack == 0)

return 0;

SendByte(write_data);

if (ack == 0)

return 0;

Stop_I2C();

delayus(4);

return 1;

}


uchar read_current()

{

uchar read_data;

Start_I2C();

SendByte(DS3231_ReadAddress);

if(ack==0)

return(0);

read_data = RcvByte();

Ack_I2C(1);

Stop_I2C();

return read_data;

}


uchar read_random(uchar random_addr)

{

Start_I2C();

SendByte(DS3231_WriteAddress);

if(ack==0)

return(0);

SendByte(random_addr);

if(ack==0)

return(0);

return(read_current());

}


void ModifyTime(uchar yea,uchar mon,uchar da,uchar hou,uchar min,uchar sec,uchar wee)

{

uchar temp=0;

temp=HEX2BCD(yea);

write_byte(DS3231_YEAR,temp); //修改年

temp=HEX2BCD(mon);

write_byte(DS3231_MONTH,temp); //修改月

temp=HEX2BCD(da);

write_byte(DS3231_DAY,temp); //修改日

temp=HEX2BCD(hou);

write_byte(DS3231_HOUR,temp); //修改时

temp=HEX2BCD(min);

write_byte(DS3231_MINUTE,temp); //修改分

temp=HEX2BCD(sec);

write_byte(DS3231_SECOND,temp); //修改秒


temp=HEX2BCD(wee);

write_byte(DS3231_WEEK,temp); //修星期

}


void SetAlarm(uchar alhou,uchar almin)//修改闹钟1

{

uchar temp = 0;

// temp = HEX2BCD(da);

// write_byte(DS3231_AL1DAY,temp); //修改日

temp = HEX2BCD(alhou);

write_byte(DS3231_ALARM1HOUR,temp); //修改时

temp = HEX2BCD(almin);

write_byte(DS3231_ALARM1MINUTE,temp); //修改分

}


/*void SetA2arm(uchar da,uchar hour,uchar min)//修改闹钟2

{

uchar temp = 0;

temp = HEX2BCD(da);

write_byte(DS3231_AL2DAY,temp); //修改日

temp = HEX2BCD(hour);

write_byte(DS3231_AL2HOUR,temp); //修改时

temp = HEX2BCD(min);

write_byte(DS3231_AL2MIN,temp); //修改分

}*/

void TimeDisplay(uchar Dhour,uchar Dmin,uchar Dsec) //时间

{

if(key2n==2&wss==0) //调时闪烁

{

dis_buf[7]=dis_buf[6]=0;

}

else

{

dis_buf[7]=dis_code[Dhour / 10]; // 时十位

dis_buf[6]=dis_code[Dhour % 10]; // 时个位

}

if(key2n==1&wss==0) //调分闪烁

{

dis_buf[4]=dis_buf[3]= 0;

}

else

{

dis_buf[4]=dis_code[Dmin / 10]; // 分十位

dis_buf[3]=dis_code[Dmin % 10]; // 分个位

}

dis_buf[1]=dis_code[Dsec / 10]; // 秒十位

dis_buf[0]=dis_code[Dsec % 10]; // 秒个位

dis_buf[2]=dis_buf[5]=0x40; // 显示"-"

}



void DateDisplay(uchar Dyear,uchar Dmonth,uchar Dday) //日期

{

if(key2n==5&wss==0) //调年闪烁

{

dis_buf[7]=dis_buf[6]=0;

}

else

{

dis_buf[7]=dis_code[Dyear / 10]; // 年十位

dis_buf[6]=dis_code[Dyear % 10]; // 年个位

}


if(key2n==4&wss==0) //调月闪烁

{

dis_buf[4]=dis_buf[3]=0;

}

else

{

dis_buf[4]=dis_code[Dmonth / 10]; // 月十位

dis_buf[3]=dis_code[Dmonth % 10]; // 月个位

}


if(key2n==3&wss==0) //调天闪烁

{

dis_buf[1]=dis_buf[0]=0;

}

else

{

dis_buf[1]=dis_code[Dday / 10]; // 天十位

dis_buf[0]=dis_code[Dday % 10]; // 天个位

}


dis_buf[2]=dis_buf[5]=0; // 显示" "

}


void TimeDisplay1(uchar xin,uchar T1,uchar T2,uchar T3) //星期,温度

{

if(key2n==6&wss==0) //调星期闪烁

{

dis_buf[6]=0; //星期

}

else

{

dis_buf[6]=dis_code[xin %10]; //星期

}

dis_buf[3]=dis_code[T1 % 11]; //温度十位

dis_buf[2]=dis_code[T2 / 11] | 0x80; //温度个位带点

dis_buf[1]=dis_code[T3 % 11]; //小数位

dis_buf[0]=0x58; //显示c

dis_buf[5]=dis_buf[7]=0x40; //显示"-"

dis_buf[4]=0;

}


void displayAL(uchar alhou,uchar almin) //显示闹钟1

{

dis_buf[7]=0x77; //显示A

dis_buf[6]=0x38; //显示L


if(key3n==2&wss==0) //调时闪烁

{

dis_buf[4]=dis_buf[3]= 0;

}

else

{

dis_buf[4]=dis_code[alhou / 10]; // 时十位

dis_buf[3]=dis_code[alhou % 10]; // 时个位

}

if(key3n==1&wss==0)

{

dis_buf[1]=dis_buf[0]=0; //调分闪烁

}

else

{

dis_buf[1]=dis_code[almin / 10]; // 分十位

dis_buf[0]=dis_code[almin % 10]; // 分个位

}

dis_buf[2]=0x40; // 显示"-"

dis_buf[5]=0x01; // 显示"-"

}


/*void displayAL(uchar A,B) //显示闹钟2

{

smg[0] = 16; // 显示"A" 闹钟

smg[1] = 17; // 显示"L" 闹钟

smg[3] = sz[0]/10; //“时“

smg[4] = sz[0]%10; //“时“

smg[6] = sz[1]/10; //“分“

smg[7] = sz[1]%10; //“分“

sz[0] = A;

sz[1] = B;

smg[2] = 10; // 显示"-"

smg[5] = 10; // 显示"-"

}*/


void get_show_time(void) //时间显示

{

uchar Htemp1,Htemp2,Mtemp1,Mtemp2,Stemp1,Stemp2;

Htemp1=read_random(DS3231_HOUR); //时 24小时制

Htemp1&=0x3f;

Htemp2=BCD2HEX(Htemp1);

Mtemp1=read_random(DS3231_MINUTE); //分

Mtemp2=BCD2HEX(Mtemp1);

Stemp1=read_random(DS3231_SECOND); //秒

Stemp2=BCD2HEX(Stemp1);

TimeDisplay(Htemp2,Mtemp2,Stemp2); //时间显示函数

}


void get_show_date(void) //日期显示

{

uchar Ytemp1,Ytemp2,Mtemp1,Mtemp2,Dtemp1,Dtemp2;

Ytemp1=read_random(DS3231_YEAR); //年

Ytemp2=BCD2HEX(Ytemp1);

Mtemp1=read_random(DS3231_MONTH); //月

Mtemp2=BCD2HEX(Mtemp1);

Dtemp1=read_random(DS3231_DAY); //日

Dtemp2=BCD2HEX(Dtemp1);

DateDisplay(Ytemp2,Mtemp2,Dtemp2); //日期显示函数

}



void get_show_Temperature(void) //温度显示

{

uchar G,G1,Ttemp1,Ttemp2,Ttemp3,Ttemp4;

Ttemp1=read_random(DS3231_TEMPERATUREH); //温度 高字节

Ttemp2=BCD2HEX(Ttemp1);

Ttemp3=read_random(DS3231_TEMPERATUREL); //温度低字节

Ttemp4=BCD2HEX(Ttemp3);


G = read_random(DS3231_WEEK); //星期;

G1=BCD2HEX(G);


TimeDisplay1(G1,Ttemp2,Ttemp4); //星期 温度显示函数

}


/*******************读取闹铃1时间********************/

void ReadAlarm()

{

uchar A,A1,B,B1;

A = read_random(DS3231_ALARM1HOUR); //时

A1 = BCD2HEX(A);


B = read_random(DS3231_ALARM1MINUTE); //分

B1 = BCD2HEX(B);

// temp = read_random(DS3231_AL1DAY); //星期or日

// A = BCD2HEX(temp);

displayAL(A1,B1); //送显示

}

/***************读取闹铃2时间***************/

/*void ReadA2arm()

{

uchar temp,A2,B2,C2;

temp = read_random(DS3231_AL2MIN); //分

C2 = BCD2HEX(temp);

temp = read_random(DS3231_AL2HOUR); //时

B2 = BCD2HEX(temp);

temp = read_random(DS3231_AL2DAY); //星期or日

A2 = BCD2HEX(temp);

display(A2,B2,C2); //送显示

}*/


void didi(void) //按键发音

{

SPK=1;

delayus(5000);

SPK=0;

}


void didial(void) //按键发音

{

SPK=1;

delayus(2000);

SPK=0;

}


void keyal1(void) //查看闹钟

{

// if(key2==0) //查看闹钟1

// {

// zz=0;

// }


/* if(key3==0) //查看闹钟2

{

ReadAlarm();

}*/

}


void key() //调时间函数

{

if(key1==0)

{

delayus(500);

if(key1==0)

{

didi();

key3n=0;

while(!key1);

key2n++;

if(key2n==7)

{

key2n=0;

key1n=0;

miao1=0;

}

if(key2n==1) //调时间显示时间

{

key1n=0;

}

if(key2n==3) //调日期显示日期

{

key1n=6;

}

if(key2n==6) //调星期显示星期

{

key1n=7;

}

}

}


if((key2n==1)&key2==0) //分加加

{

delayus(500);

if(key2==0)

{

didi();

while(!key2);

min++;

if(min==60)min=00;

temp=HEX2BCD(min);

write_byte(DS3231_MINUTE,temp); //修改分

}

}


if((key2n==1)&key3==0) //分减减

{

delayus(500);

if(key3==0)

{

didi();

while(!key3);

min--;

if(min==-1)min=59;

temp=HEX2BCD(min);

write_byte(DS3231_MINUTE,temp); //修改分

}

}


if((key2n==2)&key2==0) //时加加

{

delayus(500);

if(key2==0)

{

didi();

while(!key2);

hou++;

if(hou==24)hou=00;

temp=HEX2BCD(hou);

write_byte(DS3231_HOUR,temp); //修改时

}

}


if((key2n==2)&key3==0) //时减减

{

delayus(500);

if(key3==0)

{

didi();

while(!key3);

hou--;

if(hou==-1)hou=23;

temp=HEX2BCD(hou);

write_byte(DS3231_HOUR,temp); //修改时

}

}

if((key2n==3)&key2==0) //日加加

{

delayus(500);

if(key2==0)

{

didi();

while(!key2);

da++;

if(da==32)da=01;

temp=HEX2BCD(da);

write_byte(DS3231_DAY,temp); //修改日

}

}


if((key2n==3)&key3==0) //日减减

{

delayus(500);

if(key3==0)

{

didi();

while(!key3);

da--;

if(da==-1)da=31;

temp=HEX2BCD(da);

write_byte(DS3231_DAY,temp); //修改日

}

}

if((key2n==4)&key2==0) //月加加

{

delayus(500);

if(key2==0)

{

didi();

while(!key2);

mon++;

if(mon==13)mon=1;

temp=HEX2BCD(mon);

write_byte(DS3231_MONTH,temp); //修改月

}

}


if((key2n==4)&key3==0) //月减减

{

delayus(500);

if(key3==0)

{

didi();

while(!key3);

mon--;

if(mon==-1)mon=12;

temp=HEX2BCD(mon);

write_byte(DS3231_MONTH,temp); //修改月

}

}

if((key2n==5)&key2==0) //年加加

{

delayus(500);

if(key2==0)

{

didi();

while(!key2);

yea++;

if(yea==30)yea=15;

temp=HEX2BCD(yea);

write_byte(DS3231_YEAR,temp); //修改年

}

}


if((key2n==5)&key3==0) //年减减

{

delayus(500);

if(key3==0)

{

didi();

while(!key3);

yea--;

if(yea==14)yea=30;

temp=HEX2BCD(yea);

write_byte(DS3231_YEAR,temp); //修改年

}

}

if((key2n==6)&key2==0) //星期加加

{

delayus(500);

if(key2==0)

{

didi();

while(!key2);

wee++;

if(wee==8)wee=1;

temp=HEX2BCD(wee);

write_byte(DS3231_WEEK,temp); //修改星期

}

}


if((key2n==6)&key3==0) //星期减减

{

delayus(500);

if(key3==0)

{

didi();

while(!key3);

wee--;

if(wee==0)wee=7;

temp=HEX2BCD(wee);

write_byte(DS3231_WEEK,temp); //修改星期

}

}

}


void keyal(void) //调闹钟函数

{

if(key4==0)

{

delayus(500);

if(key4==0)

{

didi();

key1n=9; //显示闹钟

while(!key4);

key3n++;

if(key3n==3)

{

key2n=0;

key3n=0;

key1n=0;

miao1=0;

}

}

}


if((key3n==1)&key2==0) //分加加

{

delayus(500);

if(key2==0)

{

didi();

while(!key2);

almin++;

if(almin==60)almin=0;

temp=HEX2BCD(almin);

write_byte(DS3231_ALARM1MINUTE,temp); //修改分

}

}


if((key3n==1)&key3==0) //分减减

{

delayus(500);

if(key3==0)

{

didi();

while(!key3);

almin--;

if(almin==-1)almin=59;

temp=HEX2BCD(almin);

write_byte(DS3231_ALARM1MINUTE,temp); //修改分

}

}

if((key3n==2)&key2==0) //时加加

{

delayus(500);

if(key2==0)

{

didi();

while(!key2);

alhou++;

if(alhou==24)alhou=0;

temp=HEX2BCD(alhou);

write_byte(DS3231_ALARM1HOUR,temp); //修改时

}

}


if((key3n==2)&key3==0) //时减减

{

delayus(500);

if(key3==0)

{

didi();

while(!key3);

hou--;

if(hou==-1)hou=23;

temp=HEX2BCD(hou);

write_byte(DS3231_ALARM1HOUR,temp); //修改时

}

}

}


void ALzx() //闹钟执行程序与整点报时

{

uchar Y,Z,X,V,W;

X = read_random(DS3231_ALARM1HOUR); //闹钟“时”

V = read_random(DS3231_ALARM1MINUTE); //闹钟“分”

Y = read_random(DS3231_HOUR); //时 24小时制

Z = read_random(DS3231_MINUTE); //分

W = read_random(DS3231_SECOND); //秒

if(((X == Y) && (V == Z))) //如果闹钟时间和时钟时间相同,bz12为闹钟控制位

{

didial(); //闹钟翻转 报警

}

……………………





关键词: DS3231 时钟芯片 RTC 数码管 电子钟

专家
2021-04-11 00:02:40 打赏
2楼

感谢楼主的分享,很实用了。


工程师
2021-04-11 00:11:24 打赏
3楼

感谢楼主的分享,很实用了。


高工
2021-04-11 07:56:30 打赏
4楼

好资料!谢谢楼主分享!



工程师
2021-04-11 17:47:29 打赏
5楼

干货


工程师
2021-04-11 17:52:58 打赏
6楼

感谢了楼主


工程师
2021-04-11 18:01:34 打赏
7楼

学习一下


工程师
2021-04-11 18:08:19 打赏
8楼

感谢分享


工程师
2021-04-11 18:12:41 打赏
9楼

学习到了


工程师
2021-04-11 18:17:09 打赏
10楼

学习到了


共18条 1/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]