打印

UP8楼!但是:**这楼这么高了,我还是删了吧,

[复制链接]
23653|154
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
救火车|  楼主 | 2007-6-13 18:33 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
————————————————————————
斑竹竞选报名结束,初选投票正式开始! (截止日期2007-06-30) 
————————————————————————
投票处(点击进入)
————————————————————————

这是两年前我的徒弟遇到过一个故障。当时开发的一个产品,一项功能是在通电后播放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;     //这是好几条汇编



经验总结:
如果在中断程序中改变了多字节类型的变量,那么中断程序以外的程序中(主程序,子函数),读写前要关中断,读写后再开中断。
举一反三:
其他的数据类型也可能有这种影响。例如:长整型、浮点型。
上面的例子是中断里写,主程序中读。相反主程序写,中断里读也可能出错。

发了这篇文章希望能对大家有所帮助,做到防患于未燃。更希望大家支持我竞选版副。

相关帖子

来自 2楼
平常人| | 2007-6-13 22:16 | 只看该作者

学过操作系统的人都知道,这是互斥访问的概念

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

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

在使用ms_counter做判断前作如下操作:
 do {
    tmp_counter = ms_counter;
 while (tmp_counter != ms_counter);

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

使用特权

评论回复
板凳
rotice| | 2007-6-13 19:14 | 只看该作者

不错,我帮你顶一顶

使用特权

评论回复
地板
HotPower| | 2007-6-13 19:41 | 只看该作者

3、不错~~~投一票~~~

使用特权

评论回复
5
孤独泪| | 2007-6-13 20:12 | 只看该作者

为什么要关中断呢

在这个程序中,外部使用了中断里面的变量,楼主用了在变量使用之前和变量使用之后开关中断。但是这个定时中断还有一个作为时钟用途的时候什么办,中断本来就是要及时相应的。此程序作一下修改,你看能够达到要求。
if (ms_counter<400)
{
    if (tt==0)
    {
        tt=1;
        Sound_on();
    }
}
else if(ms_counter>=400)
{
    Sound_off();
}   

本人的经验是尽量不改变中断的功能, 如中断使用变量外部使用尤其注意,如出现这样的判断,可以如以上的改动。

使用特权

评论回复
6
程序匠人| | 2007-6-13 21:24 | 只看该作者

加裤,以示鼓励。如果其他竞选者发竟选**,也享受同样

使用特权

评论回复
7
awey| | 2007-6-13 21:32 | 只看该作者

这条裤子是少不了的

使用特权

评论回复
8
dengm| | 2007-6-13 22:29 | 只看该作者

投一票

使用特权

评论回复
9
fsaok| | 2007-6-14 04:01 | 只看该作者

volatile

使用特权

评论回复
10
turmary| | 2007-6-14 04:56 | 只看该作者

5楼的方案可能不行哦

使用特权

评论回复
11
平常人| | 2007-6-14 08:00 | 只看该作者

嘿嘿,讨条裤子穿

在21IC涉水近一年来,自认为发表在8楼的帖子是本人在21IC发表的所有帖子中最有技术含量的帖子,所以舔着脸向斑竹讨条裤子穿,望斑竹成全,嘿嘿嘿。。。

使用特权

评论回复
12
zhaoyu2005| | 2007-6-14 08:04 | 只看该作者

怎么投票?

我也想投票

使用特权

评论回复
13
程序匠人| | 2007-6-14 08:22 | 只看该作者

可以满足

平常人 发表于 2007-6-14 08:00 侃单片机 ←返回版面    

12楼: 嘿嘿,讨条裤子穿 

在21IC涉水近一年来,自认为发表在8楼的帖子是本人在21IC发表的所有帖子中最有技术含量的帖子,所以舔着脸向斑竹讨条裤子穿,望斑竹成全,嘿嘿嘿。。。




签名:

 
 

使用特权

评论回复
14
maychang| | 2007-6-14 08:35 | 只看该作者

这句不错

3、三个行必有我师。人人都有善长的技能,也有知识的盲点。不要因为人家问了一个简单的问题就嘲笑他“连这个都不会!”说不定你今天嘲笑他不懂三极管,明天却要向他请教WINDOWS API函数。即便是新手,以后也有可能变成高手、成为技术好友、成为你的客户。 

就凭这句,救火车有资格当版主。

使用特权

评论回复
15
zhiwei| | 2007-6-14 08:46 | 只看该作者

这是当然的

共享全局变量,特别是中断时使用就需要特别注意,我以前注意到了,所以还没有出现过这个问题。

使用特权

评论回复
16
gtw| | 2007-6-14 08:48 | 只看该作者

8楼

可以解决问题吗?

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

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

在使用ms_counter做判断前作如下操作:
do {
    tmp_counter = ms_counter;
while (tmp_counter != ms_counter);

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

如果判断ms_counter后再修改它的值,你可如何避免这个问题?
在中断中也修改值、主程序中也修改值的情况下,这样是不能解决问题的。

只能避免两边同时访问,比如加一个使用标志。

使用特权

评论回复
17
HWM| | 2007-6-14 08:55 | 只看该作者

使用操作系统中的一个基本概念(即红绿灯)

实际就是给一个共享资源配备一个标志,用来防范访问的冲突,以保证资源访问的完整性。

使用特权

评论回复
18
river1972| | 2007-6-14 09:04 | 只看该作者

我通常的做法是在100ms的中断中加一个FLAG

我通常的做法是在100ms的中断中加一个FLAG,通常是FLAG=1的时候才执行
if(flag100ms==1)
{
flag100ms=0;
if (ms_counter<400)
        {
            if (tt==0)
            {
            tt=1;
            Sound_on();
            }
        }
        else
        {
            Sound_off();
        }   
}
这样的话应该不会有问题。当然你的程序执行其它的东西超过100ms是可能会有问题,这只能修改你的定时时间

使用特权

评论回复
19
mryyh| | 2007-6-14 09:41 | 只看该作者

8楼正解

19楼的方法与关闭中断的方法一样,会使你的定时器不准确。

使用特权

评论回复
20
wolver| | 2007-6-14 09:49 | 只看该作者

受益....

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

113

主题

1249

帖子

2

粉丝