当前位置: 代码迷 >> 综合 >> 51单片机学习总结(五)DS1302(内含模块化代码)
  详细解决方案

51单片机学习总结(五)DS1302(内含模块化代码)

热度:49   发布时间:2024-01-09 07:07:58.0

目录

  • 原理图
    • DS1302

原理图

新人求赞 ? 谢谢大家

主控芯片原理图
在这里插入图片描述

DS1302
在这里插入图片描述

DS1302


修订:模块化代码里面,InitLcd1602()这一个函数在最开始版本里面,因为原理图的VCC里面是接了电池的,但是我的实物里面是没有接电池的,返回的dat值跟模块化代码不匹配,所以是不需要考虑掉电DS1302是否继续走,所以把那一段代码改了一下,变成了一个直接初始化值的代码,把原来的可以判断是否掉电的代码注释掉了,大家看的时候可以注意一下。


老样子,如果大家不想看长篇的知识点,可以直接跳到后面看模块化代码
知识点
单片机和人一样,你总要知道现在处于什么时间点,而DS1302就能够告诉你现在的时间
DS1302芯片图和引脚
在这里插入图片描述在这里插入图片描述BCD码
为了让单片机中的2进制代码和我们现实生活中的10进制代码能够完美转换,前辈们设计出了BCD码,我的DS1302中的时钟寄存器使用的是最常用的8421码型的BCD码
BCD码就是用4位2进制数来表示一位十进制数0-9
比如1001就是表示9,那么10用BCD码转换之后就变成了0001 0000;

/*BCD码转换代码*/
/*以把45转化成BCD码为实例*/
unsigned char data1,data2 = 45;
data1 = data2/10;	 //BCD码转换
data2 %= 10;	 //BCD码转换
data2 += data1*16; //BCD码转换

DS1302控制命令
DS1302的一条指令是一个字节共8位
在这里插入图片描述第7位,固定为1,如果这个写成了0,那么写进去的命令也是无效的
第6位,是选择RAM还是CLOCK,如果是1则要用RAM,如果是0则要用CLOCK
第5位到第1位,是寄存器的五位地址
第0位,是读写位,如果是0就是读,如果是1就是写
5位地址分别是0b00000-0b00111,但是芯片手册里面已经把7 6 0位的值给了出来,所以指令就变成了0x80,0x81这些类别。
DS1302寄存器
芯片中寄存器可以说是一个非常重要的东西
DS1302可以理解成包含时钟日历和控制寄存器,静态RAM寄存器和突发模式配置寄存器

DS1302
时钟日历
控制寄存器8Fh 8Eh
秒寄存器 81h 80h
小时寄存器 85h 84h
日寄存器
...
31字节静态RAM
工作模式寄存器

时钟日历寄存器包含在7个读/写寄存器中
秒寄存器 BIT7定义为时钟暂停标志(CH),当此位置为1,时钟振荡器停止,为0时,开始运行,也就是说如果此位为0,时钟芯片掉电之后,如果还有备用电源仍然可以继续运行。剩下的7位里面,低4位是秒的各位,中高3位是秒的十位
分钟寄存器 和秒寄存器类似
小时寄存器 BIT7用于定义DS1302是在12小时模式还是24小时模式,为1时,为12小时,当BIT5为AM/PM位,24小时模式时,此位是小时数据位
日寄存器 BIT5 BIT4代表十位 BIT3-0代表个位
周年寄存器 类似,具体可以看下列表格
控制寄存器 BIT7为写保护位,其他7位均为0.在任何对时钟读写操作之前,BIT7必须为0,当BIT7为1的时候,不允许进行写操作
举个例子
如果给时钟发送81,那么就返回秒。发送83返回分,这是正常读取数据的方法。
在这里插入图片描述31字节静态RAM
在这里插入图片描述
突发模式寄存器
在这里插入图片描述
在这里插入图片描述
操作DS1302顺序
在实际的操作过程中,如果我们一位一位读,那就有可能会出现比如时间在00:59的时候读出应该是00:59,但是一位一位读,在读出59的时候,时钟瞬间进了一位,导致读分的时候读出来是1,也就变成了1:59,也就产生了错误,所以,就有了突发模式这一说法
突发模式就是把5位地址位全部写1,操作指令变成0XBF,那么8个字节同时会锁存在缓冲区里面,我们读的就是缓冲区的数据,也就没有误差了。
通信时序
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
模块化代码
接口就是DS1302.c里面的几个函数

/*pbdata.h*/
#ifndef __PBDATA_H__
#define __PBDATA_H__
#define uchar unsigned char
#define uint unsigned int#include <reg52.h>
#include "DS1302.h"/*DS1302*/
sbit DS1302_CE = P1^2;//使能
sbit DS1302_CK = P1^0;//时钟线
sbit DS1302_IO = P1^1;//双通信引脚#endif
/*DS1302.h*/
#ifndef __DS1302_H__
#define __DS1302_H__struct sTime {
     //日期时间结构体定义
unsigned int year; //年
unsigned char mon; //月
unsigned char day; //日
unsigned char hour; //时
unsigned char min; //分
unsigned char sec; //秒
unsigned char week; //星期
};void DS1302ByteWrite(unsigned char dat);
unsigned char DS1302ByteRead();
void DS1302SingleWrite(unsigned char reg, unsigned char dat);
unsigned char DS1302SingleRead(unsigned char reg);
void DS1302BurstWrite(unsigned char *dat);
void DS1302BurstRead(unsigned char *dat);
void GetRealTime(struct sTime *time);//得到当前时间
void SetRealTime(struct sTime *time);//设置当前时间
void InitDS1302();//初始化DS1302 自己在.c里面修改初始化的时间#endif
/*DS1302.c*/
#include "pbdata.h"bit flag200ms = 0; //200ms 定时标志
unsigned char T0RH = 0; //T0 重载值的高字节
unsigned char T0RL = 0; //T0 重载值的低字节/* 发送一个字节到DS1302 通信总线上 */
void DS1302ByteWrite(unsigned char dat)
{
    unsigned char mask;for (mask=0x01; mask!=0; mask<<=1) //低位在前,逐位移出,一位一位发数据{
    								   //也就是0000 0001和dat来比,来做到一位一位发数据if ((mask&dat) != 0) //首先输出该位数据DS1302_IO = 1;elseDS1302_IO = 0;DS1302_CK = 1; //然后拉高时钟DS1302_CK = 0; //再拉低时钟,完成一个位的操作}DS1302_IO = 1; //最后确保释放IO 引脚
}
/* 由DS1302 通信总线上读取一个字节 */
unsigned char DS1302ByteRead()
{
    unsigned char mask;unsigned char dat = 0;for (mask=0x01; mask!=0; mask<<=1) //低位在前,逐位读取{
    if (DS1302_IO != 0) //首先读取此时的IO 引脚,并设置dat 中的对应位{
    dat |= mask;}DS1302_CK = 1; //然后拉高时钟DS1302_CK = 0; //再拉低时钟,完成一个位的操作}return dat; //最后返回读到的字节数据
}
/* 用单次写操作向某一寄存器写入一个字节,reg-寄存器地址,dat-待写入字节 */
void DS1302SingleWrite(unsigned char reg, unsigned char dat)
{
    DS1302_CE = 1; //使能片选信号DS1302ByteWrite((reg<<1)|0x80); //发送写寄存器指令DS1302ByteWrite(dat); //写入字节数据DS1302_CE = 0; //除能片选信号
}
/* 用单次读操作从某一寄存器读取一个字节,reg-寄存器地址,返回值-读到的字节 */
unsigned char DS1302SingleRead(unsigned char reg)
{
    unsigned char dat;DS1302_CE = 1; //使能片选信号DS1302ByteWrite((reg<<1)|0x81); //发送读寄存器指令dat = DS1302ByteRead(); //读取字节数据DS1302_CE = 0; //除能片选信号return dat;
}
/* 用突发模式连续写入8 个寄存器数据,dat-待写入数据指针 */
void DS1302BurstWrite(unsigned char *dat)
{
    unsigned char i;DS1302_CE = 1;DS1302ByteWrite(0xBE); //发送突发写寄存器指令for (i=0; i<8; i++) //连续写入8 字节数据{
    DS1302ByteWrite(dat[i]);}DS1302_CE = 0;
}
/* 用突发模式连续读取8 个寄存器的数据,dat-读取数据的接收指针 */
void DS1302BurstRead(unsigned char *dat)
{
    unsigned char i;DS1302_CE = 1;DS1302ByteWrite(0xBF); //发送突发读寄存器指令for (i=0; i<8; i++) //连续读取8 个字节{
    dat[i] = DS1302ByteRead();}DS1302_CE = 0;
}
/* 获取实时时间,即读取DS1302 当前时间并转换为时间结构体格式 */
void GetRealTime(struct sTime *time)
{
    unsigned char buf[8];DS1302BurstRead(buf);time->year = buf[6] + 0x2000;time->mon = buf[4];time->day = buf[3];time->hour = buf[2];time->min = buf[1];time->sec = buf[0];time->week = buf[5];
}/* 设定实时时间,时间结构体格式的设定时间转换为数组并写入DS1302 */
void SetRealTime(struct sTime *time)
{
    unsigned char buf[8];buf[7] = 0;buf[6] = time->year;buf[5] = time->week;buf[4] = time->mon;buf[3] = time->day;buf[2] = time->hour;buf[1] = time->min;buf[0] = time->sec;DS1302BurstWrite(buf);
}
/* DS1302 初始化,如发生掉电则重新设置初始时间 */
void InitDS1302()
{
    unsigned char dat;struct sTime code InitTime = {
     //2020 年6 月 8 日 12:30:00 星期二0x2020,0x06,0x03, 0x14,0x02,0x00, 0x03};DS1302_CE = 0; //初始化DS1302 通信引脚DS1302_CK = 0;dat = DS1302SingleRead(0); //读取秒寄存器DS1302SingleWrite(7, 0x00); //撤销写保护以允许写入数据SetRealTime(&InitTime); //设置DS1302 为默认的初始时间
}
/*原来的版本 void InitDS1302() {unsigned char dat;struct sTime code InitTime[] = { //2020 年6 月2 日 12:30:00 星期二0x2020,0x06,0x02, 0x12,0x30,0x00, 0x02};DS1302_CE = 0; //初始化DS1302 通信引脚DS1302_CK = 0;dat = DS1302SingleRead(0); //读取秒寄存器if ((dat & 0x80) != 0) //由秒寄存器最高位CH 的值判断DS1302 是否已停止{DS1302SingleWrite(7, 0x00); //撤销写保护以允许写入数据SetRealTime(&InitTime); //设置DS1302 为默认的初始时间} }*/