嵌入式常用算法:时间触发下的嵌入式软件设计模式
2016-07-27 12:43
344 查看
在嵌入式软件开发当中,常常第一步就是设计整个系统的架构。有基于OS的,也有裸机的。我们先拿裸机说事儿,我想很多人在做单片机的裸机开发(甚至基于OS)时脑海里根本没有设计架构的想法,从来都是while(1)循环到底,能写点状态机已经算是基础扎实的人物了。那么问题来了,while(1)是什么?在嵌入式设计模式里是怎么给while(1)定义的。《C嵌入式编程设计模式》一书中将while(1)称之为“超循环模式”,也就是嵌入式的入门傻瓜模式。在此模式下即使有前台监听也势必会导致系统实时性傻逼,从硬件上分析:while(1)的高CPU占用率也使得功耗大大提高。当然存在即合理,超循环模式在安全性和可靠性上是非常占优势的。结构简单也易于理解,这对于安全性能要求较高的系统上还是非常具有吸引力的。
说了这么多不上代码真没意思,具体的看书吧,强烈推荐《C嵌入式编程设计模式》,在此也做一个小广告:朋友埋头2年编写的关于嵌入式设计架构书籍(基于飞思卡尔系列MCU)也即将在明年年初由清华大学出版社出版,爱好飞思卡尔的同学可以关注一下哦。
老规矩,不分析代码了,代码加起来也没几行,数据结构也很简单,静下心来一定看得懂的。这段代码在51单片机(12MHZ,12T)上实际测试在1ms的时标下,满载12个任务下的CPU使用率仅为89%,依然有11%的空闲。如果使用国产STC15系列的1T单片机情况估计刚好相反(没实际测试过,仅仅猜测)。
在看懂代码后,也许有人要问我循环调度下响应事件就迟滞了,实时性就降低了呀!那么针对这样的疑问我想说以下几点:
1:迟滞是相对的,比起超循环系统的while(1)+中断标志位+阻塞延时,轮询调度的响应速度足够快了。
2:循环调度一般情况下还是添加短任务的比较好,长任务忽略的好,至于为什么,自己去琢磨吧。
3:这段代码不是在写操作系统,只能作为嵌入式系统代码中的一部分,不要吹毛求疵,当你能1s读完红楼梦时再来喷吧。
4:任务抖动是无法避免的,除非你是抢占式核,可以抢占CPU使用权。本人汇编菜鸟,写不出来。
5:说的很明确,本代码仅限于裸机开发。
感恩,感谢...
4000
...
使用过程中出现任何BUG请联系我本人QQ:951253606,说明bug现象以及重现过程。
寻求MCU产品开发请联系我本人QQ:951253606。
说了这么多不上代码真没意思,具体的看书吧,强烈推荐《C嵌入式编程设计模式》,在此也做一个小广告:朋友埋头2年编写的关于嵌入式设计架构书籍(基于飞思卡尔系列MCU)也即将在明年年初由清华大学出版社出版,爱好飞思卡尔的同学可以关注一下哦。
/** ****************************************************************************** * @file cx_sch.c * @author CX * @version V1.0.0.1 * @date 2016-7-26 * @brief 1.0.0.1 修改任务数据结构,增加一级抢占任务 加入RunNum预编译选项,限制是否开启任务执行次数 1.0.0.0 完成基础架构搭建 ****************************************************************************** * @attention * * 项目 :None * 官网 : None * 实验室 :None ****************************************************************************** */ #include "cx_sch.h" sTask_Typedef SCH_tasks_G[SCH_MAX_TASKS]; /** * @brief 增加任务 * @param pFunction 任务指针, Delay 延迟时标, Peroid 任务执行周期, RunNum 任务执行次数, ModeEnum 任务模式 * @retval 任务队列索引 * @notice None */ uint8_t SCH_Add_Task(void(*pFunction)(), uint32_t Delay, uint32_t Peroid, uint8_t RunNum, TaskMode_Enum ModeEnum) { uint8_t Index = 0; while((SCH_tasks_G[Index].pTask != 0) && (Index < SCH_MAX_TASKS)) { Index++; } if(Index == SCH_MAX_TASKS) { return SCH_MAX_TASKS; } SCH_tasks_G[Index].pTask = pFunction; SCH_tasks_G[Index].Delay = Delay; SCH_tasks_G[Index].Peroid = Peroid; SCH_tasks_G[Index].RunMe = 0; #if RunNum_ON SCH_tasks_G[Index].RunNum = RunNum; #endif SCH_tasks_G[Index].ModeEnum = ModeEnum; return Index; } /** * @brief 删除任务 * @param Index, 任务队列索引 * @retval None * @notice None */ void SCH_Delete_Tasks(uint8_t Index) { SCH_tasks_G[Index].pTask = 0; SCH_tasks_G[Index].Delay = 0; SCH_tasks_G[Index].Peroid = 0; SCH_tasks_G[Index].RunMe = 0; #if RunNum_ON SCH_tasks_G[Index].RunNum = 0; #endif } /** * @brief 更新任务 * @param None * @retval None * @notice 需要心跳支持, 抢占任务执行时长必须小于任务调度器的时标 */ void SCH_Update_Tasks(void) { u8 Index; for(Index = 0;Index < SCH_MAX_TASKS;Index++) { if(SCH_tasks_G[Index].pTask) { if(SCH_tasks_G[Index].Delay == 0) { switch(SCH_tasks_G[Index].ModeEnum) { case SEIZ_Enum: //抢占任务立即运行 SCH_tasks_G[Index].pTask(); if(SCH_tasks_G[Index].RunMe > 0) { SCH_tasks_G[Index].RunMe--; #if RunNum_ON if(SCH_tasks_G[Index].RunNum > 0) { SCH_tasks_G[Index].RunNum--; if(SCH_tasks_G[Index].RunNum == 0) { SCH_Delete_Tasks(Index); } } #endif } break; case COOP_Enum: SCH_tasks_G[Index].RunMe++; break; default:break; } if(SCH_tasks_G[Index].Peroid) { SCH_tasks_G[Index].Delay = SCH_tasks_G[Index].Peroid; } } else { SCH_tasks_G[Index].Delay--; } } } } /** * @brief 任务调度器 * @param None * @retval None * @notice None */ void SCH_Dispatch_Tasks(void) { u8 Index; while(1) { for(Index = 0;Index < SCH_MAX_TASKS;Index++) { if(SCH_tasks_G[Index].RunMe > 0) { SCH_tasks_G[Index].pTask(); SCH_tasks_G[Index].RunMe--; #if RunNum_ON if(SCH_tasks_G[Index].RunNum > 0) { SCH_tasks_G[Index].RunNum--; if(SCH_tasks_G[Index].RunNum == 0) { SCH_Delete_Tasks(Index); } } #endif if(SCH_tasks_G[Index].Peroid == 0) { SCH_Delete_Tasks(Index); } } } } } /** * @brief 任务初始化 * @param None * @retval None * @notice None */ void SCH_Init(void) { TIM2Base_Config(10); } /** * @brief 启动任务调度 * @param None * @retval None * @notice None */ void SCH_Start(void) { TIM_Cmd(TIM2, ENABLE); }
#ifndef __CX_SCH_H #define __CX_SCH_H #include "stm32f10x.h" #include "cx_timbase.h" #define RunNum_ON 0 typedef enum { COOP_Enum = 0x0, SEIZ_Enum = 0x1 }TaskMode_Enum; typedef struct { void (*pTask)(void); uint32_t Delay; uint32_t Peroid; uint8_t RunMe; //标记任务就绪 #if RunNum_ON uint8_t RunNum; //指定任务执行次数,执行完自动销毁 #endif TaskMode_Enum ModeEnum; }sTask_Typedef; #define SCH_MAX_TASKS 10 void SCH_Init(void); void SCH_Start(void); uint8_t SCH_Add_Task(void(*pFunction)(), uint32_t Delay, uint32_t Peroid, uint8_t RunNum, TaskMode_Enum ModeEnum); void SCH_Update_Tasks(void); void SCH_Dispatch_Tasks(void); void SCH_Delete_Tasks(uint8_t Index); #endif
老规矩,不分析代码了,代码加起来也没几行,数据结构也很简单,静下心来一定看得懂的。这段代码在51单片机(12MHZ,12T)上实际测试在1ms的时标下,满载12个任务下的CPU使用率仅为89%,依然有11%的空闲。如果使用国产STC15系列的1T单片机情况估计刚好相反(没实际测试过,仅仅猜测)。
在看懂代码后,也许有人要问我循环调度下响应事件就迟滞了,实时性就降低了呀!那么针对这样的疑问我想说以下几点:
1:迟滞是相对的,比起超循环系统的while(1)+中断标志位+阻塞延时,轮询调度的响应速度足够快了。
2:循环调度一般情况下还是添加短任务的比较好,长任务忽略的好,至于为什么,自己去琢磨吧。
3:这段代码不是在写操作系统,只能作为嵌入式系统代码中的一部分,不要吹毛求疵,当你能1s读完红楼梦时再来喷吧。
4:任务抖动是无法避免的,除非你是抢占式核,可以抢占CPU使用权。本人汇编菜鸟,写不出来。
5:说的很明确,本代码仅限于裸机开发。
感恩,感谢...
4000
...
使用过程中出现任何BUG请联系我本人QQ:951253606,说明bug现象以及重现过程。
寻求MCU产品开发请联系我本人QQ:951253606。
相关文章推荐
- 国内php原创论坛
- 新手报道
- 为什么你吭哧吭哧写的原创没有人看了?
- 先了解什么是网站的权重,再谈如何提高
- 【原创】中秋小品剧本
- linux下如何设置IP地址
- 力挺2007年国内原创音乐届最权威大赛!
- 个人网站
- android 第一季
- 安卓中的Context
- 第一次作业
- 原创和伪原创你怎么看?
- CSS介绍
- Dede自动采集伪原创发布更新一体化插件
- 面对百度原创性质量标准算法的一些策略
- 对于0基础的我来说,学了越久越发现基础才是最难懂的,记下来以后看
- 黑马程序员=======总结集合笔记
- 黑马程序员=======集合Collection
- android studio导入eclipse或者 android studio工程文件的超简技巧
- 揭秘:程序员面试