对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);代码的思考的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 arm neon 8bit 乘加和到 32 位向量?