8位单片机处理16位数据错误问题--2020.10.23

最近做的项目采用的主控芯片是8位的MCU,在但是在写下3行代码后,就出现了无法解决的Bug,而且导师告诉我,之前去华为的那个工程师当时也遇到过这个问题,具体是怎么解决的他也不清楚,好吧,只能靠自己了。首先告诉你们,初始化配置是没有任何问题的,但是就这3行代码的Bug让我找了一星期。废话不多说,下面是代码。

unsigned short int time_count = 0;
int main()
{
    
    	
	tim0_init();/* 5ms定时器初始化 */
	uart1_init();/* 串口1初始化 */
	printf("uart init ok!\r\n");
	while(1)
	{
    
    
		if(time_count >= 400)
		{
    
    	
			time_count = 0;
			printf("time is end!\r\n");/* 时间到了 */
		}
	}
}
void tim0_isr() interrupt 1/* 5ms定时器中断 */
{
    
    
	time_count++;
}

代码十分简单,定义了个16位的变量,在5Ms的定时器中断中自加,当这个变量大于等于400,即2S时,通过串口打印输出时间到了。

但是,但是,请注意,在实际测试时发现,偶尔,是偶尔,没有规律,这个数到了256后就打印输出时间到了,而且这个出现的次数是随机的,没有任何规律。

我瞬间懵了,这个代码有问题?学了这么多年C喂了狗了?一刹那我都恍惚了,于是向别人请教,他人经过一番思索,折腾了一上午,最后也没办法解决。上网百度更是搜索不到,但是搜索到不少 “你相信玄学吗?”,我可是一个崇尚科学的三好少年,我就不相信真的是所谓的玄学。我相信只要学的深,就能解决。

在经过不断的思索以及上网查找资料,后来和厂家联系,最后终于找到了问题所在。

因为使用的是8位的单片机,8位,顾名思义,一个指令周期CPU只能处理8位数据,在代码中我定义的是16位的变量,也就是说在对这个变量进行操作时,需要两个指令周期,但是每一个指令周期结束后,cpu都会判断有没有中断产生,从而去响应中断事件。

问题就出在这里,如果在操作这个16位变量时,恰巧有中断产生,就可能会有问题。好,明确了问题的方向,找起来就比较简单了。在主函数中,采用if条件判断,判断 count_time >= 400;一般编译器对if条件判断基本是采用作差的形式,即判断 count_time - 400 是否大于0,条件为真,就成立。由于变量是16位,8位的CPU需要两个指令周期,即两次才能判断出来。

第一次,用变量 count_time 的低8位 - 400的低8位,400的低8位是 (0b10010000)。如果这时候刚好定时器中断来了,那么去响应中断事件,对 count_time这个变量自加,假如中断来之前,count_time这个变量的值为255,即(0b11111111),那么进入中断后,这个数就变为256,即(0b00000001 00000000),产生了高位进位。中断处理结束后,继续回去处理主函数,由于上一次判断了低8位,这次判断高8位,由于产生了进位,所以变量的高8位是1,恰巧400的高8位也是1,然后就判断这两个数相等,这个if条件就成立了。

这里可能有小伙伴会问,为什么要先判断低8位呢,如果先判断高8位,不就不会出现这个问题了吗,这个就和编译器有关系了,因为51单片机采用的存储模式是大端模式,即高位数据存放在高位地址。当从这个变量的起始地址取数据时,优先取到的是低地址的数据,即变量的低字节,因此会优先判断低8位。

问题到此已经找到了,要解决的话就比较容易了,代码如下:

int main()
{
    
     
 unsigned short int time = 0;
 tim0_init();/* 5ms定时器初始化 */
 uart1_init();/* 串口1初始化 */
 printf("uart init ok!\r\n");
 while(1)
 {
    
    
  time = time_count;
  if(time == time_count)
  {
    
    
	if(time >= 400)
	 {
    
       
	    time_count = 0;   
	    printf("time is end!\r\n");/* 时间到了 */
	 }
  }
 }
}

这样就可以了,先把这个值赋给一个临时变量,然后判断这两个值是否相等,判断的目的就是为了防止在赋值后出现进位的情况,如果出现了,那么这两个数就不相等,条件不成立,等待下一次循环到来时,就一定会相等,因为定时器中断刚刚发生,不会立马再进中断,所以这样就可以解决时间未到2s就进去的情况发生。

到此为止,问题解决。所以,还是要相信科学,我们口中所谓的玄学不过是无知罢了,哈哈。

如有错误之处,还请及时指正,在此谢过!

猜你喜欢

转载自blog.csdn.net/weixin_42952614/article/details/109251285