说明
本人使用的是清翔的51单片机开发板,如果型号相同最方便,但是如果型号不同也可以参考,因为芯片都是一样的,只是外设不同而已,使用时只需要对照自己的开发板原理图稍微修改下引脚即可。
|
本次笔记对应视频教程的第44,45集 实时时钟DS1302(理论+实践)
如果笔记之中有任何错误,请在评论区指出,谢谢
一、DS1302
1.1 简介
1.2 引脚图
引脚功能
DS1302与单片机相连只需要3根线:I/O, CE, SCLK
1.3 参考电路
芯片5,6,7引脚接单片机
开发板上的原理图为
1.4 结构框图
1.5 控制方法
1.6 时序图
注意,由于数据是从最低位开始传输的,因此要注意顺序
1.7 数据地址
DS1302的数据要用BCD码,最常用的是8421(如无特殊说明,以下BCD码均指8421码),也就是用4位二进制表示1位十进制数,这四位二进制从高到低表示十进制的8 4 2 1,比如数字7=4+2+1,那么用8421码表示就是0111,注意BCD码只能表示1位十进制数字,也就是0~9,要表示多位,每一位都要用BCD码表示,比如37,就要分成3和7分别表示,3的BCD码是0011,7的BCD码是0111,那么37的BCD码就是0011 0111。
前段时间看数字电路教材刚好看到了,就弄张图来看看
主要就看这个表就行,意思就是我说的那个意思
1.8 寄存器的介绍
涓流充电控制寄存器
涓流充电结构图
数据手册给的一个不太直观的图
其中B. RAM部分就是PPT中的这个表
瞬间就直观了
1.9 突发模式
二、编程
2.1 创建工程
复制上一份工程文件夹,修改名称为“16.实时时钟DS1302”,进入项目文件夹,打开工程文件,删除main.c函数的内容。
2.2 main.c
main.c里面写一下函数定义,比如发送,读取函数,突发模式函数等,以及main函数
先给出一些相关函数
1. 发出1个字节(只管在数据引脚上发送,不管CE(也就是TRST)是否为高电平)
/**********************************************************************************/
/************************* DS1302 *********************************************/
/**********************************************************************************/
//只管发送1个字节过去,前期准备需要在调用的时候写
void DS1302_WChar(uchar dat)
{
uchar i;
for (i = 0; i < 8; i++)
{
TSCLK = 0;
TI0 = dat & 0x01;
TSCLK = 1; //上升沿,数据被DS1302读取
dat >>= 1; //数据从最低位开始传输
}
}
2.发送一条写入命令并写入给出的数值,这里要调用2次刚才的函数,并且要控制CE(TRST的高低电平)
void DS1302_Write(uchar cmd, uchar dat)
{
TRST = 0;
TRST = 1;
DS1302_WChar(cmd);
DS1302_WChar(dat);
TRST = 0;
}
3.读取1字节的函数,需要给出命令,并接收数据线上的值
uchar DS1302Read(uchar cmd)
{
ucahr i,dat;//读取数据使用
TRST = 0;
TRST = 1;
DS1302_WChar(cmd);//发送读数据命令
for (i = 0; i < 8; i++)
{
TSCLK = 0;//产生下降沿,让DS1302输出数据
dat >>= 1;
dat |= (TIO << 7);
TSCLK = 1;//拉高时钟,准备下一次下降沿产生
}
return (dat);
}
下面两个是数据转BCD码以及BCD码转数字,这两个视频教程里面写的太复杂不好理解,我修改了一下,在CodeBlock验证过是正确的。转换解释在代码里面注释部分,我就不再写一遍了,已经注释非常清晰了。
//数据转换BCD码
uchar dat2BCD(uchar dat)
{
//十位左移4位,加上个位,由于十位和个位都是0~9的数,所以十位和个位都是只占用了8位二进制的低4位,
//而低4位又是按照8421排列的,只需要把十位左移到个位前面,就得到了BCD码
return ((dat/10<<4) + (dat%10));
}
//BCD码转换数据
ucahr BCD2dat(uchar dat)
{
//BCD码的高4位是十位,低4位是个位,只需要把高4位(十位)取出来×10再加上低4位(个位)就得到原来的数值
return ((dat>>4)*10 + (dat&0x0f));
}
展示一下视频的代码,瞬间觉得我的代码眉清目秀了,视频里面的代码我理解了好一会儿才明白他什么意思,为什么能这样做,视频里也没解释清楚直接说这样就得到了BCD码
//数据转BCD码
uchar Dat_Chg_BCD(uchar dat)
{
uchar dat1, dat2;
dat1 = dat / 10;
dat2 = dat % 10;
dat2 = dat2 + dat1 * 16;
return dat2;
}
//BCD码转换为数据
uchar BCD_Chg_Dat(uchar dat)
{
uchar dat1, dat2;
dat1 = dat / 16;
dat2 = dat % 16;
dat2 = dat2 + dat1 * 10;
return dat2;
}
main函数如下
void main()
{
ucahr second,minute,hour;
uchar i;
DS1302_Write(0x8e,0x00);//关闭写保护
DS1302_Write(0x80,dat2BCD(30));//在秒寄存器写入30
DS1302_Write(0x82,dat2BCD(15));
DS1302_Write(0x84,dat2BCD(19));
DS1302_Write(0x8e,0x80);//打开写保护
while (1)
{
DS1302_Write(0x8e,0x00);//关闭写保护
second = BCD2dat(DS1302Read(0x81));
minute = BCD2dat(DS1302Read(0x83));
hour = BCD2dat(DS1302Read(0x85));
DS1302_Write(0x8e,0x80);//打开写保护
for (i = 0; i < 50; i++)
{
SEG_DIS(1,hour/10);
SEG_DIS(2,hour%10);
SEG_DIS(2,22);
SEG_DIS(3,minute/10);
SEG_DIS(4,minute%10);
SEG_DIS(4,22);
SEG_DIS(5,second/10);
SEG_DIS(6,second%10);
}
}
}
在while循环前面几行写入数据时,直接写入了秒,分,小时的数据,而并没有考虑要设置秒寄存器的 BIT7 定义为时间暂停位,以及是否设置12/24小时模式,是因为我这里面的BCD代码转换只写了转换2位的,而并没有写转换3位的(配置最高位时是一个3位数),而寄存器低位才是真正存放数据的位置,所以我们代码没改变BIT7。写入的数据全放在了存放数据的位置。
所以如果想要配置他们,需要自己修改BCD转换代码,三位数,每位数用4个二进制表示,那么就需要12位来表示,所以返回值应该是一个int类型,然后自己在根据转换2位数的思路去转换3位数,然后还要修改一下发送部分代码,让它能发送12位。
如果就是普通使用,其实直接设置年月日,默认24小时制也够用了。
2.3 main.h
/************************************************ DS1302 *******************/
sbit TSCLK = P1^0;
sbit TIO = P1^1;
sbit TRST = P1^2;
/************************************************ 定义数据类型 *******************/
typedef unsigned char uchar;
typedef unsigned char ucahr;
typedef unsigned int uint;
unsigend char我定义了两次,一次uchar ,一次ucahr,
是因为我容易把a和h打反,编译报错,懒得去改,
索性直接定义两个,随便用
2.4 现象
三、突发功能和静态RAM读写
先留着,以后写【doge】
本次笔记对应视频教程的第44,45集 实时时钟DS1302(理论+实践),到此结束。
|
下次笔记将对应视频教程的第46,47集 LCD1602与指针(理论+实践)
|
如果笔记之中有任何错误,请在评论区指出,谢谢