基于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既可以做为独立的应用 ...
随机推荐
- update更新修改数据
update ---整表更新数据 update 表名 set 需要调整字段1= '值1' ,需要调整字段2= '值2' …… ---更新条件数据 update 表名 set 需要调整字段 ...
- Subclass UICollectionViewFlowLayout,自定义流布局
需求:为实现第一行显示一个,第二行以后显示两个 方案1:用系统自带的流布局,实现的效果是,若第二行只有一个,则系统默认会居中显示,不是左对齐(如下图),不符合项目要求. 方案2:自定义系统的UICol ...
- javascript根据文件字节数返回文件大小
function getFileSize(fileByte) { var fileSizeByte = fileByte; var fileSizeMsg = ""; if(fil ...
- jquery--DOM操作基础
元素的访问 元素属性操作 获取:attr(name):$("#my").attr("src"); 设置:attr(name,value):$("#my ...
- es6 Proxy对象详解
Proxy用于修改某些操作的默认行为,也可以理解为在目标对象之前架设一层拦截,外部所有的访问都必须先通过这层拦截,因此提供了一种机制,可以对外部的访问进行过滤和修改.这个词的原理为代理,在这里可以表示 ...
- Java敲地鼠代码
package test; import java.awt.EventQueue; import java.awt.event.MouseAdapter; import java.awt.event. ...
- Redis(九):Redis的Java客户端Jedis
Redis的Java客户端Jedis导航目录: 安装JDK 安装Eclipse Jedis所需要的Jar包 Jedis常用操作 JedisPool 安装JDK tar -zxvf jdk-7u67-l ...
- TCC : Tiny C Compiler (2018-2-6)
饭墙下载,有缘上传: https://files.cnblogs.com/files/bhfdz/tcc-0.9.27-win32-bin.zip https://files.cnblogs.com/ ...
- Python学习笔记八:文件操作(续),文件编码与解码,函数,递归,函数式编程介绍,高阶函数
文件操作(续) 获得文件句柄位置,f.tell(),从0开始,按字符数计数 f.read(5),读取5个字符 返回文件句柄到某位置,f.seek(0) 文件在编辑过程中改变编码,f.detech() ...
- 20145209刘一阳《网络对抗》Exp6信息搜集与漏洞扫描
20145209刘一阳<网络对抗>Exp6信息搜集与漏洞扫描 实践内容 信息搜集和漏洞扫描 信息搜集 whois查询 用whois查询博客园网站的域名注册信息可以得到注册人的名字.城市等信 ...