这个很重要,有时候你程序莫名其妙的问题都是这个导致的。
我在做外置sram实验的时候没有注意,导致从sram里面出来的数据和写进去的不一样,像sram芯片有坏块一样。
//读LCD数据
//返回值:读到的值
u16 LCD_RD_DATA(void)
{
vu16 ram; //防止被优化
ram=LCD->LCD_RAM;
return ram;
}
像这种的代码,明显的问题,自己都写了开了高等级优化选项会被优化掉。
正确的写法是
u16 LCD_RD_DATA(void)
{
volatile u16 ram=LCD->LCD_RAM;//或者__IO u16 ram=LCD->LCD_RAM;
return ram;
}
地址操作的时候也是这样,像下面这个正确应该这么写
typedef struct
{
volatile u16 LCD_REG;
volatile u16 LCD_RAM;
} LCD_TypeDef;
//使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11 A18作为数据命令区分线
//注意设置时STM32内部会右移一位对其!
#define LCD_BASE ((u32)(0x60000000 | 0x0007FFFE))
#define LCD ((volatile LCD_TypeDef *) LCD_BASE)
vu16 其实就是typedef __IO uint16_t vu16; 已经给你加了volatile。#define __IO volatile
还有就是在sdram里面的变量,外设寄存器的变量,中断中改变的变量都要加。
如果你-o0的情况下正常的程序,一开-o3就不正常了,那一般都是volatile这个问题。
原因:
编译器会优化代码的
比如你往一个地址写个数值,后面的程序没有去读他。或者你从一个地址读,但是前面没有往这个地址写东西。编译器都会认为你这个读写操作是无用的操作,直接给你优化掉。
加了volatile就是告诉编译器,每次都必须去读写这个变量。
其他的道理都一样,你程序流程里没有明确改变的变量,编译器都可能不生成掉读他或者写他的代码。所以在你程序流程外有可能改变的变量都要加volatile。比如中断里面改变的变量。
修改寄存器也是一样的,你写了个数值到外设寄存器里面,后面又没有读他。编译器认为你这个写操作没有意义,无效代码,直接给你省略掉了。所以你看人家库里面的寄存器地址都是带volatile。
编译器这个逻辑其实很正常。比如你建立了一个全局变量,但是你的程序根本没有用他,那为了节省内存当然是不建立这个变量。你往一个地址写数据后面又从来没有用过他,编译器当然认为这个写操作是可以省略掉的。 |