天天看点

《alios things开发实战系列》第三篇:Alios上使用RTC记录时间

大家好,我是阿桃,一个想成为被点赞关注的程序员。

工控行业、物联网行业、机器人行业软件开发可联系我

 对于不同底层驱动的rtc操作实现,alios提供统一封装的hal rtc接口。 hal相关头文件位于目录:include/aos/hal。hal相关实现位于具体的mcu目录下,如:platform/mcu/stm32f1xx/hal/。

API列表

《alios things开发实战系列》第三篇:Alios上使用RTC记录时间

以上是基本的初始化,获取与设置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 things开发实战系列》第三篇:Alios上使用RTC记录时间

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的主要内容了。

文章每周持续更新,原创虽短,确不容易,欢迎大家点赞关注,一起交流技术一起提升成长。