DS1302是时钟芯片
DS1302的寄存器地址定义如下:
单字节读写时序如下图,均为上升沿触发:
由于DS1302时钟芯片不是常用的SPI协议,与SPI协议很像,所以需要初始化普通GPIO口手工实现该协议通信。
设置分别连接DS1302的CE、SCLK、Data口的GPIO,PB8\PB9\PB10:
打开gpio.h文件,定义结构体和预处理:
#define W_SECOND 0x80
#define W_MINUTE 0x82
#define W_HOUR 0x84
#define W_DAY 0x86
#define W_MONTH 0x88
#define W_WEEK 0x8A
#define W_YEAR 0x8C
#define W_CONTR 0x8E
#define R_SECOND 0x81
#define R_MINUTE 0x83
#define R_HOUR 0x85
#define R_DAY 0x87
#define R_MONTH 0x89
#define R_WEEK 0x8B
#define R_YEAR 0x8D
#define R_CONTR 0x8F
#define RST_L HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET)
#define RST_H HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET)
#define CLK_L HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET)
#define CLK_H HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET)
#define DATA_L HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET)
#define DATA_H HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET)
#define DATA_READ HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10)
typedef struct {
uint8_t year;
uint8_t week;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
uint8_t second;
}timeNow_t;
由于数据发送和接受是共用PB10,编写数据写GPIO和读GPIO的初始化:
static void DS1302_Data_Write_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/*Configure GPIO pin : PB10 */
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
static void DS1302_Data_Read_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/*Configure GPIO pin : PB10 */
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
定义读和写寄存器的操作函数:
void DS1302_Single_Byte_Write(uint8_t data)
{
DS1302_Data_Write_Init();
CLK_L;
for(int i=0;i<8;i++)
{
CLK_L;
if((data&0x01)==0x01)
DATA_H;
else
DATA_L;
data>>=0x01;
CLK_H;
}
}
void DS1302_Write_Register(uint8_t regAddress,uint8_t regData)
{
RST_L;
CLK_L;
RST_H;
DS1302_Single_Byte_Write(regAddress);
DS1302_Single_Byte_Write(regData);
RST_H;
}
uint8_t DS1302_Read_Register(uint8_t regAddress)
{
RST_L;
CLK_L;
uint8_t regData=0x00;
RST_H;
DS1302_Single_Byte_Write(regAddress);
DS1302_Data_Read_Init();
for(int i=0;i<8;i++)
{
regData>>=0x01;
CLK_H;
CLK_L;
HAL_Delay(1);
if(DATA_READ==GPIO_PIN_SET)
regData=regData|0x80;
}
RST_H;
return regData;
}
设置和读取时间函数:
void DS1302_Set_Time(uint8_t year,uint8_t week,uint8_t month,uint8_t day,uint8_t hour,uint8_t minute,uint8_t second)
{
DS1302_Write_Register(W_CONTR,0x00);
DS1302_Write_Register(W_YEAR,year);
DS1302_Write_Register(W_WEEK,week);
DS1302_Write_Register(W_MONTH,month);
DS1302_Write_Register(W_DAY,day);
DS1302_Write_Register(W_HOUR,hour);
DS1302_Write_Register(W_MINUTE,minute);
DS1302_Write_Register(W_SECOND,second);
DS1302_Write_Register(W_CONTR,0x80);
}
timeNow_t DS1302_Read_Time(void)
{
timeNow_t timeNow;
timeNow.year=DS1302_Read_Register(R_YEAR);
timeNow.week=DS1302_Read_Register(R_WEEK);
timeNow.month=DS1302_Read_Register(R_MONTH);
timeNow.day=DS1302_Read_Register(R_DAY);
timeNow.hour=DS1302_Read_Register(R_HOUR);
timeNow.minute=DS1302_Read_Register(R_MINUTE);
timeNow.second=DS1302_Read_Register(R_SECOND);
return timeNow;
}
显示时间:
void DS1302_Print_Time(void)
{
timeNow_t timeNow=DS1302_Read_Time();
printf("20%02X-%02X-%02X %02X:%02X:%02X\n",timeNow.year,timeNow.month,timeNow.day,timeNow.hour,timeNow.minute,timeNow.second);
}
在main函数中测试是否成功实现时钟显示:
DS1302_Set_Time(0x22,0x07,0x08,0x07,0x11,0x36,0x09);
while (1)
{
HAL_Delay(1000);
DS1302_Print_Time();
}
成功显示时钟: