基于freeRTOS定时器实现闹钟(定时)任务
基于freeRTOS定时器实现闹钟(定时)任务
在智能硬件产品中硬件中,闹钟定时任务是基本的需求。一般通过APP设置定时任务,从云端或者是APP直连硬件将闹钟任务保存在硬件flash中,硬件运行时会去处理闹钟任务。
最简单的实现方式是在循环或者定时器处理函数中不断的去判断当前时间是否等于闹钟设定时间,若相等则产生相应的动作。
这样做虽然可行,但是做了太多无用的计算。我们可以根据当前时间距离下一次闹钟激发时间,设定一个对应的定时器,定时器激发时就是闹钟时间,然后继续根据下次激发时间设定新的定时器,这样可以减少不必要的时间比较。
闹钟任务的表示
闹钟任务的表示包含一下及部分的内容:闹钟时间、重复类型、响应操作。
闹钟任务的本地表示可以根据cron格式来定义,当然也可以DIY一个,只要包含以上三个方面内容的就可以。
cron格式的时间表示如下:
| Character | Descriptor | Acceptable Values |
|---|---|---|
| 1 | Minute | 0~59, * (no specific value) |
| 2 | Hour | 0~23, * (no specific value) |
| 3 | Day of month | 1~31, * (no specific value) |
| 4 | Month | 1~12, * (no specific value) |
| 5 | Day of week | 0~7, * (no specific value) |
比如对于一个周一到周五早上7:00的闹钟,可以表示如为:0 7 * * 1,2,3,4,5。
我在代码中定义了如下的闹钟任务:
/* cron 格式时间表示 */
typedef struct
{
int min; // minute, 0xFFFFFFFF表示*
int hour; // hour, 0xFFFFFFFF表示*
int wday; // day of week, 0xFFFFFFFF表示*,bit[0~6] 表示周一到周日,如周一到周五每天响铃,则0x1F
int mday; // day of month, 0xFFFFFFFF表示*, bit[0~31] 表示1~31日,每月1,3,5号响铃,则0x15
int mon; // month, 0xFFFFFFFF表示*,bit[0~11] 表示1~12月
} cron_tm_t;
/* 闹钟任务 */
typedef struct
{
int id; // 任务ID
cron_tm_t cron_tm; // cron格式时间
int action; // 响应操作,对于灯控产品来说,action可以表示开关、颜色、场景等等
TimerHandle_t xTimer; // 定时器句柄
list_node_t node; // 节点,用于将一系列定时任务组织成list
} alarm_task_t;
闹钟下一次激发时间
基于定时器实现闹钟的原理是在每次设置闹钟时计算出距离下一次激发的间隔时间,然后设置一个相应时间的定时器。
首先需要根据cron格式时间计算出下一次激发的时间
/* 距离闹钟下一次激发的时间(min) */
int get_expiry_time(alarm_task_t *alarm_task)
{
/* 首先获取当前时间 */
time_t t;
struct tm now;
time(&t);
localtime_r(&t, &now);
int ret = 0;
if(alarm_task->cron_tm.min != 0xFFFFFFFF)
{
ret += cron_tm.min - now.tm_min;
}
if(alarm_task->cron_tm.hour != 0xFFFFFFFF)
{
int flag = 0;
for(int i=0; i<24; i++)
{
if(i == alarm_task->cron_tm.hour){
flag=1;
break;
}
}
if(flag){
ret += 60*(i-now.tm_hour);
}
}
/* 找到wday或者mday中距离今天最近的一天 */
int t = ret<0?1:0;
int d_wday=0;
int d_mday=0;
for(int i=0; i<7; i++)
{
int wday = now.tm_wday + t +i;
if(1<<(wday%7) & alarm_task->cron_tm.wday){
d_wday=i+t;
break;
}
}
for(int i=0; i<30; i++)
{
int mday = now.tm_mday + t +i;
if(1<<(mday%30) & alarm_task->cron_tm_.mday){
d_mday = i+t;
break;
}
}
int d = d_mday<d_wday?d_mday:d_wday;
ret += d*24*60;
return ret;
}
设置定时器
每次硬件上电时,或者闹钟激发时,都要根据下一次激发的时间,设置一次定时器。
int set_timer(alarm_task_t *alarm_task)
{
int t = get_expiry_time(alarm_task);
if(t <= 0) return -1; // 不需要设置下一次闹钟,不重复的闹钟,且时间已过
alarm_task->xTimer = xTimerCreate( "timer",
t / portTICK_RATE_MS,
1,
(void*)alarm_task,
timer_task_callback );
if(alarm_task->xTimer == NULL)
{
printf("!!! timer created failed\n");
return -1;
}
else
{
xTimerStart(alarm_task->xTimer, 0);
}
return 0;
}
基于freeRTOS定时器实现闹钟(定时)任务的更多相关文章
- FreeRTOS 定时器组
以下转载自安富莱电子: http://forum.armfly.com/forum.php 本章节为大家讲解 FreeRTOS 支持的定时器组,或者叫软件定时器,又或者叫用户定时器均可.软件定时器的功 ...
- 订餐系统之定时器Timer不定时
经过几天漫长的问题分析.处理.测试.验证,定时器Timer终于定时了,于是开始了这篇文章,希望对还在纠结于“定时器Timer不定时”的同学有所帮助,现在的方案,在系统日志中会有警告,如果您有更好的方案 ...
- 定时器Timer不定时
订餐系统之定时器Timer不定时 经过几天漫长的问题分析.处理.测试.验证,定时器Timer终于定时了,于是开始了这篇文章,希望对还在纠结于“定时器Timer不定时”的同学有所帮助,现在的方案,在系统 ...
- 乐鑫esp8266基于freeRtos实现私有服务器本地远程OTA升级
目录 一.前言: 二.回顾下OTA的流程: 三.lwip网络框架的知识的使用: 四.如何处理服务器返回的数据? 五.扇区的擦除和烧写? 六.如何调用? 七.好好享用吧! 八.下载: 九.工程截图: 代 ...
- JS定时器使用,定时定点,固定时刻,循环执行
JS定时器使用,定时定点,固定时刻,循环执行 本文概述:本文主要介绍通过JS实现定时定点执行,在某一个固定时刻执行某个函数的方法.比如说在下一个整点执行,在每一个整点执行,每隔10分钟定时执行的方法. ...
- java.util.Timer类似于闹钟定时做任务
在web中实现任务计划,相当于实现闹钟的功能,要完成2个步骤: 1.定时器的设置: 2.对这个定时器的启动运行和停止进行实时监听 java.util.Timer定时器,实际上是个线程,定时调度所拥有的 ...
- stm32f10x基于freeRTOS的低功耗实现
0. 写在前面 没有太多时间更新,可能偶尔有时间就更新一些. 因为突然有项目用到了stm32f10x系列并且是电池驱动的,所以需要对功耗进行优化,其他CM3核心系列应该也同样适用. 1. 背景 Stm ...
- Java系列--第八篇 基于Maven的SSME之定时邮件发送
关于ssme这个我的小示例项目,想做到麻雀虽小,五脏俱全,看到很多一些web都有定时发送邮件的功能,想我ssme也加入一下这种功能,经查询相关文档,发现spring本身自带了一个调度器quartz,下 ...
- 基于Quartz实现简单的定时发送邮件
一.什么是Quartz Quartz 是一个轻量级任务调度框架,只需要做些简单的配置就可以使用:它可以支持持久化的任务存储,即使是任务中断或服务重启后,仍可以继续运行.Quartz既可以做为独立的应用 ...
随机推荐
- 管理Django1.9静态文件static
管理Django1.9静态文件static 网站通常需要增加图片.JavaScript.或者CSS等文件提供服务.在Django中,我们把这些文件称为“静态文件”(static files).Djan ...
- 为什么我们需要DTO?
最近在写代码时突然产生了这个疑惑,我们为什么需要DTO进行数据传输呢? 要了解DTO首先我们要知道什么是DAO,DAO就是数据库的一个数据模型,是一个类文件里面存储着数据库的字段及其getter&am ...
- about route
route add default dev my_iface1 route del default route add default gw 192.168.120.1 route add -net ...
- easyui datagrid 异步加载数据时滚动条有时会自动滚到最底部的问题
在使用easyui 的datagrid异步加载数据时发现滚动条有时会自动滚到最底部.经测试发现,如果加载数据前没有选中行则不会出现这个问题.这样我们可以在重新异步加载数据前取消选中行就可以避免这个问题 ...
- vue服务端渲染缓存应用
vue缓存分为页面缓存.组建缓存.接口缓存,这里我主要说到了页面缓存和组建缓存 页面缓存: 在server.js中设置 const LRU = require('lru-cache') const m ...
- restframework中的那些参数你知道吗?
序列化是很重要的过程, 在构建数据结构的时候, 往往会出现很多意想不到的问题, 有一些参数你要用, 但是没有办法穿过来, 怎么办> 今天这篇博客就是写我之前的一个小项目中用restframewo ...
- mysql 几种搜索引擎的比较
mysql中常见的数据库引擎之间的比较 转载自 深入浅出mysql数据库 MySQL5.5以后默认使用InnoDB存储引擎,其中InnoDB和BDB提供事务安全表,其它存储引擎都是非事务安全表. 若 ...
- PHP删除临时文件
/** * 下载后直接删除临时文件 */ public function deldir($dir) { $dh=opendir($dir); whil ...
- try catch finally 中 returne的执行顺序
结论:1.不管有没有出现异常,finally块中代码都会执行:2.当try和catch中有return时,finally仍然会执行:3.finally是在return后面的表达式运算后执行的(此时并没 ...
- Hive命令行及参数配置
1 . Hive 命令行 输入$HIVE_HOME/bin/hive –H 或者 –help 可以显示帮助选项: 说明: 1. -i 初始化 HQL 文件. 2. -e 从命令行执行指定的 HQL ...