开启辅助访问 切换到窄版

打印 上一主题 下一主题

频繁中断狂轰乱炸,操作系统很难招架

[复制链接]
楼主
跳转到指定楼层
| 只看该作者 回帖奖励 |倒序浏览 |阅读模式
「牛人业话」是电子产品世界新推出的栏目。在这里会有业界大牛分享他们在工作中遇到的问题与解决办法。当然,本栏目也会让你见识到工程师不只会写程序,他们写出来的文章也是妙笔生花。




夏天,是充满生命
力的季节。


太阳早早地爬起身来上班站岗,毫不疲倦地用脚丈量着每个地方,驱赶着黑暗和凉爽无处躲藏。笔直挺拔的白杨树装扮上绿油油的浓妆,在带着暖意的风儿吹动下,摇晃着,荡漾着粼粼的阳光。


趁着太阳躲进云层的空档,鸟儿急急忙忙出来舒展几下翅膀,扑腾几下便出了汗,便又躲进树丛中乘凉。知了倒是不知疲倦地喊叫着,气息绵长,仿佛力气永远不会用光。在那悠远、神秘的高空里,一切的一切,都似乎充满了火热的能量。


外面天干物燥、地面滚烫,幸好,我们有空调房,心中透亮,身体微凉,倘若工作起来得心应手,那真叫一个倍爽!


[size=1.2]1


天微微蒙亮,洒家已然起床。连日来工作繁忙,正好昨天,干起活来心情倍爽,于是一鼓作气,一直忙活到华灯初上,一抬眼,星星早已裹挟着月光,洒下遍地清凉。由于地处偏郊,交通不便,反正夏天睡觉也方便,于是没有回家,在办公室里点上蚊香,直接打地铺了事。



这段时间一直忙活一款汽车车身控制器的活,时间紧,任务重,好在年轻力壮,精力十足,又颇有些开发类似产品的经验,工作起来倒也算得心应手。闻道有先后,术业有专攻,本着让合适的人干合适的事情的原则,领导委派我做这款产品的软件。





车身控制器,顾名思义,根据外部输入的各种信号控制车身系统上的各个执行单元,输入信号大多来自用户对汽车上各类开关的操作,包括车灯组合开关、雨刮组合开关、门控开关等,执行单元即控制对象则散布在车身上的各个角落,包括各类车灯、前后雨刮、车窗玻璃、四门的门锁、后视镜等。除了实现控制功能,车身控制器还需要通过CAN总线网络与汽车其它电子控制单元交互,完成网关、网络管理等功能,通过射频通信与遥控钥匙交互,完成遥控、汽车防盗等功能。


看得出来,虽然号称“车身控制器”,其实控制对象并不复杂,既没有所谓的电磁效应,也不需要考虑近似、理想化等数学意义上的逼近,大多就是个“开启”和“关闭”的动作,而且由于都是直流信号,所以基本上不用考虑负载是感性、容性还是阻性,一律简化为阻性,总之,即便牵扯到一些数学运算,也都是代数运算,即牵扯不到向量,也没有所谓控制系统的传递函数。


一句话,这活儿容易得紧。


[size=1.2]2


时间一天一天地过去了,洒家按部就班地实现了多个模块,开关检测模块写好了,LIN通信加上了,由于输入信号大部分来自开关和LIN通信送来的开关信号,写好这两个模块之后,洒家开始着手实现各个负载的控制,虽然繁琐,逻辑上也需要费些周折,但是只要胆大心细,实现这些控制模块是却无大碍的。


这些模块逻辑上清晰,基本上就是来了什么信号,就对负载做什么样的动作,信号变了,调整负载的动作模式即可,从概念上和操作系统中的任务和信号机制非常类似。





笔者当时使用了源码开放的ucos操作系统,把各类负载的控制划分成各个任务,这些控制逻辑需要检测的开关信号就是任务里的信号,概念上非常规整,所以使用ucos自然而然、顺理成章。


距离提交样机的日子越来越近了,洒家的代码也愈发完善,再加上遥控接收和CAN通信,代码就写得差不多了。


洒家一面盘算着工作量,之前在裸机下做过遥控接收程序,在这里不过照搬过来而已;一面盘算着时间余额,感受着对开发进度收放自如的掌控感。不错不错,这种感觉好极了


[size=1.2]3


春困秋乏夏打盹,睡不醒的冬三月。洒家一面克制着午饭后不断袭来的阵阵睡意,一面添加着遥控接收程序,不过是从裸机下挪到操作系统的框架下,应该问题不大。笔者复制、粘贴、修改,一顿操作猛如虎,扫视一番信心鼓,便开始志得意满地调试起来。


按了一下遥控器,嗯?仿真器怎么好像和电脑断开连接了?哎,天杀的windows!肯定是windows恰好把仿真器的驱动程序给搞死了。笔者重新把仿真器插拔了一番,继续下载程序、运行、调试。按下遥控器,嗯?没反应,把程序停下来,嗯?停不下来!不死心地重启了电脑,重新来过,原来,确实是一按遥控器就貌似死了机了。





一丝阴影从洒家心头掠过,盘旋在脑中的困意也一瞬间消失的无影无踪。不消说,碰上事了!


夏天,最是一个容易上火焦躁的时节,在烈日的威逼下,干渴的大地冒着腾腾的热气,不住地无声喘息。白杨树兀自矗立在似火的骄阳里,慢慢扇动着被晒得快要冒烟的绿叶,显出一副无精打采的样子。知了不停地求饶,可是炽热的太阳全然不听它的祷告。鸟儿忍受着饥肠辘辘,也不愿意出来觅食。顶着日头匆匆赶路的俊男靓女们,挥汗如雨,被汗水一遍遍刷过的脸上早已没有了香水的气息。


时间不多了,快要提交样机了,却碰上这等大问题,尽管身处空调房,洒家依然心中发凉,倍感不爽。


[size=1.2]4


洒家揉了揉已然刻上了几条皱纹的额头,站起身,茫然环顾,有的同事正在热火朝天地打游戏,有的同事看着小说,有的同事叉着腰、扎煞着胳膊,唠着闲嗑,看我站起身来,随即送来带着笑意的目光。哎,多么和谐的场景啊!


佛家有谓,因果不欺,自作自受,白话就是,谁的福谁享,谁的罪谁受。他们玩他们的,洒家干洒家的!


那么,好端端的,程序怎么就死了机呢?看调试器的反应,倒像是跑不动了一样,既如此,统计一下系统负载率吧,ucos正好提供了这项功能。


果不其然,一按遥控器,系统负载率就蹭蹭蹭地摸高到了100%,屡试不爽,本来系统负载率在百分之二三十之间,只要按下遥控,系统立马死给你看。





笔者工作多年,身经百战,掰着脚趾头掐指一算,肯定是遥控接收中断太频繁了,导致ucos把大量的时间用在系统调度上,以至于根本就没有了空闲时间,为何如此,且听洒家娓娓道来。


系统被ucos划分成多个任务,这些任务平时处于“等待”某些信号的状态,信号一来,便进入“就绪”状态,倘若没有更高优先级的任务,处于就绪态的任务就得到了MCU的计算资源,进入任务执行程序,执行完后,便再次回到等待状态。倘若来了中断,ucos便中断当前任务,存储系统上下文、任务上下文,执行中断服务程序,然后判断是否存在被中断服务程序推入就绪态、优先级高于被中断任务的任务,如果有,进入新任务,如果没有,恢复被中断任务的上下文继续执行。


ucos本来在系统的各个任务之间调度得好好的,偶尔来了个中断,就存一下任务上下文,执行以下上文所述的操作,只要中断次数有限,系统还是可以正常稳定运行的。可是,一旦中断非常频繁,以至于中断时间间隔和ucos存储任务上下文、执行中断服务程序、恢复任务上下文的时间很接近的话,显然,ucos就基本上干不了有用的事情了,它会把几乎所有时间消耗在存储、恢复任务上下文这些“辅助性”的操作上。


遥控报文是一连串射频信号,每个上升沿都会触发中断,对于ucos和所选用MCU的主频来说,遥控报文的频繁中断简直就是狂轰乱炸,搞得操作系统很难招架。


[size=1.2]5


行文至此,脑力敏捷的读者可能会抢答说,既然如此,那就不用ucos了,解决方法很简单,把操作系统去掉,再换成裸机形式不就可以了吗?


对此,我只想套用一下《卖拐》里本山大叔对脑袋大、脖子粗的伙夫范伟的一句评语:恭喜你,都会抢答了!


我们都听说过一个大致类似的典故,说有一个家伙想学钢琴,打听学费几何,老师问清楚这个家伙有一点基础之后,就故作高深地说,如果没学过,学费1万,如果学过,学费2万。不等学员把诧异的眼睛睁圆,老师悠悠地自问自答,为什么需要多交费?原因无他,只是需要多花时间把你的错误习惯改过来而已。





笔者在ucos的框架下已经写了那么多程序,你提议让我去掉ucos,然后改写那些依赖于ucos的任务、信号、消息机制的诸多代码?时日无多,徒奈其何,哪里有那么多的时间呢?最好是不仅能去掉ucos,把ucos切割开,同时尽量把其它相关代码的修改量降到最低,不改那些依赖它的任务、信号机制的代码!


“怎么办?最简单也最困难,饭要粒粒分开,还要沾着蛋,嘿,蛋炒饭。”


[size=1.2]6


疾风知劲草,板荡识忠臣,考验洒家能耐的时刻到了!


显然,任务和信号这些概念必须保留下来,皮之不存,毛将焉附?如果没有了这些概念,所有基于信号进行控制的代码都要通通改写!且不说时间是否来得及,单是忙活多日,一觉醒来,却发现绕回了原点,洒家脆弱的心灵也颇有些难以承受。


不过,没有了ucos的框架,还要使用在其框架下的概念,就必须找出裸机形式下新的类似框架!既然是照葫芦画瓢,我们首先要提取出这颗“葫芦”的主要特征。


透过代码的重重迷雾,洒家百般搜索,千般思量,最终认定,新瓢和老葫芦的共同之处乃是:任务的数据结构和调度机制





敲敲黑板,画画重点。任务是操作系统执行所有功能的载体,操作系统的作用无非是建立各个任务的数据结构,然后设计一个调度机制,让系统资源在这些任务的执行体里面来回切换、轮转而已。显然,新的框架要解决两个问题,“任务”的数据结构、“任务调度”机制。


在ucos的机制中,每个任务都有自己的消息队列,向该任务里发信号,就是把信号内容放到这个消息队列里。Ucos的主要调度机制是每个时钟滴答下检查一下是否存在就绪态任务,如果有,进行任务上下文切换,跳转到新任务体里执行即可。


既如此,我们完全可以设计一种“逻辑任务”,每个任务都有自己的消息队列,任务执行体里面检查自己的消息队列里是否存在新的信号,有信号就执行,和ucos下的形式一模一样。至于“任务调度”,中断太频繁,显然不可能再照搬着搞任务上下文的存储和恢复那一套了,裸机形式下的整个系统只有一个上下文,所谓调度完全可以借鉴简单操作系统里面的按时间片调度,弄成循环执行的方式,依次执行每个任务即可。


如此一来,所有控制任务的执行代码都不需要进行任何改动,穿梭在各个“逻辑任务”之间的信号依然是之前代码里定义好的那些信号,最大程度上做到了程序的复用。


更难得的是,在裸机形式的系统里,建立了任务和消息的机制,模块之间的低耦合强内聚特性得到了保留,为后续代码的开发和维护提供了大大的方便。


[size=1.2]结语


去年桃花此门中,桃花人面相映红,人面不知何处去,桃花依旧笑春风。ucos虽然不知跑到那里去了,但是大部分代码的骨架还在,任务-消息-模块的神韵犹在。我们唯一需要牢牢记住的只是:频繁中断狂轰乱炸,操作系统很难招架。




成为技术专家的必由之路:一门深入,长时薰修

合理设置MCU滴答,千万不要累着它

千错万错,都是中断和堆栈惹的祸!

写代码不写注释?!无注释主义了解一下

指针就是飞刀,随时都会中招

嵌入式软件工程师:两手都要硬!

写代码需要民主,更需要专政!
管脚兼容是谎话,总有一点小偏差
“恃才傲物、自以为是”乃工程师之大忌

时序就像脉搏 一点都错不得

万千代码,文档奈何只是几行淡墨

天灵灵地灵灵 遥控为何会失灵

六个核桃也救不了工程师的不爱动脑

数组越界真可怕,莫名就闯到了别人家
蹉跎了人生,也就辜负了自我


↓↓↓↓点击阅读原文,查看更多新闻

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表