嵌入式技术之RAlarm接口说明

嵌入式技术

1362人已加入

描述

在实际的开发项目中,很多时候我们需要定时的做一些事情,举例:

①路上的路灯,每天晚上6:00准时打开,每天早上6:00准时关闭;

②定时闹钟,起床上班。这些行为其实都是定时任务--闹钟。

大部分单片机都提供了rtc alarm硬件闹钟,但是实际很少人使用,就举个简单的例子,rt-thread的BSP中也没有几个芯片适配了alarm硬件闹钟。但是我们要使用怎么办??

我受到RTOS的调度的启发,像M3/M4这种内核都是SysTick产生时钟节拍,以供系统处理所有和时间有关的事情,如线程延时,线程的时间片轮转,以及定时器超时等。

有了第3点的经验,那么我们可以写一个软件闹钟功能就容易多了,只需要提供一个刷新节拍,定时查看哪一个闹钟需要唤醒,就可以解决闹钟的管理了。

闹钟组件名字:RAlarm(全称Rice Alarm)。

RAlarm

RAlarm接口说明:

跨平台

RTOS的种类很多,接口差异性大,所以RAlarm为了解决这个问题,统一为上层提供一整套接口。

线程接口。

typedef void *ralarm_task_id;

struct ralarm_task_attr{
    const char *name;       // name of the task
    uint32_t stack_size;     // size of stack
    uint8_t priority;       // initial task priority
};

typedef void(*ralarm_task_func)(void *arg);

ralarm_task_id ralarm_task_create(ralarm_task_func func, void *arg, const struct ralarm_task_attr *attr);
void ralarm_task_delete(ralarm_task_id thread);

互斥量接口。

typedef void *ralarm_mutex_id;

ralarm_mutex_id ralarm_mutex_create(void);
ralarm_err_t ralarm_mutex_lock(ralarm_mutex_id mutex);
ralarm_err_t ralarm_mutex_unlock(ralarm_mutex_id mutex);
void ralarm_mutex_delete(ralarm_mutex_id mutex);

事件接口。

typedef void *ralarm_event_id;

ralarm_event_id ralarm_event_create(void);
uint32_t ralarm_event_recv(ralarm_event_id event, uint32_t flags);
ralarm_err_t ralarm_event_send(ralarm_event_id event, uint32_t flags);
void ralarm_event_delete(ralarm_event_id event);

RAlarm目前已经提供了两个环境的适配,如cmsis,rtthread。

接口使用简单

接口 说明
ralarm_init 初始化
ralarm_deinit 去初始化
ralarm_create 创建闹钟
ralarm_start 启动闹钟
ralarm_stop 停止闹钟
ralarm_modify 修改闹钟
ralarm_delete 删除闹钟

闹钟初始化接口:初始化闹钟的链表,闹钟任务,事件,互斥锁;去初始化接口:注销闹钟组

/* 闹钟初始化 */
ralarm_err_t ralarm_init(void);

/* 闹钟去初始化 */
void ralarm_deinit(void);

闹钟创建:

参数说明:

参数 描述
setup 闹钟的时间和标志,flag可为:RALARM_ONESHOT(只设置一次)和RALARM_DAILY(每天都设置)
cb 闹钟时间到了,唤醒的回调函数指针:typedef void (*ralarm_response_cb)(ralarm_t alarm)
userData 设置闹钟时,自带的用户数据的指针
返回 ——
ralarm_t 闹钟创建成功,放回闹钟句柄
NULL 闹钟创建失败

函数说明:

①申请闹钟控制块的空间。

②设置闹钟参数到控制块中。

③将闹钟加入到闹钟链表中。

struct ralarm_setup {
    ralarm_flag flag;
    struct ralarm_time time;
};
typedef struct ralarm_setup *ralarm_setup_t;

struct ralarm {
    ralarm_state state;
    struct ralarm_setup setup;
    ralarm_response_cb cb;
    void *userData;
    ralarm_list_t list;
};
typedef struct ralarm *ralarm_t;

ralarm_t ralarm_create(ralarm_setup_t setup, ralarm_response_cb cb, void *userData)
{
    ralarm_t alarm = NULL;
    
    if(setup == NULL) {
        RALARM_LOGE("Create alarm failed, Setup param is NULL");
        return NULL;
    }
    alarm = RALARM_MALLOC(sizeof(struct ralarm));                           // ----①
    if(alarm == NULL) {
        RALARM_LOGE("Malloc alarm memory failed");
        return NULL;
    }

    ralarm_list_init(&alarm->list);                                         // ----②
    memset((void *)alarm, 0, sizeof(struct ralarm));
    memcpy((void *)&alarm->setup, setup, sizeof(struct ralarm_setup));
    alarm->cb = cb;
    alarm->userData = userData;

    ralarm_mutex_lock(g_container.mutex);
    ralarm_list_insert_after(&g_container.list, &alarm->list);              // ----③
    ralarm_mutex_unlock(g_container.mutex);
    return alarm;
}

闹钟启动:将闹钟的状态的start bit置为1。

ralarm_err_t ralarm_start(ralarm_t alarm)
{
    if(alarm == NULL) {
        return RALARM_ERROR;
    }
    ralarm_mutex_lock(g_container.mutex);
    alarm->state |= RALARM_STATE_START;

    ralarm_mutex_unlock(g_container.mutex);
    return RALARM_EOK;
}

闹钟停止:将闹钟的状态的start bit置为0。

ralarm_err_t ralarm_stop(ralarm_t alarm)
{
    if(alarm == NULL) {
        return RALARM_ERROR;
    }
    ralarm_mutex_lock(g_container.mutex);
    alarm->state &= ~RALARM_STATE_START;

    ralarm_mutex_unlock(g_container.mutex);
    return RALARM_EOK;
}

闹钟修改:修改闹钟的标志和闹钟的时间

参数说明:

参数 描述
alarm 闹钟的句柄
setup 要修改闹钟的时间和标志参数
返回 ——
RALARM_EOK 修改成功
RALARM_ERROR 修改失败


ralarm_err_t ralarm_modify(ralarm_t alarm, ralarm_setup_t setup)

{
    if(alarm == NULL) {
        return RALARM_ERROR;
    }
    ralarm_mutex_lock(g_container.mutex);

    memcpy((void *)&alarm->setup, setup, sizeof(struct ralarm_setup));

    ralarm_mutex_unlock(g_container.mutex);
    return RALARM_EOK;
}

删除闹钟:

函数说明:

①将闹钟的状态的start bit置为0。

②将闹钟从闹钟链表中移除。

③释放闹钟的内存。

ralarm_err_t ralarm_delete(ralarm_t alarm)

{
    if(alarm == NULL) {
        return RALARM_ERROR;
    }
    ralarm_mutex_lock(g_container.mutex);

    alarm->state &= ~RALARM_STATE_START;        // ---①
    ralarm_list_remove(&alarm->list);           // ---②
    RALARM_FREE(alarm);                         // ---③
    alarm = NULL;

    ralarm_mutex_unlock(g_container.mutex);
    return RALARM_EOK;
}

适配简单

根据系统能力,提供获取时间方法,创建ralarm的ops并注册获取时间接口。

struct ralarm_ops{
    ralarm_err_t (*time_get)(ralarm_time_t time);
};

ralarm_err_t ralarm_register_ops(struct ralarm_ops *ops);

提供刷新节拍,然后调用刷新接口。

void ralarm_refresh(void);

RAlarm运行逻辑:

闹钟的refresh接口需要用户提供一个刷新节拍,以提供闹钟的生命。

refresh根据闹钟链表是否存在已设置的闹钟,选择发送事件给更新任务,更新检测闹钟的状态。

如下图:当检测闹钟链表无设置的闹钟,则不会发送事件给更新任务

RTOS

如下图:

当用户创建了闹钟,则会将闹钟挂在闹钟量表中。

刷新节拍调用refresh之后,发送事件给更新任务,然后调用wakeup检测闹钟的状态。

如果某个闹钟时间到,则会调用对应闹钟的回调函数。

RTOS

RAlarm的使用

在RT-Thread下使用ralarm组件:

① 闹钟的处理函数,当闹钟时间到了,则会调用这个函数。

② 提供给ralarm组件时间接口。

③ 创建ops,提供时间接口。

④ 软件定时器的处理函数,调用ralarm的刷新函数,提供刷新节拍。

⑤ ralarm组件初始化,注册ops。

⑥ 创建闹钟。

⑦ 创建一个软件定时器,为ralarm组件提供刷新节拍。

static rt_timer_t timer;
ralarm_t alarm_test = NULL;

static void alarm_handler(ralarm_t alarm)                               // ---①
{
    rt_kprintf("Time: %02d:%02d:%02d
", alarm->setup.time.hour,      
                alarm->setup.time.minute, alarm->setup.time.second);
    ralarm_stop(alarm);
    ralarm_dump();
}

static ralarm_err_t alarm_time_get(ralarm_time_t timer)                 // ---②
{
    time_t current;
    struct tm *local;
    
    time(¤t);
    local = localtime(¤t);
    timer->hour = local->tm_hour;
    timer->minute = local->tm_min;
    timer->second = local->tm_sec;
    return RALARM_EOK;
}

static struct ralarm_ops ops = {                                        // ---③
    .time_get = alarm_time_get,
};

static void time_handler(void *param)                                   // ---④
{
    ralarm_refresh();
}

int main(void)
{
    ralarm_init();                                                      // ---⑤
    ralarm_register_ops(&ops);

    struct ralarm_setup setup;
    setup.flag = RALARM_DAILY;
    setup.time.hour = 15;
    setup.time.minute = 0;
    setup.time.second = 0;

    alarm_test = ralarm_create(&setup, alarm_handler, NULL);            // ---⑥
    ralarm_start(alarm_test);

    ralarm_dump();

    timer = rt_timer_create("timer", time_handler,                      // ---⑦
                             RT_NULL, 800,
                             RT_TIMER_FLAG_PERIODIC);
    if (timer != RT_NULL) 
        rt_timer_start(timer);
}

验证结果:

RTOS

编辑:黄飞

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分