typedef union { byte Byte; struct { byte COPWAI :1; /* COP stops in WAIT mode */ byte RTIWAI :1; /* RTI stops in WAIT mode */ byte CWAI :1; /* CLK24 and CLK23 stop in WAIT mode */ byte PLLWAI :1; /* PLL stops in WAIT mode */ byte ROAWAI :1; /* Reduced Oscillator Amplitude in WAIT mode */ byte SYSWAI :1; /* System clocks stop in WAIT mode */ byte PSTP :1; /* Pseudo Stop */ byte PLLSEL :1; /* PLL selected for system clock */ } Bits; } CLKSELSTR; //(1) extern volatile CLKSELSTR _CLKSEL @(REG_BASE + 0x00000039);//(2) #define CLKSEL _CLKSEL.Byte // (3) #define CLKSEL_COPWAI _CLKSEL.Bits.COPWAI #define CLKSEL_RTIWAI _CLKSEL.Bits.RTIWAI #define CLKSEL_CWAI _CLKSEL.Bits.CWAI #define CLKSEL_PLLWAI _CLKSEL.Bits.PLLWAI #define CLKSEL_ROAWAI _CLKSEL.Bits.ROAWAI #define CLKSEL_SYSWAI _CLKSEL.Bits.SYSWAI #define CLKSEL_PSTP _CLKSEL.Bits.PSTP #define CLKSEL_PLLSEL _CLKSEL.Bits.PLLSEL
解读:
1.寄存器 CLKSELSTR是一个联合体,Byte和Bits共用一个地址,如此一来,既可以给整个8位同时赋值,也可以给某一位赋值。例如:
CLKSELSTR.Byte =0x01;//给整个八位赋值
CLKSELSTR.Bits.PLLSEL=1;//给最低位赋值
(2)此语句定义寄存器的地址。REG_BASE是一个寄存器的基址,后面是其偏移量。两个地址相加,就是该寄存器的绝对地址。
寄存器当然是全局变量了,所以要加extern.
那么volatile又是什么意思呢?
volatile是“易变的”意思。由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化。比如:
static int i="0";
int main(void) { ... while (1) { if (i) dosomething(); } }
/* Interrupt service routine. */ void ISR_2(void) { i="1"; }
程序的本意是希望ISR_2中断产生时,在main当中调用dosomething函数,但是,由于编译器判断在main函数里面没有修改过i,因此,可能只执行一次对从i到某寄存器的读操作,然后每次if判断都只使用这个寄存器里面的“i副本”,导致dosomething永远也不会被 调用。如果将将变量加上volatile修饰,则编译器保证对此变量的读写操作都不会被优化(肯定执行)。此例中i也应该如此说明。 一般说来,volatile用在如下的几个地方: 1、中断服务程序中修改的供其它程序检测的变量需要加volatile; 2、多任务环境下各任务间共享的标志应该加volatile; 3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能有不同意义; 另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打断了重写),在1中可以通过关中断来实 现,2中可以禁止任务调度,3中则只能依靠硬件的良好设计了。
3.这些宏定义的作用就是简单的替换而已。比如:
CLKSELSTR_CLKSEL.Bits.PLLSEL可以写成: CLKSELSTR_CLKSEL_PLLSEL.
以后就可以通过 CLKSELSTR_CLKSEL_PLLSEL直接给PLLSEL这一位赋值了。这种定义在freescale的codewarrior里面非常常见。
|
文章评论(0条评论)
登录后参与讨论