嵌入式系统是硬件搭台、软件唱戏,就像你可以在同一个舞台上演出不同的剧目一样,嵌入式设备的硬件做好后,只要硬件上支持,你可以根据不同的功能要求烧写不同的代码。
在嵌入式软件的开发阶段,需要经过多次更新迭代,软件版本可以以“里程碑”的形式,通过版本标号(x.y)对各个软件版本进行标识和区分。而且,一般情况下,不同的软件版本中可能会隐藏不同表现形式的缺陷,为了提高软件的可靠性和完善性能,需要查找缺陷或者定位缺陷的引入时间,这个时候就需要对不同版本的软件进行并行测试,以定位缺陷的原因和具体位置。
相比而言,硬件版本相对固定,分不出大哥和二哥,从而无法通过辨认硬件电路特征判断当前被测试的软件的版本,进而无法进一步分析。如果软件本身包含版本信息,通过一种手段从软件中获得版本信息,便可以解决上述问题。
显然,这里有一个不言自明的需求:获取当前的代码版本信息。对于存在多个代码版本的嵌入式硬件而言,这是一个“刚需”。
1
曾几何时,读取软件版本只是中高端嵌入式设备的专利,责任越大,能力越大,中高端如它,总有读取软件版本信息并呈现出来的方法。
低端设备忝列鄙视链的末端,它要么只有一种软件实现的版本,从而根本不存在获取代码版本信息的需求,要么虽然有几个版本,但是“有心*贼,无力回天”,只能把代码版本信息隐藏在卑微的尘埃里。
但是,在很多情况下,低端设备也有获取代码版本信息的诉求。
洒家需要做一款信号转换器,其中,要把电机转速信息(单位是rpm,转/分钟)转换成车速信息(单位为km/h),根据公式,车速信息由变速箱的减速比、车轮直径和电机转速计算得来。
这个信号转换器非常之简单,没有任何通信端口,故而无法通过通信的方式、以配置的手段将不同的减速比和车轮直径下载到信号转换器中,让信号转换器根据不同的配置计算车速。
为了实现信号转换器的通用性,让它可以适应不同的速比和轮径,洒家采取的笨办法是在同一个硬件上设计几种不同的软件版本,分别对应不同的减速比和车轮直径,这样一来,在相应的代码中求同存异,就可以复用硬件资源并提高产品的开发效率。
这种思路固然是好,可是问题是,在日常的生产、库存管理中,如何从一群已经烧录了代码又长得一模一样的信号转换器中,辨认出它到底支持哪种速比和轮径呢?
于是,获取代码版本信息以就变得十分必要而且迫切了。
2
可是,没有任何通信端口,没有任何显示界面,还想要获取代码版本信息,其可得乎?于是,洒家向周边的同仁征询意见。
左边的张工讥我痴人说梦,右边的李工说我异想天开,前边的徐工笑我痴心妄想,后面的赵工却神秘兮兮地竖起一根手指,在我眼前晃来晃去,口中念念有词:波罗波罗蜜,醒起!
哗啦啦四周泼下几盆凉水来,眨眼间浇了我一个透心凉。在这闹闹哄哄的冷嘲热讽中,洒家倒横下一条心来:世界千奇百怪,众生千差万别,但是佛曰,众生平等。代码版本就像是人类的身份信息,怎么就答不得别人的一句-“尊兄台甫?”
获取代码版本的基本操作就是“你来问,我来答”,需要和外部世界进行交互。说到交互,自然需要借助信号转换器当前的接口。接口接口,顾名思义,设备内部连接外部的端口。
如前所述,这个信号转换器是一个很简单的产品,连接器上的端口都是一些普通的模拟输入输出端口、数字输入输出口、脉冲输入和PWM输出端口。
看官们也许已经模模糊糊地想到了,可以从未使用的端子上下手,一个输进去,就是“你来问”,一个输出来,就是“我来答”。按键形式输入,LED形式输出,操作起来方便,显示方式也直观。
洒家一开始也是这么想的,而且想得更为细致。
可以在信号转换器的外接线缆上用夹线针把其中两根线的信号取出来,另一边一个接按键,一个接LED。同时,当然要在信号转换器的硬件上添加两处电路,一处实现按键采集,一个实现LED输出驱动,这些电路都很简单,自不待言。
想好解决方案后,洒家起身环顾,把张李诸工叫过来,鼓着腮帮子、喷着唾沫星子和他们讲起了我的方案。当其时也,洒家突然心下一凛,想起了一个关键的问题:端口够用否?
我赶紧数了数信号转换器连接器上还未曾使用过的端子,倒霉催的,没有用过的端口居然只剩下一路了!待我把目光投向MCU的IO上时,更加心惊地发现,除了用过的IO口和仿真编程口,可用的IO口也只有一个了!
3
一支穿云箭,千军万马来相见。斧头帮的混混可以把牛皮吹破了天,可我现在只能对着板子大眼瞪着小眼。
说出去的话,泼出去的水。大话已经出口,再难收回,怎么办?
只剩一根线,既要输入,又得输出,既可检测出按键状态,还要输出得了LED的驱动,除了复用别无他途。而且,除了接口端子上要实现复用之外,MCU的IO那里也必须一脚两用。
大概而言,MCU IO长时间处于输入状态,检测到按键按下后便切换为输出模式,通过LED按照一定的规律显示完代码版本信息之后,便再次切换回输入状态。
具体怎么实现就颇有些烧脑了。洒家调整好呼吸,正襟危坐,如入禅定,一点一滴地思索着。
MCU的IO分时切换输入和输出方向,初始方向设置为输入。周期性地读取IO状态,检测按键的按下和弹起状态。
检测到有效的按键按下时,等待按键弹起引发的IO状态切换。当弹起时将IO口的方向设置为输出,然后以脉冲的方式驱动LED。
为了区分版本号中的大版本(又称“基线版本”)和小版本(又称“更新版本”),需要以不同的频率输出相应数量的方波脉冲,以方便观察者判断大版本和小版本号。
比如,当版本号为2.4时,基线版本/大版本号为2,更新版本/小版本号为4。可以让LED以频率为2Hz、占空比为50%的PWM形式输出2个周期方波,间歇2秒后,再以频率为1Hz、占空比为50%的PWM形式输出4个周期的方波脉冲。
更一般的,版本号是a.b时,LED的闪烁方式为a个2Hz频率方波 间歇2秒 b个1Hz频率方波。
当LED的显示完成后,需要再次将IO脚设置为输入方向,以等待下一次按键形式的问询。通过在按键按下并弹起后统计2s间歇时间前后的LED闪烁次数,便可以得到基线版本和更新版本号。
4
相信经过上面的描述,各位看官已经大致了解了如何用一个IO口一个外接端子获取代码版本信息。但是,从硬件上怎么实现还有些摸不着头脑。
帮人帮到底,送佛送到西,洒家也不藏私,把电路图贴上来。
平时,IO口处于输入状态,按键处于弹起状态,IO口处电平为低,LED处于熄灭状态。当按下按键,R1上处短接VCC,IO口处电压为高,而LED被反向截止,故而继续处于熄灭状态。对LED而言,只要IO口是输入方向,无论按键按下还是弹起都是熄灭状态。
当将IO设置为输出方向时,在按键处于弹起状态的条件下,IO电平为高时,LED导通点亮,IO电平为低时,LED截止熄灭。
如此一来,通过在单个IO管脚上实现按键检测与LED驱动的复用,以最少的资源实现了便实现了软件版本的获取,该方案在资源极其受限的低端嵌入式设备领域上肯定具有广泛的适用性。
后记
我和同事们通报了这种方案后,诸工依然不置可否,但洒家却按捺不住地志得意满。这种方式简单高效,易于实现,正所谓: 一根信号线,代码版本来相见。
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved