目录
2.1 Write/Rrad与input/output联系【1】
1. DS1302与各接口简介
DS1302 计时芯片包含一个实时时钟/日历和 31 字节的静态 RAM.通过简单的串行接口(SCLK,IO,CE)与微处理器通讯。(该A2单片机板子备用电源VCC1没有硬件支持,所以没有断电后计时功能)
图1.1. DS1302模块图
图1.2 DS1302内部逻辑结构图
- VCC2: 双供电配置中的主电源供应管脚,VCC1 连接到备用电源,在主电源 失效时保持时间和日期数据。
- X1、X2:连接到振荡器和标准32.768kHz石英晶振相连,为时钟提供精确1HZ频率。
- CE: 输入.CE信号在读写时必须保持高电平
- I/O: 输入/(推挽)输出,双向传输数据管脚
- SCLK : 用来同步(控制)串行接口上的数据动作
2.Write与Read操作
2.1 Write/Rrad与input/output联系【1】
图2.1 单片机芯片与外设通信
- 单片机芯片Read外设芯片/器件Output的数据;
- 单片机芯片Write的数据通过外设芯片/器件Input;
2.2命令字——DS1302的操作指令
命令字存于DS1302中控制寄存器,命令字启动每一次数据传输,每次read或write前八个周期上升沿就是将命令字写入DS1302控制寄存器,随后便根据这个命令字决定如何处理接着的数据。
- 位 7 必须是逻辑 1. 如果是 0, 则禁止对 DS1302写入.
- 位 6 在逻辑 0时表示接下来操作的是时钟/日历数据,逻辑 1时则为 RAM数据.
- 位 0 在逻辑0时为Write操作,逻辑1时为Read操作.
- 位1-位5为要操作的(寄存器或RAM)地址(A0-A4与下图为A1-A5一样)
图 2.2 命令字(指令)格式
2.3 RTC存放时钟相关寄存器
注意存放时钟日期(年月日时分秒星期)相关寄存器采用BCD码存储在寄存器中(因此时钟自动进位是按照BCD码进行进位的,所以要以BCD码输入和BCD转换成十进制输出)。因此输入write建议用16进制0xXX输入,Read时记得转BCD为十进制。(A0-A4就是A1-A5)
例如想对秒寄存器写34s:
那命令字为 1 0 00000 0 =0x80
写入数据为0x34,秒寄存器内内容为 0011 0100
2.4 write/read周期与SCLK、SE时钟联系
对于数据input:输入写命令字的 8个 SCLK周期后 ,接下来的 8个 SCLK 周期的上升沿数据字节被输入。在第一次使用DS1302时,必须将WP写保护位置0,允许写人操作。
/*完成一次将命令字Command与Data写入DS1302中Command指定寄存器或RAM*/
void DS1302_WriteByte(unsigned char Command,Data) {
unsigned char i;
//以下根据write时序图控制write的CE与SCLK电平
DS1302_CE = 1;//开始CE必须先置高电平1
for(i=0;i<8;i++)//前八个周期上升沿IO内容作为命令字被写入DS1302控制寄存器
{
DS1302_IO = Command&(0x01<<i);//将低位到高位送到IO
DS1302_SCLK =1;//上升沿发送
DS1302_SCLK =0;//恢复低电平0
}
for(i=0;i<8;i++)//后八个周期上升沿IO内容作为要写入数据被写入DS1302
{
DS1302_IO = Data&(0x01<<i);//将低位到高位送到IO
DS1302_SCLK =1;//上升沿发送
DS1302_SCLK =0;//恢复低电平0
}
DS1302_CE = 0;//恢复CE低电平0
}
对于数据output:输入读命令字的 8个 SCLK周期后, 随后的 8个 SCLK 周期的下降沿,一个数据字节被输出。 注意第一个数据位的传送发生在命令字节被写完后的第一个下降沿。
/*完成一次将命令字Command写入DS1302控制寄存器,并根据Command内容读出Data*/
unsigned char DS1302_ReadByte(unsigned char Command) {
unsigned i,Data=0x00;
Command = Command|1;//根据规律:DS1302_ReadCommand[i] = DS1302_WriteCommand[i] | 1
DS1302_CE = 1;//开始CE必须先置高电平1
//Read的整个周期比Write少一个周期,因为在第八个上升沿接着的下降沿IO就收到DS1302数据了
for(i=0;i<8;i++)
{
DS1302_IO = Command&(0x01<<i);//将低位到高位送到IO
DS1302_SCLK =0;//恢复上一次(第一次循环i=0时SCLK=0不起作用)循环中上升沿1
DS1302_SCLK =1;//上升沿发送
}
DS1302_IO = 0;//这里不加会导致readbyte函数在循环中读出255,原因还没想到捏
for(i=0;i<8;i++)//DS1302将数据Output到IO上,接着被单片机read到
{
DS1302_SCLK =0;//i=0时,为第八个上升沿接着的下降沿
if(DS1302_IO == 1)
Data = Data|(0x01<<i);//将Output到IO上的数据放到Data上(知识:二进制转十进制每位权值,移位操作)
if(i!=7)
DS1302_SCLK =1;//i<7时,根据时序图,需要拉高电平
else
DS1302_SCLK =0;//在i=7时,整个Read周期结束,不必再置高电平
}
DS1302_CE = 0;//恢复CE低电平0
Data = BCD2D(Data);//因为DS1302存储时间为BCD码格式,将其转十进制返回
return Data;
}
3.初始化时钟并通过LCD1602显示实验程序
/*DS1302模块代码*/
#include <REGX52.H>
#include "LCD1602.H"
#define DS1302_WP_Command = 0x8e;//写保护字的命令字
sbit DS1302_SCLK = P3^6; //根据开发板原理图定义与DS1602通信线
sbit DS1302_IO = P3^4;
sbit DS1302_CE = P3^5;
//从[0]到[6]存放年、月、日、时、分、秒、星期
unsigned char DS1302_TimeInit[7]= {0x23,0x02,0x08,0x21,0x40,0x00,0x03};
//存放写入RTC年、月、日、时、分、秒、星期寄存器中命令字
unsigned char DS1302_WriteCommand[7] = {0x8c,0x88,0x86,0x84,0x82,0x80,0x8a};
/*
根据规律:DS1302_ReadCommand[i] = DS1302_WriteCommand[i] | 1
0x81 =0x80 | 1 = =0x80 | 0x0000 0001£;
就不用定义DS1302_ReadCommand[i]了,在使用时|=就行
*/
/*初始化,令CE与SCLK为低电平*/
void DS1302_Init(void) {
DS1302_CE = 0;
DS1302_SCLK =0;
}
/*将BCD码转为10进制*/
unsigned char BCD2D(unsigned char BCD) {
unsigned char Data;
Data = BCD/16*10 + BCD%16;
return Data;
}
/*完成一次将命令字Command与Data写入DS1302中Command指定寄存器或RAM*/
void DS1302_WriteByte(unsigned char Command,Data) {
unsigned char i;
//以下根据write时序图控制write的CE与SCLK电平
DS1302_CE = 1;//开始CE必须先置高电平1
for(i=0;i<8;i++)//前八个周期上升沿IO内容作为命令字被写入DS1302控制寄存器
{
DS1302_IO = Command&(0x01<<i);//将低位到高位送到IO
DS1302_SCLK =1;//上升沿发送
DS1302_SCLK =0;//恢复低电平0
}
for(i=0;i<8;i++)//后八个周期上升沿IO内容作为要写入数据被写入DS1302
{
DS1302_IO = Data&(0x01<<i);//将低位到高位送到IO
DS1302_SCLK =1;//上升沿发送
DS1302_SCLK =0;//恢复低电平0
}
DS1302_CE = 0;//恢复CE低电平0
}
/*完成一次将命令字Command写入DS1302控制寄存器,并根据Command内容读出Data*/
unsigned char DS1302_ReadByte(unsigned char Command) {
unsigned i,Data=0x00;
Command = Command|1;//根据规律:DS1302_ReadCommand[i] = DS1302_WriteCommand[i] | 1
DS1302_CE = 1;//开始CE必须先置高电平1
//Read的整个周期比Write少一个周期,因为在第八个上升沿接着的下降沿IO就收到DS1302数据了
for(i=0;i<8;i++)
{
DS1302_IO = Command&(0x01<<i);//将低位到高位送到IO
DS1302_SCLK =0;//恢复上一次(第一次循环i=0时SCLK=0不起作用)循环中上升沿1
DS1302_SCLK =1;//上升沿发送
}
DS1302_IO = 0;//这里不加会导致readbyte函数在循环中读出255,原因还没想到捏
for(i=0;i<8;i++)//DS1302将数据Output到IO上,接着被单片机read到
{
DS1302_SCLK =0;//i=0时,为第八个上升沿接着的下降沿
if(DS1302_IO == 1)
Data = Data|(0x01<<i);//将Output到IO上的数据放到Data上(知识:二进制转十进制每位权值,移位操作)
if(i!=7)
DS1302_SCLK =1;//i<7时,根据时序图,需要拉高电平
else
DS1302_SCLK =0;//在i=7时,整个Read周期结束,不必再置高电平
}
DS1302_CE = 0;//恢复CE低电平0
Data = BCD2D(Data);//因为DS1302存储时间为BCD码格式,将其转十进制返回
return Data;
}
/*根据DS1302_TimeInit[]内各时间与对应的写命令字DS1302_WriteCommand[]写入各个存放时间寄存器内*/
void DS1302_InitTime(void) {
unsigned char i;
DS1302_WriteByte(0x8e,0x00);//关闭写保护,允许修改DS1302内容
for(i=0;i<7;i++)
{
DS1302_WriteByte(DS1302_WriteCommand[i],DS1302_TimeInit[i]);
}
DS1302_WriteByte(0x8e,0x80);//打开写保护,禁止修改DS1302内容
}
/*与DS1302_InitTime()功能一样,只是换个名字为了以后项目扩展*/
void DS1302_SetTime() {
DS1302_InitTime();
}
/*修改DS1302_TimeInit[]内时间为调用该函数时的DS1302内运行的时间*/
void DS1302_getRTCTime(void) {
unsigned char i;
for(i=0;i<7;i++)
{
DS1302_TimeInit[i] = DS1302_ReadByte(DS1302_WriteCommand[i]|1);
}
}
/*将DS1302此时的时间(年-月-日\n时:分:秒)显示到LCD1602*/
void DS1302_ShowTime(void) {
unsigned char d;
d = DS1302_ReadByte(DS1302_WriteCommand[0]|1);
LCD_ShowString(1,1,"20");LCD_ShowNum(1,3,d,2);
d = DS1302_ReadByte(DS1302_WriteCommand[1]|1);
LCD_ShowString(1,5,"-");LCD_ShowNum(1,6,d,2);
d = DS1302_ReadByte(DS1302_WriteCommand[2]|1);
LCD_ShowString(1,8,"-");LCD_ShowNum(1,9,d,2);
d = DS1302_ReadByte(DS1302_WriteCommand[3]|1);
LCD_ShowNum(2,1,d,2);
d = DS1302_ReadByte(DS1302_WriteCommand[4]|1);
LCD_ShowString(2,3,":");LCD_ShowNum(2,4,d,2);
d = DS1302_ReadByte(DS1302_WriteCommand[5]|1);
LCD_ShowString(2,6,":");LCD_ShowNum(2,7,d,2);
}
/*main函数部分*/
#include <REGX52.H>
#include "DS1302.H"
#include "LCD1602.H"
//#include "Delay1ms.h"
unsigned char s;
void main()
{
LCD_Init();
DS1302_Init();
DS1302_InitTime();
while(1)
{
DS1302_ShowTime();
}
}
——————————————————————————————————————————
【1】查看时序图,芯片是上升沿还是下降沿读写数据_dragon_cdut的博客-CSDN博客_sclk和sdata区别上升沿读数据还是写数据