对SFR_8BIT(DCOCTL);代码的思考

Posted guochaoxxl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对SFR_8BIT(DCOCTL);代码的思考相关的知识,希望对你有一定的参考价值。

  其实对MSP430F169的单片机使用有段时间了。有些代码觉得还是不是很透彻。几乎每个例程里都会有这么一句:WDTCTL = WDTPW +WDTHOLD; 这行代码初看非常简单,仔细看来其实也不是那么容易的。

  一、从UserGuide手册中不难查到:Watchdog Timer Registers(看门狗定时器寄存器):

  名称:Watchdog timer control register

  简写: WDTCTL

  寄存器类型:Read/write

  寄存器地址:0120h

  初始化内容:06900h with PUC

  寄存器的每一位信息:

  WDTPW    Bits15-8     Watchdog timer password. Always read as 069h. Must be written as 05Ah, ora PUC will be generated.
  WDTHOLD   Bit 7     Watchdog timer hold. This bit stops the watchdog timer. Setting WDTHOLD= 1 when the WDT is not in use conserves power.
                0 Watchdog timer is not stopped
                1 Watchdog timer is stopped
  WDTNMIES   Bit 6     Watchdog timer NMI edge select. This bit selects the interrupt edge for the NMI interrupt when WDTNMI = 1. Modifying this bit can trigger an NMI. Modify this bit when                   WDTNMI = 0 to avoid triggering an accidental NMI.
                0 NMI on rising edge
                1 NMI on falling edge
  WDTNMI     Bit 5     Watchdog timer NMI select. This bit selects the function for the RST/NMI pin.
                0 Reset function
                1 NMI function
  WDTTMSEL   Bit 4     Watchdog timer mode select
                0 Watchdog mode
                1 Interval timer mode
  WDTCNTCL   Bit 3     Watchdog timer counter clear. Setting WDTCNTCL = 1 clears the count value to 0000h. WDTCNTCL is automatically reset.
                0 No action
                1 WDTCNT = 0000h
   WDTSSEL    Bit 2     Watchdog timer clock source select
                0 SMCLK
                1 ACLK
  WDTISx     Bits1-0  Watchdog timer interval select. These bits select the watchdog timer interval to set the WDTIFG flag and/or generate a PUC.
                00 Watchdog clock source /32768
                01 Watchdog clock source /8192
                10 Watchdog clock source /512
                11 Watchdog clock source /64

  阅读文档后很容明白,只要对寄存器WDTCTL中的WDTPW和WDTHOLD分别设置为:05Ah和1就可以关闭看门狗了。

  但是代码中既没有05Ah也没有1,这就是很奇怪的。

  二、首先是借助msp430f169.h这个头文件

    #define WDTPW                  (0x5A00)  

    上面代码通过宏定义完成了5A的写入,由于16位数据,只写入高八位,因此,写入的数据是0x5A00H

    #define WDTHOLD                (0x0080)

    上面这行代码实现了对WDTHOD的置位操作,具体如下:

    通过宏定义后WDTHOLD 等效为 0000 0000 1000 0000 由于WDTHOLD正好是Bit 7,这样就实现将WDTHOLD置位的目标

    通过中间的+实现或运算,实现了对需要操作的位进行操作,其他位保持不变。

  三、接着就是WDTCTL是怎么等效成寄存器的

    看到头文件里有SFR_16BIT(WDTCTL);                            /* Watchdog Timer Control */这个代码,

    追踪到:#define SFR_16BIT(address)  extern volatile unsigned int address

    代码稍微复杂了点:就是定义了宏函数,以后用SFR_16BIT(address)表示extern volatile unsigned int address

    前者非常简单,说下后者:1、address就是地址了

                2、int就是整型数据了

                3、unsigned就是无符号

                4、volatile是c中的关键字,表示该变量无需优化,每次都从变量中取得,不用缓存的数据

                5、extern是C中的关键字,表示变量是其他文件已定义的,就是这个extern让我困惑了很久

    回归到代码SFR_16BIT(WDTCTL);中,WDTCTL是个标号而已,它什么时候成地址了

  四、继续深入挖掘:文件msp430f169.cmd中

    有一行代码:WDTCTL             = 0x0120;,原来这个文件中定义了标号WDTCTL是一个地址,这个地址正好就是该寄存器的地址,也就是说,从此后用WDTCTL标号就可以表示寄存器了,完成了标号到地址的转换,实现了寄存器的标号化

    由于这个标号定义在头文件之外,因此,所有的标号都是在msp430f169.cmd定义,而标号在头文件msp430f169.h中使用,可不得必须加extern吗

  其实还有一个文件值得一看:lnk_msp430f169.cmd

  五、这其中在ARM编程中常见的一种用法:

    在嵌入式系统编程中,需要能够利用C语言访问固定的内存地址。按C语言的语法来看,在操作某个内存地址,比如0xc5时,步骤为:
       若ARM是八位的寄存器,就用char,当是32位,就用long

    首先将地址强制转换为指针类型,语法:

    (unsigned  char * )0xc5;经过这样操作,此刻地址被强制转换成了unsigned char类型的指针,指向了地址0xc5。
       如果需要获取对应地址的量,直接对指针变量解引用 即可,语法:

     *((unsigned  chart * )0xc5)

      此刻就能象操作其他指针一样操作强制转的指针了,获取指针所指向的地址内容
        为了避免由于编译器的优化,影响数据的同步性,加上volatile关键字

     为了更好地规范代码,代码中尽量不出现字面量,因此常用宏定义#define 0xc5  addr

     总之,将所有元素考虑进去后,形成#define REG8(addr) (*(volatile unsigned char * const)(addr))

    将#define宏中的参数用括号括起来,避免不必要的麻烦,有了以上定义,就可以用以下方式操作某个需要地址了:
    如果有unsigned  char  temp = 12;
    读取内容:temp = REG8(addr)      //将addr值所在的地址寄存器中的内容读取到temp中
    写入内容:REG8(addr) = temp      //将temp内容写进addr值所在的地址寄存器中
  六、c语言中@的妙用

    看#define DEFC(name, address)  __no_init  volatile unsigned char name @ address

    这个宏定义中其他的都比较熟悉了,只不过这个宏定义有两个参数把前边的部分替换为了 __no_init  volatile unsigned char name @ address,将连个参数连接起来而已,记得宏定义只是在替换,没有什么很高深的内容

  七、结构体和联合体共同作用:

    typedef  struct _bit{

      char  var1:1

      char  var2:3

      char  var3:4

      } BIT;

    定义结构体,使用位定义,其实就是BIT.var3占据4~7位, BIT.var2占据第1~3位, BIT.var1占据第0位

    typedef unino color{

      BIT  bitc;

      char col;

    } COL;

    定义一个联合体类型COL,其中包含BIT类型的变量和char型变量,由于联合体永远只有一个变量存储内容,一次可以实现对COL的变量可以按位操作,也可以整体操作。

    COL  col1;

    想实现第0位,第1位和第4位为1,可以只用:

    col1.col = 0001 0011或者直接 col1.col = 0x13H

    也可以:col1.bitc.var1 = 1

        col1.bitc.var2 = 1

        col1.bitc.var3 = 1

    达到了最好的结合状态。

    

 

  

    

以上是关于对SFR_8BIT(DCOCTL);代码的思考的主要内容,如果未能解决你的问题,请参考以下文章

特殊功能寄存器SFR

如何使用 arm neon 8bit 乘加和到 32 位向量?

8051汇编示例

先走一步啦(112路径总和),对解题代码的深入思考

bit,sbit,sfr,sfr16这些数据类型是相对C语言的扩展,分析这些存储类型的特点,

某日看代码对代码可读性的思考