网上查了资料,先看英文的,看看外国人怎么解释:
Using C, I was trying to assign a variable name to a register address so that my code would be readable. An example of how to do this is as follows:
#define DDRA (*(volatile unsigned char *)(0x22))
This means that if a register or memory location exists at address 0×22, I can use DDRA to read or write to it like so..
DDRA = 0x05
In my C code.The #define looks really cryptic at first. The way to understand this is by breaking it down into pieces.
First of all,
unsigned char
means we are using a byte-sized memory location. Byte being 8-bits wide.
unsigned char *
means we are declaring a pointer that points to a byte-sized location.
(unsigned char *) (0x22)
means the byte-sized pointer points to address 0×22. The C compiler will refer to address 0×22 when the variable DDRA is used. The assembly code will end up using 0×22 in Load(LD) and Store (STR) insturctions.
(*(unsigned char *)(0x22))
The first asterisk from the left signifies that we want to manipulate the value in address 0×22. * means “the value pointed to by the pointer”.
volatile
volatile forces the compiler to issue a Load or Store anytime DDRA is accessed as the value may change without the compiler knowing it.
再看看中文的解释:
使用一个32位处理器,要对一个32位的内存地址进行访问,可以这样定义
#define RAM_ADDR (*(volatile unsigned long *)0x0000555F)
然后就可以用C语言对这个内存地址进行读写操作了
读:tmp = RAM_ADDR;
写:RAM_ADDR = 0x55;
定义volatile是因为它的值可能会改变,大家都知道为什么改变了;
如果在一个循环操作中需要不停地判断一个内存数据,例如要等待RAM_ADDR的I标志位置位,因为RAM_ADDR也是映射在SRAM空间,为了加快速度,编译器可能会编译出这样的代码:把RAM_ADDR 读取到Register中,然后不停地判断Register相应位。而不会再读取RAM_ADDR,这样当然是不行了,因为程序或其它事件(中断等)会改变RAM_ADDR,结果很可能是一个死循环出不来了。如果定义成volatile型变量,编译的代码是这样的:每次要操作一个变量的时候都从内存中读取一次。
#define rGPACON(*(volatile unsigned long *)0x56000000)
对于不同的计算机体系结构,设备可能是端口映射,也可能是内存映射的。如果系统结构支持独立的IO地址空间,并且是端口映射,就必须使用汇编语言完成实际对设备的控制,因为C语言并没有提供真正的“端口”的概念。如果是内存映射,那就方便的多了。
举个例子,比如像寄存器A(地址假定为0x48000000)写入数据0x01,那么就可以这样设置了。
#define A (*(volatile unsigned long *)0x48000000)
...
A = 0x01;
...
这实际上就是内存映射机制的方便性了。其中volatile关键字是嵌入式系统开发的一个重要特点。上述表达式拆开来分析,首先(volatile unsigned long *)0x48000000的意思是把0x48000000强制转换成volatile unsigned long类型的指针,暂记为p,那么就是#define A *p,即A为P指针指向位置的内容了。这里就是通过内存寻址访问到寄存器A,可以读/写操作。
用GCC编译时。volatile所指示的寄存器不进行优化!!!