Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2835386
  • 博文数量: 523
  • 博客积分: 11908
  • 博客等级: 上将
  • 技术积分: 5475
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-03 15:50
文章分类

全部博文(523)

文章存档

2019年(3)

2013年(4)

2012年(71)

2011年(78)

2010年(57)

2009年(310)

分类: LINUX

2009-07-16 21:15:09

理解#define SREG    (*(volatile unsigned char *)0x5F)
这样的定义,总是感觉很奇怪,不知道为什么,今天终于有了一点点心得,请大虾们多多批砖~~~

   嵌入式系统编程,要求程序员能够利用C语言访问固定的内存地址。既然是个地址,那么按照C语言的语法规则,这个表示地址的量应该是指针类型。所以,知道要访问的内存地址后,比如0x5F
  
第一步是要把它强制转换为指针类型
unsigned char *)0x5FAVRSREG是八位寄存器,所以0x5F强制转换为指向unsigned char类型。
   volatile
(可变的)这个关键字说明这变量可能会被意想不到地改变,这样编译器就不会去假设这个变量的值了。这种意想不到地改变,不是由程序去改变,而是由硬件去改变——意想不到。
  
第二步,对指针变量解引用,就能操作指针所指向的地址的内容了
   *(volatile unsigned char *)0x5F
  
第三步,小心地把#define宏中的参数用括号括起来,这是一个很好的习惯,所以#define SREG    (*(volatile unsigned char *)0x5F)

    类似的,如果使用一个32位处理器,要对一个32位的内存地址进行访问,可以这样定义#define RAM_ADDR     (*(volatile unsigned long *)0x0000555F)
   
然后就可以用C语言对这个内存地址进行读写操作了

   
读:tmp = RAM_ADDR
   
写:RAM_ADDR = 0x55

定义volatile是因为它的值可能会改变,大家都知道为什么改变了;
如果在一个循环操作中需要不停地判断一个内存数据,例如要等待SREGI标志位置位,因为SREG也是映射在SRAM空间,为了加快速度,编译器可能会编译出这样的代码:把SREG读取到Register中,然后不停地判断Register相应位。而不会再读取SREG,这样当然是不行了,因为程序或其它事件(中断等)会改变SREG,结果很可能是一个死循环出不来了。如果定义成volatile型变量,编译的代码是这样的:每次要操作一个变量的时候都从内存中读取一次。
#define SREG *(volatile unsigned char *)0x5F) 之后,

可以进行如下基本操作,
unsigned char temp
*ptr;
temp=SREG;
SREG值保存到temp

SREG=temp;
temp的值赋给SREG
ptr
& SREG; 不知对否,大家试一下。

 

 

 

 

 

#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,即AP指针指向位置的内容了。这里就是通过内存寻址访问到寄存器A,可以读/写操作。

GCC编译时。volatile所指示的寄存器不进行优化!!!

 

 

 

#define U0RBR (*((volatile unsigned char *) 0xE000C000))

这个在单片机里很常见,

((volatile unsigned char *) 0xE000C000) 是将0xE000C000强制转换为

保存可能随时更新(volatile的作用)无符号字符型数据的地址

前面又加了*,是表示指向这个地址里面的值,这与其他普通定义的指针一样了,如char x,y,*p;p=&x;*p=y;y=*p

就如同一个变量一样,既可以从这里读出值,也可以给被赋值,这里需要注意的是,这个地址值里的东西是不是既可以读又可以写,这个在datasheet应该有定义,或者看程序中都拿他干什么。

#define U0RBR (*((volatile unsigned char *) 0xE000C000)) 这个是宏定义,即UORBR替换(*((volatile unsigned char *) 0xE000C000)),宏定义是为了程序书写方便,因为在程序中可能有好多地方要使用(*((volatile unsigned char *) 0xE000C000)),在用时,总要写这么多东西麻烦。

 

(1<<16),没错这个也是左移,只不过不是给变量里的数左移,而是直接把1左移16位,也即把16位数中的最高位置1

0000 0000 0000 0001   //1

移之后

1000 0000 0000 0000   //0x8000

 

#define DIRECT1 1<<10 //接收数据拉低,发送数据抬高

#define DIRECT0 1<<16 //接收数据拉低,发送数据抬高

 

拿着这个两个宏定义给寄存器赋值,或者是与寄存器按位与或者按位或等等。

这个应该懂了吧,应该是给位9和位15(从位0开始)置1

我猜想位9应该控制的是发送数据,位15控制的是控制的是发送数据

 

 

 

理解#define rRTCCON    (*(volatile unsigned char *)0x57000043) //RTC control

这样的定义,总是感觉很奇怪,今天终于有了一点点心得, 嵌入式系统编程,要求程序员能够利用C语言访问固定的内存地址。既然是个地址,那么按照C语言的语法规则,这个表示地址的量应该是指针类型。所以,知道要访问的内存地址后,比如0x57000043


  
第一步是要把它强制转换为指针类型


unsigned char *)0x57000043s3c2410rRTCCON是单字节访问的,所以0x57000043强制转换为指向unsigned char类型。
   volatile
(可变的)这个关键字说明这变量可能会被意想不到地改变,这样编译器就不会去假设这个变量的值了。这种意想不到地改变,不是由程序去改变,而是由硬件去改变——意想不到。


  
第二步,对指针变量解引用,就能操作指针所指向的地址的内容了


   *(volatile unsigned char *)0x57000043


  
第三步,小心地把#define宏中的参数用括号括起来,这是一个很好的习惯

在嵌入式系统中经常使用到Volatile,对于volatile的用法

,我根据自己的理解做如下阐述,希望大家可以发表评论:


c语言中,volatile关键字是一种类型修饰符, 用它声明的类型变量表示该变量可以被某些编译器未知的外部因素(比如:操作系统、硬件或者其它线程)更改. 遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址(定义的变量在内存中的地址)的稳定访问。


编译器对代码的优化是指

CPU在执行的过程中,因为访问内存的速度远没有cpu的执行速度快,为了提高效率,引入了高速缓存cache. C编译器在编译时如果不知道变量会被其它外部因素(操作系统、硬件或者其它线程)修改,那么就会对该变量进行标识,即优化.那么这个变量在CPU的执行过程中,就会被放到高速缓存cache,进而达到对变量的快速访问. 在了解了优化的概念后,试想如果我们事先就知道该变量会被外部因素改变,那么我们就在这个变量定义前加上Volatile,这样编译器就不会对该变量进行优化.这样该变量在cpu处理的过程当中,就不会被放到高速缓存cache


为什么要让变量在执行的过程中不被放到cache中去呢?

如果变量是被外部因素改变,那么cpu就无法判断出这个变量已经被改变,那么程序在执行的过程中如果使用到该变量,还会继续使用cache中的变量,但是这个变量其实已经被改变了.需要到内存地址中更新其内容了.

还有一个原因,在一些寄存器变量或数据端口的使用中,因为寄存器变量本身也是靠cache来处理,为了避免引起错误,也可以使用volatile修饰符.

 

简单的说使用volatile的目的就是:

让对volatile 变量的存取不能缓存到寄存器,每次使用时需要重新存取。

 

 

阅读(2100) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~