蓝桥杯单片机之DS1302时钟模块的使用
DS1302简介
DS1302是美国DALLAS公司推出的高性能、低功耗的实时时钟,采用SPI三线接口与MCU进行同步通信,实时时钟可提供秒、分、时、日、星期、月和年。 简单来说,DS1302可以理解为一个电子手表,可以设定时间,也可以读取时间。
在DS1302中有两块存储器:日历时钟寄存器和RAM存储器。前者用于记录实时时间,后者用于记录其他数据。重点是对日历时钟寄存器得理解,设定时间参数就是往该寄存器写入内容,同时读取时间是也是在该寄存器中读取。
SPI串口简介
BCD码
BCD码(Binary-Coded Decimal),用4位二进制数来表示1位十进制数中的0~9这10个数码,是一种二进制的数字编码形式,用二进制编码的十进制代码。BCD码这种编码形式利用了四个位元来储存一个十进制的数码,使二进制和十进制之间的转换得以快捷的进行。(来自百度百科)
在这里使用的是最基本的BCD码——8421有权BCD码;
对照表:
十进制数 | 8421码 |
---|---|
0 | 0 |
1 | 1 |
2 | 10 |
3 | 11 |
4 | 100 |
5 | 101 |
6 | 110 |
7 | 111 |
8 | 1000 |
9 | 1001 |
8为8421码的计算方法:合四为一
例如: 8421码: 0010 0011 ——>十进制:24
0010——>2
0011——>4
2*10 + 4 =24
阅读手册获取寄存器信息
日历时钟寄存器
手册中的描述:
DS1302可以在12小时或24小时模式下运行。小时寄存器(85H、84H)的BIT7定义为12或24小时模式选择位。高电平时,选择12小时模式。在12小时模式下,BIT5是AM/PM位,逻辑高电平为PM。在24小时模式下,第5位是第二个10小时位(20–23小时)。
CH :时钟暂停标志位
- CH=0;时钟停止
- CH=1;时钟运行
WP:写保护位
- WP=0:可以对时钟或RAM寄存器进行写操作
- WP=1:禁止一切对任一寄存器的写操作
控制字
手册中的描述:
DS1302将地址和读写控制放到一个字节(功能寄存器)里面,形成一个控制字,格式如下:
BIT7:必须为1,如果等于0,则无法将数据写入DS1302
BIT6:0表示存取日历时钟数据,1表示存取RAM数据
BIT5~BIT1:表示操作单元的地址
BIT0:0表示写操作,1表示读操作
将手册中的数据进行分析可得
控制字作用时能够在一个功能寄存器中进行两种功能操作(写与读)!!!
所以我们进行功能操作时是发送控制字到主机对应的功能寄存器。
寄存器名称 | 读控制字 | 写控制字 | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 | Range |
秒 | 81H | 80H | CH | 10 Seconds | Seconds | 00-59 | |||||
分 | 83H | 82H | 10 Minutes | Minutes | 00-59 | ||||||
时 | 85H | 84H | 12制/24制 | 0 | 10 | Hour | Hour | 1-12/0-23 | |||
AM/PM | |||||||||||
日 | 87H | 86H | 0 | 0 | 10 Date | Date | 1—31 | ||||
月 | 89H | 88H | 0 | 0 | 0 | 10 Month | Month | 1—12 | |||
星期 | 8BH | 8AH | 0 | 0 | 0 | 0 | 0 | Day | 1—7 | ||
年 | 8DH | 8CH | 10 Year | Year | 0-99 |
完整代码示例:
#include "reg52.h"
#include "ds1302.h"
#include "intrins.h"
unsigned char code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; //读对应的控制字
unsigned char code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c}; //写对应的控制字
unsigned char TIME[7] = {0x30, 0x50, 0x23, 0x17, 0x02, 0x06, 0x18}; //时间数据存储数组,读数据之前存放了时间初始化参数
unsigned char SMG_NoDot[19] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x80, 0xc6, 0xc0, 0x86, 0x8e, 0xbf, 0x7f, 0xff}; //0-9、A-F、'-'、'.'
void Delay500us();
void Timer_Display();
void DisplaySMG_Temperature(unsigned int dat);
void Digital_Tube(unsigned char Position, unsigned char Typeface);
void Delay500us() //@12.000MHz
{
unsigned char i, j;
i = 6;
j = 211;
do
{
while (--j);
}
while (--i);
}
void DS1302_Config() //时间参数初始化
{
unsigned char n;
Write_Ds1302_Byte(0x8E,0x00); //打开读写保护,允许写入
for (n=0; n<7; n++)
{
Write_Ds1302_Byte(WRITE_RTC_ADDR[n],TIME[n]); //将时间初始化参数写入对应寄存器
}
Write_Ds1302_Byte(0x8E,0x80); //关闭读写保护,禁止写入
}
void DS1302_ReadTime()
{
unsigned char n;
for (n=0; n<7; n++)
{
TIME[n] = Read_Ds1302_Byte(READ_RTC_ADDR[n]); //将寄存器中的数据读入TIME缓冲区
}
}
void Digital_Tube(unsigned char Position, unsigned char Typeface) //Position是数码管第几位(从左到右,0开始),Typeface是显示的字样
{
unsigned char Bit[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
P2 = P2 & 0x1f | 0xc0;
P0 = Bit[Position];
P2 = P2 & 0x1f | 0xe0;
P0 = Typeface;
Delay500us();
P0 = 0XFF;
P2 = P2 & 0x1f ; //数码管消影
}
void Timer_Display()
{
Digital_Tube(0,SMG_NoDot[TIME[2]/16]); //取十位
Digital_Tube(1,SMG_NoDot[TIME[2]&0x0f]); //取个位
Digital_Tube(2,SMG_NoDot[16]);
Digital_Tube(3,SMG_NoDot[TIME[1]/16]); //取十位
Digital_Tube(4,SMG_NoDot[TIME[1]&0x0f]); //取个位
Digital_Tube(5,SMG_NoDot[16]);
Digital_Tube(6,SMG_NoDot[TIME[0]/16]); //取十位
Digital_Tube(7,SMG_NoDot[TIME[0]&0x0f]); //取个位
/*数码管全灭,消影作用*/
P2 = P2 & 0x1f | 0xc0;
P0 = 0XFF;
P2 = P2 & 0x1f | 0xe0;
P0 = 0XFF;
}
main()
{
DS1302_Config(); //DS1302初始化时间参数
while(1)
{
DS1302_ReadTime(); //读取时间参数
Timer_Display(); //显示时间参数
}
}
总结
其实对DS1302的基本操作就是设定时间参数(void DS1302_Config();
)与读取实时时间参数(DS1302_ReadTime();
);
单个字节的读写函数在赛点资料包底层驱动已经存在,我们需要做的就是调用对应的函数,将我们想要的数据写入对应的寄存器或者在对应的寄存器读出时间数据。这里利用的就是C语言的数组部分知识。