RTC DS1302
RTC DS1302
SPI接口DS1302时钟芯片操作
今天,又花了差不多一天时间,从手册看起,到写完代码,最后仿真。期间出现了一个细小的差错,折腾了约1个钟头才解决掉(所以,最怕底层细小之处出现错误)。
DS1302是达拉斯公司出品的一款实时时钟芯片。具体且详细的资料介绍在其芯片手册上面都有写着。说起来自己读DS1302芯片手册,也花了不少精力,主要是对一个问题一直没理解。
下图是DS1302时钟寄存器的结构。(注意左边READ与WRITE两列)
下图是DS1302的命令字节(就是跟它通信的格式)
其中A4到A0可以代表寄存器的地址。我想,5bit表示的地址,翻遍了手册,在上面也没有说明5bit的地址是怎么表示的(手册上只有读写地址,8bit)。就这样,我纳闷了,就去问问搜索引擎。网上挂出来最多的尽是些代码(说实话,驱动代码不难写,难的是对芯片的理解),最终还是找到了一篇博文(写了对DS1302的理解),而且我才焕然大悟,原来READ与WRITE两列是什么的。
举个例子:写秒寄存器的地址是0x80,展开成8bit的就是1000,0000(结合命令字节看看),你会发现其实就是命令字节。
现在来说说DS1302的SPI接口(其实比标准的SPI接口少了一根线),它包含RST线、SCLK线、IO线(双向传送数据用,标准的SPI则将其分成两根MISO与MOSI)3条接线。
上面这张图片就是其时序图,单字节读取和单字节写。相比1条线的单总线、2条线的IIC,这个SPI貌似是最简单的。每次传送时,需要先发送8bit命令字节,再发送/接收8bit数据。
再细小的看,CE(也就是RST)先拉至高电平,在IO线上事先要准备好数据,然后将SCLK拉高,一个上升沿,发完了1bit。如此往复,发完接下来的几位。如果是发送数据的话,注意每次都是上升沿发送1bit。如果是接收数据的话,注意,在传完最后命令字节的1(高电平)之后的第一个下降沿后DS1302发送数据。当然DS1302能够每次传送多个字节。
说完了通信机制,通信内容,基本上差不多了。值得提醒的是,DS1302内部有31字节RAM,可以用来保存数据。
今天写的有点少。下面贴上调好的代码:
#ifndef __hal_ds1302_h__
#define __hal_ds1302_h__
#include<reg52.h>
#include"datatype.h"
#include"delay.h"
#include"hal.h"
sbit rst=P3^2;
sbit sclk=P3^3;
sbit sda_ds1302=P1^7;
#define RST rst
#define SCLK sclk
#define SIO sda_ds1302
#define WRITE_SECONDS 0x80//秒
#define READ_SECONDS 0x81
#define WRITE_MINUTES 0x82//分
#define READ_MINUTES 0x83
#define WRITE_HOUR 0x84//时
#define READ_HOUR 0x85
#define WRITE_DATE 0x86//日
#define READ_DATE 0x87
#define WRITE_MONTH 0x88//月
#define READ_MONTH 0x89
#define WRITE_DAY 0x8a//星期
#define READ_DAY 0x8b
#define WRITE_YEAR 0x8c//年
#define READ_YEAR 0x8d
#define WRITE_WP 0x8e//写保护bit7为高时,不允许写
#define READ_WP 0x8f//所以写之前需将其设为0
//ds1302时间结构体类型
struct ds1302_time
{
//秒0-59
uchar seconds;
//分0-59
uchar minutes;
//时0-23(24小时模式)
//如果需要12小时模式,跟寄存器格式需要一致
uchar hour;
//星期1-7
enum{Sunday=1,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday} day;
//日1-31
uchar date;
//月1-12
uchar month;
//年0-99
uchar year;
};
//参数1:写保护;参数0:取消写保护
#define HAL_DS1302_WRITE_PROTECT(wp) hal_ds1302_single_byte_write(WRITE_WP,wp?0x80:0x00)
void hal_ds1302_init();
void hal_ds1302_single_byte_write(uchar comm,uchar val);
uchar hal_ds1302_single_byte_read(uchar comm);
void hal_ds1302_init_time(struct ds1302_time time);
void hal_ds1302_get_time(struct ds1302_time * time);
#endif
C文件部分:
1 #include"hal_ds1302.h"
2
3 void hal_ds1302_init()
4 {
5 RST=0;
6 SCLK=0;
7 SIO=1;
8 }
9
10 //实质上传送了16bit
11 void hal_ds1302_single_byte_write(uchar comm,uchar val)
12 {
13 //RST低电平 SCLK低电平
14 uchar i;
15 RST=1;
16 for(i=0;i<8;i++)//从低位开始传送
17 {
18 if(comm&(0x01<<i))
19 SIO=1;
20 else
21 SIO=0;
22 SCLK=1;//SCLK一个上升沿,读取了SDA上的电平
23 //单片机时钟周期1us情况下,几乎不用考虑延时
24 SCLK=0;
25 }
26 for(i=0;i<8;i++)
27 {
28 if(val&(0x01<<i))
29 SIO=1;
30 else
31 SIO=0;
32 SCLK=1;//上升沿读取
33 SCLK=0;
34 }
35 RST=0;
36 //RST低电平 SCLK低电平 SDA电平未知
37 }
38
39 //实质上传送了16bit
40 uchar hal_ds1302_single_byte_read(uchar comm)
41 {
42 //RST低电平 SCLK低电平
43 uchar i,tmp=0;
44 RST=1;
45 for(i=0;i<8;i++)
46 {
47 SCLK=0;//放在这儿是为了第8次SCLK依旧是高电平
48 if(comm&(0x01<<i))
49 SIO=1;
50 else
51 SIO=0;
52 SCLK=1;//上升沿,DS1302读取值
53 }
54 //现在SCLK依旧是高电平
55 //而且达拉斯考虑到了总线释放问题,所以传送的最后一位都为1
56 for(i=0;i<8;i++)
57 {
58 SCLK=1;//放在此处是为了i=7时候,SCLK仍为低电平
59 SCLK=0;//下降沿,DS1302输出数据
60 if(SIO)
61 tmp=tmp|(0x01<<i);
62 }
63 RST=0;
64 return tmp;
65 //RST低电平 SCLK低电平 SDA电平状态未知
66 }
67
68 //参数char类型16进制
69 //传出2个4位BCD码组成的8bit数据
70 uchar hal_ds1302_uchar2BCD(uchar val)
71 {
72 uchar shi=0,ge=0;
73 shi=val/10%10;
74 ge=val%10;
75 return (shi<<4)|ge;
76 }
77
78 uchar hal_ds1302_BCD2uchar(uchar val)
79 {
80 uchar shi=0,ge=0;
81 shi=val>>4;
82 ge=val&0x0f;//小心,就是这儿0x0f写错了,不是0xf0
83 return shi*10+ge;
84 }
85
86 //1.设置写保护位为0
87 //2.设置秒字节,同时将bit7置1(暂停计时)
88 //3.设置年、月、日、星期、时、分
89 //4设置秒字节,晶振起震
90 //5.设置写保护字节bit7为1
91 //6.之后可以读取时间了
92 void hal_ds1302_init_time(struct ds1302_time time)
93 {
94 HAL_DS1302_WRITE_PROTECT(0);
95 delay_ms(1);
96 hal_ds1302_single_byte_write(WRITE_SECONDS,0x80);
97 delay_ms(1);
98 hal_ds1302_single_byte_write(WRITE_YEAR,hal_ds1302_uchar2BCD(time.year));
99 delay_ms(1);
100 hal_ds1302_single_byte_write(WRITE_MONTH,hal_ds1302_uchar2BCD(time.month));
101 delay_ms(1);
102 hal_ds1302_single_byte_write(WRITE_DATE,hal_ds1302_uchar2BCD(time.date));
103 delay_ms(1);
104 hal_ds1302_single_byte_write(WRITE_DAY,hal_ds1302_uchar2BCD(time.day));
105 delay_ms(1);
106 hal_ds1302_single_byte_write(WRITE_HOUR,hal_ds1302_uchar2BCD(time.hour));
107 delay_ms(1);
108 hal_ds1302_single_byte_write(WRITE_MINUTES,hal_ds1302_uchar2BCD(time.minutes));
109 delay_ms(1);
110 hal_ds1302_single_byte_write(WRITE_SECONDS,hal_ds1302_uchar2BCD(time.seconds));
111 delay_ms(1);
112 HAL_DS1302_WRITE_PROTECT(1);
113 }
114
115 //注意对12小时模式没有进行编写,如有需要,需要额外修改
116 void hal_ds1302_get_time(struct ds1302_time * time)
117 {
118 time->year=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_YEAR));
119 delay_ms(1);
120 time->month=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_MONTH));
121 delay_ms(1);
122 time->date=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_DATE));
123 delay_ms(1);
124 time->day=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_DAY));
125 delay_ms(1);
126 time->hour=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_HOUR));
127 delay_ms(1);
128 time->minutes=hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_MINUTES));
129 delay_ms(1);
130 time->seconds= hal_ds1302_BCD2uchar(hal_ds1302_single_byte_read(READ_SECONDS));
131 }





浙公网安备 33010602011771号