乐趣区

关于开源:RTThread-应用笔记-RTC-Alarm-组件的使用

RT-Thread 利用笔记 – 不正确应用 LOG 也会引发 hard fault

RT-Thread 利用笔记 – RTC Alarm 组件的应用

RT-Thread 利用笔记 – freemodbus RTU RS485 从机

RT-Thread 利用笔记 – freemodbus RTU RS485 主机

RT-Thread 利用笔记 – libmodbus RTU RS485 从机

RT-Thread 利用笔记 – libmodbus RTU RS485 主机

RT-Thread 利用笔记 – STM32 CAN 通信双机

RT-Thread USB 学习实际系列
背景

调试完 rtc,须要实现闹钟的性能,rt-thread 曾经有了闹钟 alarm 的组件。但没找到较具体的应用文档或实现例程。相熟 MCU 平台的 rtc alarm 性能,把 rt-thread alarm 组件用起来。

使能 RTC Alarm 组件

应用 rt-thread ENV 工具:menuconfig

[RT-Thread Components] -> [Device Drivers] -> [Using RTC device drivers] -> [Using RTC alarm]

使能 alarm

组件蕴含:

alarm.h alarm 组件头文件
alarm.c alarm 组件性能实现

闹钟的应用办法

什么是闹钟?闹钟,相似于定时器,如手机上的闹钟,你设置好工夫,工夫到了,就能够触发闹钟事件,振动或声音揭示。能够同时设置几个闹钟?闹钟,对于用户来讲,实践上能够设置有限个闹钟!!,但对于底层硬件,只有一个,也就是你只能设置一个 alarm 工夫。设置屡次,只有最初一次的失效!如何实现多个闹钟?底层只能设置一个闹钟,但用户须要多个闹钟。所以,须要引入闹钟 alarm 组件,用于治理多个闹钟。你能够认为每创立一个闹钟,就有一个闹钟的节点,链入到闹钟的链表里。alarm 组件 alarm 链表有几个?如何实现其中局部闹钟的使能?alarm 组件链表只有一个链表。比方你创立了 4 个闹钟,只开启 2 个闹钟。闹钟构造体,有使能的标记,你不使能,那这个闹钟就不工作。

alarm 组件根本工作原理

闹钟的创立:rt_alarm_create

例程如下:

static struct rt_alarm * p_alarm_hour = RT_NULL;

/ 闹钟的回调函数,多个闹钟,能够有多个回调函数,用于创立闹钟时注册。闹钟工夫到了,会执行此函数 /
static void alarm_hour_cb(rt_alarm_t alarm, time_t timestamp)
{

LOG_D("alarm_hour_cb ok!\n");

}

static void rtc_alarm_hour_create(void)
{

static time_t now;
struct tm *p_tm;
struct rt_alarm_setup alarm_setup_test;

if (p_alarm_hour != RT_NULL)
    return;

now = time(NULL);
p_tm = localtime(&now);
alarm_setup_test.flag = RT_ALARM_HOUR;
alarm_setup_test.wktime.tm_year = p_tm->tm_year;
alarm_setup_test.wktime.tm_mon = p_tm->tm_mon;
alarm_setup_test.wktime.tm_mday = p_tm->tm_mday;
alarm_setup_test.wktime.tm_wday = p_tm->tm_wday;
alarm_setup_test.wktime.tm_hour = p_tm->tm_hour + 1;
alarm_setup_test.wktime.tm_min = p_tm->tm_min;
alarm_setup_test.wktime.tm_sec = p_tm->tm_sec;

p_alarm_hour = rt_alarm_create(alarm_hour_cb, &alarm_setup_test);

}

闹钟创立后,并不会执行!闹钟有个 flag,用于标识此闹钟是一次性的,还是周期性的。创立闹钟时的 flag 参数

介绍如下:

/ alarm flags /
/ 一次性的闹钟,【rtc 到了这个工夫】,闹钟响应后,就不再工作!只有一次 /

define RT_ALARM_ONESHOT 0x000 / only alarm onece /

/ Daily,闹钟每天这个工夫,都会响一次 每天一次 /

define RT_ALARM_DAILY 0x100 / alarm everyday /

/ weekly,闹钟【每周的这一天】【rtc 到了这个工夫】,会响一次 每周一次 /

define RT_ALARM_WEEKLY 0x200 / alarm weekly at Monday or Friday etc. /

/ monthly,闹钟【每月的这一天】【rtc 到了这个工夫】,会响一次,每月一次 /

define RT_ALARM_MONTHLY 0x400 / alarm monthly at someday /

/ yearly,闹钟【每年,并且这个月的这一天】【rtc 到了这个工夫】,会响一次,每年一次/

define RT_ALARM_YAERLY 0x800 / alarm yearly at a certain date /

/ each hourly,闹钟【每小时】【这个工夫:分钟:秒】,会响一次,每天 24 次!!/

define RT_ALARM_HOUR 0x1000 / alarm each hour at a certain min:second /

/ each minute,闹钟【每分钟】【这个工夫:秒】,会响一次,每小时 60 次!!/

define RT_ALARM_MINUTE 0x2000 / alarm each minute at a certain second /

/ each second,闹钟【每秒】【这个工夫:不关怀!】,会响一次,每分钟 60 次!!/

define RT_ALARM_SECOND 0x4000 / alarm each second /

闹钟设置,个别 MCU 只会设置 hh:mm:ss。MCU 的 alarm,个别能够设置按天、按周等周期性的反复响应,也能够设置一次性的。按天周期性的闹钟,一天一次,设置时,只关怀 hh:mm:ss
按小时周期性的闹钟,一天 24 次,设置时,只关怀 mm:ss,也就是分钟:秒钟,每个小时都会触发一次。按分钟周期性的闹钟,一分钟一次,只关怀秒。下一分钟的那个秒,就会触发。按秒周期性的闹钟,每一秒触发一次!!设置的 hh:mm:ss,不关怀!!alarm 开启:rt_alarm_start

相似于定时器的开启

static void rtc_alarm_hour_start(void)
{

if (p_alarm_hour != RT_NULL)
    rt_alarm_start(p_alarm_hour);

}

alarm 进行:rt_alarm_stop

相似于定时器的进行

static void rtc_alarm_hour_stop(void)
{

if (p_alarm_hour != RT_NULL)
    rt_alarm_stop(p_alarm_hour);

}

alarm 删除:rt_alarm_delete

闹钟的删除,删除后,再次应用,须要从新创立闹钟

static void rtc_alarm_hour_delete(void)
{

if (p_alarm_hour != RT_NULL)
{if (rt_alarm_delete(p_alarm_hour) == RT_EOK)
        p_alarm_hour = RT_NULL;
}

}

alarm 组件的工作原理

闹钟创立一个,就会新增一个闹钟的节点在闹钟的链表上。留神,无排序。闹钟启动:每次遍历一遍闹钟的链表,找到最先超时的闹钟,并设置闹钟。闹钟的进行:更改闹钟的 flag 为不使能。闹钟的删除:闹钟的链表上,删除这个闹钟节点,目前,闹钟节点句柄是全局的。闹钟中断,须要调用:rt_alarm_update
rt_alarm_update 会依据闹钟的周期性标记位,判断是否超时,并执行注册的闹钟回调函数。并从新遍历闹钟链表,获取最先超时的闹钟。并设置闹钟。alarm 组件的实现

首先须要实现 rtc 的性能
配置 MCU alarm,默认使能 [按天]周期性响应的闹钟。欠缺 rtc 的平台适配:drv_rtc.c control 函数
示例如下:

static struct rt_rtc_device rtc_device;

ifdef RT_USING_ALARM

static rt_err_t rtc_alarm_time_set(struct rt_rtc_device* p_dev);
static int rt_rtc_alarm_init(void);

endif

/ rtc 与 alrm,共用 control 函数 /
static rt_err_t rt_rtc_control(rt_device_t dev, int cmd, void *args)
{

rt_err_t result = RT_EOK;

ifdef RT_USING_ALARM

struct rt_rtc_wkalarm *p_wkalarm = RT_NULL;

endif

RT_ASSERT(dev != RT_NULL);

switch (cmd)
{
case RT_DEVICE_CTRL_RTC_GET_TIME:
    *(rt_uint32_t *)args = get_rtc_timestamp();
    LOG_D("RTC: get rtc_time %x\n", *(rt_uint32_t *)args);
    break;

case RT_DEVICE_CTRL_RTC_SET_TIME:
    if (set_rtc_timestamp(*(rt_uint32_t *)args))
    {result = -RT_ERROR;}

ifdef RT_USING_ALARM

    rt_alarm_update(&rtc_device.device, 1);

endif

    LOG_D("RTC: set rtc_time %x\n", *(rt_uint32_t *)args);
    break;

ifdef RT_USING_ALARM

case RT_DEVICE_CTRL_RTC_GET_ALARM:
    args = &rtc_device.wkalarm;
    break;

case RT_DEVICE_CTRL_RTC_SET_ALARM:
    p_wkalarm = (struct rt_rtc_wkalarm *)args;
    if (p_wkalarm != RT_NULL)
    {
        rtc_device.wkalarm.enable = p_wkalarm->enable;
        rtc_device.wkalarm.tm_hour = p_wkalarm->tm_hour;
        rtc_device.wkalarm.tm_min = p_wkalarm->tm_min;
        rtc_device.wkalarm.tm_sec = p_wkalarm->tm_sec;
        rtc_alarm_time_set(&rtc_device);
    }
    else
    {result = -RT_ERROR;}
    break;

endif

}

return result;

}

/ 设置闹钟的 MCU 适配函数,不同的 MCU,会有区别 /
static rt_err_t rtc_alarm_time_set(struct rt_rtc_device* p_dev)
{

am_hal_rtc_time_t rtc_Time = {0};
time_t timestamp = 0;
struct tm *p_tm;

if (p_dev->wkalarm.enable)
{timestamp = get_rtc_timestamp();
    p_tm = localtime(&timestamp);

    if (p_tm->tm_year < 100)
    {return -RT_ERROR;}

    rtc_Time.ui32Second = p_dev->wkalarm.tm_sec ;
    rtc_Time.ui32Minute = p_dev->wkalarm.tm_min ;
    rtc_Time.ui32Hour   = p_dev->wkalarm.tm_hour;
    LOG_D("%s-%d:%d:%d", __func__, p_dev->wkalarm.tm_hour,
        p_dev->wkalarm.tm_min,p_dev->wkalarm.tm_sec);
    rtc_Time.ui32DayOfMonth    = p_tm->tm_mday;
    rtc_Time.ui32Month   = p_tm->tm_mon + 1 ;
    rtc_Time.ui32Year    = p_tm->tm_year - 100;
    rtc_Time.ui32Weekday = p_tm->tm_wday + 1;

    am_hal_rtc_alarm_set(&rtc_Time, RTC_ALM_RPT_INTERVAL);
    rt_rtc_alarm_enable();}

return RT_EOK;

}

alarm 组件性能验证

创立了 alarm,怎么晓得是否胜利?除了 LOG 的打印,等事件是很难的,如设置了一年后,须要一年后再回来看后果?应用 date 更改零碎的工夫!!alarm 组件提供 alarm 查问性能,如下:

msh />alarm_dump

alarm_id YYYY-MM-DD hh:mm:ss weekday flags
No 0 2000-01-01 00:00:20 6 0x4003

msh />

后期能够应用 MSH CMD 命令,进行闹钟的创立、开启、进行、删除操作。参考文档:RTC 设施

原文链接:https://club.rt-thread.org/as…

退出移动版