时钟
DS1302 时钟芯片。开发板上已经集成的芯片,本次实验目的是用数码管显示出当前时间,以hh-mm-ss的格式。

VCC2:电源
VCC1:备用电源,即单片机断电后维持时钟继续运行的。STC89C52 是没有的,即断电就停止运行。
X1X2:晶振。
CE:使能。
IO:输入输出。
SCLK:时钟。
操作流程就是将数据写入 DS1302 的寄存器来设置当前时间格式,然后 DS1302 时钟运作后我们再将寄存器中数据读出。
DS1302 中存储顺序是秒分时日月周年,存储格式是 BCD 码。

首先,CE/RST在整个读写过程中要保持是高电平,一次字节读写完毕后要返回低电平。
然后,控制指令字输入后的下一个 SCLK 上升沿数据写入,下降沿数据读出,在图中可以看得出来,都是从低位0先读,最后出高位7. 第一位代表读或写,后四位代表地址(年、月、日、时、分、秒有着不同的地址),R/C 代表存取 RAM 数据还是读取时钟数据。最高位只有=1才能启用时钟。后面八位是读或写的数据。
读时序注意:因此写命令的第八个上升沿结束后,紧接着第八个下降沿就开始读数据了。
写时序注意:先关闭写保护 WP,1是只读,0才可以写。

我们先试着写入一个秒初值,然后读取时钟里的秒数值,应该是1s一加。
记得 BCD 码和十进制的转换。

#include"REG52.H"
#include"LCD1602.h"
sbit DS1302_CLK=P3^6;//时钟管脚
sbit DS1302_CE=P3^5;//复位管脚
sbit DS1302_IO=P3^4;//数据管脚
typedef unsigned char u8;
void ds1302Init(){
DS1302_CE=0;
DS1302_CLK=0;
}
void ds1302WriteByte(u8 command,u8 dat)
{
u8 i;
DS1302_CE=1;
for(i=0;i<8;i++)
{
DS1302_IO=command&(0x01<<i);//从低到高写入数据
DS1302_CLK=1;
DS1302_CLK=0;
//需要查询最小执行时间。不过这里执行时间都大于最小时间了。
}
for(i=0;i<8;i++)
{
DS1302_IO=dat&(0x01<<i);//从低到高写入数据
DS1302_CLK=1;
DS1302_CLK=0;
//需要查询最小执行时间。不过这里执行时间都大于最小时间了。
}
DS1302_CE=0;
}
u8 ds1302ReadByte(u8 command)
{
u8 i;
u8 dat=0x00;//全局变量会有初值0,局部变量不会。data 是要写入的数据
DS1302_CE=1;
for(i=0;i<8;i++)
{
DS1302_IO=command&(0x01<<i);//从低到高写入数据
DS1302_CLK=0;
DS1302_CLK=1;//这里为什么和 write 是相反的?因为我们注意到 read 是先上升沿读入8位,再切换为下降沿读入8位。、
//如果还是先1后0,读入第8位时不仅会把上升沿读掉,下降沿也会读掉,导致错过第九位。
//需要查询最小执行时间。不过这里执行时间都大于最小时间了。
}
for(i=0;i<8;i++)
{
DS1302_CLK=1;
DS1302_CLK=0;
//需要查询最小执行时间。不过这里执行时间都大于最小时间了。
if(DS1302_IO)dat|=(0x01<<i);//从低到高写入数据
}
DS1302_CE=0;
DS1302_IO=0;//读取前要归0,因为内部是以 BCD 码格式存储。
return dat;
}
void main(){
u8 second;
LCD_Init();
ds1302Init();
//ds1302WriteByte(0x8E,0x00);//如果读出数据>59,可能是处于 wp 写保护,需要通过这句关闭
ds1302WriteByte(0x80,0x01);//写入55s,就是0x55,与内部BCD码对应
LCD_ShowString(1,1,"DS1302");
second=ds1302ReadByte(0x81);
while(1){LCD_ShowNum(2,1,second/16*10+second%16,3);}
}
写入其他变量时分秒都一样。就是更换不同的地址。
不过全部定义变量明显太麻烦。可以先 define 定义了所有地址,再定义一个数组存所有值。
u8 ds1302_address[7]={0x80, 0x82, 0x84, 0x86, 0x88, 0x8c};// second, minute, hour, date, month, year
u8 ds1302_time[7]={0x55, 0x59, 0x11, 0x07, 0x02, 0x23};
void main(){
u8 i;
u8 time_temp[6];
u8 temp;
LCD_Init();
ds1302Init();
//ds1302WriteByte(0x8E,0x00);//如果读出数据>59,可能是处于 wp 写保护,需要通过这句关闭
ds1302WriteByte(0x80,0x01);
ds1302WriteByte(0x82,0x37);
for(i=0;i<6;i++){
ds1302WriteByte(ds1302_address[i], ds1302_time[i]);
}
LCD_ShowString(1,1," - - ");
LCD_ShowString(2,1," : : ");
while(1){
for(i=0;i<6;i++){
temp=ds1302ReadByte(ds1302_address[i]+1);
time_temp[i]=temp/16*10+temp%16;
}
for(i=0;i<6;i++){
LCD_ShowNum(1+i/3,1+3*(i%3), time_temp[5-i],2);
}
//LCD_ShowNum(2,1,minute/16*10+minute%16,2);
//LCD_ShowNum(2,3,second/16*10+second%16,2);
}
}
然后我们让按键可以修改时钟值,这样用户可以手动更改时钟。
按键1切换切换要调整的位,按键2切换回第0位,按键3+1,按键4-1.
难点主要在于+ -的溢出情况。这里我们不考虑秒+1进位对分钟或小时等影响,大多数闹钟也是这样设计的。59+1就归零,0-1就变59.
if(key){
switch(key){
case KEY1_PRESS: time_set_select=0;break;
case KEY2_PRESS: time_set_select=(time_set_select+1)%6;break;
case KEY3_PRESS:
if(time_set_select<=1&&ds1302_time[time_set_select]==59){//second, minute 59-00
ds1302_time[time_set_select]=0;
}
else if(time_set_select==2&&ds1302_time[time_set_select]==23)ds1302_time[time_set_select]=0;//hour 23-00
else if(time_set_select==3&&ds1302_time[time_set_select]==maxDate(ds1302_time[3],ds1302_time[4],ds1302_time[5]))ds1302_time[time_set_select]=1;//date 超过最大日期 -01
else if(time_set_select==4&&ds1302_time[time_set_select]==12)ds1302_time[time_set_select]=1;//month 12-00
else if(time_set_select==5&&ds1302_time[time_set_select]==99)ds1302_time[time_set_select]=0;//year 99-00
else ds1302_time[time_set_select]++;break;
case KEY4_PRESS:
if((ds1302_time[time_set_select]&&time_set_select!=3&&time_set_select!=4)
||ds1302_time[time_set_select]>1)ds1302_time[time_set_select]--;//date month!=0
else if(time_set_select<=1)ds1302_time[time_set_select]=59;
else if(time_set_select==2)ds1302_time[time_set_select]=23;
else if(time_set_select==3)ds1302_time[time_set_select]=maxDate(ds1302_time[3],ds1302_time[4],ds1302_time[5]);
else if(time_set_select==4)ds1302_time[time_set_select]=12;
else if(time_set_select==5)ds1302_time[time_set_select]=99;
break;
}
if(key>=3)timeSet();
计算日期最大值函数:
u8 maxDate(u8 date, u8 month,u8 year){
if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)return 31;
else if((month==4||month==6||month==9||month==11)&&date==31)return 30;
else if(year%4)return 28;
else if(year%4==0&&year%100)return 28;
else return 29;
}
有个弊端就是不知道现在在操作哪一位(只能自己记住)。可以利用定时器的定时闪烁,让在被操作的位不停闪烁。(重复写入空格或数值。)
还有就是按下按键,时钟会停走,不松开就一直停着。可以改按键触发条件为按下或弹起的上升沿或下降沿,避免按键处理函数死循环。
DS1302时钟芯片与数码管显示时间实现
本文介绍了如何使用DS1302时钟芯片通过数码管显示当前时间,包括芯片的工作原理,如VCC电源、晶振、CE、IO和SCLK引脚的作用,以及读写时序。代码示例展示了初始化、写入和读取时间的函数,同时提到了按键修改时钟值的实现思路,强调了处理溢出和写保护的问题。
7538

被折叠的 条评论
为什么被折叠?



