一、实验的基本功能:
1.实现时钟系统,在51单片机的液晶显示屏中显示:年月日、时分秒,并且随时间进行跳动 2.实现可调功能,能够调整日期和时间
二、硬件上的准备:
1.DS1302时钟芯片的引脚
·CE芯片使能:控制信号通信的逻辑控制端,相当于逻辑控制的“与门”,51端口P3_5
·IO数据输入输出:信号通信端口,发送命令和数据,51端口P3_4
·SCLK:时序控制端.51端口P3_6
·x1,x2:使DS1302能够不通过写入数据,而自动进行时间增长
2.DS1302通信的时序定义
·分为读写对应的不同的时序过程,内容也分为命令和数据部分
·当CE上沿,整个通信有效,为总控。当传命令时,SCLK上沿表示一位数据有效。 当写数据时,SCLK上沿表示一位数据有效。当读数据时,SCLK下沿表示一位数据有效
3.寄存器定义
对应的读写功能指令,例如:0x81为读取DS1302的存储空间的内容等。可读写年月日,时分秒
三、代码实现的功能函数(当头文件)
DS1302S涉及的函数
1.void DS1302_Init(void) 调控总控制端,实现CE上沿
2.void DS1302_WriteByte(unsigned char Command,Data) 实现写入数据到寄存器中(包含命令和数据)
3.unsigned char DS1302_ReadByte(unsigned char Command)实现读入数据到电脑中(包含命令和数据)注意的数据是下沿有效
4.void DS1302_SetTime(void)实现设置DS1302初始时间,主要调用存储数组的值
5.void DS1302_ReadTime(void)实现读取DS1302寄存器的时间
6.void TimeShow(void)实现显示时间到51液晶显示屏上
7.void TimeSet(unsigned char KeyNum)实现设置DS1302的值,主要通过外部设备进行改动数组的值
8.void TimeSet(unsigned char KeyNum);实现调控中间数组的数据,实现时钟调控功能
9.void Timer0_Routine() interrupt 1调用定时器的中断代码,实现调空的数据定时闪烁
由于涉及LCD1602液晶显示和独立按键、定时器,所以调用LCD1602.h和keyboad.h,Timer0.h等头文件
四、代码演示和解释说明
1.端口的调用和地址的重置命名
sbit DS1302_SCLK = P3^6; //时序端口
sbit DS1302_IO = P3^4; //输入输出端
sbit DS1302_CE = P3^5; //使能控制端
//写入命令指令
#define DS1302_SECOND 0x80 //写入秒
#define DS1302_MINUTE 0x82 //写入分钟
#define DS1302_HOUR 0x84 //写入小时
#define DS1302_DATE 0x86 //写入日
#define DS1302_MONTH 0x88 //写入月
#define DS1302_DAY 0x8A //写入星期
#define DS1302_YEAR 0x8C //写入年
#define DS1302_WP 0x8E //写保护状态
·将51端口和写入命令的指令进行重置命名,实现更加清晰化及调用更加方便,提升代码的阅读性
2.变量定义
unsigned char DS1302_Time[] = {23,3,21,10,29,30,2};
unsigned char TimeSelect,TimeSetFlashFlag;
·DS1302_Time[]:中间存储变量,将从DS1302的数据读出的储存空间,显示数据将其读出即可
·TimeSelect:用于调控时钟数据,即更改DS1302_Time[]的数据
·TimeSetFlashFlag:调控的数字进行闪烁的控制端
3.配置总控制端CE,实现初始化
void DS1302_Init(void)
{
DS1302_CE = 0;
DS1302_SCLK = 0;
}
·将使能端先置零,为使能端上沿做准备,也防止了CE开始为1的可能
4.写入数据到DS1302寄存器中
void DS1302_WriteByte(unsigned char Command,Data)
{
unsigned char i;
DS1302_CE = 1; //使能端置1,表时序过程有效
//写入命令指令
for (i = 0;i < 8;i++)
{
DS1302_IO = Command & (0x01<<i);//传入一位比特位放入IO,0x01与Command进行位运算,Command对应的位为1就是1,0就是0
DS1302_SCLK = 1; //开始SCLK就是0,置1代表数据有效,再置0恢复状态
DS1302_SCLK = 0;
}
//写入数据
for(i = 0;i<8;i++)
{
DS1302_IO = Data & (0x01<<i);
DS1302_SCLK = 1;
DS1302_SCLK = 0;
}
DS1302_CE = 0;
}
·写入数据到DS1302存储器件中,写入命令指令和数据都是向上沿有效
·程序将信号输入到I0口上,DS1302接收数据无需关心
·命令和数据是分开的传入IO口
·写到哪里和读到哪里,是由写命令控制
5.读入数据到电脑中
unsigned char DS1302_ReadByte(unsigned char Command)
{
unsigned char i ,Data = 0x00;
//第0位表示读写,0为写,1位读
Command |= 0x01;//设置读的功能,能运用define
DS1302_CE = 1;
for(i = 0;i < 8;i++)
{
DS1302_IO = Command & (0x01<<i);
DS1302_SCLK = 0; //与上述相同,改变0/1位置,但效果不变,使读数据的下沿有效,不产生冲突
DS1302_SCLK = 1;
}
//读出数据
for(i = 0;i < 8;i++)
{
DS1302_SCLK = 1;
DS1302_SCLK = 0;
if(DS1302_IO) {Data |= (0x01<<i);} //当DS1302_IO为1时,Data对应的位置置1,当DS1302_IO为0时,Data为0
}
DS1302_CE = 0;
DS1302_IO = 0; //能解决数据不稳定的问题
return Data;
}
·读出数据,包含写入命令指令(上沿有效),读出数据(下沿有效)
·无需关心DS1302怎么发出数据的,当指令写入读数据时,DS1302开始写入数据,只需接收即可
·写到哪里和读到哪里,是由写命令控制
6.设置DS1302初始时间,主要调用存储数组的值
void DS1302_SetTime(void)
{ //十进制转BCD码后写入
DS1302_WriteByte(DS1302_WP,0x00);
DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);
DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
DS1302_WriteByte(DS1302_WP,0x80);
}
·调用前面的DS1302_WriteByte(),将数组的数据全部写入DS1302中
·DS1302接收的数据为16进制数据,所以要将十进制数据转成十六进制数据
7.实现读取DS1302寄存器的时间
void DS1302_ReadTime(void)
{ //BCD码转十进制后读取
unsigned char Temp;
Temp=DS1302_ReadByte(DS1302_YEAR);
DS1302_Time[0]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_MONTH);
DS1302_Time[1]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_DATE);
DS1302_Time[2]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_HOUR);
DS1302_Time[3]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_MINUTE);
DS1302_Time[4]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_SECOND);
DS1302_Time[5]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_DAY);
DS1302_Time[6]=Temp/16*10+Temp%16;
}
·功能是将DS1302的数据读到数组里,调用DS1302_ReadTime()
·数组采用的十进制输入,是因为LCD1602调用的是显示十进制数,所以将读出来十六进制转十进制
8.实现显示时间到51液晶显示屏上
void TimeShow(void)
{
DS1302_ReadTime();//读取时间
LCD_ShowNum(1,1,DS1302_Time[0],2);//显示年
LCD_ShowNum(1,4,DS1302_Time[1],2);//显示月
LCD_ShowNum(1,7,DS1302_Time[2],2);//显示日
LCD_ShowNum(2,1,DS1302_Time[3],2);//显示时
LCD_ShowNum(2,4,DS1302_Time[4],2);//显示分
LCD_ShowNum(2,7,DS1302_Time[5],2);//显示秒
}
·调用LCD1602功能显示中间数组的数据,即实现显示时钟的功能部分
9.实现调控中间数组的数据,实现时钟调控功能
void TimeSet(unsigned char KeyNum)
{
//选择数组位置
if(KeyNum == 2)
{
TimeSelect++;
TimeSelect %= 6;
}
//加对应的值
if(KeyNum == 3)
{
DS1302_Time[TimeSelect]++;
if(DS1302_Time[0]>99){DS1302_Time[0]=0;}//年越界判断
if(DS1302_Time[1]>12){DS1302_Time[1]=1;}//月越界判断
if( DS1302_Time[1]==1 || DS1302_Time[1]==3 || DS1302_Time[1]==5 || DS1302_Time[1]==7 ||
DS1302_Time[1]==8 || DS1302_Time[1]==10 || DS1302_Time[1]==12)//日越界判断
{
if(DS1302_Time[2]>31){DS1302_Time[2]=1;}//大月
}
else if(DS1302_Time[1]==4 || DS1302_Time[1]==6 || DS1302_Time[1]==9 || DS1302_Time[1]==11)
{
if(DS1302_Time[2]>30){DS1302_Time[2]=1;}//小月
}
else if(DS1302_Time[1]==2)
{
if(DS1302_Time[0]%4==0)
{
if(DS1302_Time[2]>29){DS1302_Time[2]=1;}//闰年2月
}
else
{
if(DS1302_Time[2]>28){DS1302_Time[2]=1;}//平年2月
}
}
if(DS1302_Time[3]>23){DS1302_Time[3]=0;}//时越界判断
if(DS1302_Time[4]>59){DS1302_Time[4]=0;}//分越界判断
if(DS1302_Time[5]>59){DS1302_Time[5]=0;}//秒越界判断
}
//减对应的值
if(KeyNum == 4)
{
DS1302_Time[TimeSelect]--;
if(DS1302_Time[0]<0){DS1302_Time[0]=99;}//年越界判断
if(DS1302_Time[1]<1){DS1302_Time[1]=12;}//月越界判断
if( DS1302_Time[1]==1 || DS1302_Time[1]==3 || DS1302_Time[1]==5 || DS1302_Time[1]==7 ||
DS1302_Time[1]==8 || DS1302_Time[1]==10 || DS1302_Time[1]==12)//日越界判断
{
if(DS1302_Time[2]<1){DS1302_Time[2]=31;}//大月
if(DS1302_Time[2]>31){DS1302_Time[2]=1;}
}
else if(DS1302_Time[1]==4 || DS1302_Time[1]==6 || DS1302_Time[1]==9 || DS1302_Time[1]==11)
{
if(DS1302_Time[2]<1){DS1302_Time[2]=30;}//小月
if(DS1302_Time[2]>30){DS1302_Time[2]=1;}
}
else if(DS1302_Time[1]==2)
{
if(DS1302_Time[0]%4==0)
{
if(DS1302_Time[2]<1){DS1302_Time[2]=29;}//闰年2月
if(DS1302_Time[2]>29){DS1302_Time[2]=1;}
}
else
{
if(DS1302_Time[2]<1){DS1302_Time[2]=28;}//平年2月
if(DS1302_Time[2]>28){DS1302_Time[2]=1;}
}
}
if(DS1302_Time[3]<0){DS1302_Time[3]=23;}//时越界判断
if(DS1302_Time[4]<0){DS1302_Time[4]=59;}//分越界判断
if(DS1302_Time[5]<0){DS1302_Time[5]=59;}//秒越界判断
}
if(TimeSelect==0 && TimeSetFlashFlag==1){LCD_ShowString(1,1," ");}
else {LCD_ShowNum(1,1,DS1302_Time[0],2);}
if(TimeSelect==1 && TimeSetFlashFlag==1){LCD_ShowString(1,4," ");}
else {LCD_ShowNum(1,4,DS1302_Time[1],2);}
if(TimeSelect==2 && TimeSetFlashFlag==1){LCD_ShowString(1,7," ");}
else {LCD_ShowNum(1,7,DS1302_Time[2],2);}
if(TimeSelect==3 && TimeSetFlashFlag==1){LCD_ShowString(2,1," ");}
else {LCD_ShowNum(2,1,DS1302_Time[3],2);}
if(TimeSelect==4 && TimeSetFlashFlag==1){LCD_ShowString(2,4," ");}
else {LCD_ShowNum(2,4,DS1302_Time[4],2);}
if(TimeSelect==5 && TimeSetFlashFlag==1){LCD_ShowString(2,7," ");}
else {LCD_ShowNum(2,7,DS1302_Time[5],2);}
}
·通过独立按键相应,来实现对应的功能
例如: KeyNum = 2对应的TimeSelect就会加1,对应LCD1602的数据闪烁位置改变
KeyNum = 3 和 KeyNum = 4对应的数组的DS1302_Time[TimeSelect]的数值加1或减1
KeyNum = 1 改变时钟模式:调控和不调控
·解决时间进位的问题(调控的进位):需要注意的是月份分大月和小月,大月31进,小月30进。
·年又份润年和平年,润年2月29天,平年28。
·再每次加1之,判断是否越界.KeyNum = 3 或 4 都要判断一下,代码重复,可封装
10.实现调空的数据定时闪烁
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18;
TH0 = 0xFC;
T0Count++;
if(T0Count>=500)
{
T0Count=0;
TimeSetFlashFlag=!TimeSetFlashFlag;
}
}
·实现定时闪烁,定时可满足,规定时间掉用中断函数,闪烁接收空白和 显示交替,所以再判断越界结束,
·执行这部分代码,先将LCD1602显示空白,再显示数据即可
五、mian函数运行
#include "DS1302.h"
#include "LCD1602.h"
#include "Timer0.h"
#include "Keyboard.h"
#include <REGX52.H>
unsigned char KeyNum,Mode;
void main()
{
LCD_Init();
DS1302_Init();
Timer0_Init();
LCD_ShowString(1,1," - - ");//?????????
LCD_ShowString(2,1," : : ");
DS1302_SetTime();
while(1)
{
KeyNum = SmallKey();
if(KeyNum == 1) //????,????
{
if(Mode == 0){Mode = 1;}
else if (Mode == 1){Mode = 0;}
}
switch(Mode)
{
case 0:TimeShow();break;
case 1:TimeSet(KeyNum);break;
}
}
}
·初始化模块的功能,使对应的模块可以使用,调用对应的功能的模块
今天的文章51单片机实验一:实现时钟功能(基础)分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/16246.html