本试验的意图是了解用于履行对MSP430 Value Line设备的初始化进程的过程。在这个操练中,您将编写初始化代码,并运转该设备运用各种时钟资源。
1、写初始化代码
2、运转CPU的MCLK的来历方法:VLO 、32768晶体、DCO
3、主体程序部分
4、调查LED闪光灯速度
MSP430时钟:
1、在MSP430单片机中一共有三个时钟源:
一个LFXT1CLK,为低速/高速晶振源,一般接32.768khz,也能够接(400khz~8Mhz);
一个为XT2CLK,外接规范高速晶振,一般是接8Mhz,也能够接(400khz~8Mhz);
还有一个叫DCOCLK,为内部晶振,有RC震动回路构成。
2、在MSP430单片机内部一共有三个时钟体系 :
一个为ACLK,一般由LFXT1CLK作为时钟源,能够经过软件操控改时钟的分频系数树;
一个为MCLK(Main CLK)一听就知道是主时钟单元,为体系内核供给时钟,它能够经过软件从三个时钟源挑选;
还有一个为SMCLK,称作辅佐主时钟,也是能够由软件挑选时钟源。
Basic Clock Module Registers(根底时钟寄存器)
DCO control register DCOCTL
Basic clock system control 1 BCSCTL1
Basic clock system control 2 BCSCTL2
Basic clock system control 3 BCSCTL3
SFR interrupt enable register 1 IE1
SFR interrupt flag register 1 IFG1
3、MSP430的时钟设置包含3个寄存器,DCOCTL、BCSCTL1、BCSCTL2、BCSCTL3
DCOCTL,DCO操控寄存器,地址为56H,初始值为60H
DCO2 |
DCO1 |
DCO0 |
MOD4 |
MOD3 |
MOD2 |
MOD1 |
MOD0 |
DCO0~DCO2: DCO Select Bit,界说了8种频率之一,而频率由注入直流发生器的电流界说。
MOD0~MOD4: Modulation Bit,频率的微调。
一般不需求DCO的场合坚持默许初始值就行了。
BCSCTL1,Basic Clock System Control 1,地址为57H,初始值为84H
XT2OFF |
XTS |
DIVA1 |
DIVA0 |
XT5V |
RSEL2 |
RSEL1 |
RSEL0 |
RSEL0~RSEL2: 挑选某个内部电阻以决议标称频率.0最低,7最高。
XT5V: 1.
DIVA0~DIVA1:挑选ACLK的分频系数。DIVA=0,1,2,3,ACLK的分频系数别离是1,2,4,8;
XTS: 挑选LFXT1作业在低频晶体方式(XTS=0)仍是高频晶体方式(XTS=1)。
XT2OFF: 操控XT2振荡器的敞开(XT2OFF=0)与封闭(XT2OFF=1)。
正常情况下把XT2OFF复位就能够了.
BCSCTL2,Basic Clock System Control 2,地址为58H,初始值为00H
SEM1 |
SELM0 |
DIVM1 |
DIVM0 |
SELS |
DIVS1 |
DIVS0 |
DCOR |
DCOR: Enable External Resistor. 0,挑选内部电阻;1,挑选外部电阻
DIVS0~DIVS1: DIVS=0,1,2,3对应SMCLK的分频因子为1,2,4,8
SELS: 挑选SMCLK的时钟源, 0:DCOCLK; 1:XT2CLK/LFXTCLK.
DIVM0~1: 挑选MCLK的分频因子, DIVM=0,1,2,3对应分频因子为1,2,4,8.
SELM0~1: 挑选MCLK的时钟源, 0,1:DCOCLK, 2:XT2CLK, 3:LFXT1CLK
我用的时分一般都把SMCLK与MCLK的时钟源挑选为XT2。
其它:
1. LFXT1: 一次有用的PUC信号将使OSCOFF复位,答应LFXT1作业,假如LFXT1信号没有用作SMCLK或MCLK,可软件置OSCOFF封闭LFXT1.
2. XT2: XT2发生XT2CLK时钟信号,假如XT2CLK信号没有用作时钟MCLK和SMCLK,能够经过置XT2OFF封闭XT2,PUC信号后置XT2OFF,即XT2的封闭的。
3. DCO振荡器:振荡器失效时,DCO振荡器会主动被选做MCLK的时钟源。假如DCO信号没有用作SMCLK和MCLK时钟信号时,可置SCG0位封闭DCO直流发生器。
4. 在PUC信号后,由DCOCLK作MCLK的时钟信号,根据需求可将MCLK的时钟源别的设置为LFXT1或XT2,设置次序如下:
(1)清OSCOFF/XT2
(2)清OFIFG
(3)延时等候至少50uS
(4)再次查看OFIFG,假如仍置位,则重复(1)-(4)步,直到OFIFG=0中止。
(5)设置BCSCTL2的相应SELM。
实例剖析
1、CPU运转在VLO时钟下:
这是最慢的时钟,在约12千赫兹下运转。因而,咱们将经过可视化的LED闪耀的赤色慢慢地在约每3秒钟率。咱们能够让时钟体系默许这种状况,设置专门来操作VLO。咱们将不运用任何ALCK外设时钟在此试验室作业,但你应该认识到,ACLK来自VLO时钟。
#include
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // 封闭看门狗定时器
P1DIR = 0x40; // P1.6 装备输出
P1OUT = 0; // 封闭LED
BCSCTL3 |= LFXT1S_2; // LFXT1 = VLO
IFG1&= ~OFIFG; // 铲除OSCFault 标志
__bis_SR_register(SCG1 + SCG0); // 封闭 DCO
BCSCTL2 |= SELM_3 + DIVM_3; // MCLK = VLO/8
while(1)
{
P1OUT = 0x40; // 敞开LED
_delay_cycles(100);
P1OUT = 0; // 封闭 LED
_delay_cycles(5000);
}
}
2、CPU运转在晶振(32768Hz)时钟下:
晶体频率为32768赫兹,约3倍的VLO。假如咱们在前面的代码中运用晶振,指示灯应闪耀大约每秒一次。你知道为什么32768赫兹是一个规范?这是因为这个数字是2的15次方,因而很容易用简略的数字计数电路,以每秒一次取得率 ——手表和其他时刻时基。认识到ACLK来自外部晶振时钟。
#include
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // 封闭看门狗定时器
P1DIR = 0x41; // P1.0 和P1.6装备输出
P1OUT = 0x01; // 敞开P1.0
BCSCTL3 |= LFXT1S_0; // LFXT1 = 32768Hz 晶振
while(IFG1&OFIFG)
{
IFG1&= ~OFIFG; // 铲除 OSCFault 标志
_delay_cycles(100000); // 为可见的标志延时
}
P1OUT = 0; // 封闭P1
__bis_SR_register(SCG1 + SCG0); // 封闭 DCO
BCSCTL2 |= SELM_3 + DIVM_3; // MCLK = 32768/8
while(1)
{
P1OUT = 0x40; // 敞开 LED
_delay_cycles(100);
P1OUT = 0; / / 封闭LED
_delay_cycles(5000);
}
}
3、CPU运转在晶振(32768Hz)和DCO时钟下:
最慢的频率,咱们能够运转DCO约在1MHz(这也是默许速度)。因而,咱们将开端切换MCLK到DCO下。在大多数体系中,你会期望ACLK上运转的VLO或32768赫兹晶振。因为ACLK在咱们现在的代码是在晶体上运转,咱们会翻开DCO核算。
#include
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // 封闭看门狗定时器
if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
{
while(1); // If cal const erased, 挂起
}
BCSCTL1 = CALBC1_1MHZ; // Set range
DCOCTL = CALDCO_1MHZ; //设置DCO方式
P1DIR = 0x41; // P1.0 和P1.6装备输出
P1OUT = 0x01; // P1.0 敞开
BCSCTL3 |= LFXT1S_0; // LFXT1 = 32768Hz
while(IFG1&OFIFG)
{
IFG1&= ~OFIFG; // 铲除OSCFault 标志
_delay_cycles(100000); // 为可见标志延时
}
P1OUT = 0; // P1.6 封闭
// __bis_SR_register(SCG1 + SCG0); // 封闭DCO
BCSCTL2 |= SELM_0 + DIVM_3; // MCLK = DCO
while(1)
{
P1OUT = 0x40; // P1.6 敞开
_delay_cycles(100);
P1OUT = 0; / / P1.6 封闭
_delay_cycles(5000);
}
}
4、CPU运转在DCO时钟下:
最慢的频率,咱们能够运转DCO约在1MHz(这也是默许速度)。因而,咱们将开端切换MCLK到DCO下。在大多数体系中,你会期望在VLO或许是晶振下运转ACLK。因为ACLK在咱们现在的代码是在VLO上运转,咱们会翻开DCO运转。
#include
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // 封闭看门狗定时器
if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
{
while(1); // If cal const erased,挂起
}
BCSCTL1 = CALBC1_1MHZ; // Set range
DCOCTL = CALDCO_1MHZ; // 设置DCO方式
P1DIR = 0x40; // P1.6 装备输出
P1OUT = 0; // P1封闭
BCSCTL3 |= LFXT1S_2; // LFXT1 = VLO
IFG1&= ~OFIFG; // 铲除 OSCFault 标志
//__bis_SR_register(SCG1 + SCG0); // 封闭DCO
BCSCTL2 |= SELM_0 + DIVM_3; // MCLK = DCO/8
while(1)
{
P1OUT = 0x40; // P1.6 封闭
_delay_cycles(100);
P1OUT = 0; // P1.6 敞开
_delay_cycles(5000);
}
}
以下将会剖析上面4个比如的代码细微差别:
首要让咱们看一下msp430x20x2.h这个文件中的内容,因为头文件信息量很大这儿就只简略阐明和以上四个代码有关的部分,其他请咱们自行阅览。
一、WDTCTL = WDTPW + WDTHOLD; // 封闭看门狗定时器(例1、2、3、4)
头文件中的相关阐明如下:
/************************************************************
* WATCHDOG TIMER
************************************************************/
#define __MSP430_HAS_WDT__ /* Definition to show that Module is available */
SFR_16BIT(WDTCTL); /* Watchdog Timer Control */
/* The bit names have been prefixed with “WDT” */
#define WDTIS0 (0x0001)
#define WDTIS1 (0x0002)
#define WDTSSEL (0x0004)
#define WDTCNTCL (0x0008)
#define WDTTMSEL (0x0010)
#define WDTNMI (0x0020)
#define WDTNMIES (0x0040)
#define WDTHOLD (0x0080)
#define WDTPW (0x5A00)
这个指令设置暗码(WDTPW)和中止位定时器(WDTHOLD),一切的WatchDog装备都需求在WDTPW的辅佐下完结。
举例如下:
A、间隔时刻由Bit0-2位编码:
1、看门狗的时钟由FSMCLK(假设为1MHz)
#define WDT_MDLY_32 (WDTPW+WDTTMSEL+WDTCNTCL) /* 32ms interval (default) */
#define WDT_MDLY_8 (WDTPW+WDTTMSEL+WDTCNTCL+WDTIS0) /* 8ms ” */
#define WDT_MDLY_0_5 (WDTPW+WDTTMSEL+WDTCNTCL+WDTIS1) /* 0.5ms ” */
#define WDT_MDLY_0_064 (WDTPW+WDTTMSEL+WDTCNTCL+WDTIS1+WDTIS0) /* 0.064ms ” */
2、看门狗的时钟由FACLK(假设为32KHz)
#define WDT_ADLY_1000 (WDTPW+WDTTMSEL+WDTCNTCL+WDTSSEL) /* 1000ms ” */
#define WDT_ADLY_250 (WDTPW+WDTTMSEL+WDTCNTCL+WDTSSEL+WDTIS0) /* 250ms ” */
#define WDT_ADLY_16 (WDTPW+WDTTMSEL+WDTCNTCL+WDTSSEL+WDTIS1) /* 16ms ” */
B、看门狗方式——在过期时刻后重启:
1、看门狗的时钟由FSMCLK(假设为1MHz)
#define WDT_MRST_32 (WDTPW+WDTCNTCL) /* 32ms interval (default) */
#define WDT_MRST_8 (WDTPW+WDTCNTCL+WDTIS0) /* 8ms ” */
#define WDT_MRST_0_5 (WDTPW+WDTCNTCL+WDTIS1) /* 0.5ms ” */
#define WDT_MRST_0_064 (WDTPW+WDTCNTCL+WDTIS1+WDTIS0) /* 0.064ms ” */
2、看门狗的时钟由FACLK(假设为32KHz)
#define WDT_ARST_1000 (WDTPW+WDTCNTCL+WDTSSEL) /* 1000ms ” */
#define WDT_ARST_250 (WDTPW+WDTCNTCL+WDTSSEL+WDTIS0) /* 250ms ” */
#define WDT_ARST_16 (WDTPW+WDTCNTCL+WDTSSEL+WDTIS1) /* 16ms ” */
#define WDT_ARST_1_9 (WDTPW+WDTCNTCL+WDTSSEL+WDTIS1+WDTIS0) /* 1.9ms ” */
二、P1DIR = 0x40; // P1.6 装备输出
P1OUT = 0; // P1封闭 (例1、2、3、4)
其间DIR 和P1OUT别离装备IO口的方向和输出值,这儿不在赘述,请参考手册。
三、BCSCTL3 |= LFXT1S_2; // LFXT1 = VLO (例1和例4)
BCSCTL3 |= LFXT1S_0; // LFXT1 = 32768Hz (例2和例3)
/************************************************************
* Basic Clock Module
************************************************************/
#define __MSP430_HAS_BC2__
/* Definition to show that Module is available */
SFR_8BIT(DCOCTL); /* DCO Clock Frequency Control */
SFR_8BIT(BCSCTL1); /* Basic Clock System Control 1 */
SFR_8BIT(BCSCTL2); /* Basic Clock System Control 2 */
SFR_8BIT(BCSCTL3); /* Basic Clock System Control 3 */
#define MOD0 (0x01) /* Modulation Bit 0 */
#define MOD1 (0x02) /* Modulation Bit 1 */
#define MOD2 (0x04) /* Modulation Bit 2 */
#define MOD3 (0x08) /* Modulation Bit 3 */
#define MOD4 (0x10) /* Modulation Bit 4 */
#define DCO0 (0x20) /* DCO Select Bit 0 */
#define DCO1 (0x40) /* DCO Select Bit 1 */
#define DCO2 (0x80) /* DCO Select Bit 2 */
#define LFXT1OF (0x01)
/* Low/high Frequency Oscillator Fault Flag */
#define XT2OF (0x02)
/* High frequency oscillator 2 fault flag */
#define XCAP0 (0x04) /* XIN/XOUT Cap 0 */
#define XCAP1 (0x08) /* XIN/XOUT Cap 1 */
#define LFXT1S0 (0x10) /* Mode 0 for LFXT1 (XTS = 0) */
#define LFXT1S1 (0x20) /* Mode 1 for LFXT1 (XTS = 0) */
#define XT2S0 (0x40) /* Mode 0 for XT2 */
#define XT2S1 (0x80) /* Mode 1 for XT2 */
#define XCAP_0 (0x00) /* XIN/XOUT Cap : 0 pF */
#define XCAP_1 (0x04) /* XIN/XOUT Cap : 6 pF */
#define XCAP_2 (0x08) /* XIN/XOUT Cap : 10 pF */
#define XCAP_3 (0x0C) /* XIN/XOUT Cap : 12.5 pF */
#define LFXT1S_0 (0x00)
/* Mode 0 for LFXT1 : Normal operation */
#define LFXT1S_1 (0x10) /* Mode 1 for LFXT1 : Reserved */
#define LFXT1S_2 (0x20) /* Mode 2 for LFXT1 : VLO */
#define LFXT1S_3 (0x30)
/* Mode 3 for LFXT1 : Digital input signal */
#define XT2S_0 (0x00) /* Mode 0 for XT2 : 0.4 – 1 MHz */
#define XT2S_1 (0x40) /* Mode 1 for XT2 : 1 – 4 MHz */
#define XT2S_2 (0x80) /* Mode 2 for XT2 : 2 – 16 MHz */
#define XT2S_3 (0xC0)
/* Mode 3 for XT2 : Digital input signal */
四、__bis_SR_register(SCG1 + SCG0); // 封闭 DCO
__bis_SR_register()是在intrinsics.h这个头文件中界说了,完成的功用是将SR中的方位零。
关于头文件中的代码效果
#ifdef __cplusplus
extern “C”
{
#endif
#ifdef __cplusplus
}
#endif /* extern “C” */
一般用于将C++代码以规范C方式输出(即以C的方式被调用),这是因为C++尽管常被以为是C的超集,可是C++的编译器仍是与C的编译器不同的。C中调用C++中的代码这样界说会是安全的。
五、BCSCTL2 |= SELM_3 + DIVM_3; // MCLK = VLO/8
BCSCTL2 |= SELM_3 + DIVM_3; // MCLK = 32768/8
BCSCTL2 |= SELM_0 + DIVM_3; // MCLK = DCO
BCSCTL2 |= SELM_0 + DIVM_3; // MCLK = DCO/8
MSP430中有如下界说:
#define RSEL0 (0x01) /* Range Select Bit 0 */
#define RSEL1 (0x02) /* Range Select Bit 1 */
#define RSEL2 (0x04) /* Range Select Bit 2 */
#define RSEL3 (0x08) /* Range Select Bit 3 */
#define DIVA0 (0x10) /* ACLK Divider 0 */
#define DIVA1 (0x20) /* ACLK Divider 1 */
#define XTS (0x40)
/* LFXTCLK 0:Low Freq. / 1: High Freq. */
#define XT2OFF (0x80) /* Enable XT2CLK */
#define DIVA_0 (0x00) /* ACLK Divider 0: /1 */
#define DIVA_1 (0x10) /* ACLK Divider 1: /2 */
#define DIVA_2 (0x20) /* ACLK Divider 2: /4 */
#define DIVA_3 (0x30) /* ACLK Divider 3: /8 */
#define DIVS0 (0x02) /* SMCLK Divider 0 */
#define DIVS1 (0x04) /* SMCLK Divider 1 */
#define SELS (0x08)
/* SMCLK Source Select 0:DCOCLK / 1:XT2CLK/LFXTCLK */
#define DIVM0 (0x10) /* MCLK Divider 0 */
#define DIVM1 (0x20) /* MCLK Divider 1 */
#define SELM0 (0x40) /* MCLK Source Select 0 */
#define SELM1 (0x80) /* MCLK Source Select 1 */
#define DIVS_0 (0x00) /* SMCLK Divider 0: /1 */
#define DIVS_1 (0x02) /* SMCLK Divider 1: /2 */
#define DIVS_2 (0x04) /* SMCLK Divider 2: /4 */
#define DIVS_3 (0x06) /* SMCLK Divider 3: /8 */
#define DIVM_0 (0x00) /* MCLK Divider 0: /1 */
#define DIVM_1 (0x10) /* MCLK Divider 1: /2 */
#define DIVM_2 (0x20) /* MCLK Divider 2: /4 */
#define DIVM_3 (0x30) /* MCLK Divider 3: /8 */
#define SELM_0 (0x00) /* MCLK Source Select 0: DCOCLK */
#define SELM_1 (0x40) /* MCLK Source Select 1: DCOCLK */
#define SELM_2 (0x80)
/* MCLK Source Select 2: XT2CLK/LFXTCLK */
#define SELM_3 (0xC0)
/* MCLK Source Select 3: LFXTCLK */
六、BCSCTL1 = CALBC1_1MHZ; //设置值 (例3、4)
#ifndef __DisableCalData
SFR_8BIT(CALDCO_16MHZ); /* DCOCTL Calibration Data for 16MHz */
SFR_8BIT(CALBC1_16MHZ); /* BCSCTL1 Calibration Data for 16MHz */
SFR_8BIT(CALDCO_12MHZ); /* DCOCTL Calibration Data for 12MHz */
SFR_8BIT(CALBC1_12MHZ); /* BCSCTL1 Calibration Data for 12MHz */
SFR_8BIT(CALDCO_8MHZ); /* DCOCTL Calibration Data for 8MHz */
SFR_8BIT(CALBC1_8MHZ); /* BCSCTL1 Calibration Data for 8MHz */
SFR_8BIT(CALDCO_1MHZ); /* DCOCTL Calibration Data for 1MHz */
SFR_8BIT(CALBC1_1MHZ); /* BCSCTL1 Calibration Data for 1MHz */
#endif /* #ifndef __DisableCalData */
关于SFR_8BIT的相关阐明:
External references resolved by a device-specific linker command file
(外部引证处理的特定于设备的连接器指令文件)
#define SFR_8BIT(address) extern volatile unsigned char address
#define SFR_16BIT(address) extern volatile unsigned int address
七、if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
{
while(1); // If cal const erased,挂起
} (例3、例4)
请注意这儿的圈套。它能够铲除内存段信息。
八、IFG1&= ~OFIFG; // 铲除OSCFault 标志 (例1、例4)
时钟体系将强制运用的MCLK作为其源的DCO在一个时钟毛病的存在。因而,咱们有必要铲除毛病标志。
FG1中止标志寄存器是1。寄存器中的位域是仅有的振荡器毛病中止标志 – OFIFG。
九、while(IFG1&OFIFG)
{
IFG1&= ~OFIFG; // 铲除OSCFault 标志
_delay_cycles(100000); // 为可见标志延时
} (例2、例3)
在上面的代码咱们把OSCFault标志持续做咱们的使命,因为时钟体系将默许为VLO。现在,咱们期望保证该标志坚持清零,这意味着晶体是发动并运转着的。
假如该毛病标志是清晰的,咱们就退出循环。咱们需求等候清算后的标志,直到咱们再次测验50微秒。该_delay_cycles(100000)。咱们需求它是那么长的时刻,所以咱们能够看到在代码最初的LED灯。不然,它会这么快,咱们的光将无法看到它。
装备:
BCSCTL1 |
BCSCTL2 |
BCSCTL3 |
DCOCTL |
IFG1 |
|
VLO(12KHz) |
SELM_3 + DIVM_3 |
LFXT1S_2 |
|||
32768KHz |
SELM_3 + DIVM_3 |
LFXT1S_0 |
While |
||
晶振、DCO |
SELM_0+ DIVM_3 |
LFXT1S_0 |
While |
||
DCO |
CALBC1_1MHZ |
SELM_0+ DIVM_3 |
LFXT1S_2 |
CALDCO_1MHZ |
成果:
ACLK |
MCLK |
LFXT1 |
|
VLO(12KHz) |
VLO |
VLO/8 |
VLO |
32768Hz |
32768Hz |
32768Hz/8 |
32768Hz |
晶振、DCO |
32768Hz |
DCO |
32768Hz |
DCO |
VLO |
DCO/8 |
VLO |
首要声明一下我也是才刚刚开端触摸MSP430的片子,算是和咱们一同学习吧,许多当地也不是很清楚。总归期望咱们好好领会一下MSP430的头文件(名为:msp430x20x2.h),假如文章中有过错的话期望咱们发邮件给我。纯属菜鸟入门等级文档,仅仅简略的剖析了一下MSP430的时钟装备问题,关于一个单片机体系而言时钟可谓是重中之重,或许刚入门多是选用51系列的片子(不包含C8051f系列)所以对时钟也就没有过多的触摸,仅仅触及速度以及延时程序的时分才会去关怀。其实芯片越是高端越是对时钟有很高的要求,不管是PIC、AVR仍是C8051F这些8位的片子,在32位的范畴更是这样,像我所了解的Cortex-M3系列包含STM32f103、Stellaris、NXP都是这样,片子内部的时钟都是适当的杂乱。
最终在来啰嗦几句,记住曾经玩51的时分那个头文件真是小儿科,只要寄存器的界说还有一些位操作。程序写起来适当的费事,许多东西都需求去回忆或许爽性去看文档,所以那个时分还特别写了一个驱动库(仿效STM32f103给STC12C5A60S2写的,取名为Easy Hw OS,其实仍是很便利的直接调用函数就能够啦),看到430的头文件才恍然大悟,这样做好,尽管没有驱动库便利可是很灵敏也不需求去回忆那些寄存器的,真的很不错。喜爱上了430为文以记之。