在进行MSP430单片机的编程时,时钟的运用很重要,MSP430一共有5个时钟源,分别是外接的XT1和XT2时钟源,介绍如下:
1.XT1CLK:低频/高频振荡器,我的MSP430F5336使用的就是32768HZ的晶振
2.VLOCLK:内部超低功耗低低频振荡器,典型频率是12khz;
3.REFOCLK:内部调整低频参考振荡器,典型值为32768hz;
4.DCOCLK:内部数字时钟振荡器,可由FLL稳定后得到;
5.XT2CLK:高频外界振荡器,我F5336接的是20MHZ晶振;
以上五个时钟大家可以理解为晶振,有的是内部自带的,如2,3,4,这三个,有的是外接自己设计的,如XT1和XT2,当我们需要用单片机处理一些高速计算时,例如做图像处理或者一些迭代计算,此时要求计算速度比较高,所以可以选用外界的XT2或者DCOCLK调整后得到。如果你需要精确定时或者计时,可以使用REFOCLK或者VLOCLK,因为他们频率较为稳定,计时精确。用的比较多的是32768HZ的频率。DCOCLK的调整比较灵活,有专门的锁频环公式,在datasheet上可以找到DCO频率的设置条件表格,可以根据它直接调整出适合的频率。
但是MSP430的时钟调用却没有那么简单,你可以想象时钟设计为做菜,上面的五个时钟只是五种最基本的食材,通过寄存器的一些特殊调用,可以利用上面的时钟源做出三道菜,分别是ACLK辅助时钟,MCLK主时钟,SMCLK子系统时钟,而我们编程所用的时钟源(也就是我们要吃的菜),是这三种时钟提供的。所以举个栗子说,我需要一个32768hz的时钟来精确定时,同时需要一个1.2M或者的时钟来控制串口通信的波特率,同时我希望我的MCU频率可以到20M,这样我恶意设置MCLK=20Mhz(MCLK时钟是系统时钟),设置ACLK时钟为32768HZ,时钟计时是我选用ACLK为时钟源,设置SMCLK时钟为1.2Mhz,串口通信时选择时钟源为SMCLK,但是我们如何使ACLK为32768hz,使MCLK为20Mhz,使SMCLK为1.2M呢,这就是通过调配这三个时钟的原料为上面的五种不同晶振。所以实际上我们在程序中一旦定下了ACLK,MCLK,SMCLK的频率,之后基本都不用管之前的5个晶振,因为都是和这三个时钟打交道。而时钟的控制一般写成一个初始化函数,在程序中调用一次就可以了。刚刚开始接触时很容易搞不清楚时钟,觉得很复杂,其实弄清楚原理还是很简单的。
现在我用一些程序来说明时钟的用法,以下我看到的一份MSP430G2553的时钟程序库,进行了一些修改,其中的函数功能等均有注释,至于那样设置的原理可以看UserGuide的寄存器说明,里面一些特定的寄存器的位代表了一些信息,例如分频系数,时钟源等等,大家可以自己参考用户手册一句一句翻译对照,相信很快能弄懂时钟的设定原理:
/*******************************************************************************************
**********************************************************************************************/
#include
/*DCOCTL 寄存器*/
/********************************************************************************
* bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
* DCO.2 CCO.1 DCO.0 MOD.4 MOD.3 MOD.2 MOD.1 MOD.0
* DCO.0——DCO.2定义8种频率之一,可分段调节DCOCLK频率,相邻两种频率相差10%。
* 而频率由注入直流发生器的电流定义。
* MOD.O——MOD.4定义在32个DCO周期中插入的fdco+l周期个数,而在余下的DCO周期
* 中为fDco周期,控制切换DCO和DCO+1选择的两种频率。如果DCO常数为7,表示已
* 经选择最高颂率,此时不能利用MOD.O-MOD.4进行频率调整。
* ********************************************************************************/
/*BCSCTL1 寄存器*/
/**********************************************************************************
* bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
* XT2OFF XTS DIVA.1 DIVA.0 XT5V Rse1.2 Rse1.1 Rse1.0
*XT2OFF控制 XT2 振荡器的开启与关闭。
*XT2OFF=0,XT2振荡器开启;
*XT2OFF=1,XT2振疡器关闭(默认XT2关闭)。
*XTS控制 LFXTl 工作模武,选择需结合实际晶体振荡器连接情况。
*XTS=0,LFXTl工作在低频模式 (默认低频模式);
*XTS=1,LFXTl工作在高频模式(必须连接有相应高频时钟源)。
*DIVA.0,DIVA.l控制ACLK分频。
*0 不分频(默认不分频);
*1 2分频;
*2 4分频;
*3 8分频。
*XT5V此位设置为0。
*Rse1.0,Rsel.l,Rse1.2三位控制某个内部电阻以决定标称频率。
*Rse1=0,选择最低的频率;
*Rse1=7,选择最低的标称频率;
***********************************************************************************/
/*BCSCTL2 寄存器*/
/***********************************************************************************
* bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
*SELM.1 SELM.0 DIVM.1 DIVM.0 SELS DIVS.1 DIVS.0 DCOR
*SELM.1,SELM.0选择 MCLK 时钟源。
*0 时钟源为 DCOLCK(默认时钟源);
*1 时钟源为DCOCLK ;
*2 时钟源为LFXTlCLK;
*3 时钟源为 LFXT1CLK 。
*DIVM.1,DlVM.0选择 MCLK 分频。
*0 1分频(默认MCLK=DCOCLK);
*1 2分频;
*2 4分频;
*3 8分频。
*DIVS.1,DIVS.0选择 SMCLK 分频。
*0 1分频(默认 SMCLK=MCLK);
*1 2分频;
*2 4分频;
*3 8分频。
************************************************************************************/
/*BCSCTL3 寄存器*/
/************************************************************************************
* bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
* XT2S1 XT2S0 LFXT1S1 LFXT1S0 XCAP1 XCAP0 XT2OF LFXT1OF
* XT2S1和XT2S0(2553不支持)
* LFXT1S1和LFXT1S0选择LFXT1的范围。
* XCAP1和XCAP0选择LFXT1的匹配电容
* 00 1pf
* 01 6pf
* 10 10pf
* 11 12.5pf
************************************************************************************/
/****************************************************************************************
* 静态函数声明
********************************************************************/
static void DcoClkSet(unsigned char x,unsigned char y); //msp430g2553datasheet P30
static void MClkSet(unsigned char Div);
static void SMClkSet(unsigned char Div);
static void AClkSet(unsigned char Div);
/************************************************************************
* 函数名 : DcoClkSet
* 函数功能 : 对时钟DCOCLK进行配置
* 函数形参 : 传入的形参为x和y,其值参考2553datsheet第28页中DCO频率表
* 函数返回值 : 无
************************************************************************/
void DcoClkSet(unsigned char x,unsigned char y) // msp430g2553datasheet P30
{
DCOCTL &=~( 0xFF);
BCSCTL1 &=~( 0xFF);
unsigned char temp=(x<<4)+y;
switch(temp){
case 0x00: {
DCOCTL &=~( DCO0 + DCO1 + DCO2);
BCSCTL1 &=~( RSEL0 + RSEL1 + RSEL2 + RSEL3);
break;
}
case 0x03: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 &=~( RSEL0 + RSEL1 + RSEL2 + RSEL3);
break;
}
case 0x13: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL0 );
break;
}
case 0x23: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL1 );
break;
}
case 0x33: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL0 + RSEL1 );
break;
}
case 0x43: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL2);
break;
}
case 0x53: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL0 + RSEL2 );
break;
}
case 0x63: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL1 + RSEL2 );
break;
}
case 0x73: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL0 + RSEL1 + RSEL2 );
break;
}
case 0x83: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL3);
break;
}
case 0x93: {