网站公告列表

  没有公告

加入收藏
设为首页
联系站长
您现在的位置: 61IC中国电子在线 >> 技术文库 >> 嵌入式 >> 文章正文
  winavr经验谈:被遗忘的语法......类型匹配           ★★★ 【字体:
winavr经验谈:被遗忘的语法......类型匹配
作者:61IC录入    文章来源:本站原创    点击数:    更新时间:2006-4-7    
项目:能量表
在一组5个的LED数码块切换显示V/I/P,另一组8个的LED数码块显示W(功,电能),掉电保存W,精度1/1000
方案:
ATMEMA8(自带EEPROM呀),显示用3片74hc595,一片生成段码,两片生成片选;SPI驱动74hc595,采样模拟量通过V/F转换生成脉冲(不用mega8的A/D是因为精度达不到要求),T1设定1秒计时,ICP1捕捉电压转换的脉冲,INT1捕捉电流转换的脉冲;模拟和数字采用光耦隔离;然后,用1秒的捕捉脉冲数做相应计算和显示。
尽管以前我从没用过AVR系列的芯片,不过这个项目硬件设计对我来说挺简单的,软件用winavr的C做应该也很快吧(我是这样想的....)。不过,苦难的历程才刚刚开始.....

硬件,一个字:顺!当然是没问题啦.... :)  通过mega8测量的脉冲表明:采样电压或电流线性与脉冲个数成正比,误差在1/3000,显然满足后面的计算要求!
于是开始编写和测试计算和掉电保存程序.....

首先是采样脉冲数和显示数的转换(简单嘛,乘个比例系数就好),首先在中断程序中声明一个全局的计数变量sample_v如下:
volatile u16_t sample_v;  // 范围:0 ~ 3036
volatile u16_t sample_i;  // 范围:0 ~ 3036

在计算显示数过程中,定义全局变量如下:
u32_t dis_v; // 显示范围:0 ~ 9000
#define C_SMP_V   3036
#define C_DIS_V   9000
u32_t dis_i; // 显示范围:0 ~ 2800
#define C_SMP_I   3036
#define C_DIS_V   2800

计算过程是这样的(部分代码):
void proc_calculate(void) {
  u32_t tmp1, tmp2, tmp3;
  
  if ((flag0 & _BV(FLAG0_T1)) == 0) {
    return; // 没到1秒,等待采样
  }
  else {
    flag0 &= ~_BV(FLAG0_T1);  // 清标志
  }
  
  
  // 计算采样显示电压(伏)
  tmp1 = sample_v;
  tmp1 *= C_DIS_V;
  tmp1 /= C_SMP_V;
  dis_v = tmp1;
  // 测试计算结果
  htobcd5(&bcd_buf[0], dis_v);  // 该函数把dis_v转化为5位BCD码,送显示缓存,供中断程序调用bcd_buf刷新LED显示


// 备注: 后面的代码就不贴了
}
测试结果显示:5个LED总为0
解决路线如下:
1)示波器看ICP1脚有无脉冲? 有
2)函数htobcd5()有bug?换成语句:htobcd5(&bcd_buf[0], sample_v),看见5个LED显示数波动03035或03036, (暗喜)说明采样、中断和LED显示没问题,大悲!原来期望是函数htobcd5()有bug的美梦破灭,晕!
3)跟踪编译的汇编代码?靠!任务时间15天,现在已经过了5天,我哪有时间去学AVR的汇编呀!再说我只有串口下载线,也没有JITAG,对AVR STUDIO4也不熟悉,跟踪个屁的汇编。唯一可以跟踪的‘窗口’就是板上的13个LED数码块。
各位老兄也许这时候也在想上面的问题所在吧,如果没有,给你5分钟稍微考虑
.....
........
............
..................
.........................
....................................
..............................................................
...........................................................................
.................................................................................................................
OK, 我周围的n多 AVR高手都没办法了,几乎都得出同样的结论:winavr编译器的bug(换句话就是: avr-gcc的bug)!也许是全局变量做乘除法四则运算导致错误返回结果!我也这样想着........

于是google和sourceforge.org(winavr的代码发源地)上找关于winavr-20050214的bug方面的信息和解决办法....一句话:没有!大概是因为我对mega8的用法太特殊了吧:你看,mega8没有除法单元(怀念51核),并且我还用它做32bit的除法,想全部转汇编写吧,时间肯定不够......
我不放弃!用各种中间变量转换....
直到我写这贴子前3个小时,终于在数码块上看到正确的结果08997~09001,bingo!于是我赶快对比历史修改文件(我每修改一次就做一次备份,建议所有写程序的老兄都养成这个好习惯!),终于让我知道问题所在--被遗忘的语法......类型匹配!解决的办法很简单:
把原来的声明volatile u16_t sample_v变成volatile u32_t sample_v,或者把计算式做强制类型转换即:tmp1 = (u32_t)sample_v;  (终于可以睡个安稳觉了)
如果就此停笔,不是我写这贴子的目的!我们要深究这个问题后隐藏的本质。
因为以前我用过很多的C编译环境,把低位数的变量附值给高位数变量时,从来不做类型转换,为什么这次在winavr-20050214里出错,注意我们这里强调版本号,是因为这个版本用的gcc-3.4.3做C代码翻译!还算好,我本来是Linux的爱好者,对GCC的各个版本的特色也比较了解....推论是:GCC-3.4以后的版本对C代码的语法要求更严格!我把我的前后两组代码修改为ICCAVR下的兼容代码并编译,也得到同样的现象:类型不匹配时数码显示结果是错的。通过查看ICCAVR的编译参数和GCC大致相同,因此可以推理ICCAVR也用GCC来解释C代码。靠!狗屁ICCAVR用GCC的工具还赚老百姓的钱!

我想对这个论坛的、和我一样的AVR初学者说:爱winavr和GCC吧!他并不象你想像的晦涩难懂。当然,如果你真发现bug,并对并反馈给原开发者,是对开源代码发布者最大的回报!
               欢迎点击进入:TI德州中文网   (国内唯一针对TI应用的中文技术网站)    文章录入:admin    责任编辑:admin 
  • 上一篇文章:

  • 下一篇文章:
  • 发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
    最新热点 最新推荐 相关文章
    没有相关文章
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
    站长:61IC 湘ICP备05002478号