WINAVRAVR-GCC中怎样使用volatile关键字.docVIP

  1. 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
  2. 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  3. 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
  4. 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
  5. 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们
  6. 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
  7. 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
WIN AVR AVR-GCC 中如何使用 volatile 关键字 volatile 的字面含义是易变的,那么将一个变量指示为 volatile是什么意思呢?是告诉编 译器这个变量是易变的?事实上也是如此。在多任务、中断等环境下,变量可能被其他的任 务改变,而编译器无法发现,volatile 就是告诉编译器这个变量在其它任务(或中断)中可 能要修改。 使用 volatile是与编译器优化有关系的。先看看下面的例子: #include avr/io.h unsigned char g_Flag=0; int main(void) { g_Flag=1; g_Flag=0; while(1); } main程序中对g_Flag先赋值1,后赋值0, 显然g_Flag=1是没有意义的,聪明的编译器发 现这个后就产生了如下的代码: int main(void) { 5c: cf e5 ldi r28, 0x5F ; 95 5e: d4 e0 ldi r29, 0x04 ; 4 60: de bf out 0x3e, r29 ; 62 62: cd bf out 0x3d, r28 ; 61 g_Flag=1; g_Flag=0; 64: 10 92 60 00 sts 0x0060, r1 while(1); 68: ff cf rjmp .-2 ; 0x68 main+0xc 编译器没有生成 g_Flag=1 的机器码, 在优化过程中 g_Flag=1被忽略了。在一般的 C程 序中这是没有问题的,但是如果 g_Flag 是个单片机 I/O口变量那就麻烦了,本来想从 I/O口 输出一逻辑正脉冲的程序就这样被编译器优化掉了,显然不是我们所希望的。这时候该怎么 办呢?请拿出利剑 volatile,他能处理我们所遇到的麻烦。 将 unsigned char g_Flag=0; 该为 volatile unsigned char g_Flag=0;后编译所产生的汇编代 码如下: int main(void) { 5c: cf e5 ldi r28, 0x5F ; 95 5e: d4 e0 ldi r29, 0x04 ; 4 60: de bf out 0x3e, r29 ; 62 62: cd bf out 0x3d, r28 ; 61 g_Flag=1; 64: 81 e0 ldi r24, 0x01 ; 1 66: 80 93 60 00 sts 0x0060, r24 g_Flag=0; 6a: 10 92 60 00 sts 0x0060, r1 while(1); 6e: ff cf rjmp .-2 ; 0x6e main+0x12 在 《AVR 单片机 GCC 程序设计》第二章中我们展开了 PORTB 这个宏, 对于 AT90S2313 它等同于 *(volatile unsigned char *)(0x38) ,现在你一定相信这里的 volatile是必不可少的。 尽管如此,有人会认为 “在一般的程序中不需要定义端口宏,因为 avr-libc 都为我们定义好 了,我只要包含 io.h 就可以了,在用户程序中 volatile 是无关紧要的” ,那么让我们再来看 一下 volatile必不可少的另一种情况。 #include avr/io.h #include avr/interrupt.h unsigned char g_Flag=0;//串口接收标记 ISR(SIG_UART_RECV) { ... ... g_Flag=1; } int main(void) { ... ... while(!g_Flag);//等待串口接收到数据 ... ... } 上面的程序看似没有任何问题,实际上 main 函数是永远也发现不了串口接收数据的。 由于编译器的优化,while(!g_Flag)将生成一个非常有意思的代码,它首先从 g_Flag 对应的 内存读一次数据到一个寄存器中,之后不停的测试此寄存器是否为非零,即使中断程序中已 经改变了 g_Flag 对应内存的值,它还是始终检查一个不再更新的寄存器。那么如何让 while 循环每次都要从内存读取后再测试它是否为零呢?你应该猜到了,就是将 g_Flag 变量指示 为 volatile,告诉编译器 g_Flag 是易变的,要对它进行保守处理。 volatile 是一种优化指示,编译器优化操作使用一种技术叫做数据流分析,分析程序中 的变量在哪里赋值、在哪里使用、在哪里失效,分析结果可以用于常量合并,常量传播等优 化,从而可以消除死代码。但有时这优化不是程序所希望的,这时可以用 volatile 关键字关 闭这个优化开关。 最后提醒读者,没有必要将所有的变

文档评论(0)

wx171113 + 关注
实名认证
文档贡献者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档