zoukankan      html  css  js  c++  java
  • 对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

        达到了最好的结合状态。

        

      

        

  • 相关阅读:
    Win7操作系统防火墙无法关闭的问题 无法找到防火墙关闭的地方的解决的方法
    【微信】微信获取TOKEN,以及储存TOKEN方法,Spring quartz让Token永只是期
    OC内存管理总结,清晰明了!
    下次自己主动登录(记住password)功能
    linux删除svn版本号库
    Python中可避免读写乱码的一个强慷慨法
    Tomcat源代码阅读#1:classloader初始化
    iOS关于图片点到像素转换之杂谈
    hdu 3804树链剖分+离线操作
    cdn缓存
  • 原文地址:https://www.cnblogs.com/guochaoxxl/p/12381011.html
Copyright © 2011-2022 走看看