msp430头文件分析

嵌入式设计应用

133人已加入

描述

  头文件包含了单片机内部寄存器的地址定义等。引用此头文件,才能正常对一些寄存器进行读写操作,例如PORT口

  在头文件中会出现这样的语句

  #define OUTMOD_0 (0*0x20u),这里的“0*”和“u”分别是什么意思?

  u是unsigned的意思,表示无符号整形变量至于前面有了0*,导致结果是0,我估计是因为后面还有其他定义,写成了1*0x20u,2*0x20u,这样的形式,为了使代码整洁好看,所以这里也写成了0*0x20u

  头文件解析之看门狗

  msp430单片机的“msp430f169.h”头文件中的 #define SHT0_0 (0*0x100u) #define CONSEQ_0 (0*2u) 什么意思?

  #define A B

  A宏名,B宏内容

  编译预处理中,程序中,所有A的宏,将用B的定义替换。

  如

  #define PI 3.14

  程序中所有出现PI的地方,将用浮点型常量,3.14代替。

  0*0x100u结果是0。u表示无符号常量。加括号,可以提高在实际程序中的运算优先级。

  如初始化ADC12的程序:

  ADC12CTL1 = SHS_1 + SHP + CONSEQ_2; // TA trig., rpt conv.

  ADC12MCTL0 = SREF_1 + INCH_10; // Channel A10, Vref+

  ADC12IE = 0x01; // Enable ADC12IFG.0

  ADC12CTL0 = SHT0_8 + REF2_5V + REFON + ADC12ON + ENC; // Config ADC12

  再理解上一段程序,就懂了。后面的内容是配置的参数,程序编译后,实际上这些内容都是常量。这种做法主要目的是增强程序的可读性。

  MSP430单片机 程序P1DIR |=0x01;这是什么意思啊?还有头文件里面#define P1DIR是什么意思?

  首先P1DIR的功能是选择P1对应的IO端口的输入输出状态,0为输出状态,1为输入状态。

  P1DIR |=0x01;的意思就是将P1DIR按位和0x01或,即将P1DIR的最低位置1其他位不变,置一的效果就是P1.0设置为输入状态。这是P1DIR二进制值是xxxxxxx1,x是前一状态没有改变的值。

  #define P1DIR 0x0008是定义了P1DIR这个寄存器的地址是根据器件型号不同而变化的,但是对于使用者来说固定的

  MSP430设定的方法方便,但前提是看懂头文件定义,只有这样才能更好的运用。 #define __MSP430_HAS_WDT__

  #define WDTCTL_ (0x0120u) DEFW( WDTCTL , WDTCTL_)

  这一段中让人费解的就是DEFW,百度可以知道它代表新版本对寄存器的定义。 #define DEFCW(name, address) __no_init union { struct {

  volatile unsigned char name##_L; volatile unsigned char name##_H; };

  volatile unsigned short name; } @ address;

  这种定义也变得相对好理解。以上的这种union的定义,将一个16位的地址存储空间分成2个8bits或者1个16位。可以实现字访问,也可以实现字节访问。

  WDTCL_代表的就是0X0120u这个地址, 那么DEFW(WDTCTL,WDTCTL_)通过宏扩展就可以理解为 __no_init union { struct {

  volatile unsigned char WDTCTL_L; volatile unsigned char WDTCTL_H; };

  volatile unsigned short WDTCTL; } @ 0X0120u; 这里指出:

  ① __no_init是IAR扩展语法里面的一个扩展关键字。作用是声明一个non-volatile类型的内存地址(Support non-valotile memory)。

  ② @是一种语法。那么它的作用很明显就是将变量放置到对应的地址中。使用@,一个变量可以明确的制定一个存储地址。

  就是将WDTCTL变量存放在0X0120u地址中,如此一来就可以为每个寄存器进行命名了,也就是说可以实现每个寄存器对应一个或者多个变量。

  #define WDTIS0 (0x0001u) 选择时钟源周期 #define WDTIS1 (0x0002u)

  #define WDTSSEL (0x0004u) 时钟源选择(0SM+1A) #define WDTCNTCL (0x0008u) 清除WDTCNT

  #define WDTTMSEL (0x0010u) 0看门狗模式,1 定时器模式

  #define WDTNMI (0x0020u) 0:RST/NMI引脚复位端,1:RST/NMI引脚为边沿触发的非屏蔽中断输入

  #define WDTNMIES (0x0040u) 0为上升沿触发NMI中断,1为下降沿 #define WDTHOLD (0x0080u) 0:WDT功能激活,1为时钟禁止输入并停止计数降低功耗

  #define WDTPW (0x5A00u) 口令

  WDT的定时时间

  WDTSSEL WDTISx 定时时间/ms IS1 IS0

  0 1 1 0.064 Tsmclk*64 0 1 0 0.51 Tsmclk*512 1 1 1 1.95 Taclk*64 0 0 1 8.19 Tsmclk*8192 1 1 0 15.63 Taclk*512 0 0 0 32.77 Tsmclk*64 1 0 1 250 Taclk*8192 1 0 0 1000 Taclk*32768

  口令 :#define WDTPW (0x5A00u)

  时钟源选择:WDTTMSEL 0为SMCLK 1为ACLK WDTCNTCL 该位为1,清除WDTCNT WDTIS1+WDTIS0

  0:计数次数32768 1:8192 2:512 3:64 结合时钟源的选择衍生出下面的定时器延时

  +++ #define

  WDT_MDLY_32 (WDTPW+WDTTMSEL+WDTCNTCL )

  MOV #WDTPW+WDTTMSEL+WDTCNTCL ,&WDTCTL 定时32ms #define

  WDT_MDLY_8 (WDTPW+WDTTMSEL+WDTCNTCL+WDTIS0 ) #define

  WDT_MDLY_0_5 (WDTPW+WDTTMSEL+WDTCNTCL+WDTIS1) #define

  WDT_MDLY_0_064 (WDTPW+WDTTMSEL+WDTCNTCL+WDTIS1+WDTIS0)

  #define

  WDT_ADLY_1000 (WDTPW+WDTTMSEL+WDTCNTCL+WDTSSEL) #define

  WDT_ADLY_250 (WDTPW+WDTTMSEL+WDTCNTCL+WDTSSEL+WDTIS0) #define

  WDT_ADLY_16 (WDTPW+WDTTMSEL+WDTCNTCL+WDTSSEL+WDTIS1)

  #define

  WDT_ADLY_1_9 WDTPW+WDTTMSEL+WDTCNTCL+WDTSSEL+WDTIS1+WDTIS0)

  #define WDT_MRST_32 (WDTPW+WDTCNTCL) #define WDT_MRST_8 (WDTPW+WDTCNTCL+WDTIS0) #define WDT_MRST_0_5 (WDTPW+WDTCNTCL+WDTIS1) #define

  WDT_MRST_0_064 (WDTPW+WDTCNTCL+WDTIS1+WDTIS0)

  #define WDT_ARST_1000 (WDTPW+WDTCNTCL+WDTSSEL) #define

  WDT_ARST_250 (WDTPW+WDTCNTCL+WDTSSEL+WDTIS0) #define

  WDT_ARST_16 (WDTPW+WDTCNTCL+WDTSSEL+WDTIS1) #define

  WDT_ARST_1_9 (WDTPW+WDTCNTCL+WDTSSEL+WDTIS1+WDTIS0)

  怎么判断头文件的数值(如0x0001)是表示十六进制数还是表示地址?

  1、#define BIT0 (0×0001) //(0×0001)不是地址,而是一个16进制数值。

  例1、P3DIR |= BIT3;实际上也可以写成P3DIR |= 0×0008;意思是将P3口的默认上电值0×0000和0×0008相与,设置P3口的第三位(即P3.3)管脚作输出使用。

  例2、WDTCTL = WDTPW + WDTHOLD;实际上就是WDTCTL=0×5A80;

  你可以在头文件中查到#define WDTPW (0×5A00)和#define WDTHOLD (0×0080)。WDTCTL是看门狗的控

  制寄存器,在msp430的User’Guide中有说明:当它的值为0×5A80时停止看门狗定时。

  那为什么我们不直接写成WDTCTL=0×5A80;呢?这样的话程序的可读性会很差。

  0×5A80只是一个数值,当你下次再看你写的程序,或者别人读你的程序时,就不明白WDTCTL=0×5A80;的

  意思了。如果写成WDTCTL = WDTPW + WDTHOLD;就好理解多了:

  WDTPW(Watchdog timer password,看门狗的密码,WDTCTL的高8位):只有WDTCTL的高8位为

  0×5A时才能对WDTCTL寄存器进行写操作。

  WDTHOLD(Watchdog timer hold,WDTCTL的第7位):当WDTCTL的第7位为1时,停止看门狗计时。

  这样我们通过PW,HOLD就可以轻松的知道WDTCTL = WDTPW + WDTHOLD;是做什么的了。可以看出

  msp430的头文件是很人性化的。

  2、当然也有表示地址的,例如,头文件中有以下部分:

  #ifdef __IAR_SYSTEMS_ASM__

  #define DEFC(name, address) sfrb name = address

  #define DEFW(name, address) sfrw name = address;

  //运用了可变参数宏的宏定义格式:#define 宏符号名(参数表) 宏体;宏体中就是写出参数表中各个参数之间的关系。

  #endif

  ……

  #define P6OUT_ (0×0035)

  DEFC( P6OUT , P6OUT_) //这里就是用了以上的可变参数宏。DEFC( P6OUT , P6OUT_) 就表示:sfrb P6OUT = P6OUT_

  //这里的0×0035就是指P6OUT这个寄存器的地址了。

  1、#define ME1_ (0x0004)

  DEFC( ME1 , ME1_)

  me1关联端口0x0004

  DEFC的C是字节的意思,也就是me1 就是地址0004处的一个字节即八位数据

  2、#define FCTL1_ (0x0128)

  DEFW( FCTL1 , FCTL1_)

  其功能是从指定地址开始,定义若干个16位数据

  对于对DEFC和DEFW的理解可以到#include《intrinsics.h》这个头文件里查看

  实质上就是要对sfrb和sfrw关键字的理解,下面就说说在C430中所扩展的关键字吧。

  include “io430.h”

  #include “msp430x47x3.h”

  #include “io430x47x3.h”

  这三个有什么区别?如何选择比较好?

  第一个是通用型号的IO头文件。

  第2个是47x所有的寄存器头文件包含IO。

  第3个是47x型号的IO寄存器头文件。

  如果你用的是47X型号的就用第2个比较好,如果你要写全系列430单片机的就用通用的。第三个不推荐使用。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分