STM8驱动RTC芯片DS1302
使用软件:IAR FOR STM8
编程方式:固件库
硬件配套:STM8S105C6T6实验板
1. DS1302.h
- 引脚定义
- 函数封装
- 时间数据结构体定义
- 数据缓冲区定义
#ifndef __DS1302_H
#define __DS1302_H
/****************************驱动 RTC 芯片 DS1302******************************/
/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
/* Defines -------------------------------------------------------------------*/
#define RTC_RESET_TIME_EN 0u
#define RTC_SCK_PORT (GPIOD)
#define RTC_SCK_PIN (GPIO_PIN_2) // PD2
#define RTC_SCK_HIGH() GPIO_WriteHigh(RTC_SCK_PORT, RTC_SCK_PIN)
#define RTC_SCK_LOW() GPIO_WriteLow (RTC_SCK_PORT, RTC_SCK_PIN)
#define RTC_IO_PORT (GPIOD)
#define RTC_IO_PIN (GPIO_PIN_3) // PD3
#define RTC_IO_IN() GPIO_Init(RTC_IO_PORT, RTC_IO_PIN, GPIO_MODE_IN_PU_NO_IT)
#define RTC_IO_STATUS() GPIO_ReadInputPin(RTC_IO_PORT, RTC_IO_PIN)
#define RTC_IO_OUT() GPIO_Init(RTC_IO_PORT, RTC_IO_PIN, GPIO_MODE_OUT_PP_HIGH_SLOW)
#define RTC_IO_HIGH() GPIO_WriteHigh(RTC_IO_PORT, RTC_IO_PIN)
#define RTC_IO_LOW() GPIO_WriteLow (RTC_IO_PORT, RTC_IO_PIN)
#define RTC_RST_PORT (GPIOD)
#define RTC_RST_PIN (GPIO_PIN_7) // PD7
#define RTC_RST_HIGH() GPIO_WriteHigh(RTC_RST_PORT, RTC_RST_PIN)
#define RTC_RST_LOW() GPIO_WriteLow (RTC_RST_PORT, RTC_RST_PIN)
/* Values --------------------------------------------------------------------*/
typedef struct Time
{
uint8_t year; // year 0-99
uint8_t month; // month 01-12
uint8_t day; // day 01-28,29,30,31
uint8_t week; // week 01-07
uint8_t hour; // hour 01-12 or 00-23
uint8_t minute; // minute 00-59
uint8_t second; // second 00-59
}TimeTypeDef;
static TimeTypeDef TimeBuffer; // 数据缓冲区(8421-BCD码)
/* Functions -----------------------------------------------------------------*/
void DS1302_Init (void);
static void DS1302_WriteByte (uint8_t byte);
static uint8_t DS1302_ReadByte (void);
static void DS1302_WriteData (uint8_t addr, uint8_t data);
static uint8_t DS1302_ReadData (uint8_t addr);
TimeTypeDef DS1302_ReadTime (void);
void DS1302_WriteTime (TimeTypeDef *TimeDisplay);
static uint8_t DectoBCD (uint8_t num);
static uint8_t BCDtoDec (uint8_t num);
static void DS1302_DLY_ms(uint16_t nCount);
static void DS1302_DLY_us(uint16_t nCount);
#endif /* __DS1302_H */
2. DS1302.c
- 引脚初始化
- 数据传输协议实现
- BCD 码和十进制数互相转换
- 数据处理
#include "ds1302.h"
/*************************************************************************
初始化
--------------------------------------------------------------------------
无参数
--------------------------------------------------------------------------
无返回值
*************************************************************************/
void DS1302_Init (void)
{
GPIO_Init(RTC_SCK_PORT, RTC_SCK_PIN, GPIO_MODE_OUT_PP_HIGH_SLOW);
GPIO_Init(RTC_RST_PORT, RTC_RST_PIN, GPIO_MODE_OUT_PP_HIGH_SLOW);
GPIO_Init(RTC_IO_PORT, RTC_IO_PIN, GPIO_MODE_OUT_PP_HIGH_SLOW);
RTC_SCK_LOW();
RTC_IO_LOW();
RTC_RST_LOW();
}
/*************************************************************************
写一字节数据
--------------------------------------------------------------------------
byte:一字节数据
--------------------------------------------------------------------------
无返回值
*************************************************************************/
static void DS1302_WriteByte (uint8_t byte)
{
uint8_t i;
BitStatus bit;
RTC_IO_OUT(); // IO 配置为输出模式
for (i = 0; i < 8; i++)
{
RTC_SCK_LOW();
bit = (BitStatus)(byte & 0x01);
if (bit != RESET)
RTC_IO_HIGH();
else
RTC_IO_LOW();
RTC_SCK_HIGH();
byte >>= 1;
//DS1302_DLY_ms(1);
}
}
/*************************************************************************
读一字节数据
--------------------------------------------------------------------------
addr:地址
--------------------------------------------------------------------------
返回值:一字节数据
*************************************************************************/
static uint8_t DS1302_ReadByte (void)
{
uint8_t i;
uint8_t data = 0;
BitStatus bit;
RTC_IO_IN(); // IO 配置为输入模式
for (i = 0; i < 8; i++)
{
data >>= 1;
RTC_SCK_LOW();
bit = RTC_IO_STATUS();
if (bit != RESET)
data |= 0x80;
else
data &= 0x7F;
RTC_SCK_HIGH();
//DS1302_DLY_ms(1);
}
return data;
}
/*************************************************************************
往指定寄存器写入一字节数据
--------------------------------------------------------------------------
addr:地址 data:一字节数据
--------------------------------------------------------------------------
无返回值
*************************************************************************/
static void DS1302_WriteData (uint8_t addr, uint8_t data)
{
// 数据传输开始
RTC_RST_LOW();
RTC_SCK_LOW();
RTC_RST_HIGH();
DS1302_WriteByte (addr); // 写入的地址
DS1302_WriteByte (data); // 写入的数据
// 数据传输结束
RTC_RST_LOW();
}
/*************************************************************************
在指定寄存器读出一字节数据
--------------------------------------------------------------------------
addr:地址
--------------------------------------------------------------------------
返回值:一字节数据
*************************************************************************/
static uint8_t DS1302_ReadData (uint8_t addr)
{
uint8_t data;
// 数据传输开始
RTC_RST_LOW();
RTC_SCK_LOW();
RTC_RST_HIGH();
DS1302_WriteByte (addr); // 要读的地址
data = DS1302_ReadByte(); // 要读的数据
// 数据传输结束
RTC_RST_LOW();
return data;
}
/*************************************************************************
读时间
--------------------------------------------------------------------------
无参数
--------------------------------------------------------------------------
返回值:时间数据
*************************************************************************/
TimeTypeDef DS1302_ReadTime (void)
{
TimeTypeDef TimeDisplay;
// 读出来的数据是 BCD 码
TimeBuffer.year = DS1302_ReadData (0x8D);
TimeBuffer.month = DS1302_ReadData (0x89);
TimeBuffer.day = DS1302_ReadData (0x87);
TimeBuffer.week = DS1302_ReadData (0x8B);
TimeBuffer.hour = DS1302_ReadData (0x85);
TimeBuffer.minute = DS1302_ReadData (0x83);
TimeBuffer.second = DS1302_ReadData (0x81); // bit7 定义为时钟暂停标志(CH)
// BCD 码转换为十进制
TimeDisplay.year = BCDtoDec (TimeBuffer.year);
TimeDisplay.month = BCDtoDec (TimeBuffer.month);
TimeDisplay.day = BCDtoDec (TimeBuffer.day);
TimeDisplay.week = BCDtoDec (TimeBuffer.week);
TimeDisplay.hour = BCDtoDec (TimeBuffer.hour);
TimeDisplay.minute = BCDtoDec (TimeBuffer.minute);
TimeDisplay.second = BCDtoDec (TimeBuffer.second);
return TimeDisplay;
}
/*************************************************************************
修改时间
--------------------------------------------------------------------------
*TimeDisplay:要显示的时间(十进制)
--------------------------------------------------------------------------
无返回值
*************************************************************************/
void DS1302_WriteTime (TimeTypeDef *TimeDisplay)
{
// 十进制转换为 BCD 码
TimeBuffer.year = DectoBCD (TimeDisplay->year);
TimeBuffer.month = DectoBCD (TimeDisplay->month);
TimeBuffer.day = DectoBCD (TimeDisplay->day);
TimeBuffer.week = DectoBCD (TimeDisplay->week);
TimeBuffer.hour = DectoBCD (TimeDisplay->hour);
TimeBuffer.minute = DectoBCD (TimeDisplay->minute);
TimeBuffer.second = DectoBCD (TimeDisplay->second);
// 关闭写保护(控制寄存器:8FH、8EH bit7:保护位)
DS1302_WriteData (0x8E, 0x00);
// 写入的数据是 BCD 码
DS1302_WriteData (0x8C, TimeBuffer.year);
DS1302_WriteData (0x88, TimeBuffer.month);
DS1302_WriteData (0x86, TimeBuffer.day);
DS1302_WriteData (0x8A, TimeBuffer.week);
DS1302_WriteData (0x84, TimeBuffer.hour);
DS1302_WriteData (0x82, TimeBuffer.minute);
DS1302_WriteData (0x80, TimeBuffer.second); // bit7 定义为时钟暂停标志(CH)
// 开启写保护(控制寄存器:8FH、8EH bit7:保护位)
DS1302_WriteData (0x8E, 0x80);
}
/*************************************************************************
十进制转BCD码
--------------------------------------------------------------------------
num:十进制数
--------------------------------------------------------------------------
返回值:BCD码
*************************************************************************/
static uint8_t DectoBCD (uint8_t num)
{
uint8_t result;
uint8_t temp1, temp2;
temp1 = (num / 10) << 4; // 十位 / 10 * 16
temp2 = num % 10; // 个位 % 10
result = temp1 + temp2;
return result;
}
/*************************************************************************
BCD码转十进制
--------------------------------------------------------------------------
num:BCD码
--------------------------------------------------------------------------
返回值:十进制
*************************************************************************/
static uint8_t BCDtoDec (uint8_t num)
{
uint8_t result;
uint8_t temp1, temp2;
temp1 = (num >> 4) * 10; // 十位 / 16 * 10
temp2 = num & 0x0F; // 个位 % 16
result = temp1 + temp2;
return result;
}
/*************************************************************************
软件延时(ms级别)
--------------------------------------------------------------------------
nCount:延时长度
--------------------------------------------------------------------------
无返回值
*************************************************************************/
static void DS1302_DLY_ms(uint16_t nCount)
{
while(nCount--)
{
DS1302_DLY_us(1000);
}
}
/*************************************************************************
软件延时(us级别)
--------------------------------------------------------------------------
nCount:延时长度
--------------------------------------------------------------------------
无返回值
*************************************************************************/
static void DS1302_DLY_us(uint16_t nCount)
{
nCount *= 2;
while(--nCount);
}
3. main.c
#include "stm8s.h"
#include "ds1302.h"
#include "uart.h"
void SystemInit_CLK(void);
void main(void)
{
// 数据显示区(十进制)
// 初始值:2022.02.25 Fri. 01:59:50
TimeTypeDef TimeDisplay = {22, 02, 25, 5, 01, 59, 50};
uint8_t TimeSecPre;
SystemInit_CLK();
UART2_Config();
DS1302_Init();
printf("Init Success!\r\n");
#if RTC_RESET_TIME_EN > 0u
DS1302_WriteTime(&TimeDisplay);
#endif
while (1)
{
TimeDisplay = DS1302_ReadTime();
if (TimeSecPre != TimeDisplay.second)
{
TimeSecPre = TimeDisplay.second;
printf("20%d年%d月%d日 星期%d\r\n", TimeDisplay.year, TimeDisplay.month, TimeDisplay.day,
TimeDisplay.week);
printf("%d时%d分%d秒\r\n", TimeDisplay.hour, TimeDisplay.minute, TimeDisplay.second);
printf("\r\n");
}
}
}
void SystemInit_CLK(void)
{
CLK_DeInit();
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); // 16MHz
CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV1);
CLK_HSICmd(ENABLE);
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
在串口打印时间: