【嵌入式底层知识修炼】使用求余(%)进行周期计算的隐藏BUG


每次累积1ms,不需要几天,程序时基就会混乱

————小白


  嵌入式中必定有一个能够产生程序时基的定时器,由于需要遵守在中断ISR中不能进行过多操作的原则,所以一般只在定时器中进行Counter计数,计数累积某个上限后,设置对应的标志位,然后通知主程序执行相关任务
在这里插入图片描述

01 - 使用求余%进行周期计算

  由于Counter一直在递增,所以需要使用某种计算让其能够在程序设定上限中触发对应动作,也就是需要周期计算,周期计算大多使用求余%,为简化编程过程,使用51系列的编程模拟:

/* 假设Timer0每1ms中断一次 */
uint8_t Counter = 0;
void Timer0_ISR(void) interrupt 1
{
	if(++Counter % 5 == 0) {
		Set_5ms_Flag();
	}
}

  以上程序中定时器产生1ms时基,每隔5ms,ISR就设置一次标记Flag,然后主程序中根据Flag的设置与否执行对应的程序

02 - 分析周期计算过程

  主程序不一定是轮询Flag,也可能Set_5ms_Flag()是一次信号触发,接下来马上调用对应的程序,无论如何,我们都假设每一次Flag的设置都会触发一次对应程序
  分析++Counter % 5,本意是Counter一直递增,每递增5个计数就设置一次Flag,因为Counter的类型是uint8_t,所以当其递增到255的时候,再递增一次,就会变成0,问题就出现在这里:

251 % 5 = 1
252 % 5 = 2
253 % 5 = 3
254 % 5 = 4
255 % 5 = 0	//Set
  0 % 5 = 0	//Set
  1 % 5 = 1

  能够看到,Counter递增溢出的时候,将会在相邻的时间内连续设置Flag,这将脱离程序员的本意,在某些情况下,如果标志所触发的程序是一次严格的周期动作,那么此动作必须在周期点触发,否则可能导致让整个系统奔溃或外界设备损坏(比如盆栽浇花、冰箱化霜、协议发送等等)

03 - 隐藏的BUG及解决办法

  在连续的时间内触发程序 or 在没到达周期点就触发程序,这就是求余%进行周期计算的隐藏BUG,之所以称为隐藏,是因为出现的BUG未知,而且就算出现,一般也是日积月累才能发现的:
  出现的BUG未知:当求余数和被求余数在溢出点处不能满足上限条件的时候,这个BUG就变成了在没到达周期点就触发程序,比如把上述代码的求余数5换成7,那么程序如下,计数还没有到达7次的时候就触发了一次程序

252 % 7 = 0	//Set
253 % 7 = 1
254 % 7 = 2
255 % 7 = 3
  0 % 7 = 0	//Set
  1 % 7 = 1

  日积月累:在连续的时间内触发程序 or 在没到达周期点就触发程序,因为间隔时间非常小,若干ms不在人类的感知范围内,只能通过长时间调试或者外界设备的变化而感知,这通常是长期的,可能在产品发布后,客户使用一段时间才能出现的BUG
  解决这个隐藏BUG的办法有2种:
  1、使用加减法代替求余%运算,这是最优解,比如把上述程序改为:

/* 假设Timer0每1ms中断一次 */
uint8_t Counter = 0;
void Timer0_ISR(void) interrupt 1
{
	if(Counter++ > 5) {
		Counter = 0;
		Set_5ms_Flag();
	}
}

  使用加减法代替有很多好处,第一是加减法比求余运算速度要快,第二是不会有溢出的情况出现,减少隐藏的BUG
  2、另外处理溢出情况,也就是当Counter到达溢出点的时候,进行另外的处理,这将浪费很多时间以及让程序可读性差,在此不进行举例

04 - 总结

  在连续的时间内触发程序 or 在没到达周期点就触发程序,经常会导致严重的后果,但是一般不是马上可见的,而且日积月累,这样将会在产品使用中产生大量的客户不良反馈,而且错误定位困难
  因此最优解是周期计算中不要使用求余%,而是使用加减运算代替,一方面,求余%运算会浪费大量时间,ISR中要做到精益求精,另一方面,求余%可能会导致连续的时间内出现触发点 or 在没到达周期点就触发程序,将有隐藏的BUG

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值