頭文件包含了單片機(jī)內(nèi)部寄存器的地址定義等。引用此頭文件,才能正常對(duì)一些寄存器進(jìn)行讀寫操作,例如PORT口
在頭文件中會(huì)出現(xiàn)這樣的語句
#define OUTMOD_0 (0*0x20u),這里的“0*”和“u”分別是什么意思?
u是unsigned的意思,表示無符號(hào)整形變量至于前面有了0*,導(dǎo)致結(jié)果是0,我估計(jì)是因?yàn)楹竺孢€有其他定義,寫成了1*0x20u,2*0x20u,這樣的形式,為了使代碼整潔好看,所以這里也寫成了0*0x20u
頭文件解析之看門狗
msp430單片機(jī)的“msp430f169.h”頭文件中的 #define SHT0_0 (0*0x100u) #define CONSEQ_0 (0*2u) 什么意思?
#define A B
A宏名,B宏內(nèi)容
編譯預(yù)處理中,程序中,所有A的宏,將用B的定義替換。
如
#define PI 3.14
程序中所有出現(xiàn)PI的地方,將用浮點(diǎn)型常量,3.14代替。
0*0x100u結(jié)果是0。u表示無符號(hào)常量。加括號(hào),可以提高在實(shí)際程序中的運(yùn)算優(yōu)先級(jí)。
如初始化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
再理解上一段程序,就懂了。后面的內(nèi)容是配置的參數(shù),程序編譯后,實(shí)際上這些內(nèi)容都是常量。這種做法主要目的是增強(qiáng)程序的可讀性。
MSP430單片機(jī) 程序P1DIR |=0x01;這是什么意思???還有頭文件里面#define P1DIR是什么意思?
首先P1DIR的功能是選擇P1對(duì)應(yīng)的IO端口的輸入輸出狀態(tài),0為輸出狀態(tài),1為輸入狀態(tài)。
P1DIR |=0x01;的意思就是將P1DIR按位和0x01或,即將P1DIR的最低位置1其他位不變,置一的效果就是P1.0設(shè)置為輸入狀態(tài)。這是P1DIR二進(jìn)制值是xxxxxxx1,x是前一狀態(tài)沒有改變的值。
#define P1DIR 0x0008是定義了P1DIR這個(gè)寄存器的地址是根據(jù)器件型號(hào)不同而變化的,但是對(duì)于使用者來說固定的
MSP430設(shè)定的方法方便,但前提是看懂頭文件定義,只有這樣才能更好的運(yùn)用。 #define __MSP430_HAS_WDT__
#define WDTCTL_ (0x0120u) DEFW( WDTCTL , WDTCTL_)
這一段中讓人費(fèi)解的就是DEFW,百度可以知道它代表新版本對(duì)寄存器的定義。 #define DEFCW(name, address) __no_init union { struct {
volatile unsigned char name##_L; volatile unsigned char name##_H; };
volatile unsigned short name; } @ address;
這種定義也變得相對(duì)好理解。以上的這種union的定義,將一個(gè)16位的地址存儲(chǔ)空間分成2個(gè)8bits或者1個(gè)16位。可以實(shí)現(xiàn)字訪問,也可以實(shí)現(xiàn)字節(jié)訪問。
WDTCL_代表的就是0X0120u這個(gè)地址, 那么DEFW(WDTCTL,WDTCTL_)通過宏擴(kuò)展就可以理解為 __no_init union { struct {
volatile unsigned char WDTCTL_L; volatile unsigned char WDTCTL_H; };
volatile unsigned short WDTCTL; } @ 0X0120u; 這里指出:
?、?__no_init是IAR擴(kuò)展語法里面的一個(gè)擴(kuò)展關(guān)鍵字。作用是聲明一個(gè)non-volatile類型的內(nèi)存地址(Support non-valotile memory)。
② @是一種語法。那么它的作用很明顯就是將變量放置到對(duì)應(yīng)的地址中。使用@,一個(gè)變量可以明確的制定一個(gè)存儲(chǔ)地址。
就是將WDTCTL變量存放在0X0120u地址中,如此一來就可以為每個(gè)寄存器進(jìn)行命名了,也就是說可以實(shí)現(xiàn)每個(gè)寄存器對(duì)應(yīng)一個(gè)或者多個(gè)變量。
#define WDTIS0 (0x0001u) 選擇時(shí)鐘源周期 #define WDTIS1 (0x0002u)
#define WDTSSEL (0x0004u) 時(shí)鐘源選擇(0SM+1A) #define WDTCNTCL (0x0008u) 清除WDTCNT
#define WDTTMSEL (0x0010u) 0看門狗模式,1 定時(shí)器模式
#define WDTNMI (0x0020u) 0:RST/NMI引腳復(fù)位端,1:RST/NMI引腳為邊沿觸發(fā)的非屏蔽中斷輸入
#define WDTNMIES (0x0040u) 0為上升沿觸發(fā)NMI中斷,1為下降沿 #define WDTHOLD (0x0080u) 0:WDT功能激活,1為時(shí)鐘禁止輸入并停止計(jì)數(shù)降低功耗
#define WDTPW (0x5A00u) 口令
WDT的定時(shí)時(shí)間
WDTSSEL WDTISx 定時(shí)時(shí)間/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)
時(shí)鐘源選擇:WDTTMSEL 0為SMCLK 1為ACLK WDTCNTCL 該位為1,清除WDTCNT WDTIS1+WDTIS0
0:計(jì)數(shù)次數(shù)32768 1:8192 2:512 3:64 結(jié)合時(shí)鐘源的選擇衍生出下面的定時(shí)器延時(shí)
+++ #define
WDT_MDLY_32 (WDTPW+WDTTMSEL+WDTCNTCL )
MOV #WDTPW+WDTTMSEL+WDTCNTCL ,&WDTCTL 定時(shí)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)
怎么判斷頭文件的數(shù)值(如0x0001)是表示十六進(jìn)制數(shù)還是表示地址?
1、#define BIT0 (0×0001) //(0×0001)不是地址,而是一個(gè)16進(jìn)制數(shù)值。
例1、P3DIR |= BIT3;實(shí)際上也可以寫成P3DIR |= 0×0008;意思是將P3口的默認(rèn)上電值0×0000和0×0008相與,設(shè)置P3口的第三位(即P3.3)管腳作輸出使用。
例2、WDTCTL = WDTPW + WDTHOLD;實(shí)際上就是WDTCTL=0×5A80;
你可以在頭文件中查到#define WDTPW (0×5A00)和#define WDTHOLD (0×0080)。WDTCTL是看門狗的控
制寄存器,在msp430的User’Guide中有說明:當(dāng)它的值為0×5A80時(shí)停止看門狗定時(shí)。
那為什么我們不直接寫成WDTCTL=0×5A80;呢?這樣的話程序的可讀性會(huì)很差。
0×5A80只是一個(gè)數(shù)值,當(dāng)你下次再看你寫的程序,或者別人讀你的程序時(shí),就不明白WDTCTL=0×5A80;的
意思了。如果寫成WDTCTL = WDTPW + WDTHOLD;就好理解多了:
WDTPW(Watchdog timer password,看門狗的密碼,WDTCTL的高8位):只有WDTCTL的高8位為
0×5A時(shí)才能對(duì)WDTCTL寄存器進(jìn)行寫操作。
WDTHOLD(Watchdog timer hold,WDTCTL的第7位):當(dāng)WDTCTL的第7位為1時(shí),停止看門狗計(jì)時(shí)。
這樣我們通過PW,HOLD就可以輕松的知道WDTCTL = WDTPW + WDTHOLD;是做什么的了??梢钥闯?/p>
msp430的頭文件是很人性化的。
2、當(dāng)然也有表示地址的,例如,頭文件中有以下部分:
#ifdef __IAR_SYSTEMS_ASM__
#define DEFC(name, address) sfrb name = address
#define DEFW(name, address) sfrw name = address;
//運(yùn)用了可變參數(shù)宏的宏定義格式:#define 宏符號(hào)名(參數(shù)表) 宏體;宏體中就是寫出參數(shù)表中各個(gè)參數(shù)之間的關(guān)系。
#endif
……
#define P6OUT_ (0×0035)
DEFC( P6OUT , P6OUT_) //這里就是用了以上的可變參數(shù)宏。DEFC( P6OUT , P6OUT_) 就表示:sfrb P6OUT = P6OUT_
//這里的0×0035就是指P6OUT這個(gè)寄存器的地址了。
1、#define ME1_ (0x0004)
DEFC( ME1 , ME1_)
me1關(guān)聯(lián)端口0x0004
DEFC的C是字節(jié)的意思,也就是me1 就是地址0004處的一個(gè)字節(jié)即八位數(shù)據(jù)
2、#define FCTL1_ (0x0128)
DEFW( FCTL1 , FCTL1_)
其功能是從指定地址開始,定義若干個(gè)16位數(shù)據(jù)
對(duì)于對(duì)DEFC和DEFW的理解可以到#include《intrinsics.h》這個(gè)頭文件里查看
實(shí)質(zhì)上就是要對(duì)sfrb和sfrw關(guān)鍵字的理解,下面就說說在C430中所擴(kuò)展的關(guān)鍵字吧。
include “io430.h”
#include “msp430x47x3.h”
#include “io430x47x3.h”
這三個(gè)有什么區(qū)別?如何選擇比較好?
第一個(gè)是通用型號(hào)的IO頭文件。
第2個(gè)是47x所有的寄存器頭文件包含IO。
第3個(gè)是47x型號(hào)的IO寄存器頭文件。
如果你用的是47X型號(hào)的就用第2個(gè)比較好,如果你要寫全系列430單片機(jī)的就用通用的。第三個(gè)不推薦使用。
評(píng)論