- 嵌入式微系统
- 王绍伟 郑德智 吴玉勇
- 1470字
- 2023-01-30 16:41:00
1.3.2 三要素实例
MS程序入口为main函数,驱动初始化后就进入第一要素大循环。
代码清单1-1:大循环
int main(void) { ushort idata message; Byte idata type, value; Init(); while(true) { message = PendMessageQueue(); type = GetMessageType(message); value = GetMessageData(message); switch(type) { case MessageKey: //按键消息处理 EnterFunction(value); //函数指针处理方式 //KeyProcess(value); //状态机处理方式 break; case MessageUsart: //串口消息处理 UsartProcess(value); break; //请填充消息及处理函数 default: //软件定时器消息处理 Function(message); break; } } }
先通过init()函数初始化系统,之后进入while(true)大循环,通过PendMessageQueue()函数读取消息,消息为16 bit,由高八位的消息类型和低八位的消息值组成。通过switch根据消息类型决定执行对应的事件处理函数,消息一般由外部设备的中断或者节拍产生。
1)MessageKey是按键消息类型,菜单界面设计支持函数指针和状态机两种方式。函数指针方式是基于EnterFunction函数指针变量执行相关按键操作;而状态机方式则是直接调用按键处理函数KeyProcess。
2)MessageUsart是串口消息类型,处理串口消息。
3)default是软件定时器,利用函数宏定义把16 bit的消息message转换成一个函数地址入口,再执行这个函数,详细内容在软件定时器部分讲解。
4)项目中新增消息,可以自己手动添加。但应注意先要在system.h的MessageType消息枚举类型中添加该消息。
大循环在不停处理消息,因为消息不能抢占,所以不适合有速度要求的设备,它只适合于界面等速度慢、处理时间长、可以被打断的进程。
第二要素系统节拍由定时器2的中断产生,代码如下。
代码清单1-2:系统节拍中断
void SystickHandler(void) interrupt 5 { KeySystickRoutine(); //按键例行服务程序 RtcSystickRoutine(); //时钟例行服务程序 TimerSystickRoutine(); //软件定时器例行服务程序 /*例行程序*/ TF2 = 0; }
由Timer216 bit自动重装作为系统节拍。interrupt为中断标志关键字,中断号为5,初始化为10ms一次,即每秒执行100次,里面执行按键扫描例行程序、RTC时钟计时服务程序及软件定时器例行程序。实际项目需求的例行程序可以继续添加。
有些例行处理执行最后,抛出一条消息作为结束,这个消息在大循环中执行,比如按键扫描和软件定时器。受MCU51的性能影响,系统节拍无法取得更低,若太低,会导致系统频繁中断,节拍之间可执行的代码量太少,以22.1184MHz单指令周期的MCU51为例,假设节拍设置为1ms,每个节拍最多运行22K个指令。若设置为0.1ms,则只能运行2.2K个指令,这个显然有些少,除非节拍内操作非常简单。MS默认设置为10ms,也就是一个节拍对应221K个指令。需要重点指出的是,节拍内的例行处理,要尽可能在节拍规定的时间内完成。若偶尔超过节拍时间,只会影响节拍的相对精度,导致后续节拍的后延,而频繁的超时,则会导致系统无法正常运行。
此外,根据项目实际情况决定节拍的中断优先级及节拍间隔,比如录音,就需要高的节拍速度及高的中断优先级。不需要太精准的控制一般不建议采用优先级太高的节拍中断,但这样,其他中断会影响节拍的相对精度。笔者提倡尽可能地多用系统节拍处理一些事情,比如按键扫描,数码管显示,读取I/O状态等,尽量少用其他中断,因为其他中断不确定性强,当多个中断同时产生时,嵌套深,不可控因素多。应该说,高可靠系统尽量用大循环及节拍,其他中断少用,当然不是说不用。
第三要素中断可以由其他任意中断产生,可以是外部设备中断源,也可以是内部设备中断源,比如串口中断,可把接收的串口数据当作按键来处理。
代码清单1-3:串口中断
static void UsartHandler(void) interrupt 4 { RI = 0; PostMessage(MessageKey, SBUF); // 模拟按键消息类型用于软件仿真 //PostMessage(MessageUsart, SBUF); // 发送串口消息 }
串口中断由各种外部中断、定时器或者串口等一些外设组成。串口中断,中断号为4,MS默认串口发送不用中断,仅接收用中断。对于简单的串口接收,尤其是数据量少的,可以直接发送串口类型消息PostMessage(MessageUsart,SBUF);对于数据量大的,复杂的串口接收,建议直接在中断中预处理成帧后,发出串口消息作为标志,再在大循环中处理。在Keil的Debug软件仿真时,可以用Serial#1串口终端作为串口显示及按键输入。对于一些外部中断,节拍扫描够用时,不建议用中断。