news 2026/8/13 23:43:29

嵌入式工程师进阶指南:RTOS事件在工程中具体应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
嵌入式工程师进阶指南:RTOS事件在工程中具体应用

普通的信号量存在两个弊端:一是无法避免优先级翻转问题,二是不具备实现一对多线程发送信号的能力。事件和信号量的设计初衷是一致的就是实现两个线程之间的同步,而事件比信号量更适合在多对多和多对一的场景上使用。

现有一个要求如下:main线程内要求使用消息队列堵塞接收来自传感器线程发送来的数据,并要求LED灯每隔500ms闪烁一次。

按照要求可以简单写出消息队列的程序:

while(1) { rt_err_t status = rt_mq_recv(mainqueuehandle, &pRev, sizeof(pRev), RT_WAITING_FOREVER); if(status == RT_EOK) { cnt++; if(pRev->temp > max) { max = pRev->temp; } if(pRev->temp < min) { min = pRev->temp; } avg += pRev->temp; avg /= cnt; rt_kprintf("time:%d max:%d min:%d avg:%d\n",pRev->timestamp,max,min,avg); } rt_pin_write(LED_PIN, 1- rt_pin_read(LED_PIN)); rt_thread_mdelay(500); }

因此消息队列使用了堵塞等待的形式, 因此对于500ms进行LED闪烁的操作无法进行。

如果不希望通过阻塞等待的方法,那么可以将阻塞等待改变为延时等待,程序修改如下:

while(1) { rt_err_t status = rt_mq_recv(mainqueuehandle, &pRev, sizeof(pRev), 500); if(status == RT_EOK) { if(pRev->temp > max) { max = pRev->temp; } if(pRev->temp < min) { min = pRev->temp; } avg += pRev->temp; avg /=2; rt_kprintf("time:%d max:%d min:%d avg:%d\n",pRev->timestamp,max,min,avg); } rt_pin_write(LED_PIN, 1- rt_pin_read(LED_PIN)); //rt_thread_mdelay(500); }

对于像执行LED闪烁这样的简单函数来说,使用延时等待的方法是可以接受的,但如果执行的其余函数时间过程和内容过大这种操作方法会导致消息队列接收数据出现实时性问题。

可以改用以下的方法来解决问题:创建一个500ms的软件定时器用于计时时间,到达之后在回调函数中直接执行发送事件的操作即可,同样需要在发送数据线程中添加首先发送事件的操作,在事件接收线程中,需要去阻塞等待事件的出现,同时检测两个事件,无论哪个事件被检测到就可直接进入分支程序运行下面的函数。

void timer_handler(void *paramter) { rt_event_send(eventhandle, T500MSENT); } int main(void) { rt_uint32_t evt = 0; DataPacket_t *pRev; static uint32_t max = 0; static uint32_t min = 0XFFFF; static uint32_t avg = 0; rt_timer_t timer; timer = rt_timer_create("500ms", timer_handler, RT_NULL, 500,RT_TIMER_FLAG_PERIODIC ); rth_sensor_create(); rth_lcd_create(); rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT); rt_timer_start(timer); while(1) { if(rt_event_recv(eventhandle, T500MSENT | DATAENT, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &evt) == RT_EOK) { if(evt & DATAENT) { rt_err_t status = rt_mq_recv(mainqueuehandle, &pRev, sizeof(pRev), RT_WAITING_FOREVER); if(status == RT_EOK) { if(pRev->temp > max) { max = pRev->temp; } if(pRev->temp < min) { min = pRev->temp; } avg += pRev->temp; avg /=2; rt_kprintf("time:%d max:%d min:%d avg:%d\n",pRev->timestamp,max,min,avg); } }else if(evt & T500MSENT) { rt_pin_write(LED_PIN, 1- rt_pin_read(LED_PIN)); } } } return RT_EOK; }
void rth_sensor_handler(void *paramter) { static DataPacket_t datapool[8]; uint8_t i = 0; while(1) { DataPacket_t* pData = &datapool[i]; pData->humi = rand()%100; pData->temp = rand()%50; pData->timestamp = rt_tick_get(); rt_event_send(eventhandle, DATAENT); rt_err_t status = rt_mq_send_wait(dataqueuehandle, &pData, sizeof(pData),10); rt_err_t flag = rt_mq_send_wait(mainqueuehandle, &pData, sizeof(pData),10); if(status == RT_EOK || flag == RT_EOK) { i = (i+1) % 8; } rt_thread_mdelay(1000); } }

此种方法既可以解决方法1的时间延时问题还可以保持CPU占用高的问题。

由此可以总结出一个关于定时执行任务和接收消息队列组合的程序框架

while(1) { if(rt_event_recv(.....) == RT_EOK) //等待事件到达 阻塞等待 { if(evt & DATAENT) //判断 数据传输事件1 { rt_err_t status = rt_mq_recv(....); //等待消息队列 //操作接收到的数据 } else if(evt....) //判断 定时执行任务事件2 { //执行定时执行任务 } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/13 23:43:17

数据安全审计系统架构设计与AI实践

1. 项目概述&#xff1a;数据安全审计的范式革命 去年参与某金融机构数据治理项目时&#xff0c;客户安全团队负责人向我展示过这样一组数据&#xff1a;他们每天需要处理来自网络设备、数据库、业务系统的审计日志超过200GB&#xff0c;但实际能有效分析的不足5%。这并非个例&…

作者头像 李华
网站建设 2026/8/13 23:42:11

SDC约束设计实战:从核心命令到工程避坑指南

1. 项目概述&#xff1a;SDC命令的江湖地位与核心价值 在数字芯片设计的江湖里&#xff0c;SDC&#xff08;Synopsys Design Constraints&#xff09;文件就是整个项目的“宪法”。它不写代码&#xff0c;却定义了芯片的“行为准则”——时钟怎么跑、信号怎么传、路径怎么约束。…

作者头像 李华
网站建设 2026/8/13 23:42:00

Python+Selenium自动化测试入门:从环境搭建到Page Object模式实战

1. 从“手动点点点”到“脚本自己跑”&#xff1a;为什么我们需要自动化测试&#xff1f;如果你是一名测试工程师&#xff0c;或者是一名需要对自己代码负责的开发&#xff0c;那么“自动化测试”这个词你一定不陌生。但很多时候&#xff0c;它就像一个挂在嘴边的“高级”概念&…

作者头像 李华
网站建设 2026/8/13 23:40:51

深入解析 OpenAI Node.js SDK 源码:架构设计与工程实践

1. 项目概述&#xff1a;为什么我们要读 openai-node 的源码&#xff1f; 如果你是一名 Node.js 或 TypeScript 开发者&#xff0c;并且正在或打算与 OpenAI 的 API 打交道&#xff0c;那么 openai-node 这个官方 SDK 大概率已经是你项目中的依赖项了。我们每天都在用 npm i…

作者头像 李华
网站建设 2026/8/13 23:40:20

运算放大器虚短虚断原理:从负反馈本质到电路分析实战

1. 从“玄学”到直觉&#xff1a;为什么运算放大器分析让你头疼&#xff1f;刚接触模拟电路&#xff0c;尤其是学到运算放大器这一章时&#xff0c;很多人都会在“虚短”和“虚断”这两个概念上卡壳。书上写的定义似乎都懂&#xff1a;理想运放下&#xff0c;同相端和反相端电压…

作者头像 李华
网站建设 2026/8/13 23:35:59

计算机毕业设计之基于spark的B站动漫评价数据分析及可视化的实现

本基于spark的B站动漫评价数据分析及可视化采用B/S架构&#xff0c;数据库是MySQL&#xff0c;网站的搭建与开发采用了先进的Python语言、爬虫技术进行编写&#xff0c;使用了Django框架&#xff0c;随着互联网技术的飞速发展&#xff0c;视频分享网站如Bilibili&#xff08;简…

作者头像 李华