![]() |
|
||||||||||||||
| . 网站首页 . 新闻 . 新品 . 方案 . 专访 . 活动 . DSP . EDA . 评测室 . 技术文库 . 会员区 . 商城 . 服务导航 . 邮购 . 资源 . | ||
|
||
|
|||||
| 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条。评论内容只代表网友观点,与本站立场无关!) |
| | 设为首页 | 加入收藏 | 联系站长 | 友情链接 | 版权申明 | 网站公告 | 管理登录 | | |||
|
|