您的位置:首页 > 其它

中断过程中,一个容易忽略的错误

2016-06-05 09:05 204 查看
这是两年前开发的一个产品,一项功能是在通电后播放40秒的语音.
    测试时发现,大约通电70-80次就有一次播放时间不够40秒就提前停止。

    当时以为复位有问题,换了复位片,没好。又先后换了CPU,语音芯片,还有电源,都没有好转。排除了硬件芯片原因导致的此现象.

    后来又从软件中查找原因。反复查找软件逻辑,也没发现问题。后来偶然发现在主while里增加大量延时后,稳定性提高。

    几乎不再出现问题。但是我还是觉得不对劲,用了两天时间终于找到了原因。因为这是公司的程序,所以不能贴源码。

    我把其他程序都略去,只把出错的程序大概写一下。大家看看能找到问题吗?

unsigned int ms_counter;                      

void T0()

{       

    //定时器程序每100毫秒中断一次,程序略     

    if (ms_counter<1000) ms_counter++;

}

void main(void)

{

//初始化定时器程序每100毫秒中断一次,程序略                           

unsigned char tt;

    ms_counter=0;

    tt=0;//用tt控制只响一次

    while(1)

    {

        if (ms_counter<400)

        {

            if (tt==0)

            {

            tt=1;

            Sound_on();

            }

        }

        else

        {

            Sound_off();

        }   

    //其他程序

    //。。。。。。    

    }



高手们不要笑,菜鸟们坐好

问题出在ms_counter不到400时,程序提前执行了Sound_off();

原因分析:if (ms_counter<400)中的ms_counter是两字节的整型,而且在中断里有增一操作。

这就有一种错误的可能

if (ms_counter<400)  //被编译器翻译成以下语句

+0000007C:   E9E0        LDI     R30,0x90         Load immediate

+0000007D:   E0F1        LDI     R31,0x01         Load immediate

+0000007E:   164E        CP      R4,R30           Compare

+0000007F:   065F        CPC     R5,R31           Compare with carry

+00000080:   F428        BRCC    +0x05            Branch if carry cleared

在ms_counter==255时  R4是255  R5是0

CP      R4,R30  ;这时R4是255   

注意!如果在这两条语句中间产生了中断  ms_counter增一 以后  R4是0    R5是1

CPC     R5,R31  ;这时R5是1

简单的说是由于在整型数增一进位的时候,又受到中断的影响。

本来正确值  0x00ff或0x0100(ms_counter),

实际错误值  0x01ff(ms_counter) 先判断低位时低位是FF,中断后判断高位时高位是01

ms_counter在255时被误认为511(0x01ff)导致提示音提前关闭。

这是一大类故障,由于中断造成的操作数更改。在其他的数据类型或编译器中也可能出现,虽然出现的机率不大,但影响是不可预知的,也是更容易忽视的。

哈哈!提醒一下没学过汇编的朋友。用C写一条语句,实际是几条汇編语句。在语句中间是有可能产生中断的。

if (ms_counter<400)  //这是好几条汇编

ms_counter++;      //这是好几条汇编

ms_counter=45;     //这是好几条汇编

 

解决方法:学过操作系统的人都知道,这是互斥访问的概念。

什么是互斥访问?简单来说,一个进程正在使用一组资源(对应到本案例中断里的ms_counter),另一个进程也要使用该资源(对应本案例中主函数对ms_counter进行判断),这时就需要慎重对待了。

 

设计程序时,脑中时刻要警惕这种互斥访问的问题。

操作系统中对这种问题有一种解决办法,即引入一个与ms_counter相同类
4000
型的临时变量:

unsigned int tmp_counter;

在使用ms_counter做判断前先把它的值赋值到临时变量:

 do {

    tmp_counter = ms_counter;

 while (tmp_counter != ms_counter);

然后使用tmp_counter代替ms_counter进行判断,这样可以保证回避楼主所述问题。

 

本文转自网络。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  中断