MSP430时钟和定时器

电赛用到了MSP430,编程和51差不太多,都是对寄存器的操作,但是它的内部资源还是比51要丰富的多,这里对它的时钟和定时器进行总结一下。

使用的芯片型号是msp430g2553,扩展板为Launchpad

1、时钟部分

1.1 编译环境

首先说一下该款单片机常用的编译环境。一是CCS,还有一个就是IAR,我使用的是后者。软件的操作在百度上面一搜就是一大堆,所以只是简单提及一下。

1.2 MSP430时钟源

MSP430基础时钟模块包含了三个时钟输入源:
1、LFXT1CLK:可接高速和低速晶振,在低速模式下,它可以外接32k的晶振而不需要负载电容,这种方式较为常见主要用来为ACLK提供低速的时钟信号,以供低速外设使用。高频模式:400kHz~16Mhz
2、DOCCLk:内部数字控制振荡器,它的频率可以通过DCOCLK进行配置。(上电复位后默认0.8~1.5Mhz)
3、XT2CLk:高速振荡器,它可以接一个0.4~16M的晶振,它相当于高速模式下的LFXT1。通常将它配置成一个高速的振荡源,为MCLK何SMCLK提供高速时钟信号。

至此,咱知道了该单片机的每一个时钟输入源产生的信号大小,那么,这些时钟源是由哪些寄存器控制,又是如何输出时钟信号的呢。

1.3 控制时钟源的寄存器

1、BCSCTL1:控制XT2,LFXT1,DCO震荡,并控制ACLK的分频情况。
2、DCOCTL:控制DCO振荡器
3、BCSCTL2:设置三个时钟源分别选择什么振荡器

1.4 时钟信号

MSP430单片机工作所需时钟信号是由1.2中的时振荡器振荡后经过1.3中的寄存器配置后产生的,三个时钟信号分别为:
1、ACLK:由LFXT1CLK信号经过1/2/4/8分频后得到的,主要用作低速外围的时钟
2、MCLK:是LFXT1CLK,XT2CLK,DCOCLK的三者之一决定,由软件选择,然后经1/2/4/8分频后得到,主要用于CPU和系统。
3、SMCLK:可由LFXT1CLK和DCOCLK,或者XT2CLK与DCOCLK决定,然后经1/2/4/8分频后得到,主要用于高速外围模块。
时钟信号时如何产生的,可以从下面这张图简单了解:

时钟图

1.5 相关代码

这儿贴一部分配置时钟信号的代码:
sys.h

1
2
3
4
5
6
7
8
#ifndef  SYSCLK_H
#define SYSCLK_H

#include "msp430g2553.h"

void BCSplus_init(unsigned char Freq);

#endif

sys.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include"sysclk.h"

void BCSplus_init(unsigned char Freq)
{
BCSCTL2 = SELM_0 + DIVM_0 + DIVS_0;//时钟控制器,MCLK时钟源DCO,0分频,SMCLK时钟源DCO,0分频
switch(Freq)
{
//DCOCTL:DCO控制 BCSCTL1:基本时钟控制寄存器1
case 1: DCOCTL = CALDCO_1MHZ; BCSCTL1 = CALBC1_1MHZ; break;
case 8: DCOCTL = CALDCO_8MHZ; BCSCTL1 = CALBC1_8MHZ; break;
case 12: DCOCTL = CALDCO_12MHZ; BCSCTL1 = CALBC1_12MHZ; break;
case 16: DCOCTL = CALDCO_16MHZ; BCSCTL1 = CALBC1_16MHZ; break;
default: break;
}
BCSCTL3 = XT2S_0 + LFXT1S_2 + XCAP_1;//LFXT1选择VLOCLK,晶振电容1pf
}

2、定时器部分

2.1 Timer_A模块

MSP430中的Timer_A定时器包括一个16位定时器和三个捕获/比较模块,整体构造如下图所示:

Timer_A 功能框图

Timer_A 功能框图

2.2 相关代码

因为与定时器有关部分的介绍都是大同小异的,包括寄存器和功能,所以这里直接贴一份配置pwm的代码和一份定时60s的代码。

2.2.1 PWM

设置周期20ms,占空比为2m,也就是10%的pwm。首先是主函数中设置时钟频率,根据上面时钟部分的代码设置即可,这里我把MCLK和SMCLK设置的都是1Mhz,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
> #define T1 2000
> #define pwm1 200
>
> void main( void )
{
WDTCTL = WDTPW + WDTHOLD; //关看门狗
BCSplus_init(1);//MCLK和SMCLK都是1Mhz
Timer1_Init();
while(1)
}

//定时器A1初始化
void Timer1_Init()
{
/*时钟源:SMCLK;
时钟分频系数:1;
PWM:普通pwm 增计数
:增计数清零
*/
TA1CTL = TASSEL_2 +ID_0+MC_1+TACLR;
TA1CCR0 =T1; //周期
TA1CCR1=PWM1; //通道1占空比
TA1CCTL1=OUTMOD_7;//主定时器模式7 输出pwm
TA1CCR2=PWM1; //通道2占空比
TA1CCTL2=OUTMOD_7;//主定时器模式7 输出pwm
P2DIR |=BIT4+BIT2; //输出 TA1.1和TA1.2
P2SEL |=BIT4+BIT2; //TIM复用为PA2.2 PA2.4
}
>

简单讲解一下上面的代码:
首先是对应的IO关系,P2.2和P2.4可以复用为timer1比较/捕获的输出输入口。输出pwm时,其中TAxCCR0一般是用来设定周期,而TAxCCR1和TAxCCR2用于设定占空比。TAxCTL寄存器,用来设置该定时器的时钟源、分频系数、捕获还是比较模式、计数模式等
然后是IO的操作,PxDIR设置IO口输入还是输出,PxSEL设置IO的复用

2.2.2 定时60s

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

#define uint unsigned int
#define T0 60000
uint flag = 0;
//定时器A01初始化
void Timer0_Init()
{
/*时钟源:SMCLK;
时钟分频系数:8;
PWM:普通pwm 增计数
:增计数清零
*/
TA0CTL = TASSEL_2 +ID_3+MC_1+TACLR;
TA0CCR0 =T0-1; //达到60ms溢出
TA0CCTL0 = CCIE;//TA0CCR0定时器使能
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void TimerA0(void)

{
k = k+1;
if(k==125) //60ms
{
flag=1;
TA0CTL = MC_0;//暂停计数
k = 0;
}
}

void main( void )
{
WDTCTL = WDTPW + WDTHOLD; //关看门狗
BCSplus_init(1);//MCLK和SMCLK都是1Mhz
Timer0_Init() ;
__enable_interrupt(); //使能总中断

while(1)
{
if(flag2==1)
{
...
}
}
}

emmmm,这部分的话和上面差不太多,看注释的话应该可以理解。因为这次电赛做的是无线充电循迹车,所以没啥太难得地方,全部代码我上传到github上去了,如果有兴趣可以下载看一下。(小声bb,传的时候传错了,懒得删,所以又传了一份压缩包,这个压缩包才是正确的代码)