前言:
RX8010SJ为一款硬件RTC芯片,通过IIC驱动。IIC建议速率100K~400K,使用STM32的HAL库函数实现IIC驱动。工程可以使用STM32CubeMX快速构建。
一.平台说明
MCU为STM32H743,使用HAL库函数,编译器使用KEIL5。
二.具体驱动实现
RX8010SJ驱动,包括初始化、设备读写函数,BCD、BIN格式转换,周计算及解析函数。
1.dev_rx8010sj.c
#include "dev_rx8010sj.h"
/*---------------------------------------------------------------------------------------
函数名: Dev_RX8010SJ_Init()
函数功能: RX8010SJ设备初始化
参数:
返回值:
备注:
----------------------------------------------------------------------------------------*/
void Dev_RX8010SJ_Init(void)
{
BSP_IIC_INIT();//IIC总线初始化
}
/*---------------------------------------------------------------------------------------
函数名: RTC_BinToBcd()
函数功能: 十进制转BCD码
参数: BinValue:十进制输入值
返回值:cacheBuf:BCD码转换值
备注:
----------------------------------------------------------------------------------------*/
static uint8_t RTC_BinToBcd(uint8_t BinValue)
{
uint8_t cacheBuf = 0;
while(BinValue >= 10)
{
BinValue -= 10;
cacheBuf += 1;
}
cacheBuf = (cacheBuf<<4) + BinValue;
return (cacheBuf);
}
/*---------------------------------------------------------------------------------------
函数名: RTC_BcdToBin()
函数功能: BCD转十进制
参数: BCDValue:BCD输入值
返回值:cacheBuf:十进制转换值,xRegister:有效位
备注:
----------------------------------------------------------------------------------------*/
static uint8_t RTC_BcdToBin(uint8_t BCDValue,uint8_t xRegister)
{
uint8_t cacheBuf = 0;
cacheBuf = ( BCDValue & (xRegister&0xF0) ) >> 4;
cacheBuf = cacheBuf*10 + (BCDValue & (xRegister&0x0F));
return (cacheBuf);
}
/*---------------------------------------------------------------------------------------
函数名: RTC_Cal_Week()
函数功能: 根据年月日计算周
参数: year:年 month:月 day:日
返回值:周序号(0~6)
备注:
----------------------------------------------------------------------------------------*/
uint8_t RTC_Cal_Week(uint16_t year,uint8_t month,uint8_t day)
{
uint8_t weekday;
if(month==1||month==2)
{
month+=12;
year--;
}
weekday=(day+2*month+3*(month+1)/5+year+year/4-year/100+year/400)%7+1;
if(weekday==7) //0代表周日,1~6代表周一至周六
{
weekday=0;
}
return weekday;
}
/*---------------------------------------------------------------------------------------
函数名: RTC_Get_Week()
函数功能: 解析RX8010返回周
参数: Weekday:RX8010SJ周寄存器值
返回值:周序号(0~6)
备注:
----------------------------------------------------------------------------------------*/
uint8_t RTC_Get_Week(uint8_t Weekday)
{
uint8_t i;
for(i=0;i<7;i++)
{
if(Weekday&(0x01<<i))
{
return i;
}
}
//周寄存器为非法值
return 0xff;
}
/*---------------------------------------------------------------------------------------
函数名: Write_To_RX8010SJ()
函数功能: 写实时时钟
参数:set_RX8010SJ_time,时间参数结构体,周需要进行二次计算
返回值:无
备注:
----------------------------------------------------------------------------------------*/
void Write_To_RX8010SJ(RX8010SJ_Info* set_RX8010SJ_time)
{
uint8_t temp_u8;
RX8010SJ_Info Time_set;
/*修改控制寄存器允许写时间*/
temp_u8 = 0x40;
BSP_IIC_Send_Data(RX8010SJ_IIC_W_ADDR,RX8010_ADDR_CTRL_REG,(uint8_t *)&temp_u8,1);
/*时间转换为BCD码*/
Time_set.time.Second = RTC_BinToBcd(set_RX8010SJ_time->time.Second);
Time_set.time.Minute = RTC_BinToBcd(set_RX8010SJ_time->time.Minute);
Time_set.time.Hour = RTC_BinToBcd(set_RX8010SJ_time->time.Hour);
Time_set.date.weekday = 0x01<<RTC_Cal_Week(set_RX8010SJ_time->date.year,set_RX8010SJ_time->date.month,set_RX8010SJ_time->date.day);
Time_set.date.day = RTC_BinToBcd(set_RX8010SJ_time->date.day);
Time_set.date.month = RTC_BinToBcd(set_RX8010SJ_time->date.month);
Time_set.date.year = RTC_BinToBcd(set_RX8010SJ_time->date.year);
BSP_IIC_Send_Data(RX8010SJ_IIC_W_ADDR,RX8010_ADDR_SECOND,(uint8_t *)&Time_set.time.Second,7);
/*修改控制寄存器禁止写时间*/
temp_u8 = 0x00;
BSP_IIC_Send_Data(RX8010SJ_IIC_W_ADDR,RX8010_ADDR_CTRL_REG,(uint8_t *)&temp_u8,1);
}
/*---------------------------------------------------------------------------------------
函数名: Read_From_RX8010SJ()
函数功能: 读实时时钟
参数:无
返回值:无
备注:
----------------------------------------------------------------------------------------*/
RX8010SJ_Info Read_From_RX8010SJ(void)
{
RX8010SJ_Info Time_read={0};
static uint8_t rx8010_buffer[7]={0};
BSP_IIC_Read_Data(RX8010SJ_IIC_R_ADDR,RX8010_ADDR_SECOND,(uint8_t *)&rx8010_buffer[0],7);
Time_read.time.Second = RTC_BcdToBin(rx8010_buffer[0],BCD_MinAndSec);
Time_read.time.Minute = RTC_BcdToBin(rx8010_buffer[1],BCD_MinAndSec);
Time_read.time.Hour = RTC_BcdToBin(rx8010_buffer[2],BCD_HourAndDay);
Time_read.date.weekday = RTC_Get_Week(rx8010_buffer[3]);
Time_read.date.day = RTC_BcdToBin(rx8010_buffer[4],BCD_HourAndDay);
Time_read.date.month = RTC_BcdToBin(rx8010_buffer[5],BCD_Months);
Time_read.date.year = RTC_BcdToBin(rx8010_buffer[6],BCD_Years);
return (Time_read);
}
2.dev_rx8010sj.h
#ifndef __DEV_RX8010SJ_H
#define __DEV_RX8010SJ_H
#include "includes.h"
/************宏定义***************/
#define RX8010SJ_IIC_W_ADDR 0x64 //写地址
#define RX8010SJ_IIC_R_ADDR 0x65 //读地址
/* RX8010SJ芯片里时间和日期寄存器的地址
* 从10H~16H共七个8位寄存器依次包含:秒(0~59)、分(0~59)、时(0~23)、
* 日(1~31)、周几(0~6)、月份(1~12)、年份(0~99)
*/
#define RX8010_ADDR_SECOND (0x10)
#define RX8010_ADDR_MINUTE (0x11)
#define RX8010_ADDR_HOUR (0x12)
#define RX8010_ADDR_WEEK (0x13)
#define RX8010_ADDR_DAY (0x14)
#define RX8010_ADDR_MONTH (0x15)
#define RX8010_ADDR_YEAR (0x16)
#define RX8010_ADDR_RSV17 (0x17)
#define RX8010_ADDR_ALM_MINUTE (0x18)
#define RX8010_ADDR_ALM_HOUR (0x19)
#define RX8010_ADDR_ALM_WEEK (0x1A)
#define RX8010_ADDR_ALM_DATE (0x1A)
#define RX8010_ADDR_TMR_CNT0 (0x1B)
#define RX8010_ADDR_TMR_CNT1 (0x1C)
#define RX8010_ADDR_EXT_REG (0x1D)
#define RX8010_ADDR_FLAG_REG (0x1E)
#define RX8010_ADDR_CTRL_REG (0x1F)
#define RX8010_ADDR_RSV1 (0x30)
#define RX8010_ADDR_RSV2 (0x31)
#define RX8010_ADDR_RSV3 (0x32)
/* RX8010SJ芯片时间寄存器最大位数
* 秒和分最多7Bits
* 时和日期最多6Bits
*/
#define BCD_MinAndSec ((uint8_t)0x7F) // 取低7位
#define BCD_HourAndDay ((uint8_t)0x3F) // 取低6位
#define BCD_Weekday ((uint8_t)0x07) // 取低3位
#define BCD_Months ((uint8_t)0x1F) // 取低5位
#define BCD_Years ((uint8_t)0xFF) // 取低8位
/*************结构体、枚举定义*****************/
typedef struct
{
struct
{
uint8_t Second;
uint8_t Minute;
uint8_t Hour;
} time;
struct
{
uint8_t weekday;
uint8_t day;
uint8_t month;
uint8_t year;
} date;
} RX8010SJ_Info;
extern RX8010SJ_Info RTC_Message;
/************函数声明***************/
static uint8_t RTC_BinToBcd(uint8_t BinValue);
static uint8_t RTC_BcdToBin(uint8_t BCDValue,uint8_t xRegister);
uint8_t RTC_Cal_Week(uint16_t year,uint8_t month,uint8_t day);
uint8_t RTC_Get_Week(uint8_t Weekday);
void Dev_RX8010SJ_Init(void);
void Write_To_RX8010SJ(RX8010SJ_Info* set_RX8010SJ_time);
RX8010SJ_Info Read_From_RX8010SJ(void);
#endif
HAL库实现IIC驱动,包括IIC的初始化配置以及IIC收发函数
3.bsp_iic.c
#include "bsp_iic.h"
#ifdef USE_HARDWARE_IIC
I2C_HandleTypeDef IIC1Handle;//IIC1句柄
/*---------------------------------------------------------------------------------------
函数名: BSP_IIC_INIT()
函数功能:IIC总线初始化
参数:无
返回值:无
备注:
----------------------------------------------------------------------------------------*/
void BSP_IIC_INIT()
{
IIC1Handle.Instance = I2C1;
IIC1Handle.Init.Timing = IIC_SPEED;
IIC1Handle.Init.OwnAddress1 = 0x00;
IIC1Handle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
IIC1Handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
IIC1Handle.Init.OwnAddress2 = 0x00;
IIC1Handle.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
IIC1Handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
IIC1Handle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
HAL_I2C_Init(&IIC1Handle);
HAL_I2CEx_AnalogFilter_Config(&IIC1Handle, I2C_ANALOGFILTER_ENABLE);
}
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(i2cHandle->Instance==I2C1)
{
__HAL_RCC_I2C1_CLK_ENABLE(); //IIC1时钟使能
//硬件IIC引脚配置
//PB7_IIC2_SCL
GPIO_InitStruct.Pin = GPIO_IIC_SCL_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; //复用推挽输出
GPIO_InitStruct.Pull = GPIO_NOPULL; //无上下拉,外部硬件上拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; //高速
GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; //复用为IIC1
HAL_GPIO_Init(GPIO_IIC_SCL_PORT, &GPIO_InitStruct);
//PB7_IIC2_SDA
GPIO_InitStruct.Pin = GPIO_IIC_SDA_PIN;
HAL_GPIO_Init(GPIO_IIC_SDA_PORT, &GPIO_InitStruct);
bsp_GPIOOutHandleStruct.PinNum+=2;
HAL_I2CEx_ConfigAnalogFilter(&IIC1Handle,I2C_ANALOGFILTER_ENABLE); //使能模拟滤波
__HAL_RCC_I2C4_FORCE_RESET();
__HAL_RCC_I2C4_RELEASE_RESET();
}
}
/*---------------------------------------------------------------------------------------
函数名: BSP_IIC_Send_Byte()
函数功能:IIC发送一个字节
参数:DevAddress设备地址,Txdata 发送数据
返回值:1:从机有应答 0:从机无应答
备注:
----------------------------------------------------------------------------------------*/
void BSP_IIC_Send_Byte(uint16_t DevAddress,uint8_t Txdata)
{
uint8_t Temp_data=Txdata;
if(HAL_I2C_Master_Transmit(&IIC1Handle,DevAddress,(uint8_t *)&Temp_data,1,0xFFFF) != HAL_OK)
{
printf("IIC Send error\r\n");
}
}
/*---------------------------------------------------------------------------------------
函数名: BSP_IIC_Read_Byte()
函数功能:IIC读取一个字节数据
参数:ack:0,无应答;1,应答
返回值:无
备注:
----------------------------------------------------------------------------------------*/
uint8_t BSP_IIC_Read_Byte(uint16_t DevAddress)
{
uint8_t Temp_data;
if(HAL_I2C_Master_Receive(&IIC1Handle,DevAddress,(uint8_t *)&Temp_data,1,0xFFFF) != HAL_OK)
{
printf("IIC Recive error\r\n");
}
return Temp_data;
}
/*---------------------------------------------------------------------------------------
函数名: BSP_IIC_Send_Data()
函数功能:IIC连续发送数据
参数: DevAddress设备地址,MemAddress寄存器地址,pData数据地址,Size数据长度
返回值
备注:
----------------------------------------------------------------------------------------*/
uint8_t BSP_IIC_Send_Data(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pData, uint16_t Size)
{
if(HAL_I2C_Mem_Write(&IIC1Handle,DevAddress, MemAddress, I2C_MEMADD_SIZE_8BIT,pData,Size,0xFFFF) != HAL_OK)
{
printf("IIC Send error\r\n");
}
return 0;
}
/*---------------------------------------------------------------------------------------
函数名: BSP_IIC_Read_Data()
函数功能:IIC连续读取数据
参数:
返回值:无
备注:
----------------------------------------------------------------------------------------*/
uint8_t BSP_IIC_Read_Data(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pData, uint16_t Size)
{
if(HAL_I2C_Mem_Read(&IIC1Handle,DevAddress,MemAddress, I2C_MEMADD_SIZE_8BIT,pData,Size,0xFFFF) != HAL_OK)
{
printf("IIC Recive error\r\n");
}
return 0;
}
#endif
4.bsp_iic.h
#ifndef __BSP_IIC_H
#define __BSP_IIC_H
/************头文件包含***************/
#include "includes.h"
#ifdef USE_HARDWARE_IIC
/************宏定义***************/
#define IIC_SPEED 0x40604E73 //硬件IIC速率设置,100k
/************函数声明***************/
void BSP_IIC_INIT(void);
void BSP_IIC_Send_Byte(uint16_t DevAddress,uint8_t Txdata);
uint8_t BSP_IIC_Read_Byte(uint16_t DevAddress);
uint8_t BSP_IIC_Send_Data(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pData, uint16_t Size);
uint8_t BSP_IIC_Read_Data(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pData, uint16_t Size);
extern I2C_HandleTypeDef IIC1Handle;//IIC1句柄
#endif
#endif
三.设计注意点
1.RX8010SJ的数据寄存器,除了周之外,都是BCD格式。设置时间需要转换为BCD码,读取RTC后根据自身需求进行数据格式转换;
2.RX8010SJ的周数据不是BCD码格式,需要单独进行处理;
四.测试建议
驱动完成后,首先设置当前时间,每间隔1秒读取时间并打印,观察时间是否正确。多测试跨分钟、小时、天、月、年等时间节点,看跨越是否正常。
结语
经测试,该套驱动可以正常驱动RX8010SJ芯片。本驱动相对较为简单,仅适用于功能快速开发,未经过长时间可靠性测试。更高深应用可参考RX8010SJ芯片手册。