影响网站排名的因素,找工作的网站平台,做淘宝客怎么建网站,模板王网站官网这次来分享一下DS1302时钟IC#xff0c;之前听说过这个IC#xff0c;但是一直没搞过#xff0c;用了半天时间就明白了原理和驱动#xff0c;说明还是很简单的。
注#xff1a;首先来区分一下DS1302和RTC时钟有什么不同#xff0c;为什么不直接用RTC呢#xff1f;
RTC不…这次来分享一下DS1302时钟IC之前听说过这个IC但是一直没搞过用了半天时间就明白了原理和驱动说明还是很简单的。
注首先来区分一下DS1302和RTC时钟有什么不同为什么不直接用RTC呢
RTC不是很精准
DS1302用于对时间精度较严格的产品上 1.首先看下实物图长什么样 2.然后我们来看看原理图长啥样
2.1无上拉电阻的配置 2.2有上拉电阻就将端口配置成开漏输出就行 3.下面来看怎么配置代码 由于DS1302的DATA根据时序图还要配成输入模式
所以还得写上区分 然后后面的代码就照抄就行只要会IIC,SPI协议这些一看就明白是什么意思啦无非就是移位和最高/最低位判断然后将DATA拉高或者拉低换汤不换药简简单单。 根据DS1302的特殊寄存器假设现在是15秒那么1302的寄存器里面存储的是0x15而不是0x0F也就是说十六进制的0xAB表示一个十进制数高四位A代表十位低四位B代表个位 但这毕竟是用16进制表示的数字我们在单片机的代码里操作起来并不方便我们需要转换为正儿八经的十进制 所以上面一大堆可能看的很乱来我们现在来捋一捋 还是假设是15秒 好我们来分析上面的也就是说十六进制的0xAB表示一个十进制数高四位A代表十位低四位B代表个位这句话
0X150001 0101
高四位右移0001 0101 40000 00011
第四位不动0000 01010X0F 0000 0101 - 0000 0101 5 0000 1111 好那么这不就是15秒吗 那么就有了后面的代码 这样就非常的清晰了吧有没有拍桌子拍案叫绝的感觉了 我将DS1302.C和DS1302.H的代码都复制到后面核心重点就讲完了毫无难度呀 DS1302.C
#include DS1302.h
#include main.hTIME Time_Hex,Time_Dec,Time_Set;#define DS1302DELAY 100const u8 Ds1302SendBuf[6] {0x23, 0x11, 0x15, 0x13, 0x49, 0x00}; //2016unsigned char Month[13] {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};void INPUT_SDA()
{RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA ,ENABLE); GPIO_InitType GPIO_InitStructure;GPIO_InitStructure.Pin GPIO_PIN_7;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;//设置使用带宽50MhzGPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU; //输入模式GPIO_InitPeripheral(GPIOA, GPIO_InitStructure);
}void OUTPUT_SDA()
{RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA ,ENABLE); GPIO_InitType GPIO_InitStructure;GPIO_InitStructure.Pin GPIO_PIN_7;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;//设置使用带宽50MhzGPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; //输出模式GPIO_InitPeripheral(GPIOA, GPIO_InitStructure);
}void uDelay(unsigned int count)
{unsigned int j;for(j0;jcount;j) ;
}void SendDat_1302(u8 Dat)
{ u8 i;u8 cTmp;for(i0;i8;i){ cTmpDatLSB; //数据端等于tmp数据的末位值if(cTmp) //1DS1302DAT_H;elseDS1302DAT_L; Dat1;uDelay(DS1302DELAY);DS1302CLK_H;uDelay(DS1302DELAY);DS1302CLK_L;uDelay(DS1302DELAY);}
}/*写入1个或者多个字节第1个参数是相关命令
#define WrMulti 0xbe //写入多个字节的指令代码
#define WrSingle 0x84 //写入单个字节的指令代码
第2个参数是待写入的值
第3个参数是待写入数组的指针
*/
void WriteByte_1302(u8 CmdDat,u8 Num,u8 *pSend)
{ u8 i0;DS1302RST_L;uDelay(DS1302DELAY); DS1302RST_H;SendDat_1302(CmdDat);for(i0;iNum;i){ SendDat_1302(*(pSendi));}DS1302RST_L;
}
/*读出字节第一个参数是命令
#define RdMulti 0xbf //读出多个字节的指令代码
第2个参数是读出的字节数第3个是指收数据数组指针
*/
void RecByte_1302(u8 CmdDat,u8 Num,u8 *pRec)
{ u8 i,j,tmp0,cTmp;DS1302RST_L;//复位引脚为低电平uDelay(DS1302DELAY);DS1302CLK_L;uDelay(DS1302DELAY);DS1302RST_H;SendDat_1302(CmdDat); //发送命令INPUT_SDA();uDelay(DS1302DELAY);for(i0;iNum;i){ for(j0;j8;j){ tmp1;cTmpDS1302DAT_READ;if(cTmp)tmp|0x80;DS1302CLK_H;uDelay(DS1302DELAY);DS1302CLK_L; uDelay(DS1302DELAY);}*(pReci)tmp;}uDelay(DS1302DELAY);OUTPUT_SDA();DS1302RST_L;//复位引脚为低电平
}
/*
当写保护寄存器的最高位为0时,允许数据写入寄存器。
写保护寄存器可以通过命令字节8E、8F来规定禁止写入/读出。写保护位不能在多字节传送模式下写入。
当写保护寄存器的最高位为1时禁止数据写入寄存器。
时钟停止位操作:当把秒寄存器的第7位时钟停止位设置为0时起动时钟开始
当把秒寄存器的第7位时钟停止位设置为1时时钟振荡器停止。根据传入的参数决定相关命令
第一个参数命令字第2个参数写入的数据
写允许命令8EH,00H
写禁止命令8EH,80H
振荡器允许命令80H,00H
振荡器禁止命令80H,80H
*/
void WrCmd(u8 CmdDat,u8 CmdWord)
{ u8* CmdBuf;CmdBufCmdWord;WriteByte_1302(CmdDat,1,CmdBuf);
}void DS1302_Init(void)
{
//DS1302WrCmd(0x80, 0x00); //?????WrCmd(0x8C, Ds1302SendBuf[0]);WrCmd(0x88, Ds1302SendBuf[1]);WrCmd(0x86, Ds1302SendBuf[2]);//const u8 Ds1302SendBuf[6] {0x23, 0x11, 0x15, 0x13, 0x49, 0x00}; //2016WrCmd(0x84, Ds1302SendBuf[3]);WrCmd(0x82, Ds1302SendBuf[4]);WrCmd(0x80, Ds1302SendBuf[5]);WrCmd(0x8e, 0x80);
}void Save_TimeDate(void)
{WrCmd(WrEnDisCmd, WrEnDat); WrCmd(0x80, 0x00); WrCmd(0x8C, Time_Hex.year);WrCmd(0x88, Time_Hex.month);WrCmd(0x86, Time_Hex.day);WrCmd(0x84, Time_Hex.hour);WrCmd(0x82, Time_Hex.minute);WrCmd(0x80, Time_Hex.second);WrCmd(0x8e, 0x80);
}void Get_Time(void)
{WrCmd(0x8F,0x00);RecByte_1302(0x8D,1,(u8*)Time_Hex.year);RecByte_1302(0x89,1,(u8*)Time_Hex.month);RecByte_1302(0x87,1,(u8*)Time_Hex.day);RecByte_1302(0x85,1,(u8*)Time_Hex.hour);RecByte_1302(0x83,1,(u8*)Time_Hex.minute); RecByte_1302(0x81,1,(u8*)Time_Hex.second);Time_Dec.year (Time_Hex.year4)*10 (Time_Hex.year0x0f); Time_Dec.month (Time_Hex.month4)*10 (Time_Hex.month0x0f);Time_Dec.day (Time_Hex.day4)*10 (Time_Hex.day0x0f);Time_Dec.hour (Time_Hex.hour4)*10 (Time_Hex.hour0x0f);Time_Dec.minute (Time_Hex.minute4)*10 (Time_Hex.minute0x0f);Time_Dec.second (Time_Hex.second4)*10 (Time_Hex.second0x0f);
}void Check_date(void)
{ Time_Dec.year Time_Set.year; Time_Dec.month Time_Set.month;Time_Dec.day Time_Set.day;Time_Dec.hour Time_Set.hour;Time_Dec.minute Time_Set.minute;Time_Dec.second Time_Set.second;if(Time_Dec.month 1) Time_Dec.month 1;if(Time_Dec.month 12) Time_Dec.month 12;if(Time_Dec.day 1) Time_Dec.day 1;if(Time_Dec.day 31) Time_Dec.day 31;if(Time_Dec.hour 23) Time_Dec.hour 23; if(Time_Dec.minute 59) Time_Dec.minute 59; if(Time_Dec.second 60) Time_Dec.second 0;if(Time_Dec.minute 60) Time_Dec.minute 0;if(Time_Dec.hour 60) Time_Dec.hour 0; if(Time_Dec.year 99) Time_Dec.year 99;Month[2] 28;if((Time_Dec.year % 4 0 Time_Dec.year % 100 ! 0) || (Time_Dec.year % 400 0) )Month[2] 29; if(Time_Dec.day Month[Time_Dec.month]) Time_Dec.day Month[Time_Dec.month]; Time_Hex.year ((Time_Dec.year/10)4) | (Time_Dec.year%10);Time_Hex.month ((Time_Dec.month/10)4) | (Time_Dec.month%10);Time_Hex.day ((Time_Dec.day/10)4) | (Time_Dec.day%10);Time_Hex.hour ((Time_Dec.hour/10)4) | (Time_Dec.hour%10);Time_Hex.minute ((Time_Dec.minute/10)4) | (Time_Dec.minute%10);Time_Hex.second ((Time_Dec.second/10)4) | (Time_Dec.second%10);
}
DS1302.H #ifndef __DS1302_H
#define __DS1302_H#include main.h#define u8 unsigned char typedef struct
{unsigned char year ;unsigned char month ;unsigned char day ;unsigned char hour ;unsigned char minute ;unsigned char second ;
} TIME;#define DS1302CLK_H GPIO_SetBits(GPIOA,GPIO_PIN_6)
#define DS1302CLK_L GPIO_ResetBits(GPIOA,GPIO_PIN_6)#define DS1302DAT_H GPIO_SetBits(GPIOA, GPIO_PIN_7)
#define DS1302DAT_L GPIO_ResetBits(GPIOA,GPIO_PIN_7)
#define DS1302DAT_READ GPIO_ReadInputDataBit(GPIOA, GPIO_PIN_7)#define DS1302RST_H GPIO_SetBits(GPIOC, GPIO_PIN_4)
#define DS1302RST_L GPIO_ResetBits(GPIOC,GPIO_PIN_4)#define WrEnDisCmd 0x8e //写允许/禁止指令代码
#define WrEnDat 0x00 //写允许数据
#define WrDisDat 0x80 //写禁止数据
#define OscEnDisCmd 0x80 //振荡器允许/禁止指令代码
#define OscEnDat 0x00 //振荡器允许数据
#define OscDisDat 0x80 //振荡器禁止数据
#define WrMulti 0xbe //写入多个字节的指令代码
#define WrSingle 0x84 //写入单个字节的指令代码
#define RdMulti 0xbf //读出多个字节的指令代码
#define RamMulti_W 0xFE //写入RAM多个字节的指令代码
#define RamMulti_R 0xFf //读出多个RAM字节的指令代码#define LSB 0x01 void WrCmd(u8 CmdDat,u8 CmdWord);
void WriteByte_1302(u8 CmdDat,u8 Num,u8 *pSend);
void RecByte_1302(u8 CmdDat,u8 Num,u8 *pRec);
void ReCmd(u8 CmdDat,u8 CmdWord);
void DS1302_Init(void);
void Get_Time(void);
void Save_TimeDate(void);
void Check_date(void);
#endif 注以上笔记仅是个人学习笔记若对你有帮忙那么最好不过共勉