文章目录

  • 一,简介
  • 二,结构体
  • 三,函数接口
  • 四,使用示例
  • 五,代码详解
    • 1,clk_t get_current_nettime();
    • 2,struct timer *tmr_new(clk_t *conf, timer_cb cb, void *arg, char *name);
    • 3, int tmr_add(struct timer *tmr);
    • 4,int tmr_remove(struct timer *tmr); and int tmr_delete(struct timer *tmr);
    • 5,void tmr_process(void *arg);

一,简介

该系统拥有一个全局时间变量global_clk,该变量记录了当前的时间(年,月,日,小时,分钟,秒),并维持一个定时任务列表。用户可以添加定时任务,删除定时任务等。定时任务执行完成后会被移除列表,但不会被释放。

二,结构体

//日历结构体
struct calendar
{unsigned int second : 6 ;  //低位unsigned int minute : 6 ;unsigned int hour : 5 ;unsigned int date : 5 ;unsigned int month : 4 ;unsigned int year : 6 ;  //高位
};//时间结构体,cal的值决定了value
union clk
{struct calendar cal;unsigned int value;
};typedef union clk clk_t;
struct timer;
typedef unsigned char (*timer_cb)(struct timer *tmr ,void *arg);    //回调函数//定时任务结构体
struct timer
{char *name;    //名称struct timer *next; //指向下一个定时clk_t timeout; //定时的时间timer_cb cb; //回调函数void *arg;    //回调参数
};
extern clk_t global_clk;    //全局时间
extern struct timer *timer_list;    //定时任务列表

三,函数接口

void printf_tmrlist();   //打印定时列表
struct timer *tmr_new(clk_t *conf,timer_cb cb,void *arg,char *name); //新建闹钟
int update_clk(clk_t *clk); //更新时间
int tmr_add(struct timer *tmr); //添加定时任务
int tmr_remove(struct timer *tmr);  //移除定时任务
int tmr_delete(struct timer *tmr);  //删除定时任务
void tmr_set_global(clk_t conf);    //设置全局时间
clk_t get_current_nettime();    //获取当前时间
int global_clk_init();  //全局时间初始化
void tmr_process(void *arg);    //定时任务处理void clock_task(void *arg); //时间系统线程

四,使用示例

首先需要对全局时间来一个初始化,确定当前的时间,这个部分是通过网络获取北京时间的。同时,该示例设置一个定时任务,每24小时就通过网络更新时间,当24小时也就是一天的定时到了,update_global_cb()就会被执行。

/** 定时器回调函数:更新全局时间*/
timer_cb update_global_cb(struct timer *tmr, void *agr)
{clk_t t = get_current_nettime();tmr_set_global(t); //更新全局时间tmr->timeout.value = global_clk.value;tmr->timeout.cal.date += 1;tmr_add(tmr); //将更新任务再次添加进return NULL;
}
/** 全局时间初始化* 获取网络事件,设置定时器,自动更新全局时间*/
int global_clk_init()
{clk_t t = get_current_nettime();  //获取网络时间tmr_set_global(t); //更新全局时间t.cal.date += 1;   //日期+1tmr_new(&t, update_global_cb, NULL, "UPDATE"); //创建定时器,每24小时更新网络时间,并添加到列表return 1;
}

接下来,在线程中,每秒调用tmr_process();保证时间系统的正常运行。

/** 时钟任务,每秒执行,处理定时任务及时间更新*/
void clock_task(void *arg)
{esp_log_level_set(TAG, ESP_LOG_INFO);while (1){vTaskDelay(1000 / portTICK_RATE_MS);tmr_process(NULL);}
}

五,代码详解

1,clk_t get_current_nettime();

该函数先调用获取网络时间的代码。esp32获取网络时间;将时间字符串转换成数字格式,复制到结构体并返回;

/** 获取当前网络时间* 返回:时间结构体*/
clk_t get_current_nettime()
{char *origin = get_Time_String(); //调用myhttp.c,获取时间字符串:"2021-03-24 04:49:53"char str[6][10] = {'\0'}; //year,month,date,hour,minute,second//printf("origin = %s\n", origin);//分别提取出时间for (int i = 0; i <= 5; i++){char *c = str[i];while (!((*origin == '-') || (*origin == ' ') || (*origin == ':'))){if (*origin == '\0'){break;}*c = *origin;origin++;c++;}origin++;}unsigned int x[6] = {0};//将字符串转换成数字for (int i = 0; i < 6; i++){x[i] = (unsigned int)atoi(str[i]);printf("x = %d\n", x[i]);}//赋值给时间结构体clk_t conf;conf.cal.year = x[0] - 2000;conf.cal.month = x[1];conf.cal.date = x[2];conf.cal.hour = x[3] + 8;conf.cal.minute = x[4];conf.cal.second = x[5];return conf;
}

2,struct timer *tmr_new(clk_t *conf, timer_cb cb, void *arg, char *name);

/** 创建一个定时器 并添加进定时队列* conf:定时时间* cb:定时回调函数* arg:回调函数参数* name:定时器名* 返回:定时器结构体指针*/
struct timer *tmr_new(clk_t *conf, timer_cb cb, void *arg, char *name)
{struct timer *tmr;clk_t clk;//tmr must > global_clkif (conf == NULL || (conf->value <= global_clk.value)){ESP_LOGI(TAG,"new tmr error\n");return 0;}tmr = (struct timer *)malloc(sizeof(struct timer));//chcek the confclk.value = conf->value;update_clk(&clk); //规范化clkESP_LOGI(TAG,"new timer %s: 20%d-%d-%d %d:%d:%d values =%u\r\n", name, clk.cal.year, clk.cal.month, clk.cal.date, clk.cal.hour, clk.cal.minute, clk.cal.second, clk.value);//printf("new timer %s: 20%d-%d-%d %d:%d:%d values =%u\r\n", name, clk.cal.year, clk.cal.month, clk.cal.date, clk.cal.hour, clk.cal.minute, clk.cal.second, clk.value);tmr->timeout.value = clk.value; //将clk赋值给定时器if (cb != NULL){tmr->cb = cb;}if (arg != NULL){tmr->arg = arg;}if (name != NULL){char *dest = (char *)malloc(strlen(name));strncpy(dest, name, strlen(name) + 1);tmr->name = dest;}tmr->next = NULL;tmr_add(tmr);printf_tmrlist();return tmr;
}
/** 更新时间结构体,使其成员符合时间规则* clk:要更新的时间* 返回:0 年份更新;1 年份未更新*/
int update_clk(clk_t *clk)
{if (clk->cal.second >= 60){//one minuteclk->cal.second = clk->cal.second - 60;clk->cal.minute++;if (clk->cal.minute >= 60){//one hourclk->cal.minute = clk->cal.minute - 60;clk->cal.hour++;if (clk->cal.hour >= 24){//date +1clk->cal.hour = clk->cal.hour - 24;clk->cal.date = clk->cal.date + 1;switch (clk->cal.month){case 1:case 3:case 5:case 7:case 8:case 10:case 12:if (clk->cal.date == 32){goto exit;}break;case 2://29 or 28 in februaryif (((clk->cal.year % 4) == 0 && clk->cal.date == 30) || ((clk->cal.year % 4 != 0) && (clk->cal.date == 29))){goto exit;}break;default:if (clk->cal.date == 31){goto exit;}break;}}}}return 1;
//month +1
exit:clk->cal.date = 1;clk->cal.month++;if (clk->cal.month == 13){clk->cal.month = 1;clk->cal.year++; //max to 2064}return 0;
}

3, int tmr_add(struct timer *tmr);

/** 将定时器插入链表,按时间先后顺序* tmr:要插入的定时器* 返回:0失败;1成功*/
int tmr_add(struct timer *tmr)
{struct timer *t, *prev = NULL;ESP_LOGI(TAG,"adding timer to timerlist:");if (tmr == NULL){ESP_LOGI(TAG, "new timer is null");return 0;}//若当前无定时器则,tmr将作为第一个定时器if (timer_list == NULL){ESP_LOGI(TAG, "timer %s is the only timer",tmr->name);//first tmrtmr->next = NULL;timer_list = tmr;}else //按时间先后顺序将tmr插入链表{t = timer_list;//时间小的在前面while (((t->timeout.value) < (tmr->timeout.value))){ESP_LOGI(TAG, "step for next timer");prev = t; //保存t的上一个if (t->next == NULL){//若t是最后一个定时器t->next = tmr; //将tmr插入t后tmr->next = NULL;ESP_LOGI(TAG, "add timer %s to the tail of the list ",tmr->name);return 1;}t = t->next; //检查下一个定时器}//上一个为空,说明tmr是最早的定时器if (prev == NULL){//tmr less than the first onetmr->next = timer_list; //tmr插入timer_list的前面timer_list = tmr;     //再更新timer_listESP_LOGI(TAG, "add timer %s to the head of list",timer_list->name);}else{tmr->next = t; //tmr插入t之前prev->next = tmr; //tmr插入prev之后ESP_LOGI(TAG, "add timer %s behind %s",tmr->name,prev->name);}}return 1;
}

4,int tmr_remove(struct timer *tmr); and int tmr_delete(struct timer *tmr);

/** 将定时器从链表移除* tmr:要移除的定时器* 返回 0失败;1成功*/
int tmr_remove(struct timer *tmr)
{struct timer *t, *prev = NULL;if (tmr == NULL){return 0;}//check if the tmr is in the listif (timer_list == NULL){return 0;}t = timer_list;//find the tmrwhile (t != tmr){if (t->next == NULL){return 0; //no match}prev = t;t = t->next;}//t==tmrif (prev == NULL){//t is the firsttimer_list = t->next;}else{if (t->next == NULL){//t is the lastprev->next = NULL;}else{//t in the middleprev->next = t->next;}}t->next = NULL;return 1;
}
/** 删除定时器,释放定时器占用的内存* tmr:要删除的定时器* 返回:0失败,1成功*/
int tmr_delete(struct timer *tmr)
{if (tmr == NULL){return 0;}tmr_remove(tmr);free(tmr->name);free(tmr);return 1;
}

5,void tmr_process(void *arg);

clk_t global_clk; //全局时间
/** 时间任务进程 负责更新全局时间以及触发定时器* 在定时器中断中,每秒执行*/
void tmr_process(void *arg)
{struct timer *t;//update the global_clkglobal_clk.cal.second++;update_clk(&global_clk);//check if timer_list is nullif (timer_list == NULL){return;}//check the first timer in listt = timer_list;//printf("timer_list value = %d\n",t->timeout.value);if (global_clk.value == (t->timeout.value)){tmr_remove(t); //若要重复定时,只需要在回调函数中调用tmr_add()printf("timer %s\n", t->name);t->cb(t, t->arg); //callback func}
}
/** 设置全局事件* conf:新的时间*/
void tmr_set_global(clk_t conf)
{global_clk.value = conf.value;
}

基于esp32 的时间系统相关推荐

  1. AI视觉组基于ESP32的裁判系统第一版本设计要求

    简 介: 面对第十六届全国大学生智能车竞赛中新增加的一些组别的要求,比如室内AI组,对于车模任务增加的检测任务,设计了基于ESP32为核心的比赛系统.本文给出了对于比赛系统功能的要求. 关键词: 比赛 ...

  2. 详细!基于ESP32的智能门禁系统(华为云iot+微信小程序)

    git地址:智能门禁(云IOT+微信小程序) 开关门效果 设备侧 产品创建 创建产品 创建产品,协议类型选择MQTT,数据格式选择JSON,其他参数自定 设备注册 找到所属产品,认证类型选择密钥,单击 ...

  3. 基于ESP32的智能车竞赛新版裁判系统的软件功能要求与实现

    简 介: 本文给出了第十六届智能车竞赛裁判系统最终的软件设计和功能实现.并进行了验证,是它可以满足比赛基本计时要求. 最后给出了完整的程序. 关键词: 智能车竞赛,ESP32,视觉AI §01 智能车 ...

  4. 基于ESP32智能车竞赛裁判系统第二版硬件调试-6-26

    简 介: 对于新版的比赛裁判系统进行硬件测试,验证了新版的硬件满足比赛的要求.对于感光板的不同区域灵敏度不同的问题,最后验证是由于LED的分布电容所引起的时间常数不同造成了.对于单条串联的LED修改成 ...

  5. 基于ESP32智能车竞赛比赛系统硬件初步调试-5-6

    简 介: 给出了对于基于ESP32设计的智能车竞赛的の比赛系统的硬件调试过程.基本上验证了硬件设计的合理与正确性.在第一部分的"修改建议"中也给出了硬件电路的修改意见. 关键词: ...

  6. 基于ESP32的竞赛裁判系统功能调试-与微机通讯

    简 介: 通过调试测试了基于ESP32设计的智能车竞赛的比赛系统方案与比赛软件联系的功能. 关键词: 智能车竞赛,比赛系统,ESP32 §01 比赛系统与微机通讯 在 基于ESP32智能车竞赛比赛系统 ...

  7. 基于ESP32的竞赛裁判系统功能调试-激光信号调试

    简 介: 通过揣进测试了新版的基于ESP32的裁判系统对于激光信号的检测能力. 关键词: 智能车竞赛,125Hz,激光信号 §01 智能车竞赛裁判系统   对于 基于ESP32的智能车竞赛裁判系统 中 ...

  8. 基于ESP32的竞赛裁判系统功能调试-硬件修改建议

    简 介: 基于前面对于基于ESP32比赛系统的第一版本的调试,给出了在硬件方面的修改意见,便于应用到未来的智能车竞赛比赛中去. 关键词: 智能车竞赛,ESP32,比赛系统 §01 基于ESP32裁判系 ...

  9. 基于ESP32的智能家庭健康系统

    M5Stick-c ESP8266 项目背景及概述: 项目最初的想法来源于当下疫情局势,每个人都关心自己及家人的健康状况.因此本产品旨在应用于人们居家隔离或复工复产过程中,对个人身体情况的实时监测.同 ...

  10. 基于ESP32的开源定时浇花系统

    基于ESP32的开源定时浇花系统 文章目录 基于ESP32的开源定时浇花系统 前言 一.软硬件环境 二.模块连接图 1.浇花功能说明 2.Web界面展示 总结 前言 养了些许花花草草,需要按时浇灌,奈 ...

最新文章

  1. Python 出现 can't use a string pattern on a bytes-like object
  2. 如何轻松拿到大厂面试offer | 掘金技术征文
  3. jmeter多用户登录跨线程组操作传值
  4. Dubbo源码分析:ThreadPool
  5. 面试题27. 二叉树的镜像
  6. yolo数据集txt标注转voc数据集xml标注格式
  7. 基础知识 + 面试题目 总结 索引页
  8. python 爬虫难吗_python写爬虫难吗
  9. python修改csv文件字段顺序_Pandas中DataFrame交换列顺序的方法实现
  10. ping,python实现批量ping包工具--小案例
  11. 【优化求解】基于matlab遗传算法求解红绿灯管理优化问题【含Matlab源码 262期】
  12. 绕过apple id的那些事
  13. mysql将收入增加200_关于一些视图的基本操作(结合YGGL.sql)
  14. 浅谈XPS文件格式。
  15. ROS学习----依据ROS入门教程,整理的ROS命令
  16. 简单记录fortran入门过程
  17. 中国计算机水平低是因为工程水平差
  18. 链改升级,区块链——炳德区块链
  19. 大数据时代下如何保障信息安全?
  20. 在移动设备上实时执行的DNN权重修剪中缺失但令人满意的稀疏性

热门文章

  1. 通往财富自由之路20160808--付费就是捡便宜
  2. 请仔细核对自己的信息
  3. org.postgresql.util.PSQLException: 不支援 10 验证类型
  4. 纯css实现三角原理,兼容IE
  5. 【精华】PB函数大全
  6. 好看的原创弹窗公告代码分享
  7. 如果没有传智播客和张老师,我现在不可能有机会在一家上市公司工作
  8. 概率分布 ---- 二项分布
  9. 票务公司加价将儿童机票售成年人赚取差价
  10. 银河麒麟V10 SELinux启动问题