大家好,我是阿桃,一个想成为被点赞关注的程序员。
工控行业、物联网行业、机器人行业软件开发可联系我
对于不同底层驱动的rtc操作实现,alios提供统一封装的hal rtc接口。 hal相关头文件位于目录:include/aos/hal。hal相关实现位于具体的mcu目录下,如:platform/mcu/stm32f1xx/hal/。
API列表
以上是基本的初始化,获取与设置RTC时间还有解初始化接口。
相关宏
#define HAL_RTC_FORMAT_DEC 1 /* Use Binary-Coded */
#define HAL_RTC_FORMAT_BCD 2 /* Use Decimal-Coded */
这两个宏用来控制读取与设置时间的编码方式是用十进制还是BCD编码。
相关数据结构
typedef struct {
uint8_t port; /* rtc port */
rtc_config_t config; /* rtc config */
void *priv; /* priv data */
} rtc_dev_t;
typedef struct {
uint8_t format; /* time formart DEC or BCD */
} rtc_config_t;
typedef struct {
uint8_t sec; /* DEC format:value range from 0 to 59, BCD format:value range from 0x00 to 0x59 */
uint8_t min; /* DEC format:value range from 0 to 59, BCD format:value range from 0x00 to 0x59 */
uint8_t hr; /* DEC format:value range from 0 to 23, BCD format:value range from 0x00 to 0x23 */
uint8_t weekday; /* DEC format:value range from 1 to 7, BCD format:value range from 0x01 to 0x07 */
uint8_t date; /* DEC format:value range from 1 to 31, BCD format:value range from 0x01 to 0x31 */
uint8_t month; /* DEC format:value range from 1 to 12, BCD format:value range from 0x01 to 0x12 */
uint8_t year; /* DEC format:value range from 0 to 99, BCD format:value range from 0x00 to 0x99 */
} rtc_time_t;
使用示例
#include <aos/hal/rtc.h>
#define RTC1_PORT_NUM 1
/* define dev */
rtc_dev_t rtc1;
int application_start(int argc, char *argv[])
{
int ret = -1;
rtc_config_t rtc_cfg;
rtc_time_t time_buf;
/* rtc port set */
rtc1.port = RTC1_PORT_NUM;
/* set to DEC format */
rtc1.config.format = HAL_RTC_FORMAT_DEC;
/* init rtc1 with the given settings */
ret = hal_rtc_init(&rtc1);
if (ret != 0) {
printf("rtc1 init error !\n");
}
time_buf.sec = 0;
time_buf.min = 0;
time_buf.hr = 0;
time_buf.weekday = 2;
time_buf.date = 1;
time_buf.month = 1;
time_buf.year = 2019;
/* set rtc1 time to 2019/1/1,00:00:00 */
ret = hal_rtc_set_time(&rtc1, &time_buf);
if (ret != 0) {
printf("rtc1 set time error !\n");
}
memset(&time_buf, 0, sizeof(rtc_time_t));
/* get rtc current time */
ret = hal_rtc_get_time(&rtc1, &time_buf);
if (ret != 0) {
printf("rtc1 get time error !\n");
}
/* finalize rtc1 */
hal_rtc_finalize(&rtc1);
while(1) {
/* sleep 500ms */
aos_msleep(500);
};
}
这里rtc设置年份time_buf.year = 2019是官方文档写错了,它是一个uint_8变量,RTC是年份设置范围是2000-2099,2019年应该设置为time_buf.year = 19,RTC会自动根据润年进行日期的转换,不需要开发者进行处理。
以上是官方API文档都能看到的,接下来讲讲我根据看了alios的hal_rtc源码讲讲官方文档上没有的内容。
由于我使用的板子RTC芯片使用的是RS8010,通过i2c地址宏可以看出来。
alios提供的是一个通用的抽象接口,像具体的底层驱动有些是没用到相关的功能,例如RS8081芯片就没一用到初始化结构体中的一些变量,还有包括编码配置的两个宏。
int32_t hal_rtc_init(rtc_dev_t *rtc)
{
int ret = 0;
uint8_t flag = 0;
uint8_t data = 0;
uint8_t ctrl[2];
int need_clear = 0;
ret = hal_i2c_mem_read(&i2c_port_1, RTC_I2C_BASE_ADDR, RX8010_FLAG, 1, &flag, 1, RTC_DEFAULT_TIME_OUT);
if (ret != 0) {
return -1;
}
flag &= ~(RX8010_FLAG_VLF);
ret = hal_i2c_mem_write(&i2c_port_1, RTC_I2C_BASE_ADDR, RX8010_FLAG, 1, &flag, 1, RTC_DEFAULT_TIME_OUT);
if (ret != 0) {
return -1;
}
data = 0xD8;
ret = hal_i2c_mem_write(&i2c_port_1, RTC_I2C_BASE_ADDR, RX8010_RESV17, 1, &data, 1, RTC_DEFAULT_TIME_OUT);
if (ret != 0) {
return -1;
}
data = 0x00;
ret = hal_i2c_mem_write(&i2c_port_1, RTC_I2C_BASE_ADDR, RX8010_RESV30, 1, &data, 1, RTC_DEFAULT_TIME_OUT);
if (ret != 0) {
return -1;
}
data = 0x08;
ret = hal_i2c_mem_write(&i2c_port_1, RTC_I2C_BASE_ADDR, RX8010_RESV31, 1, &data, 1, RTC_DEFAULT_TIME_OUT);
if (ret != 0) {
return -1;
}
data = 0x00;
ret = hal_i2c_mem_write(&i2c_port_1, RTC_I2C_BASE_ADDR, RX8010_IRQ, 1, &data, 1, RTC_DEFAULT_TIME_OUT);
if (ret != 0) {
return -1;
}
ret = hal_i2c_mem_read(&i2c_port_1, RTC_I2C_BASE_ADDR, RX8010_FLAG, 1, &ctrl[0], 2, RTC_DEFAULT_TIME_OUT);
if (ret != 0) {
return -1;
}
if (ctrl[0] & RX8010_FLAG_VLF) {
printf("\r\n Frequency stop was detected\r\n");
}
if (ctrl[0] & RX8010_FLAG_AF) {
printf("\r\n Alarm was detected\r\n");
need_clear = 1;
}
if (ctrl[0] & RX8010_FLAG_TF) {
need_clear = 1;
}
if (ctrl[0] & RX8010_FLAG_UF) {
need_clear = 1;
}
if (need_clear) {
ctrl[0] &= ~(RX8010_FLAG_AF | RX8010_FLAG_TF | RX8010_FLAG_UF);
ret = hal_i2c_mem_write(&i2c_port_1, RTC_I2C_BASE_ADDR, RX8010_FLAG, 1, &ctrl[0], 1, RTC_DEFAULT_TIME_OUT);
}
return ret;
}
设置时间函数,也是直接没用到相应的宏,因为RS8081仅支持BCD编码,所以需要做一个bcd2bin的转换。
int32_t hal_rtc_get_time(rtc_dev_t *rtc, rtc_time_t *time)
{
int ret;
uint8_t date[7];
uint8_t flag;
if ((time == NULL) || (rtc == NULL)) {
return -1;
}
ret = hal_i2c_mem_read(&i2c_port_1, RTC_I2C_BASE_ADDR, RX8010_FLAG, 1, &flag, 1, RTC_DEFAULT_TIME_OUT);
if (ret != 0) {
return -1;
}
if (flag & RX8010_FLAG_VLF)
{
printf("\r\n Frequency stop was detected\r\n");
return 1;
}
ret = hal_i2c_mem_read(&i2c_port_1, RTC_I2C_BASE_ADDR, RX8010_SEC, 1, &date[0], 7, RTC_DEFAULT_TIME_OUT);
if (ret != 0) {
return -1;
}
time->year = bcd2bin(date[RX8010_YEAR - RX8010_SEC]);
time->month= bcd2bin(date[RX8010_MONTH - RX8010_SEC] & 0x1f);
time->date = bcd2bin(date[RX8010_MDAY - RX8010_SEC] & 0x3f);
time->hr = bcd2bin(date[RX8010_HOUR - RX8010_SEC] & 0x3f);
time->min = bcd2bin(date[RX8010_MIN - RX8010_SEC] & 0x7f);
time->sec = bcd2bin(date[RX8010_SEC - RX8010_SEC] & 0x7f);
time->weekday = date[RX8010_WDAY - RX8010_SEC] & 0x7f;
return 0;
}
为了方便设置RTC可以通过cli来设置接口,具体的cli如何使用交互这里就不细写了。
int rtc_time_cli(char *type,char *fun,char *param)
{
int ret = 0;
u8 val;
if(strcmp(type,"rtc")!=0)return 0;
if(strcmp(fun,"set_year")==0){
val = strtoul(param, NULL, 10);
rtc_time_set_year(val);
printf("rtc_time_set_year is %d \n", val);
return 1;
}else if(strcmp(fun,"get_year")==0){
val = rtc_time_get_year();
printf("rtc_time_get_year is %d \n", val);
return 1;
}else if(strcmp(fun,"set_month")==0){
val = strtoul(param, NULL, 10);
rtc_time_set_month(val);
printf("rtc_time_set_month is %d \n", val);
return 1;
}else if(strcmp(fun,"get_month")==0){
val = rtc_time_get_month();
printf("rtc_time_get_month is %d \n", val);
return 1;
}else if(strcmp(fun,"set_date")==0){
val = strtoul(param, NULL, 10);
rtc_time_set_date(val);
printf("rtc_time_set_date is %d \n", val);
return 1;
}else if(strcmp(fun,"get_date")==0){
val = rtc_time_get_date();
printf("rtc_time_get_date is %d \n", val);
return 1;
}else if(strcmp(fun,"set_weekday")==0){
val = strtoul(param, NULL, 10);
rtc_time_set_weekday(val);
printf("rtc_time_set_weekday is %d \n", val);
return 1;
}else if(strcmp(fun,"get_weekday")==0){
val = rtc_time_get_weekday();
printf("rtc_time_get_weekday is %d \n", val);
return 1;
}else if(strcmp(fun,"set_hr")==0){
val = strtoul(param, NULL, 10);
rtc_time_set_hr(val);
printf("rtc_time_set_hr is %d \n", val);
return 1;
}else if(strcmp(fun,"get_hr")==0){
val = rtc_time_get_hr();
printf("rtc_time_get_hr is %d \n", val);
return 1;
}else if(strcmp(fun,"set_min")==0){
val = strtoul(param, NULL, 10);
rtc_time_set_min(val);
printf("rtc_time_set_min is %d \n", val);
return 1;
}else if(strcmp(fun,"get_min")==0){
val = rtc_time_get_min();
printf("rtc_time_get_min is %d \n", val);
return 1;
}else if(strcmp(fun,"set_sec")==0){
val = strtoul(param, NULL, 10);
rtc_time_set_sec(val);
printf("rtc_time_set_sec is %d \n", val);
return 1;
}else if(strcmp(fun,"get_sec")==0){
val = rtc_time_get_sec();
printf("rtc_time_get_sec is %d \n", val);
return 1;
}
else{
return 0;
}
return 1;
}
以上大概就是alios的主要内容了。
文章每周持续更新,原创虽短,确不容易,欢迎大家点赞关注,一起交流技术一起提升成长。