1、DS1302芯片原理图分析
引脚名称功能X1、X2外接32.768kHz 晶振,用于内部计时SCLK和主控通信的时钟线I/O数据输入输出引脚CE使能引脚VCC1接电池供电,保证主板掉电时间能继续走VCC2主板的电源供电
(1)DS1302芯片的通信接口是SPI协议接口,只有一根数据线,所以是半双工通信; (2)SPI协议可参考博客:《SPI协议详解(Standard SPI、Dual SPI和Queued SPI)》;
2、芯片寄存器地址定义
(1)与DS1302通信的大致过程:发送命令码表示本次的操作,发送要读取或者写入的数据; (2)比如:要读取秒就先发送0x81命令码,然后从数据线上接收8bit数据来获取秒数;要写入秒就先发送0x80命令码,然后往数据线上依次写8bit数据来设置秒; (3)在DS1302中,时间是以8421BCD码进行保存的,简单一点可以理解成低4bit表示一个含义,高4bit表示一个含义;
3、命令字解析
不同的bit含义bit7必须是逻辑 1. 如果是 0,则禁止对 DS1302写入bit60表示读写日期,1表示操作DS1302内部31字节的RAMbit5-bit1寄存器地址bit00表示写入,1表示读取
4、读写时序分析
(1)起始条件:使能线从低变高,在整个通讯期间使能线必须保持高电平; (2)先发送命令字,表示此次是什么操作; (3)从数据线写入/读取数据; 总结:CE线变高表示通信周期的开始;在每个上升沿,DS1302从数据线读取数据;在每个下降沿,DS1302往数据线写入数据;
5、写芯片寄存器的函数
// 向ds1302的内部寄存器addr写入一个值value
void ds1302_write_reg(unsigned char addr, unsigned char value)
{
unsigned char i = 0;
unsigned char dat = 0;
// 第1部分: 时序起始
SCLK = 0;
delay();
RST = 0;
delay();
RST = 1; // SCLK为低时,RST由低变高,意味着一个大的周期的开始
delay();
// 第2部分: 写入第1字节,addr
//在每个上升沿之前,把要发送给DS1302的数据放到数据线上
for (i=0; i<8; i++)
{
dat = addr & 0x01; // 从低位开始传输的
DSIO = dat; // 把要发送的bit数据丢到IO引脚上去准备好
SCLK = 1; // 制造上升沿,让DS1302把IO上的值读走
delay(); // 读走之后,一个小周期就完了
SCLK = 0; // 把SCLK拉低,是为了给下一个小周期做准备
delay();
addr >>= 1; // 把addr右移一位
}
// 第3部分: 写入第2字节,value
for (i=0; i<8; i++)
{
dat = value & 0x01; // SPI是从低位开始传输的
DSIO = dat; // 把要发送的bit数据丢到IO引脚上去准备好
SCLK = 1; // 制造上升沿,让DS1302把IO上的值读走
delay(); // 读走之后,一个小周期就完了
SCLK = 0; // 把SCLK拉低,是为了给下一个小周期做准备
delay();
value = value >> 1; // 把addr右移一位
}
// 第4部分: 时序结束
SCLK = 0; // SCLK拉低为了后面的周期时初始状态是对的
delay();
RST = 0; // RST拉低意味着一个大周期的结束
delay();
}
6、读芯片寄存器的函数
// 从ds1302的内部寄存器addr读出一个值,作为返回值
unsigned char ds1302_read_reg(unsigned char addr)
{
unsigned char i = 0;
unsigned char dat = 0; // 用来存储读取到的一字节数据的
unsigned char tmp = 0;
// 第1部分: 时序起始
SCLK = 0;
delay();
RST = 0;
delay();
RST = 1; // SCLK为低时,RST由低变高,意味着一个大的周期的开始
delay();
// 第2部分: 写入要读取的寄存器地址,addr
//在每个上升沿之前,把要发送给DS1302的数据放到数据线上
for (i=0; i<8; i++)
{
dat = addr & 0x01; // 从低位开始传输的
DSIO = dat; // 把要发送的bit数据丢到IO引脚上去准备好
SCLK = 1; // 制造上升沿,让DS1302把IO上的值读走
delay(); // 读走之后,一个小周期就完了
SCLK = 0; // 把SCLK拉低,是为了给下一个小周期做准备
delay();
addr >>= 1; // 把addr右移一位
}
// 第3部分: 读出一字节DS1302返回给我们的值
dat = 0;
for (i=0; i<8; i++)
{
// 在前面向ds1302写入addr的最后一个bit后,ds1302就会将读取到的寄存器值
// 的第一个bit放入到IO引脚上,所以我们应该先读取IO再制造下降沿然后继续
// 读取下一个bit
tmp = DSIO;
dat |= (tmp << i); // 读出来的数值是低位在前的
SCLK = 1; // 由于上面SCLK是低,所以要先拉到高
delay();
SCLK = 0; // 拉低SCLK制造一个下降沿,让DS1302往数据线放下一个数据
delay();
}
// 第4部分: 时序结束
SCLK = 0; // SCLK拉低为了后面的周期时初始状态是对的
delay();
RST = 0; // RST拉低意味着一个大周期的结束
delay();
// 第5部分:解决读取时间是ff的问题,如果读取时间没有FF乱码,可不加
DSIO = 0;
return dat;
}