欢迎入群共同学习交流
时间记录:2024/4/30
一、知识点
(1)读写数据时序(伪SPI协议)
1.1 读写时序默认电平均为SCLK线低电平,CE线低电平
1.2 写数据,CE线拉高为高电平,开始传输数据,然后准备数据在SCLK线的上升沿DS1302读取数据,发送8位控制命令后,发送8位数据(低位先发)
1.3 读数据,CE线拉高为高电平,开始传输数据,然后在SCLK低电平时准备数据,上升沿发送数据,发送8位控制命令后,下一个下降沿开始读取数据(低位先发,低位先读)
(2)读写命令及数据格式
2.1 READ和WRITE的命令即为发送和读取数据前需要先发送的对应8位控制命令
2.2 秒数据的BIT7位CH决定时钟的开启/关闭
2.3 小时数据的BIT7位决定是12小时显示还是24小时显示
2.4 WP位决定开启写保护还是取消写保护,写入0取消写保护,写入1打开写保护
(3)数据转换
3.1 DS1302读取的数据为BCD编码格式,需要转为10进制,写入时10进制数据需要转为BCD格式
3.2 BCD->10进制,BCD/1610+BCD%16
3.3 10进制->BCD,10进制/1016+10进制%10
二、示例代码
(1)头文件
#ifndef __DS1302_H__
#define __DS1302_H__
#include "stm32f10x.h"typedef struct __DS1302TIME
{int year;int mon;int day;int hour;int min;int sec;int week;
}ds_time;void vDS1302_Init(void);
void vDS1302_SetTime(ds_time *sys_time);
void vDS1302_GetTime(ds_time *sys_time);#endif
(2)源文件
#include "ds1302.h"/*** 模块引脚宏定义*/
#define DS1302_SCLK_PORT GPIOA
#define DS1302_SCLK_PIN GPIO_Pin_10
#define DS1302_DAT_PORT GPIOA
#define DS1302_DAT_PIN GPIO_Pin_11
#define DS1302_RST_PORT GPIOA
#define DS1302_RST_PIN GPIO_Pin_12/*** 获取设置时间命令宏定义*/
#define READ_SEC 0x81
#define WRITE_SEC 0x80
#define READ_MIN 0x83
#define WRITE_MIN 0x82
#define READ_HOUR 0x85
#define WRITE_HOUR 0x84
#define READ_DAY 0x87
#define WRITE_DAY 0x86
#define READ_MON 0x89
#define WRITE_MON 0x88
#define READ_WEEK 0x8B
#define WRITE_WEEK 0x8A
#define READ_YEAR 0x8D
#define WRITE_YEAR 0x8C
#define ENABLE_WRITE 0x00
#define DISABLE_WRITE 0x80/*** 枚举定义*/
enum __LINEMODE
{INPUT_MODE = 0,OUTPUT_MODE
};/*** 函数声明*/
static void vDatLineMode(u8 mode);
static void vWriteRam(u8 addr, u8 data);
static u8 vReadRam(u8 addr);/*** 初始化函数定义*/
void vDS1302_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = DS1302_SCLK_PIN;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DS1302_SCLK_PORT, &GPIO_InitStruct);GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);GPIO_InitStruct.GPIO_Pin = DS1302_RST_PIN;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DS1302_RST_PORT, &GPIO_InitStruct);GPIO_ResetBits(DS1302_RST_PORT, DS1302_RST_PIN);
}/*** 数据引脚切换输入输出模式*/
static void vDatLineMode(u8 mode)
{GPIO_InitTypeDef GPIO_InitStruct;if (mode == INPUT_MODE){GPIO_InitStruct.GPIO_Pin = DS1302_DAT_PIN;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DS1302_DAT_PORT, &GPIO_InitStruct);}else if (mode == OUTPUT_MODE){GPIO_InitStruct.GPIO_Pin = DS1302_DAT_PIN;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DS1302_DAT_PORT, &GPIO_InitStruct);}
}/*** 写入数据*/
static void vWriteRam(u8 addr, u8 data)
{vDatLineMode(OUTPUT_MODE);GPIO_SetBits(DS1302_RST_PORT, DS1302_RST_PIN); // 开始传输数据for (u8 i = 0; i < 8; i++) // 传输控制字节{GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN); // 低电平准备数据if (addr & 0x01) // 低位先发GPIO_SetBits(DS1302_DAT_PORT, DS1302_DAT_PIN);elseGPIO_ResetBits(DS1302_DAT_PORT, DS1302_DAT_PIN);GPIO_SetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN); // 上升沿发送数据addr >>= 1;}for (u8 i = 0; i < 8; i++) // 传输数据字节{GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);if (data & 0x01)GPIO_SetBits(DS1302_DAT_PORT, DS1302_DAT_PIN);elseGPIO_ResetBits(DS1302_DAT_PORT, DS1302_DAT_PIN);GPIO_SetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);data >>= 1;}// 传输完毕,恢复取消传输数据状态GPIO_ResetBits(DS1302_RST_PORT, DS1302_RST_PIN);GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);
}/*** 读取数据*/
static u8 vReadRam(u8 addr)
{vDatLineMode(OUTPUT_MODE);GPIO_SetBits(DS1302_RST_PORT, DS1302_RST_PIN);u8 retData = 0x00;for (u8 i = 0; i < 8; i++) // 传输控制字节{GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN); // 低电平准备数据if (addr & 0x01) // 低位先发GPIO_SetBits(DS1302_DAT_PORT, DS1302_DAT_PIN);elseGPIO_ResetBits(DS1302_DAT_PORT, DS1302_DAT_PIN);GPIO_SetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);addr >>= 1;}vDatLineMode(INPUT_MODE);for (u8 i = 0; i < 8; i++){retData >>= 1;GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);if (GPIO_ReadInputDataBit(DS1302_DAT_PORT, DS1302_DAT_PIN))retData |= 0x80;GPIO_SetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);}GPIO_ResetBits(DS1302_RST_PORT, DS1302_RST_PIN);GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);return (retData & 0x7F); // 最高位是一些标志位可清零不获取
}void vDS1302_SetTime(ds_time *sys_time)
{vWriteRam(0x8E, ENABLE_WRITE); // 关闭写保护sys_time->year = sys_time->year - 2000;vWriteRam(WRITE_YEAR, ((sys_time->year / 10 * 16) + (sys_time->year % 10)));vWriteRam(WRITE_MON, ((sys_time->mon / 10 * 16) + (sys_time->mon % 10)));vWriteRam(WRITE_DAY, ((sys_time->day / 10 * 16) + (sys_time->day % 10)));vWriteRam(WRITE_HOUR, ((sys_time->hour / 10 * 16) + (sys_time->hour % 10)));vWriteRam(WRITE_MIN, ((sys_time->min / 10 * 16) + (sys_time->min % 10)));vWriteRam(WRITE_SEC, ((sys_time->sec / 10 * 16) + (sys_time->sec % 10)));vWriteRam(WRITE_WEEK, ((sys_time->week / 10 * 16) + (sys_time->week % 10)));vWriteRam(0x8E, DISABLE_WRITE); // 开启写保护
}void vDS1302_GetTime(ds_time *sys_time)
{u8 tempDat = 0x00;tempDat = vReadRam(READ_YEAR);sys_time->year = (tempDat / 16 * 10) + (tempDat % 16) + 2000;tempDat = vReadRam(READ_MON);sys_time->mon = (tempDat / 16 * 10) + (tempDat % 16);tempDat = vReadRam(READ_DAY);sys_time->day = (tempDat / 16 * 10) + (tempDat % 16);tempDat = vReadRam(READ_HOUR);sys_time->hour = (tempDat / 16 * 10) + (tempDat % 16);tempDat = vReadRam(READ_MIN);sys_time->min = (tempDat / 16 * 10) + (tempDat % 16);tempDat = vReadRam(READ_SEC);sys_time->sec = (tempDat / 16 * 10) + (tempDat % 16);tempDat = vReadRam(READ_WEEK);sys_time->week = (tempDat / 16 * 10) + (tempDat % 16);
}