原创 单片机里面寄存器定义的解读zz

2010-6-26 16:39 3112 14 14 分类: MCU/ 嵌入式
单片机里面寄存器定义的解读








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条评论)

登录后参与讨论
我要评论
0
14
关闭 站长推荐上一条 /2 下一条