九层妖塔 起于垒土

蓝桥杯模块DS1302时钟芯片Part_2
一、Notes
●同步串行通信
●三线通信
●内含一个实时时钟/日历和31字节静态RAM
●时钟/RAM的读/写数据以一个字节或多达31个字节的字符组方式通信。
二、写时序
1、时序图

2、官方底层驱动代码:
//-------第十届资料包,日期:2011-8-9,应该是针对12T单片机
void Write_Ds1302(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK=0;
SDA=temp&0x01;
temp>>=1;
SCK=1;
}
}
//------2020年国信长天组织的模拟测试-------//
void Write_Ds1302_Byte(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK=0;
SDA=temp&0x01;
temp>>=1;
SCK=1;
Delay2ms();
}
}
3、Template:
void DS1302_Write(uchar temp)
{
uchar i;
for (i=0;i<8;i++)
{
SCK=0;
SDA=temp&0x01;
temp>>=1; //移位兼延时
SCK=1; //上升沿写入数据
Delay1us();//稳定电平
}
}
4、Notes:
●在SCLK周期的上升沿输入字节。DS1302每检测到一个SCLK上升沿就从I/O引脚(SDA)接收1位数据。
●先将SCK=0;再送数据,因为min(
t
D
C
t_{DC}
tDC)=50ns,因此将移位temp>>=1;放于此移位兼延时。
●再使SCK=1;产生上升沿,写入一位数据。
●Delay1us();min(
t
C
H
t_{CH}
tCH)=250ns和min(
t
C
L
t_{CL}
tCL)=250ns。即串行时钟信号SCK高低电平至少各为250ns。12T单片机12MHz主时钟,一个空指令_nop_();=一个机器周期=1个时钟周期=1/
f
o
s
c
f_{osc}
fosc=1/12MHz=1/12us,不够250ns,直接延时1us来稳定电平。
●至于min(
t
C
L
t_{CL}
tCL)=250ns,由SCK=0;与SCK=1;之间的执行代码充当延时。
●2020年国信长天组织的模拟测试中给出延时2ms,似乎有点过分?!
三、写字节
1、官方底层驱动代码:
//------两个版本的驱动除了子函数名不一样外,完全相同----//
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )
{
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
Write_Ds1302(dat);
RST=0;
}
2、Template:
//仅改了函数名,添加了注释
//------------------------------------------------DS1302写字节-----------------//
void DS1302_Write_Byte(uchar address,uchar dat)
{
RST=0; _nop_(); //复位
SCK=0; _nop_(); //复位
RST=1; _nop_(); //开始数据传输
DS1302_Write(address);//地址字节
DS1302_Write(dat); //数据字节
RST=0; //复位,关闭数据传输
}
四、读字节
1、时序图

2、官方底层驱动代码:
//-------第十届资料包,日期:2011-8-9,应该是针对12T单片机
unsigned char Read_Ds1302_Byte ( unsigned char address )
{
unsigned char i,temp=0x00;
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
for (i=0;i<8;i++)
{
SCK=0;
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
}
RST=0; _nop_();
SCK=0; _nop_();
SCK=1; _nop_();
SDA=0; _nop_();
SDA=1; _nop_();
return (temp);
}
//------2020年国信长天组织的模拟测试-------//
unsigned char Read_Ds1302 ( unsigned char address )
{
unsigned char i,temp=0x00;
RST=0;
_nop_();
SCK=0;
_nop_();
RST=1;
_nop_();
Write_Ds1302_Byte(address);
for (i=0;i<8;i++)
{
SCK=0;
temp>>=1;
Delay2ms();
if(SDA)
temp|=0x80;
SCK=1;
}
RST=0;
_nop_();
RST=0;
SCK=0;
_nop_();
SCK=1;
_nop_();
SDA=0;
_nop_();
SDA=1;
return (temp);
}
3、Template:
//------------------------------------------------DS1302读字节-----------------//
uchar DS1302_Read_Byte(uchar address)
{
uchar i,temp=0x00;
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
DS1302_Write(address); //地址字节
for (i=0;i<8;i++)
{
SCK=0; //开始读数据字节
temp>>=1; //延时+移位
Delay1us();//延时稳定电平
if(SDA)
temp|=0x80;
SCK=1;
}
RST=0; _nop_();
SCK=0; _nop_();
SCK=1; _nop_();
SDA=0; _nop_();
SDA=1; _nop_();
return (temp);
}
4、Notes:
●Template与官方驱动没有实质性的变化。只是为了便于查找修改了子函数名,增加1us延时来稳定电平。
●还有最后的五行操作不知为啥,其他地方也没找到。
●2020模拟测试最后比以前多出来一行,写的更乱;其他地方的缩进,函数名都是极具个性的。
五、时钟设置
1、RCT寄存器:

2、Template:
uchar DS1302_Init_time[3]={23,59,50}; //DS1302初始化时间
//------------------------------------------------DS1302时钟设置-----------------//
void DS1302_Set_RCT(uchar *DS1302_Init_time)
{
uchar RCT;
DS1302_Write_Byte(0X8E,0); //WP=0,允许写操作
RCT = ((DS1302_Init_time[0]/10)<<4)+(DS1302_Init_time[0]%10);
DS1302_Write_Byte(0X84,RCT); //设置时
RCT = ((DS1302_Init_time[1]/10)<<4)+(DS1302_Init_time[1]%10);
DS1302_Write_Byte(0X82,RCT); //设置分
RCT = ((DS1302_Init_time[2]/10)<<4)+(DS1302_Init_time[2]%10);
DS1302_Write_Byte(0X80,RCT); //设置秒
DS1302_Write_Byte(0X8E,0X80); //WP=1,禁止写操作
}
3、Notes:
●数组名是数组首元素的地址。数组表示法其实是在变相地使用指针。
●子函数定义了无符号指针型地形参,虽然形参名为数组名,但并不指向数组,形参名只是一个代表。
●输入的shi实参为数组名,指向数组首元素的地址,用实参来代替符号式的形参。
●允许写操作→写操作→关闭写操作
●时钟设置子函数DS1302_Set_RCT()将数据写入RCT寄存器组,来初始化时间,只需执行一遍。
●时间信息(秒,分,时,日,月,年)是将十进制的十位和个位分开分别转化为8421BCD码存储在相关寄存器中的。
六、读取时钟
1、Template:
uchar DS1302_time[3]; //从DS1302读取到的实时时间
//------------------------------------------------DS1302读取时钟-----------------//
void DS1302_Read_RCT(uchar *DS1302_time)
{
uchar RCT;
RCT = DS1302_Read_Byte(0X85); //读取时
DS1302_time[0] = (RCT>>4)*10+(RCT&0X0F);
RCT = DS1302_Read_Byte(0X83); //读取分
DS1302_time[1] = (RCT>>4)*10+(RCT&0X0F);
RCT = DS1302_Read_Byte(0X81); //读取秒
DS1302_time[2] = (RCT>>4)*10+(RCT&0X0F);
}
七、主函数
void main(void)
{
All_Init(); //开发板初始化
DS1302_Set_RCT(DS1302_Init_time); //设置初始时钟
while(1)
{
DS1302_Read_RCT(DS1302_time); //DS1302读取时钟
yi=DS1302_time[0]/10;
er=DS1302_time[0]%10;
san=23;
si=DS1302_time[1]/10;
wu=DS1302_time[1]%10;
liu=23;
qi=DS1302_time[2]/10;
ba=DS1302_time[2]%10;
SEG_1_2(yi,er);
SEG_3_4(san,si);
SEG_5_6(wu,liu);
SEG_7_8(qi,ba);
SEG_Init();
}
}
本文详细解析了DS1302实时时钟模块的驱动原理及实现,包括同步串行通信、三线通信机制,以及如何通过写时序、写字节、读字节等功能进行数据交互,特别关注时钟设置与读取的操作细节。

961

被折叠的 条评论
为什么被折叠?



