概述:
本实验的目的是了解用于执行对MSP430 Value Line设备的初始化过程的步骤。在这个练习中,您将编写初始化代码,并运行该设备使用各种时钟资源。
1、写初始化代码
2、运行CPU的MCLK的来源方式:VLO 、32768晶体、DCO
3、主体程序部分
4、观察LED闪光灯速度
工具/原料
-
MSP430g2xx
-
IAR Embedded Workbench For MSP430 5.2
-
MSP-EXP430G2 LaunchPad 实验板用户指南
-
MSP-EXP430G2 LaunchPad Experimenter Board User's Guide
-
MSP-EXP430G2 LaunchPad Quick Start Guide
步骤/方法
时钟介绍:
-
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
Basic clock system control 1
Basic clock system control 2
Basic clock system control 3
SFR interrupt enable register 1
SFR interrupt flag register 1
-
3、MSP430的时钟设置包括3个寄存器,DCOCTL、BCSCTL1、BCSCTL2、BCSCTL3
DCOCTL,DCO控制寄存器,地址为56H,初始值为60HDCO2
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 <msp430g2231.h>
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; 关闭看门狗定时器
P1DIR = 0x40; 配置输出
P1OUT = 0; 关闭LED
BCSCTL3 |= LFXT1S_2;
IFG1 &= ~OFIFG;清除OSCFault 标志
__bis_SR_register(SCG1 + SCG0);关闭 DCO
BCSCTL2 |= SELM_3 + DIVM_3;
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 <msp430g2231.h>
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; 关闭看门狗定时器
P1DIR = 0x41;和P1.6配置输出
P1OUT = 0x01;开启P1.0
BCSCTL3 |= LFXT1S_0; 晶振
while(IFG1 & OFIFG)
{
IFG1 &= ~OFIFG; 清除 OSCFault 标志
_delay_cycles(100000); 为可见的标志延时
}
P1OUT = 0;关闭P1
__bis_SR_register(SCG1 + SCG0); 关闭 DCO
BCSCTL2 |= SELM_3 + DIVM_3;
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 <msp430g2231.h>
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; 关闭看门狗定时器
if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
{
while(1); 挂起
}
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ; 设置DCO模式
P1DIR = 0x41;和P1.6配置输出
P1OUT = 0x01; 开启
BCSCTL3 |= LFXT1S_0;
while(IFG1 & OFIFG)
{
IFG1 &= ~OFIFG; 清除OSCFault 标志
_delay_cycles(100000); 为可见标志延时
}
P1OUT = 0; 关闭
// __bis_SR_register(SCG1 + SCG0); 关闭DCO
BCSCTL2 |= SELM_0 + DIVM_3;
while(1)
{
P1OUT = 0x40; 开启
_delay_cycles(100);
P1OUT = 0; 关闭
_delay_cycles(5000);
}
}
-
4、CPU运行在DCO时钟下:
最慢的频率,我们可以运行DCO约在1MHz(这也是默认速度)。因此,我们将开始切换MCLK到DCO下。在大多数系统中,你会希望在VLO或者是晶振下运行ACLK。由于ACLK在我们目前的代码是在VLO上运行,我们会打开DCO运行。
#include <msp430g2231.h>
void main(void)
{
WDTCTL = WDTPW + WDTHOLD;关闭看门狗定时器
if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
{
while(1); 挂起
}
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ; 设置DCO模式
P1DIR = 0x40; 配置输出
P1OUT = 0; 关闭
BCSCTL3 |= LFXT1S_2;
IFG1 &= ~OFIFG;清除 OSCFault 标志
//__bis_SR_register(SCG1 + SCG0); 关闭DCO
BCSCTL2 |= SELM_0 + DIVM_3;
while(1)
{
P1OUT = 0x40; 关闭
_delay_cycles(100);
P1OUT = 0; 开启
_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灯。否则,它会这么快,我们的光将无法看到它。 -