嵌入式C编译器肯定是要提供一种访问某个特定地址RAM的方法。例如:访问Atmega16中的UBRRL,对应RAM中的0x29单元。ICC提供的头文件是这样描述的:#define UBRRL (*(volatile unsigned char *)0x29)
*(&i) 表示i,也就是地址为&i RAM单元的内容,那么只要
(*(volatile
unsigned char *)0x29)中的(unsigned char *)0x29表示地址为0x29的RAM单元的地址,(*(volatile unsigned char *)0x29)就是地址为0x29的RAM单元内容了。
那(unsigned char *)0x29是不是表示地址为0x29的RAM单元的地址?先定义个变量unsigned int i ;那(unsigned
char *)i就是将i强制转换成一个指向unsigned char类型变量的指针变量。由于指针变量的内容表示地址,那么(unsigned char *)i也就表示地址。这个地址是变量i中的内容,如果i=0x29,那么就是0x29单元了,(unsigned char *)0x29表示RAM的0x29单元。
简单点,就将(unsigned char *)0x29记作:将常数0x29变成一个地址值得了。
那么volatile的作用又是什么呢?
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样编译器就不去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保持在寄存器里的备份。
#include<pic.h>
__CONFIG(0x1832);
#define VAR0
*((unsigned char *)0x21)
#define VAR1
*((volatile unsigned char*)0x22)
void main(void)
{
unsigned char i=0;
VAR0 = 0xAA;
i = VAR0;
VAR1 = 0x55;
i = VAR1;
while(1);
}
反汇编出来的代码是:
…
BCF 0x3, 0x5
BCF 0x3, 0x6
CLRF 0x20
MOVLW 0xaa
MOVWF 0x21
MOVWF 0x20
;并未重新读取VAR0的值
MOVLW 0x55
MOVWF 0x22
MOVF 0x22,W
;重新读取了VAR1的值
MOVWF 0x20
…
这也就是定义寄存器的时候要用volatile的原因吧。
文章评论(0条评论)
登录后参与讨论