打印
[AVR单片机]

AVR-GCC是垃圾么?

[复制链接]
4239|21
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
yiz|  楼主 | 2007-12-17 16:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
同样的程序不同的优化级别程序运行结果竟然不一样甚至出错,而且出错了极难找到原因,郁闷中~~不知有谁遇到过类似情况?
今天发现做的一批产品中,同样的软件,同样的硬件,唯一不同的只是硬件序列号,竟然有些产品运行到某些地方的时候莫名其妙出错,找了半天原因最终锁定出错于以下代码:
void activation_1(void){
    uchar snx[8]={0,0,0,0,0,0,0,0};
    uint code0,code1,code2,code3;
    uchar i,k;
    LCM_cls();
    showsn();
    showstr(0,12,"Code:");
    showchar(5,12,'0');
    code0=(uint) val_input(0,24,6,5,0,0);
    showchar(5,12,'1');
    code1=(uint) val_input(0,24,6,5,0,0);
    showchar(5,12,'2');
    code2=(uint) val_input(0,24,6,5,0,0);
    showchar(5,12,'3');
    code3=(uint) val_input(0,24,6,5,0,0);
    snx[0]=code0>>8;
    snx[1]=code0&0xff;
    snx[2]=code1>>8;
    snx[3]=code1&0xff;
    snx[4]=code2>>8;
    snx[5]=code2&0xff;
    snx[6]=code3>>8;
    snx[7]=code3&0xff;
    k=1;
    for(i=0;i<8;i++)
    {    if(snx!=randomx[sn^manufacturer])
            k=0;
    }
    if(k==0)
    {    delay(5000);
        poweroff();
        while(1);
    }else
    {    for(i=0;i<8;i++)
            EEPROM_write(i+0xab,snx);
        EEPROM_write(0xa3,'Y');
        EEPROM_write(0xa4,'S');
        EEPROM_write(0xa5,0x00);
        EEPROM_write(0xa6,0x00);
        setchecksum();
    }
}

void activation_2(void){
    uchar snx[8]={0,0,0,0,0,0,0,0};
    uint code0,code1,code2,code3;
    uchar i,k;
    LCM_cls();
    showsn();
    showstr(0,12,"Code:");
    showchar(5,12,'0');
    code0=(uint) val_input(0,24,6,5,0,0);
    showchar(5,12,'1');
    code1=(uint) val_input(0,24,6,5,0,0);
    showchar(5,12,'2');
    code2=(uint) val_input(0,24,6,5,0,0);
    showchar(5,12,'3');
    code3=(uint) val_input(0,24,6,5,0,0);
    snx[0]=code0>>8;
    snx[1]=code0&0xff;
    snx[2]=code1>>8;
    snx[3]=code1&0xff;
    snx[4]=code2>>8;
    snx[5]=code2&0xff;
    snx[6]=code3>>8;
    snx[7]=code3&0xff;
    k=1;
    for(i=0;i<8;i++)
    {    if(snx!=randomx[sn^brand])
            k=0;
    }
    if(k==0)
    {    delay(5000);
        poweroff();
        while(1);
    }else
    {    EEPROM_write(0xa5,0xaa);
        EEPROM_write(0xa6,0x00);
        setchecksum();
    }
}

这两个函数基本一样,但问题就出函数activation_2运行到最后的EEPROM_write(0xa5,0xaa);这一行时竟然跳到函数activation_1里去了!!
后来把这两个函数改为:
void activation_1(void){
    uchar snx[8]={0,0,0,0,0,0,0,0};
    uint code0,code1,code2,code3;
    uchar i,k;
    LCM_cls();
    showsn();
    showstr(0,12,"Code A:");
    showchar(7,12,'0');
    code0=(uint) val_input(0,24,6,5,0,0);
    showchar(7,12,'1');
    code1=(uint) val_input(0,24,6,5,0,0);
    showchar(7,12,'2');
    code2=(uint) val_input(0,24,6,5,0,0);
    showchar(7,12,'3');
    code3=(uint) val_input(0,24,6,5,0,0);
    snx[0]=code0>>8;
    snx[1]=code0&0xff;
    snx[2]=code1>>8;
    snx[3]=code1&0xff;
    snx[4]=code2>>8;
    snx[5]=code2&0xff;
    snx[6]=code3>>8;
    snx[7]=code3&0xff;
    k=1;
    for(i=0;i<8;i++)
    {    if(snx!=randomx[sn^manufacturer])
            k=0;
    }
    if(k==0)
    {    delay(5000);
        poweroff();
        while(1);
    }else
    {    for(i=0;i<8;i++)
            EEPROM_write(i+0xab,snx);
        EEPROM_write(0xa3,'Y');
        EEPROM_write(0xa4,'S');
        EEPROM_write(0xa5,0x00);
        EEPROM_write(0xa6,0x00);
        setchecksum();
    }
}

void acti(void){
    EEPROM_write(0xa6,0x00);
    EEPROM_write(0xa5,0xaa);
    setchecksum();
}

void pwo(void){
    delay(4000);
    poweroff();
    for(;;);

}

void activation_2(void){
    uchar snx1[8]={0,0,0,0,0,0,0,0};
    uint code0,code1,code2,code3;
    uchar i,k;
    LCM_cls();
    showsn();
    showstr(0,12,"Code B:");
    showchar(7,12,'0');
    code0=(uint) val_input(0,24,6,5,0,0);
    showchar(7,12,'1');
    code1=(uint) val_input(0,24,6,5,0,0);
    showchar(7,12,'2');
    code2=(uint) val_input(0,24,6,5,0,0);
    showchar(7,12,'3');
    code3=(uint) val_input(0,24,6,5,0,0);
    snx1[0]=code0>>8;
    snx1[1]=code0&0xff;
    snx1[2]=code1>>8;
    snx1[3]=code1&0xff;
    snx1[4]=code2>>8;
    snx1[5]=code2&0xff;
    snx1[6]=code3>>8;
    snx1[7]=code3&0xff;
    k=1;
    for(i=0;i<8;i++)
    {    if(snx1!=randomx[sn^brand])
            k=0;
    }
    if(k==0)
    {    pwo();
    }else
    {    acti();
    }
}
,即把activation_2最后的部分写成独立的函数,才能正确运行。请问各位大侠,不知这如何解释?

相关帖子

沙发
aweyfan| | 2007-12-17 16:43 | 只看该作者

堆栈设置?

使用特权

评论回复
板凳
yiz|  楼主 | 2007-12-17 16:51 | 只看该作者

堆栈要如何设置

请问aweyfan,我是用AVR-Studio集成环境写的程序,连makefile都不用写,要如何设置堆栈?上面的问题与堆栈设置有关么?谢谢!

使用特权

评论回复
地板
dai_weis| | 2007-12-17 20:55 | 只看该作者

你的延时5000,大约延时多久?

看门狗怎么处理的?

使用特权

评论回复
5
yiz|  楼主 | 2007-12-18 16:48 | 只看该作者

延时5000

delay(5000)约延时5000mS,使用定时器定时,看门狗关闭未使用,这与上述问题有关么?

使用特权

评论回复
6
OneMillion| | 2007-12-18 22:19 | 只看该作者

AVR-Studio 有时候是有莫名其妙的问题,

  一个月前,
 写了段代码,中间调用了自己写的printf("...");
 开始调用没问题,接下来多调用几次就不正常了,频繁的复位,未用狗
  比如

   printf("abcdefg");
   printf("abcdefg");
   printf("abcdefg");
   printf("abcdefg");

不正常

然后
   printf("abcdefg");
 //  printf("abcdefg");
 //  printf("abcdefg");
   printf("abcdefg");
就正常了,哈哈,很是郁闷的,也没去探究是什么缘故。

使用特权

评论回复
7
m_m| | 2007-12-18 23:09 | 只看该作者

有时候自己不会用

反而自己成了垃圾

有时留一条后路给自己好一点~~~~

使用特权

评论回复
8
jjl3| | 2007-12-19 09:12 | 只看该作者

回复6楼

这样改一下看还出错吗?
printf("abcdefg\n");
printf("abcdefg\n");
printf("abcdefg\n");
printf("abcdefg\n");
如果不出错则说明不是编译器的问题,原因再解释;
如果还是出错则说明我的想法错了

使用特权

评论回复
9
jjl3| | 2007-12-19 09:29 | 只看该作者

avr-gcc可能确实有bug

我也碰到一个怪现象.我有一个程序:

char a;
...

void abc(void)
{
  a =0;
  ...
 while(!a);
 ...

}

中断程序中:
 a = 0xFF;

用优化等级-01,
编译之后老是发现程序死在这句while(!a); 即使中断程序已经执行,并且阿a的值已经是0xFF.
看反汇编发现在循环中,只在开始读了一次a的值,以后循环就不再读a的值.
用优化等级 -00和 -01结果不同.
但一天后仍然用-01的优化等级发现又正确了,不知道什么原因

使用特权

评论回复
10
dai_weis| | 2007-12-19 10:15 | 只看该作者

LS 假如很不幸

中断的发生时刻正好在你的函数执行a = 0之前,于是a = 0xff,然后中断返回,于是执行a = 0;于是你就停在那里了

使用特权

评论回复
11
jjl3| | 2007-12-19 10:29 | 只看该作者

10楼误会了

其实我的中断是在等按键,程序只有执行到while(!a);这个语句时等待按键.
所以中断绝对不可能发生在a =0之前.并且通过jtag观察此时a的值确实是0xFF了.

正常情况下这个循环应该是:
a ---> 寄存器
判断寄存器的值,为0则再执行上一句,为0xFF往下执行.

但我碰到的情况是:
a ---> 寄存器
判断寄存器的值,为0则再读寄存器的值,为0xFF往下执行.
所以他只执行了一次 a ---> 寄存器.
因此即使后来a = 0xFF了,他依然循环.

使用特权

评论回复
12
jjl3| | 2007-12-19 10:40 | 只看该作者

搂主的现象我也碰到过

所以编译好后产生hex文件下载.
另外熔丝设置不对也可能产生错误.
如: ATmega128的两种运行模式.

免费的,大家就别太计较了

使用特权

评论回复
13
dai_weis| | 2007-12-19 10:49 | 只看该作者

确实误会了

不过程序中尽量不要用这种死等的办法
有更多的方案:可以使用条件语句来判断,而且对于a = 0的执行应该是有条件的,对于同一个变量的赋值要相互制约,不能随便修改这样可靠性不高
GCC是不是有BUG应该有的,但是我用它开发很久了并没有遇到,而且优化级别都很高
如果遇到问题可以考虑换一个思路或者程序的实现方法,不要在一条路上等
尤其涉及到全局变量的多个函数的修改问题,通过增加状态码确认执行的情况然后处理变量的修改要不然会有隐含的问题

使用特权

评论回复
14
yiz|  楼主 | 2007-12-19 13:42 | 只看该作者

或许真的是我不会用

但是,这个AVR-GCC有时真的让人莫名其妙,比如现在这个工程,优化级别为-00 -01 -02 -0s都能编译成功,唯独-3优化级别竟然出错:
d:\atmel\avr tools\compilers\winavr\bin\..\lib\gcc\avr\4.1.2\..\..\..\..\avr\bin\ld.exe: region text is full (ProcessCalibrator.elf section .text)
真是奇怪,.text段满了?有哪位认为自己会用的朋友说说这又是什么意思?

使用特权

评论回复
15
simon21ic| | 2007-12-19 16:12 | 只看该作者

11楼的问题好像是没有用volatile的原因吧

中断会修改的变量最好加上volatile属性(强迫每次读操作不被优化)
在国外很多人用AVR-GCC的,也没听说什么严重的问题,我自己使用也没碰到过什么问题
LS的问题可以去看一下各个优化级别的区别
建议调试一下,看一下出错的原因。在原因没有找到前,不要妄下结论

使用特权

评论回复
16
jjl3| | 2007-12-19 21:04 | 只看该作者

回15楼

也曾用volatile char a; 定义试过了还是不行.
但后来不知什么原因又正常了

使用特权

评论回复
17
yichang99| | 2008-3-10 15:06 | 只看该作者

是堆栈问题

由于内存有限,定义的数组太大就会导致堆栈溢出,而编译环境看不见。
像这种语句:
printf("abcdefg\n");
后面引号内的其实是const变量,编译生成的代码会做一个变量,放到内存,启动的时候,从flash里面加载到RAM,调用的时候传递RAM指针。所以多几个这种变量,内存就不够了。

ICC AVR不是这样做的,它直接使用flash空间做const,节约了RAM。

使用特权

评论回复
18
hotpower| | 2008-3-11 00:03 | 只看该作者

哈哈~~~俺觉得gccavr很不错~~~

使用特权

评论回复
19
BitFu| | 2008-3-11 10:26 | 只看该作者

我最讨厌两种人:一是有种族歧视的,二是黑人,三是不识

如题

使用特权

评论回复
20
dld2| | 2008-3-11 10:27 | 只看该作者

楼上说法有趣

使用特权

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

本版积分规则

yiz

12

主题

48

帖子

3

粉丝