||
1.OS前传->从前后台到两个while(1){}切换:
记得是2007年的五一长假,想学习ARM7,利用一周时间在UV3上模拟跑通了两个while(1){}切换;那时候的想法很天真,每个前后台程序的主循环只要一个while(1){},加入有两个while(1){},能不能从这个while(1){}的随意一点切换至另一个while(1){}的中的某一点呢,或者两个while(1){}交替运行呢?从网上找了来一份uC/OS-II的任务切换的汇编代码来修改,那时候偶基本看不懂ARM7TDMI的汇编,经过一周的摸索,终于成功完成了两个while(1){}的时间片轮换,明白了OS的最基本概念->任务切换。看到虚拟串口print出来的"Task1 is running!","Task2 is running!",不禁想难道这就是传说中的OS。
2.FreeRTOS之初体验:
现在总算明白了,任务切换本身并不难,难的是什么时候进行任务切换。
在后来的项目中,偶把两个while(1){}切换的机制引入进来,其实并没有改变前后台系统的本质。比如定时器中断服务程序和主程序不就是两个while(1){}在切换吗?
一个偶然机会,认识了FreeRTOS,并且下载了5.0.0版本的源代码。
由于没有针对RealView编译器的Port,自己进行了修改,然后RealView对C内嵌汇编比较苛刻(可以参考编译器文档),仿照其他的Port来修改很费劲。虽然最后能运行了,但是发现对PortEXIT_SWITCHING_ISR宏的处理不能实现。后来找到了5.1.1版本,里面终于有了针对RVDS的Port,将其拿到5.0.0版本中几乎不用怎么修改就可以用。
现在系统已经在LPC2138目标板上跑起来了,该板有RTC,KeyBoard,5.7寸单色LCD,两路24位ADC模拟量输入,打印机,FlashMemory存储。启动了三个Task,TimerTask,MainTask,PrintTask,按优先级从高到低排列。
TimerTask调用API vTaskDelayUntil实现精确的cycle级延时。键盘扫描,ADC转换结果的读取等都放在了这个里面执行。当键盘值或ADC值取得后通过消息队列通知MainTask。为了时间按秒更新,同时还向MainTask发送1s定时消息。
MainTask通过调用API xQueueReceive每隔一定时间检查消息队列是否接收到消息,处理消息并更新LCD界面。当接收到打印键按下时,MainTask会给PrintTask发送消息。PrintTask也调用xQueueReceive每隔一定时间检查它的消息队列。最初,偶准备把MainTask和PrintTask合并,但考虑掉打印过程是一个比较慢的过程,打印过程中可能会影响LCD的显示,因此决定把PrintTask独立成一个单独的任务。起初,对于xQueueReceive( xQueue, pvBuffer, xTicksToWait )的第三个参数不太明白,后来才知道为了延时一定Ticks再检查。最开始我向xTicksToWait 传递的值为0,这样由于PrintTask优先级低时钟得不到运行。把PrintTask和MainTask改成同一优先级,就可以打印了,证明FreeRTOS把相同优先级的任务做time slicing调度。后来明白了xTicksToWait 的意义,就又把PrintTask恢复为低优先级,将MainTask的xQueueReceive设置成每隔一定时间检查消息队列。这样PrintTask便有了控制CPU的可能。
看到系统稳定运行了几个小时后,才发现有了OS就是爽。否则打印这样的事务怎么处理才好呢?
一点小小的感受,希望大家赐教啊^_^