拓冰建站拓冰建站
首页 / 资讯中心 / 正文

嵌入式工程师进阶指南: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 (i1) % 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 { //执行定时执行任务 } }
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门