本文是在学习江科大51单片机DS1302定时器教程后所做的笔记
所用软件 μvision4
DS1302定时器流程图
![](https://img-blog.csdnimg.cn/img_convert/ed60aea3b99002ea819eab45ff49c5c2.jpeg)
DS1302
是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能
引脚定义和应用电路
![](https://img-blog.csdnimg.cn/img_convert/3efd2cfdd4f784937a9115308153bd7e.png)
图1
内部结构图
![](https://img-blog.csdnimg.cn/img_convert/6959764449386ab73d4cf77f7678e1a3.png)
图2
寄存器的定义
![](https://img-blog.csdnimg.cn/img_convert/a53ec504a028e88075e4f9ada1dd5e8a.png)
图3
![](https://img-blog.csdnimg.cn/img_convert/927f08fdd400013e8811cbf3e3fb7a11.png)
图4
如何配置寄存器
配置寄存器需配置8位
READ 读取所调用的地址,例如我想读取此时DS1302芯片中的时间
unsigned char DS1302_ReadByte(unsigned char Command)//读取字节
{
unsigned char i,Data=0x00;
Command |= 0x01; //将传入的Command地址第一位置为1,变成READ的地址
DS1302_CE=1;
for(i=0;i<8;i++)
{
DS1302_IO=Command&(0x01<<i); //原理同DS1302_WriteByte
DS1302_SCLK=0;
DS1302_SCLK=1;
}
for(i=0;i<8;i++)
{
DS1302_SCLK=1;
DS1302_SCLK=0;
if(DS1302_IO){Data|=(0x01<<i);}
}
DS1302_CE=0;
return Data; //将读取到的时间的BCD码return
}
WRITE 写入所调用的地址
void DS1302_WriteByte(unsigned char Command,Data)//这个是根据图4的时序图写的"写入字节函数"
{
unsigned char i;
DS1302_CE=1;
for(i=0;i<8;i++)
{
DS1302_IO=Command&(0x01<<i); //从右边数,将Command里的第i个位赋予IO,依次左移
DS1302_SCLK=1;
DS1302_SCLK=0;
}
for(i=0;i<8;i++) //从右边数,将Data里的第i个位赋予IO,依次左移
{
DS1302_IO=Data&(0x01<<i);
DS1302_SCLK=1;
DS1302_SCLK=0;
}
DS1302_CE=0;
}
BCD码
DS1302里是用BCD码储存的时间,即四个字节代表一个十进制的数
因此对DS1302执行一些操作时要将BCD码转为十进制,公式如下:
![](https://img-blog.csdnimg.cn/img_convert/86a5ab831d338a15a77e1baa34ead901.png)
源文件编写
以下是调用的.h文件与.c文件,是我跟着江科大的一起敲的,在共享一下:
DS1302.h源码
#ifndef _DS1302_H_
#define_DS1302_H_
extern unsigned char DS1302_Time[];
void DS1302_Init(void);
void DS1302_WriteByte(unsigned char Command,Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_ReadTime(void) ;
void DS1302_SetTime(void);
#endif
DS1302.c源码
#include <REGX52.H>
sbit DS1302_SCLK = P3^6;
sbit DS1302_IO = P3^4;
sbit DS1302_CE = P3^5;
//这部分是图3时间地址的重定义,是为了后续方便操作
#define DS1302_Second 0x80
#define DS1302_Minutes 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
unsigned char DS1302_Time[]={23,2,23,9,16,30,1};//用一个数组存放十进制的时间
void DS1302_Init()
{
DS1302_CE=0;
DS1302_SCLK=0;
}
//以下是基于时序图编写的读取和写入DS1302芯片的代码
//DS1302_WriteByte字节写入 DS1302_ReadByte字节读取
//Command是写入时间的地址,Data是写入的时间数据(BCD码)
//DS1302_WriteByte 根据图4的时序图写的"写入字节函数"
void DS1302_WriteByte(unsigned char Command,Data)
{
unsigned char i;
DS1302_CE=1;
for(i=0;i<8;i++)
{
DS1302_IO=Command&(0x01<<i); //从右边数,将Command里的第i个位赋予IO,依次左移
DS1302_SCLK=1;
DS1302_SCLK=0;
}
for(i=0;i<8;i++) //从右边数,将Data里的第i个位赋予IO,依次左移
{
DS1302_IO=Data&(0x01<<i);
DS1302_SCLK=1;
DS1302_SCLK=0;
}
DS1302_CE=0;
}
unsigned char DS1302_ReadByte(unsigned char Command)//读取字节
{
unsigned char i,Data=0x00;
Command |= 0x01; //将传入的Command地址第一位置为1,变成READ的地址
DS1302_CE=1;
for(i=0;i<8;i++)
{
DS1302_IO=Command&(0x01<<i); //原理同DS1302_WriteByte
DS1302_SCLK=0;
DS1302_SCLK=1;
}
for(i=0;i<8;i++)
{
DS1302_SCLK=1;
DS1302_SCLK=0;
if(DS1302_IO){Data|=(0x01<<i);}
}
DS1302_CE=0;
return Data; //将读取到的时间的BCD码return
}
// DS1302_SetTime 封装了DS1302_WriteByte,将DS1302的年月日等等全部设置
void DS1302_SetTime(void) //存入十六进制的日期
{
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_Minutes,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,0x00); //关闭写入保护
}
// DS1302_ReadTime 封装了DS1302_ReadByte,将数组中的时间数据更新
void DS1302_ReadTime(void)
{
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_Minutes);
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;
}
main.c源码
#include <REGX52.H>
#include "DS1302.h"
#include "LCD1602.h"
#include "Timer0.h"
#include "MatrixKey.h"
#include "Key.h"
unsigned char KeyNum,Mode=0,TimeSetSelect=0,TimeSetFlashFlag;
void Time_Show()
{
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);
}
void Time_Set()
{
//判断模式选择按钮是否按下
if(KeyNum==2)
{
TimeSetSelect++;
TimeSetSelect%=6;
}
//加减年月日判断
if(KeyNum==3)
{
DS1302_Time[TimeSetSelect]++;
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;}
}
else
{
if(DS1302_Time[2]>28){DS1302_Time[2]=1;}
}
}
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[TimeSetSelect]--;
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;}
if(DS1302_Time[2]>29){DS1302_Time[2]=1;}
}
else
{
if(DS1302_Time[2]<1){DS1302_Time[2]=28;}
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(TimeSetSelect==0 && TimeSetFlashFlag==1){LCD_ShowString(1,1," ");}
else{LCD_ShowNum(1,1,DS1302_Time[0],2);}
if(TimeSetSelect==1 && TimeSetFlashFlag==1){LCD_ShowString(1,4," ");}
else{LCD_ShowNum(1,4,DS1302_Time[1],2);}
if(TimeSetSelect==2 && TimeSetFlashFlag==1){LCD_ShowString(1,7," ");}
else{LCD_ShowNum(1,7,DS1302_Time[2],2);}
if(TimeSetSelect==3 && TimeSetFlashFlag==1){LCD_ShowString(2,1," ");}
else{LCD_ShowNum(2,1,DS1302_Time[3],2);}
if(TimeSetSelect==4 && TimeSetFlashFlag==1){LCD_ShowString(2,4," ");}
else{LCD_ShowNum(2,4,DS1302_Time[4],2);}
if(TimeSetSelect==5 && TimeSetFlashFlag==1){LCD_ShowString(2,7," ");}
else{LCD_ShowNum(2,7,DS1302_Time[5],2);}
//LCD_ShowNum(2,10,TimeSetSelect,2);
//LCD_ShowNum(2,13,TimeSetFlashFlag,2);
}
void main()
{
LCD_Init();
DS1302_Init();
Timer0_Init();
LCD_ShowString(1,1," - - ");
LCD_ShowString(2,1," : : ");
DS1302_SetTime();
while(1)
{
KeyNum=Key();
if(KeyNum==1)
{
if(Mode==0){Mode=1;TimeSetSelect=0;}
else if (Mode==1){Mode=0;DS1302_SetTime();}
}
switch(Mode)
{
case 0:Time_Show();break;
case 1:Time_Set();break;
}
}
}
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=500)//ms
{
T0Count=0;
TimeSetFlashFlag=!TimeSetFlashFlag;
}
}
如有不太懂的同学可以观看视频:江科大51单片机DS1302定时可调时钟
受码龄6年的大佬大一同学口头训话,说学这一块一定要写博客
因此,作者这是作者的第二篇博客,也逐渐了解到,写博客不仅仅是对所学知识作的笔记,更是一种思考、归纳与提高。
2023.2.24
21:51
于深圳大学机电与控制工程学院ROS俱乐部