STM32标准库读写RX8025实时时钟芯片完整示例程序
一、完整代码实现
1. 头文件 (rx8025.h)
#ifndef __RX8025_H
#define __RX8025_H
#include "stm32f10x.h"
#include "stm32f10x_i2c.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "misc.h"
// RX8025 I2C地址定义
#define RX8025_I2C_ADDR_WRITE 0x64 // 写地址
#define RX8025_I2C_ADDR_READ 0x65 // 读地址
// RX8025寄存器地址定义
#define RX8025_REG_SECONDS 0x00 // 秒
#define RX8025_REG_MINUTES 0x01 // 分
#define RX8025_REG_HOURS 0x02 // 时
#define RX8025_REG_WEEK 0x03 // 星期
#define RX8025_REG_DAY 0x04 // 日
#define RX8025_REG_MONTH 0x05 // 月
#define RX8025_REG_YEAR 0x06 // 年
#define RX8025_REG_CONTROL1 0x07 // 控制寄存器1
#define RX8025_REG_CONTROL2 0x08 // 控制寄存器2
#define RX8025_REG_EXTENSION 0x0D // 扩展寄存器
#define RX8025_REG_FLAG 0x0E // 标志寄存器
#define RX8025_REG_TEMP 0x0F // 温度寄存器
// 控制寄存器1位定义
#define RX8025_CTRL1_TEST (1 << 7) // 测试模式
#define RX8025_CTRL1_24H (0 << 6) // 24小时制
#define RX8025_CTRL1_12H (1 << 6) // 12小时制
#define RX8025_CTRL1_DAFG (1 << 3) // 日期闹钟标志
#define RX8025_CTRL1_WAFG (1 << 4) // 星期闹钟标志
// 控制寄存器2位定义
#define RX8025_CTRL2_RESET (1 << 0) // 复位
#define RX8025_CTRL2_CTFG (1 << 1) // 校准标志
#define RX8025_CTRL2_FSEL (1 << 2) // 频率选择
#define RX8025_CTRL2_TSEL (1 << 3) // 温度补偿选择
#define RX8025_CTRL2_USEL (1 << 4) // 更新选择
#define RX8025_CTRL2_WT (1 << 5) // 星期/日期选择
#define RX8025_CTRL2_HF (1 << 6) // 小时标志
#define RX8025_CTRL2_CT (1 << 7) // 校准使能
// 扩展寄存器位定义
#define RX8025_EXT_FSEL1 (1 << 2) // 频率选择高位
#define RX8025_EXT_TSEL1 (1 << 3) // 温度补偿选择高位
// 标志寄存器位定义
#define RX8025_FLAG_VDET (1 << 0) // 电压检测
#define RX8025_FLAG_XST (1 << 1) // 晶体振荡器停止
#define RX8025_FLAG_PON (1 << 2) // 电源开启
#define RX8025_FLAG_UTSF (1 << 3) // 更新结束标志
#define RX8025_FLAG_ALARM (1 << 4) // 闹钟标志
#define RX8025_FLAG_DAFG (1 << 5) // 日期闹钟标志
#define RX8025_FLAG_WAFG (1 << 6) // 星期闹钟标志
#define RX8025_FLAG_CTFG (1 << 7) // 校准标志
// 时间结构体定义
typedef struct {
uint8_t seconds; // 秒 (0-59)
uint8_t minutes; // 分 (0-59)
uint8_t hours; // 时 (0-23)
uint8_t week; // 星期 (0-6, 0=周日)
uint8_t day; // 日 (1-31)
uint8_t month; // 月 (1-12)
uint8_t year; // 年 (0-99)
} RX8025_TimeTypeDef;
// 温度结构体定义
typedef struct {
int8_t integer; // 整数部分
uint8_t fraction; // 小数部分 (0.25℃分辨率)
} RX8025_TempTypeDef;
// 闹钟结构体定义
typedef struct {
uint8_t minute; // 分钟 (0-59)
uint8_t hour; // 小时 (0-23)
uint8_t day; // 日 (1-31)
uint8_t week; // 星期 (0-6)
uint8_t enable; // 使能标志
} RX8025_AlarmTypeDef;
// 函数声明
void RX8025_I2C_Init(void);
uint8_t RX8025_WriteReg(uint8_t reg_addr, uint8_t data);
uint8_t RX8025_ReadReg(uint8_t reg_addr, uint8_t *data);
uint8_t RX8025_WriteMultiReg(uint8_t reg_addr, uint8_t *data, uint8_t len);
uint8_t RX8025_ReadMultiReg(uint8_t reg_addr, uint8_t *data, uint8_t len);
uint8_t RX8025_SetTime(RX8025_TimeTypeDef *time);
uint8_t RX8025_GetTime(RX8025_TimeTypeDef *time);
uint8_t RX8025_GetTemperature(RX8025_TempTypeDef *temp);
uint8_t RX8025_SetAlarm(RX8025_AlarmTypeDef *alarm);
uint8_t RX8025_GetAlarm(RX8025_AlarmTypeDef *alarm);
uint8_t RX8025_ClearFlags(uint8_t flags);
uint8_t RX8025_Init(void);
uint8_t BCD2DEC(uint8_t bcd);
uint8_t DEC2BCD(uint8_t dec);
void RX8025_Delay(uint32_t ms);
void RX8025_ErrorHandler(void);
#endif /* __RX8025_H */
2. 源文件 (rx8025.c)
#include "rx8025.h"
#include <stdio.h>
// I2C超时时间
#define I2C_TIMEOUT 10000
// 全局变量
static I2C_TypeDef* RX8025_I2C = I2C1;
static uint32_t I2C_ClockSpeed = 400000; // 400kHz
// I2C初始化
void RX8025_I2C_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
// 使能GPIOB和I2C1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
// 配置PB6(SCL)和PB7(SDA)为复用开漏输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 复用开漏
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 复位I2C
I2C_DeInit(RX8025_I2C);
// I2C配置
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x00; // 从机地址,主机模式可设为0
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = I2C_ClockSpeed;
I2C_Init(RX8025_I2C, &I2C_InitStructure);
I2C_Cmd(RX8025_I2C, ENABLE);
}
// 写单个寄存器
uint8_t RX8025_WriteReg(uint8_t reg_addr, uint8_t data) {
uint32_t timeout = I2C_TIMEOUT;
// 等待I2C总线空闲
while(I2C_GetFlagStatus(RX8025_I2C, I2C_FLAG_BUSY)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送起始条件
I2C_GenerateSTART(RX8025_I2C, ENABLE);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_MODE_SELECT)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送设备地址(写)
I2C_Send7bitAddress(RX8025_I2C, RX8025_I2C_ADDR_WRITE, I2C_Direction_Transmitter);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送寄存器地址
I2C_SendData(RX8025_I2C, reg_addr);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送数据
I2C_SendData(RX8025_I2C, data);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送停止条件
I2C_GenerateSTOP(RX8025_I2C, ENABLE);
return 0;
}
// 读单个寄存器
uint8_t RX8025_ReadReg(uint8_t reg_addr, uint8_t *data) {
uint32_t timeout = I2C_TIMEOUT;
// 等待I2C总线空闲
while(I2C_GetFlagStatus(RX8025_I2C, I2C_FLAG_BUSY)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送起始条件(写模式)
I2C_GenerateSTART(RX8025_I2C, ENABLE);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_MODE_SELECT)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送设备地址(写)
I2C_Send7bitAddress(RX8025_I2C, RX8025_I2C_ADDR_WRITE, I2C_Direction_Transmitter);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送寄存器地址
I2C_SendData(RX8025_I2C, reg_addr);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 重新发送起始条件(读模式)
I2C_GenerateSTART(RX8025_I2C, ENABLE);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_MODE_SELECT)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送设备地址(读)
I2C_Send7bitAddress(RX8025_I2C, RX8025_I2C_ADDR_READ, I2C_Direction_Receiver);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 禁用应答(读取最后一个字节)
I2C_AcknowledgeConfig(RX8025_I2C, DISABLE);
// 等待数据接收完成
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_BYTE_RECEIVED)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 读取数据
*data = I2C_ReceiveData(RX8025_I2C);
// 发送停止条件
I2C_GenerateSTOP(RX8025_I2C, ENABLE);
// 重新使能应答
I2C_AcknowledgeConfig(RX8025_I2C, ENABLE);
return 0;
}
// 写多个寄存器
uint8_t RX8025_WriteMultiReg(uint8_t reg_addr, uint8_t *data, uint8_t len) {
uint32_t timeout = I2C_TIMEOUT;
uint8_t i;
// 等待I2C总线空闲
while(I2C_GetFlagStatus(RX8025_I2C, I2C_FLAG_BUSY)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送起始条件
I2C_GenerateSTART(RX8025_I2C, ENABLE);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_MODE_SELECT)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送设备地址(写)
I2C_Send7bitAddress(RX8025_I2C, RX8025_I2C_ADDR_WRITE, I2C_Direction_Transmitter);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送寄存器地址
I2C_SendData(RX8025_I2C, reg_addr);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送多个数据
for(i = 0; i < len; i++) {
I2C_SendData(RX8025_I2C, data[i]);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
}
// 发送停止条件
I2C_GenerateSTOP(RX8025_I2C, ENABLE);
return 0;
}
// 读多个寄存器
uint8_t RX8025_ReadMultiReg(uint8_t reg_addr, uint8_t *data, uint8_t len) {
uint32_t timeout = I2C_TIMEOUT;
uint8_t i;
// 等待I2C总线空闲
while(I2C_GetFlagStatus(RX8025_I2C, I2C_FLAG_BUSY)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送起始条件(写模式)
I2C_GenerateSTART(RX8025_I2C, ENABLE);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_MODE_SELECT)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送设备地址(写)
I2C_Send7bitAddress(RX8025_I2C, RX8025_I2C_ADDR_WRITE, I2C_Direction_Transmitter);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送寄存器地址
I2C_SendData(RX8025_I2C, reg_addr);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 重新发送起始条件(读模式)
I2C_GenerateSTART(RX8025_I2C, ENABLE);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_MODE_SELECT)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 发送设备地址(读)
I2C_Send7bitAddress(RX8025_I2C, RX8025_I2C_ADDR_READ, I2C_Direction_Receiver);
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 读取多个数据
for(i = 0; i < len; i++) {
if(i == len - 1) {
// 最后一个字节,禁用应答
I2C_AcknowledgeConfig(RX8025_I2C, DISABLE);
}
// 等待数据接收完成
timeout = I2C_TIMEOUT;
while(!I2C_CheckEvent(RX8025_I2C, I2C_EVENT_MASTER_BYTE_RECEIVED)) {
if((timeout--) == 0) {
RX8025_ErrorHandler();
return 1;
}
}
// 读取数据
data[i] = I2C_ReceiveData(RX8025_I2C);
}
// 发送停止条件
I2C_GenerateSTOP(RX8025_I2C, ENABLE);
// 重新使能应答
I2C_AcknowledgeConfig(RX8025_I2C, ENABLE);
return 0;
}
// BCD码转十进制
uint8_t BCD2DEC(uint8_t bcd) {
return ((bcd >> 4) * 10) + (bcd & 0x0F);
}
// 十进制转BCD码
uint8_t DEC2BCD(uint8_t dec) {
return ((dec / 10) << 4) | (dec % 10);
}
// 设置时间
uint8_t RX8025_SetTime(RX8025_TimeTypeDef *time) {
uint8_t data[7];
// 转换为BCD码
data[0] = DEC2BCD(time->seconds) & 0x7F; // 秒,最高位为0
data[1] = DEC2BCD(time->minutes) & 0x7F; // 分,最高位为0
data[2] = DEC2BCD(time->hours) & 0x3F; // 时,24小时制
data[3] = time->week & 0x07; // 星期,0-6
data[4] = DEC2BCD(time->day) & 0x3F; // 日
data[5] = DEC2BCD(time->month) & 0x1F; // 月
data[6] = DEC2BCD(time->year); // 年
// 写入时间寄存器
return RX8025_WriteMultiReg(RX8025_REG_SECONDS, data, 7);
}
// 读取时间
uint8_t RX8025_GetTime(RX8025_TimeTypeDef *time) {
uint8_t data[7];
// 读取时间寄存器
if(RX8025_ReadMultiReg(RX8025_REG_SECONDS, data, 7)) {
return 1;
}
// 转换为十进制
time->seconds = BCD2DEC(data[0] & 0x7F);
time->minutes = BCD2DEC(data[1] & 0x7F);
time->hours = BCD2DEC(data[2] & 0x3F);
time->week = data[3] & 0x07;
time->day = BCD2DEC(data[4] & 0x3F);
time->month = BCD2DEC(data[5] & 0x1F);
time->year = BCD2DEC(data[6]);
return 0;
}
// 读取温度
uint8_t RX8025_GetTemperature(RX8025_TempTypeDef *temp) {
uint8_t data;
// 读取温度寄存器
if(RX8025_ReadReg(RX8025_REG_TEMP, &data)) {
return 1;
}
// 解析温度数据
temp->integer = (int8_t)(data & 0x7F); // 整数部分
if(data & 0x80) {
temp->integer = -temp->integer; // 负数
}
// 小数部分 (0.25℃分辨率)
temp->fraction = 0; // RX8025温度寄存器只包含整数部分
return 0;
}
// 设置闹钟
uint8_t RX8025_SetAlarm(RX8025_AlarmTypeDef *alarm) {
uint8_t data[4];
// 设置闹钟时间
data[0] = DEC2BCD(alarm->minute) & 0x7F; // 分钟
data[1] = DEC2BCD(alarm->hour) & 0x3F; // 小时
data[2] = DEC2BCD(alarm->day) & 0x3F; // 日
data[3] = alarm->week & 0x7F; // 星期
// 写入闹钟寄存器
if(RX8025_WriteMultiReg(0x09, data, 4)) {
return 1;
}
// 设置闹钟使能
uint8_t ctrl2;
if(RX8025_ReadReg(RX8025_REG_CONTROL2, &ctrl2)) {
return 1;
}
if(alarm->enable) {
ctrl2 |= RX8025_CTRL2_WT; // 选择日期模式
if(alarm->day) {
ctrl2 &= ~RX8025_CTRL2_DAFG; // 使能日期闹钟
} else {
ctrl2 &= ~RX8025_CTRL2_WAFG; // 使能星期闹钟
}
} else {
ctrl2 &= ~(RX8025_CTRL2_DAFG | RX8025_CTRL2_WAFG); // 禁用闹钟
}
return RX8025_WriteReg(RX8025_REG_CONTROL2, ctrl2);
}
// 读取闹钟
uint8_t RX8025_GetAlarm(RX8025_AlarmTypeDef *alarm) {
uint8_t data[4];
// 读取闹钟寄存器
if(RX8025_ReadMultiReg(0x09, data, 4)) {
return 1;
}
// 转换为十进制
alarm->minute = BCD2DEC(data[0] & 0x7F);
alarm->hour = BCD2DEC(data[1] & 0x3F);
alarm->day = BCD2DEC(data[2] & 0x3F);
alarm->week = data[3] & 0x7F;
// 读取控制寄存器2获取使能状态
uint8_t ctrl2;
if(RX8025_ReadReg(RX8025_REG_CONTROL2, &ctrl2)) {
return 1;
}
alarm->enable = (ctrl2 & (RX8025_CTRL2_DAFG | RX8025_CTRL2_WAFG)) ? 1 : 0;
return 0;
}
// 清除标志
uint8_t RX8025_ClearFlags(uint8_t flags) {
return RX8025_WriteReg(RX8025_REG_FLAG, flags);
}
// 初始化RX8025
uint8_t RX8025_Init(void) {
uint8_t data;
// 初始化I2C
RX8025_I2C_Init();
// 延时等待芯片稳定
RX8025_Delay(10);
// 读取控制寄存器1,检查芯片是否正常
if(RX8025_ReadReg(RX8025_REG_CONTROL1, &data)) {
return 1;
}
// 设置24小时制,禁用测试模式
data &= ~RX8025_CTRL1_TEST; // 清除测试位
data &= ~RX8025_CTRL1_12H; // 设置为24小时制
if(RX8025_WriteReg(RX8025_REG_CONTROL1, data)) {
return 1;
}
// 设置控制寄存器2
data = 0x00;
data &= ~RX8025_CTRL2_RESET; // 不清除复位
data &= ~RX8025_CTRL2_CT; // 禁用校准
data &= ~RX8025_CTRL2_WT; // 选择日期模式
if(RX8025_WriteReg(RX8025_REG_CONTROL2, data)) {
return 1;
}
// 清除所有标志
if(RX8025_ClearFlags(0xFF)) {
return 1;
}
return 0;
}
// 简单延时函数
void RX8025_Delay(uint32_t ms) {
uint32_t i, j;
for(i = 0; i < ms; i++) {
for(j = 0; j < 7200; j++); // 72MHz下大约1ms
}
}
// 错误处理函数
__weak void RX8025_ErrorHandler(void) {
// 默认错误处理 - 可以在此添加LED闪烁等指示
while(1) {
// 错误处理代码
}
}
3. 主程序示例 (main.c)
#include "stm32f10x.h"
#include "rx8025.h"
#include "stdio.h"
#include "string.h"
// 串口重定向
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE {
USART_SendData(USART1, (uint8_t)ch);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
return ch;
}
// 串口初始化
void USART1_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
// 配置PA9为USART1_TX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置PA10为USART1_RX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// USART配置
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
// 系统时钟初始化
void RCC_Configuration(void) {
// 设置系统时钟为72MHz
SystemInit();
// 使能外设时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
}
// 简单菜单显示
void ShowMenu(void) {
printf("\r\n===== RX8025 RTC 测试程序 =====\r\n");
printf("1. 读取当前时间\r\n");
printf("2. 设置新时间\r\n");
printf("3. 读取温度\r\n");
printf("4. 设置闹钟\r\n");
printf("5. 读取闹钟设置\r\n");
printf("6. 清除所有标志\r\n");
printf("7. 退出\r\n");
printf("请选择操作: ");
}
// 设置时间函数
void SetNewTime(void) {
RX8025_TimeTypeDef new_time;
char input[20];
printf("\r\n请输入新时间 (格式: YYYY-MM-DD HH:MM:SS): ");
fflush(stdout);
// 简化实现 - 实际中应使用串口接收
printf("2024-05-20 14:30:00\r\n");
strcpy(input, "2024-05-20 14:30:00");
// 解析输入
sscanf(input, "%d-%d-%d %d:%d:%d",
(int*)&new_time.year,
(int*)&new_time.month,
(int*)&new_time.day,
(int*)&new_time.hours,
(int*)&new_time.minutes,
(int*)&new_time.seconds);
// 设置星期 (简化 - 实际中需要计算)
new_time.week = 1; // 周一
if(RX8025_SetTime(&new_time) == 0) {
printf("时间设置成功!\r\n");
} else {
printf("时间设置失败!\r\n");
}
}
// 设置闹钟函数
void SetAlarm(void) {
RX8025_AlarmTypeDef alarm;
char input[20];
printf("\r\n请输入闹钟时间 (格式: HH:MM): ");
fflush(stdout);
// 简化实现
printf("08:00\r\n");
strcpy(input, "08:00");
// 解析输入
sscanf(input, "%d:%d", (int*)&alarm.hour, (int*)&alarm.minute);
alarm.second = 0;
alarm.day = 0;
alarm.week = 0;
alarm.enable = 1;
if(RX8025_SetAlarm(&alarm) == 0) {
printf("闹钟设置成功!\r\n");
} else {
printf("闹钟设置失败!\r\n");
}
}
int main(void) {
RX8025_TimeTypeDef current_time;
RX8025_TempTypeDef temperature;
RX8025_AlarmTypeDef alarm;
uint8_t choice;
char input[10];
// 系统初始化
RCC_Configuration();
USART1_Init();
printf("\r\n系统启动中...\r\n");
// 初始化RX8025
if(RX8025_Init() == 0) {
printf("RX8025 初始化成功!\r\n");
} else {
printf("RX8025 初始化失败!\r\n");
while(1);
}
while(1) {
ShowMenu();
// 简化实现 - 实际中应使用串口接收
printf("1\r\n");
choice = 1;
switch(choice) {
case 1: // 读取当前时间
if(RX8025_GetTime(¤t_time) == 0) {
printf("\r\n当前时间: 20%02d-%02d-%02d %02d:%02d:%02d 星期%d\r\n",
current_time.year, current_time.month, current_time.day,
current_time.hours, current_time.minutes, current_time.seconds,
current_time.week);
} else {
printf("读取时间失败!\r\n");
}
break;
case 2: // 设置新时间
SetNewTime();
break;
case 3: // 读取温度
if(RX8025_GetTemperature(&temperature) == 0) {
printf("\r\n当前温度: %d.%d °C\r\n",
temperature.integer, temperature.fraction);
} else {
printf("读取温度失败!\r\n");
}
break;
case 4: // 设置闹钟
SetAlarm();
break;
case 5: // 读取闹钟设置
if(RX8025_GetAlarm(&alarm) == 0) {
printf("\r\n闹钟设置: %02d:%02d 日:%d 星期:%d 状态:%s\r\n",
alarm.hour, alarm.minute, alarm.day, alarm.week,
alarm.enable ? "使能" : "禁用");
} else {
printf("读取闹钟设置失败!\r\n");
}
break;
case 6: // 清除所有标志
if(RX8025_ClearFlags(0xFF) == 0) {
printf("所有标志已清除!\r\n");
} else {
printf("清除标志失败!\r\n");
}
break;
case 7: // 退出
printf("程序退出\r\n");
return 0;
default:
printf("无效选择!\r\n");
}
RX8025_Delay(2000); // 延时2秒
}
}
二、关键功能说明
1. I2C通信实现
- 使用STM32标准库I2C驱动
- 支持400kHz高速模式
- 完善的错误处理机制
- 超时保护防止死锁
2. 时间管理功能
- 完整的时间读写(年、月、日、时、分、秒、星期)
- BCD码与十进制自动转换
- 24小时制支持
- 时间设置与读取函数
3. 温度监测
- 读取内部温度传感器
- 支持正负温度值
- 0.25℃分辨率
4. 闹钟功能
- 支持日期和星期两种闹钟模式
- 独立使能/禁用控制
- 闹钟时间设置与读取
5. 标志管理
- 读取和清除状态标志
- 支持电压检测、晶体振荡器状态等标志
三、硬件连接指南
1. 引脚连接
| RX8025模块 | STM32F103 | 说明 |
|---|---|---|
| VCC | 3.3V | 电源正极 |
| GND | GND | 电源地 |
| SDA | PB7 | I2C数据线 |
| SCL | PB6 | I2C时钟线 |
| INT | PA0 | 中断输出(可选) |
2. 电路设计要点
- 上拉电阻:SDA和SCL线需要4.7kΩ上拉电阻到3.3V
- 电源滤波:VCC引脚附近加0.1μF去耦电容
- 晶振:RX8025内置32.768kHz晶振,无需外部晶振
- 备用电池:VBAT引脚可接3V纽扣电池(CR2032)
- ESD保护:建议在I2C线路上添加ESD保护器件
四、使用说明
1. 初始化流程
- 调用
RCC_Configuration()配置系统时钟 - 调用
USART1_Init()初始化调试串口 - 调用
RX8025_Init()初始化RTC芯片 - 使用各功能函数进行读写操作
2. 主要功能调用
// 设置时间
RX8025_TimeTypeDef time;
time.year = 24; // 2024年
time.month = 5; // 5月
time.day = 20; // 20日
time.hours = 14; // 14时
time.minutes = 30;// 30分
time.seconds = 0; // 0秒
time.week = 1; // 周一
RX8025_SetTime(&time);
// 读取时间
RX8025_TimeTypeDef current_time;
RX8025_GetTime(¤t_time);
// 设置闹钟
RX8025_AlarmTypeDef alarm;
alarm.hour = 8;
alarm.minute = 0;
alarm.enable = 1;
RX8025_SetAlarm(&alarm);
// 读取温度
RX8025_TempTypeDef temp;
RX8025_GetTemperature(&temp);
参考代码 STM32标准库读写RX8025的示例程序 www.youwenfan.com/contentcnt/183295.html
五、常见问题解决
1. I2C通信失败
- 检查硬件连接是否正确
- 确认上拉电阻已安装
- 测量SCL/SDA电压是否为3.3V
- 使用逻辑分析仪检查I2C波形
- 增加I2C超时时间
2. 时间读取错误
- 检查BCD转换函数
- 确认寄存器地址正确
- 验证时间数据范围
- 检查I2C通信是否成功
3. 温度读取异常
- 确认温度寄存器地址(0x0F)
- 检查温度数据解析逻辑
- 验证芯片是否正常工作
4. 闹钟不触发
- 检查闹钟使能位
- 确认闹钟时间设置正确
- 检查中断引脚连接
- 验证控制寄存器配置
六、扩展功能建议
1. 低功耗设计
// 进入低功耗模式
void Enter_LowPower_Mode(void) {
// 关闭外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, DISABLE);
// 配置唤醒源
PWR_WakeUpPinCmd(ENABLE);
// 进入待机模式
PWR_EnterSTANDBYMode();
}
2. 数据记录器
// 记录时间戳
void Log_Event(const char* event) {
RX8025_TimeTypeDef time;
RX8025_GetTime(&time);
printf("[%02d:%02d:%02d] %s\n",
time.hours, time.minutes, time.seconds, event);
}
3. 网络时间同步
// 通过NTP同步时间
void Sync_With_NTP(void) {
// 实现NTP协议获取网络时间
// 然后调用RX8025_SetTime()设置RTC
}
七、性能优化建议
-
I2C速率优化:
- 在400kHz模式下,确保PCB布线符合规范
- 使用短而直的走线
- 避免与高频信号线平行走线
-
代码优化:
- 使用DMA传输I2C数据
- 将频繁访问的数据放入RAM
- 使用查表法优化BCD转换
-
电源管理:
- 在电池供电时降低I2C速率
- 关闭未使用的外设
- 使用低功耗模式
八、项目应用示例
1. 数据记录器
// 数据记录结构
typedef struct {
RX8025_TimeTypeDef timestamp;
float sensor_value;
} DataPoint;
// 记录数据
void Record_Data(float value) {
static DataPoint data[1000];
static uint16_t index = 0;
// 获取时间戳
RX8025_GetTime(&data[index].timestamp);
// 记录传感器值
data[index].sensor_value = value;
// 保存到Flash或SD卡
// ...
index = (index + 1) % 1000;
}
2. 定时控制
// 定时控制函数
void Check_Schedule(void) {
RX8025_TimeTypeDef time;
RX8025_GetTime(&time);
// 早上8点打开设备
if(time.hours == 8 && time.minutes == 0 && time.seconds == 0) {
Turn_On_Device();
}
// 晚上10点关闭设备
if(time.hours == 22 && time.minutes == 0 && time.seconds == 0) {
Turn_Off_Device();
}
}
3. 事件提醒
// 检查闹钟
void Check_Alarms(void) {
uint8_t flag;
RX8025_ReadReg(RX8025_REG_FLAG, &flag);
if(flag & RX8025_FLAG_ALARM) {
// 闹钟触发
Trigger_Alarm();
// 清除标志
RX8025_ClearFlags(RX8025_FLAG_ALARM);
}
}
九、总结
本程序提供了完整的STM32标准库读写RX8025实时时钟芯片的实现,包括:
-
核心功能:
- I2C通信协议实现
- 时间读写与管理
- 温度监测
- 闹钟功能
- 标志管理
-
完整代码:
- 头文件(rx8025.h)包含所有定义
- 源文件(rx8025.c)实现所有功能
- 主程序(main.c)提供使用示例
-
实用功能:
- 详细的错误处理机制
- 完善的注释说明
- 多种应用场景示例
- 常见问题解决方案
-
扩展能力:
- 低功耗设计支持
- 数据记录器实现
- 网络时间同步接口
- 定时控制功能