共2条
1/1 1 跳转至页
volatile 转:《有关硬件寄存器、volatile...》的一点补充
问
《有关硬件寄存器、volatile...》的一点补充
龙大置首页的《有关硬件寄存器、volatile、和不该发生的C编译器优化》
show.aspx?id=78&cid=10
说到的问题的确是经常发生:) 特别是在大系统中 类似的问题包括TC BC等都出现过
但是 反而是Keil较少出现-_-!
其实 这个问题归根到底 就是volatile和变量优化的问题
简单的说 C编译器 为了“偷懒”-_-b 在他认为你这个变量不会被修改的时候 就把相应的
代码给“喀嚓”掉
比如龙大的那个程序:
void IRQHandler(void)
{
u16 Int_Flag;
Int_Flag = REG_IF; // Read the interrupt flags
SV32Bit++;
REG_SCCNT=0x5080;
REG_IF = Int_Flag; // Write back the interrupt flags
}
编译器看Int_Flag 好像是个没有在函数内被修改的变量 就偷懒 认为这个变量是无用的
类似与我们在keil中写个
char xxx;
main
{
char a;
a = xxx ;
xxx = a ;
while(1);
}
他多半是会把这样的代码给优化掉—— 也就是不编译出代码了
这个时候 volatile 就有用了 简单的说 所有的标准 C 编译器 遇见volatile修饰的变量
都认为这个变量的值是随机的 任何时候都是不同的 这样 每次对这样的变量的读出和写入
都必须实际的去读写对应的地址 而不可以偷懒用:寄存器中的拷贝中的数据、可能数值一
样的其他变量/常数等来“糊弄”系统 ^_^
比如我上面的那个main()编译器发现 xxx被读出然后无修改的重新写入 就懒得麻烦读写 索
性优化掉了
其实 volatile 在大多数的代码中 很少使用
简单的说:他用来修饰那些可能会在你不知道的地方给修改的变量 比如
1.定义成寄存器空间的变量 事实上 这个是他最大的一个用处!!
比如ARM/C51/AVR/PIC等等的控制寄存器(SFR)空间 虽然 Keil用了一个sfr关键字来修饰寄
存器:sfr P0 = 0x80 ……
但是 在标准C中 是必须使用这样的形式:#define P0 *(volatile unsighed char *)0x80
2.会被中断修改的变量 有时候也需要加 不过这个不是项上一个那样是绝对的
和编译器本身和你选择的优化等级等有关系 我的建议 在ADS中最好还是加上 Keil中就可以
不用麻烦了
回到龙大的那个问题上 龙大的问题虽然解决了 不过并不好 因为他把
u16 定义成了 volatile unsigned short 这个对程序运行结果不会造成任何影响 不过带来
了一个无法对变量优化的毛病
事实上 这个问题的带来 是因龙大使用的那个 gba.h的一个bug
我看到网上很多的gba.h的寄存器的定义 都吧寄存器们定义成:
#define REG_XXX *(u16*)0x??????的形式
这样 当龙大的IRQHandler程序进入后 编译器认为:
REG_IF没有在函数里给修改 也没有给真正赋值
a=x;
x=a;
这样 IRQHandler函数 在形式上 也就被认为和后面我写的那个main一样了
这样的代码 编译器肯定是喀嚓的了
那么 如果只把gba.h中的REG_IF的定义 加上volatile 修饰 而u16 依然是 unsighed short
呢?
当然是一切都解决了…… 答 1: 回 答 2: 做个记号.已收
龙大置首页的《有关硬件寄存器、volatile、和不该发生的C编译器优化》
show.aspx?id=78&cid=10
说到的问题的确是经常发生:) 特别是在大系统中 类似的问题包括TC BC等都出现过
但是 反而是Keil较少出现-_-!
其实 这个问题归根到底 就是volatile和变量优化的问题
简单的说 C编译器 为了“偷懒”-_-b 在他认为你这个变量不会被修改的时候 就把相应的
代码给“喀嚓”掉
比如龙大的那个程序:
void IRQHandler(void)
{
u16 Int_Flag;
Int_Flag = REG_IF; // Read the interrupt flags
SV32Bit++;
REG_SCCNT=0x5080;
REG_IF = Int_Flag; // Write back the interrupt flags
}
编译器看Int_Flag 好像是个没有在函数内被修改的变量 就偷懒 认为这个变量是无用的
类似与我们在keil中写个
char xxx;
main
{
char a;
a = xxx ;
xxx = a ;
while(1);
}
他多半是会把这样的代码给优化掉—— 也就是不编译出代码了
这个时候 volatile 就有用了 简单的说 所有的标准 C 编译器 遇见volatile修饰的变量
都认为这个变量的值是随机的 任何时候都是不同的 这样 每次对这样的变量的读出和写入
都必须实际的去读写对应的地址 而不可以偷懒用:寄存器中的拷贝中的数据、可能数值一
样的其他变量/常数等来“糊弄”系统 ^_^
比如我上面的那个main()编译器发现 xxx被读出然后无修改的重新写入 就懒得麻烦读写 索
性优化掉了
其实 volatile 在大多数的代码中 很少使用
简单的说:他用来修饰那些可能会在你不知道的地方给修改的变量 比如
1.定义成寄存器空间的变量 事实上 这个是他最大的一个用处!!
比如ARM/C51/AVR/PIC等等的控制寄存器(SFR)空间 虽然 Keil用了一个sfr关键字来修饰寄
存器:sfr P0 = 0x80 ……
但是 在标准C中 是必须使用这样的形式:#define P0 *(volatile unsighed char *)0x80
2.会被中断修改的变量 有时候也需要加 不过这个不是项上一个那样是绝对的
和编译器本身和你选择的优化等级等有关系 我的建议 在ADS中最好还是加上 Keil中就可以
不用麻烦了
回到龙大的那个问题上 龙大的问题虽然解决了 不过并不好 因为他把
u16 定义成了 volatile unsigned short 这个对程序运行结果不会造成任何影响 不过带来
了一个无法对变量优化的毛病
事实上 这个问题的带来 是因龙大使用的那个 gba.h的一个bug
我看到网上很多的gba.h的寄存器的定义 都吧寄存器们定义成:
#define REG_XXX *(u16*)0x??????的形式
这样 当龙大的IRQHandler程序进入后 编译器认为:
REG_IF没有在函数里给修改 也没有给真正赋值
a=x;
x=a;
这样 IRQHandler函数 在形式上 也就被认为和后面我写的那个main一样了
这样的代码 编译器肯定是喀嚓的了
那么 如果只把gba.h中的REG_IF的定义 加上volatile 修饰 而u16 依然是 unsighed short
呢?
当然是一切都解决了…… 答 1: 回 答 2: 做个记号.已收
共2条
1/1 1 跳转至页
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
与电子爱好者谈读图二被打赏50分 | |
【FRDM-MCXN947评测】Core1适配运行FreeRtos被打赏50分 | |
【FRDM-MCXN947评测】双核调试被打赏50分 | |
【CPKCORRA8D1B评测】---移植CoreMark被打赏50分 | |
【CPKCORRA8D1B评测】---打开硬件定时器被打赏50分 | |
【FRDM-MCXA156评测】4、CAN loopback模式测试被打赏50分 | |
【CPKcorRA8D1评测】--搭建初始环境被打赏50分 | |
【FRDM-MCXA156评测】3、使用FlexIO模拟UART被打赏50分 | |
【FRDM-MCXA156评测】2、rt-thread MCXA156 BSP制作被打赏50分 | |
【FRDM-MCXN947评测】核间通信MUTEX被打赏50分 |