在实际的开发项目中,很多时候我们需要定时的做一些事情,举例:
大部分单片机都提供了rtc alarm硬件闹钟,但是实际很少人使用,就举个简单的例子,rt-thread的BSP中也没有几个芯片适配了alarm硬件闹钟。但是我们要使用怎么办??
我受到RTOS的调度的启发,像M3/M4这种内核都是SysTick产生时钟节拍,以供系统处理所有和时间有关的事情,如线程延时,线程的时间片轮转,以及定时器超时等。
有了第3点的经验,那么我们可以写一个软件闹钟功能就容易多了,只需要提供一个刷新节拍,定时查看哪一个闹钟需要唤醒,就可以解决闹钟的管理了。
闹钟组件名字:RAlarm(全称Rice Alarm),源码连接:https://gitee.com/RiceChen0/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_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;
}
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;
}
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;
}
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;
}
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);
static rt_timer_t timer;
ralarm_t alarm_test = NULL;
static void alarm_handler(ralarm_t alarm) // ---①
{
rt_kprintf("Time: %02d:%02d:%02d\r\n", 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);
}