搜索
bottom↓
回复: 9

请教马老师一个问题,困扰了我好久了。

[复制链接]

出0入0汤圆

发表于 2010-8-21 09:35:36 | 显示全部楼层 |阅读模式
小弟最近调试一个程序,其中用到了T/C2定时中断程序:
T/C2四毫秒初始化
void Timer2_4MS()
{
    TCCR2 = 0x00;
    TCNT2 = 0x0000;
    OCR2 = 249; //focn=16M/2*N*(1+OCR2)
    TCCR2 = 0x0C;//CTC模式,256分频,OC2无输出
    TIMSK_OCIE2 = 1;//OCIE2:T/C2 输出比较匹配中断使能
}
中断函数
#pragma vector = TIMER2_COMP_vect
__interrupt  void timer2_comp(void)
{  
  TIMSK_OCIE2 = 0;
        giPressTimeCount++;
  TIMSK_OCIE2 = 1;
}
然后主程序里面设置while等待语句:
while( (!gbStopPress_Flag)&&(giPressTimeCount < 300) );
gbStopPress_Flag为一个串口标志位,值为零。
程序本意为gbStopPress_Flag置位或者giPressTimeCount计数超过300的时候即可跳出while。
调试过程中发现,gbStopPress_Flag没有置位的情况下,giPressTimeCount在256的时候就跳出了while循环。
小弟百思不得其解,在中断里设置了断点调试,有时候giPressTimeCount可以到达300,有时候giPressTimeCount=256时就跳出循环。
想不明白为什么256的时候会跳出while循环,希望论坛的各位前辈能够指点迷津,多谢!!!

编译器采用IAR4.20版本。
后续:后来将300改为250后,目前测试至今未出现这样的情况,莫非T/C2在255的时候或者堆栈之类的会发生意想不到的情况?还是由于while()语句的条件判识导致的?继续迷茫中
再补充:giPressTimeCount为int型测试,发现256的时候会出现问题
              giPressTimeCount为float型测试,发现128时会出现问题~

出0入0汤圆

发表于 2010-8-22 13:01:27 | 显示全部楼层
这种用法容易出现问题的。

注意到giPressTimeCount < 300 是个16位的比较,在AVR中不可能是一条指令完成的,需要3-4条指令才可以。

考虑一下,当处理器在执行giPressTimeCount < 300 过程中,比较到一半,中断来了,giPressTimeCount变化了,这个比较就要出问题了,尤其在低8位向高8位进位时。

具体需要把IAR4.20编译giPressTimeCount < 300 比较生成的汇编列出来,看编译器是如何处理的。

出0入0汤圆

 楼主| 发表于 2010-8-22 13:25:13 | 显示全部楼层
while语句的汇编:
LDS        R16, gbStopPress_Flag
TST        R16
BRNE     0x1172
LDI         R30, 0x5A
LDI         R31, 0x02
LD          R16, Z
LDD       R17, Z+1
CPI         R16, 0x2C
LDI         R18, 0x01  
CPC        R17, R18
BRLT       0x115A

出0入0汤圆

发表于 2010-8-22 13:34:57 | 显示全部楼层
LD          R16, Z
此时中断发生,如果刚好giPressTimeCount 在此时从255变成256时,那R16已经是255了,接着下面R17会变成1,杯具产生了。。。
LDD       R17, Z+1

出0入0汤圆

发表于 2010-8-22 13:53:46 | 显示全部楼层
跟我判断的相同
1、这段代码没有禁止中断吧。

2、300为0x12c

LDI         R30, 0x5A
LDI         R31, 0x02    ===》这里Z是giPressTimeCount的地址
LD          R16, Z       ===》R16拿到低8位
LDD       R17, Z+1       ===》R17拿到高8位
CPI         R16, 0x2C    ===》低8位与300的低8位比较
LDI         R18, 0x01    ===》R18是300的高8位
CPC        R17, R18      ===》比较高8位
BRLT       0x115A

3、分析,当然不是每次都那么巧合,但肯定会发生

假定此时giPressTimeCount为255


LDI         R30, 0x5A
LDI         R31, 0x02    ===》这里Z是giPressTimeCount的地址
LD          R16, Z       ===》R16拿到低8位 注意是255!!
       =====》                此时中断来了,响应中断,giPressTimeCount为256了!!                     

LDD       R17, Z+1       ===》R17拿到高8位

       ======》这样R17为1(256),而R16为0xff,256,合在一起是0x01ff,比0x012c大了!!

CPI         R16, 0x2C    ===》低8位与300的低8位比较
LDI         R18, 0x01    ===》R18是300的高8位
CPC        R17, R18      ===》比较高8位
BRLT       0x115A

4、IAR如此烂?为什么不先取高位和比较高位?这样会好点,但也还是存在不足。

5、不管使用什么编译系统,在中断需要改变的变量都是敏感的,在其它地方使用是需要特别当心。比如,在比较前禁止中断,比较后再开放,或使用影子存储器等方法。

出0入0汤圆

发表于 2010-8-22 14:08:05 | 显示全部楼层
建议:

#pragma vector = TIMER2_COMP_vect
__interrupt  void timer2_comp(void)
{   
  TIMSK_OCIE2 = 0;
       if (++giPressTimeCount>=300) flag = 0;
  TIMSK_OCIE2 = 1;
}

然后主程序里面设置while等待语句:
while( (!gbStopPress_Flag)&& flag);
flag = 1;

出0入0汤圆

 楼主| 发表于 2010-8-22 17:28:13 | 显示全部楼层
多谢马老师和snoopyzz 的指点,惭愧,基本功还有待于加强,多谢多谢。

出0入33汤圆

发表于 2010-8-22 18:55:36 | 显示全部楼层
“调试过程中发现,gbStopPress_Flag没有置位的情况下,giPressTimeCount在256的时候就跳出了while循环。 ”

检查你的giPressTimeCount这个变量的类型,如果是unsigned char的话255+1就是0了,你可能需要定义成int类型

出0入0汤圆

发表于 2010-8-22 18:59:37 | 显示全部楼层
楼上,LZ已经说定义成INT型了。如果是CHAR,它就死在循环中了。你还是明白不了。

出0入0汤圆

发表于 2010-8-22 19:09:18 | 显示全部楼层
Mark!学习。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-29 15:28

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表