【MSP430趣谈】MSP430第八讲之时钟设置

写到现在已经是第八讲了,希望大家多多支持。可能我的行文风格和我们的标题不大符合,趣谈,对吧。但是希望能够仔细的讲到每一点,让所有初学者能够明白。如果大家有不懂的地方也麻烦留言一下,也有帮助我补充和完善这个教程。

其实大家入门了之后会发现你精通了一个你再去学习其他的也都很好理解,但是这其中希望大家能够坚持从0走到1,这一步是最难的,因为从数学上讲,从0到1的增长倍数是无穷倍,而之后从1到2也最多是一倍了,所以希望大家在从零到一这个过程中能够坚持下来。

我这里大概分享一下我的学习经历吧,一开始从51开始,因为没有人督促,也没有实际项目,所以前前后后学了一个学期的那种情况,就是看了前面几个部分,看到难的放弃了,一两个礼拜甚至一个月之后再返回来在从第一页开始看的那种状态,中间还转去看了430的使用,当时觉得太难了,什么资料都是英文的,参考资料也少,遇到问题也基本百度不到答案,再加上CCS编译器不是那么人性化,真的很难,不过中间也锻炼了我去找资料的能力。之后我们用51做了一个平衡杆小车的项目,才算是真正意义上的运用了单片机,之后也就慢慢的步入单片机学习的正规,到后来的STM32等等。32我也没有全部学完,因为我觉得没有必要,因为到那个时候你已经具备了一定的学习能力,当你需要用到它的某个功能时你再去学习就可以了,全部都学当然也有好处,还是要自己能不能坚持下去。后期我们可能也会进行一些相关的活动大家一起做一些项目,来帮助大家更好的运用430.

所以我的建议是大家对于单片机的基本通用模块你需要在入门的时候学习,包括基本的IO控制,时钟配置,定时器配置,一些比较常用的通信协议IIC、UART、SPI等等这些要懂,其他的相对而言都是属于扩展的模块,可以在需要的时候在去学习也可以。

还有很重要一点就是要形成自己的学习方法,这样子当你再去接触一个新事物的时候才能够让你很快就上手,我觉得这一点是非常重要的。

好了废话讲了一堆,我们现在正式进入新的一讲,在前面我们说到时钟配置是十分重要的,但是上次我们用的是图形化的配置方式,那么如果其他的单片机没有这种配置方式怎么办?这次我们来讲一下运用库函数和运用寄存器配置的方式来给大家说明一下该如何正确配置这些时钟。

在这里说明一下我之后会说明的库函数文件和数据手册。

库函数参考手册:MSP430FR58xx, MSP430FR59xx, MSP430FR68xx, and MSP430FR69xx Family User's Guide.pdf

数据手册:MSP430FR5xx_6xx_DriverLib_Users_Guide-2_21_00_08.pdf

这两份文档应该是最经常用的了。

推荐大家之后在学习其他单片机的时候也可以养成这样学习方式,当时只是建议你参考这种方式,写程序的时候把这两份文档开在旁边随时查阅。当然这个也看个人习惯了哈。

我们看到在Clock System这个章节中有这些宏定义方便我们后期的调用,下面就是相关的函数了。这个有点太多了,我们没有办法一个一个去讲,我们就一边用一边讲好了。

所先我们需要使用到这个函数,关于具体如何找到每一个函数中的参量改填什么相信大家通过上次说的也应该都有所了解了我们也就不在过多的描述了,所以我们这里就直接写了,但是我会加上很详细的注释。

我们详细阅读数据手册中的可以看到当中有一个词汇:Bypass mode,这里我谈谈我的理解,在百度百科中我们看到旁路模式的解释是一个系统中遇到一个短时间没有办法解决的绕过该问题的一个机制。而在430这边的话按照我的个人理解的话应该就是可以进行选择的,我们可以配置为单片机内部的时钟源也可以选择我们外部的时钟源,当我们选择外部的这些时钟源的时候就是所谓的“Bypass mode”。可能这个说法还是有点欠缺正确性,希望大家帮忙指正,具体大家以数据手册为准。

好了现在我们看下如何利用库函数进行配置。

所先我们设置一下DCO的频率,使用下面这个函数,通过他的说明我们可以很明显知道他的使用方法以及我们可以设置的频率,我们设置DCO为1MHz的频率。

代码如下:

//设置内部DCO频率为1MHz

CS_setDCOFreq(CS_DCORSEL_0,CS_DCOFSEL_0);

这里配置的时候要格外小心,因为两个参数何其相似,中间仅仅相差了一个字母,一个是R,另外一个是F,一定不能大意。

//设置我们的SMCLK时钟源为来自DCO,其他的时钟我们都默认不改变                  CS_initClockSignal(CS_SMCLK,CS_DCOCLK_SELECT,CS_CLOCK_DIVIDER_1);

也就是简单的两句话,我们设置了内部DCO的频率和SMCLK的时钟,这个DCO频率是由厂家进行出厂校正过的,频率也相对较为准确,只要我们不需要用到非常精准的时间,这个内置的DCO频率都是可以满足我们日常使用的,但是如果需要说做具体的时间计算,就需要使用外部晶振,或者说使用时钟芯片。

接下来的代码和我们上次的一样。配置定时器,使能中断。在中断中翻转LED的状态。

我们这里的设置的SMCLK的时钟。因为我们在定时器上面选择的输入也是这个时钟来源,我们还进行了20分频,所以最终定时器得到的是100K的计数频率,那么我们得到定时器计数一次是20us,如果我们要设置成1S闪烁一次的话,那么我们就是要计数50000次,两者相乘得到的就是1s中的时间,所以我们最终定时器的配置如下,

好了,大概的时钟配置就是这样了,想要自定义的配置时钟频率,可以根据我们的需要进行修改,相信大家如果懂得了之前的方法对后面根据自己的需求进行改进也是能够得心应手的。

不过这个表格还是很重要的,就是我们的430时钟构造的那个图。

在时钟的选择上面,我们在CS的配置函数中的参量选择也可以进行查看,430的时钟系统还是相对复杂一点的,这一点和他的低功耗有一定的关系,我们之前也有说到,可以通过关闭一些没有必要的时钟来节约功耗,这里我们暂时不介绍。

时钟还是非常重要的,希望大家可以多多再去看看。这里我们就暂时说到这里,之后我们还会接触这个的。

下面我们给出我们工程代码如何编写成利用寄存器方式实现的。

这里给一个小插曲,我们来看一下如何查看TI官方给的参考例程,之前我们安装过了MSP430Ware,如果不知道怎么安装的,就去看下前面的几讲我们有说到具体的安装方法,我们在这里就不在说明了。

首先我们找到view下面的Resource explorer

得到下面的界面:

接下来我们找到:

在其中找到我们的单片机对应的型号:

就可以得到右边的代码列表了:

在这里给出了很多的参考例程,单击它我们可以得到下面这个窗口,选择好我们的单片机型号,然后点击那个蓝色按钮,creat project,就可以生成该工程,我这里软件遇到了一个bug。

这个bug如下图:还没有解决,如果有了解决方法我会在补充说明的。

在这里我们利用另外一种方法,我们看到这里有三个可选的模式,第一个是选择进行示例代码工程,第二个是查看c代码文件,第三个是查看汇编代码文件。我们选择第二个选项,查看c代码文件,一个投机取巧的方法就是自己建立一个带有main函数的工程,然后把这个代码复制黏贴过去,不要怪我太机智!!!

在这里我们从右边的解释中可以看到

我们这里可以参考5个文档对系统时钟进行一个设定。大家可以依次点进去看看,我这里就不演示了。直接给出下面的代码:

int main(void) {

WDTCTL = WDTPW | WDTHOLD;        // Stop watchdog timer

PM5CTL0 &= ~LOCKLPM5;

// Configure GPIO

P1DIR |= BIT0;

P1OUT |= BIT0;

//  Clock System Setup

//  解释说明:因为CS寄存器是锁定的,我们必须开锁才可以进行配置。

CSCTL0_H = CSKEY >> 8;                    // Unlock CS registers

CSCTL1 = DCOFSEL_0;                       // Set DCO to 1MHz

CSCTL2 = SELM__DCOCLK;  // Set SMCLK = DCO,The Other is Default

CSCTL3 = DIVM__1;     // Set SMCLK divider to 1

TA0CCTL0 = CCIE;                          // TACCR0 interrupt enabled

TA0CCR0 = 50000;                          // Set CCR0

TA0CTL = TASSEL__SMCLK | MC__UP;          // SMCLK, UP mode

/*

* 这里我们配置的是1MHz,没有进行分频,那么一次的时间是10us,这里

* 我们数了50000次,所以就是500ms

* 如果要分频,看下面的注解1

*/

__enable_interrupt();

return 0;

}

#pragma vector = TIMER0_A0_VECTOR

__interrupt void Timer_A0_ISR(void)

{

P1OUT ^= BIT0;

}

前面的退出LPM5模式和关闭看门狗以及GPIO口的配置,我们就不再说明了。

我说明一下这里的 CSCTL0_H = CSKEY >> 8; 这一句的意思:我们在数据手册中找到这一句,也就是说只有当我们在这个寄存器中写入了正确的值,我们才可以对CS寄存器进行修改,就和我们只有拿了正确的钥匙才能开正确的门是一样的哈。所以我们这里必须要进行解锁,否则下面对CS寄存器的修改将是无效的,这其实我们关闭LPM5模式的那个语句一样,PM5CTL0 &= ~LOCKLPM5;这一句是我们配置GPIO的“钥匙”。

对于定时器的书写我参考了下图中红色的.c文件进行了修改。所以大家在写程序的时候,如果说不知道该如何配置的话,可以参考别人的代码,当然这里参考的是官方的代码,更加可靠一点,但是官方的东西相对的话就会少很多,民间的代码当然更多了。

注解1:

分频的配置:

我们看到库函数那边的分频配置竟然有20种分频,而我们在寄存器中找根本没有找到这么多的可分频配置啊!那么他是怎么实现的呢?

我们打开我们刚刚以库函数写的工程,进入Timer_A_initUpMode这个函数,找到下面这一行,我们看到它配置了称之为TAxEX0和TAxCTL的寄存器。哇!原来如此!!

我们找到这两个寄存器的描述分别如下:

这两个寄存器共同完成了定时器的分频工作,那我们看看库函数是怎么实现的。

我们看下图中,两个寄存器分别对输入的clockSourceDivider进行了相应的处理,那这些处理是什么含义呢?我们解释一个,大家自然就可以明白了!

我们这里取clockSourceDivider |= TIMER_A_CLOCKSOURCE_DIVIDER_20

可以得知,TIMER_A_CLOCKSOURCE_DIVIDER_20 = 0x14,具体怎么得知的,我偷偷在告诉你一次,按住ctrl然后你懂的。

对于第一句:clockSourceDivider & 0x7

0x14 & 0x07 = 0001_0100 & 0000_0111 = 0000_0100 ;

这样子我们得到TAxEX0的值为0x04,我们对应我们的寄存器描述可以得到,此时的TAIDEX = 100(上图红框),所以是5分频。

下一句:( clockSourceDivider >>3) << 6

首先要右移三位:

0x14 >> 3 =  0001_0100  >>  3 = 0000_0010  (空位补零)

0000_0010  <<  6 = 1000_0000

最后我们得到TAxCTL的值为0xC0,对应的寄存器中的ID = 10(上图红框),因为ID是寄存器的6-7位,而寄存器的最低位为0开始数的,所以这取我们八位数的第七和第八位,对应寄存器描述可以得到分频数为4分频。

好了,接下来回过头来看我们的timer那个block diagram的图:

可以看到我们四个时钟输入,分频数由ID和IDEX两个决定,也就是我们上面说明的两个寄存器的相关位决定的。可以看出两个是串联的关系,那么最终得到的分频数就是应该两个相乘,这个应该可以明白吧,不明白的自行脑补吧!!!

所以这里分频数就是4 X 5 = 20,和我们的标识名一样!TIMER_A_CLOCKSOURCE_DIVIDER_20。

其他的几个也是类似可以通过这样的分析方法得到,相信大家明白一个就可以明白另外一个了。

那么用寄存器怎么写呢?

很简单,就是加上这两句:

TA0CCTL0 = ID_2 | CCIE;

TA0EX0 = TAIDEX_5;

首先可以在我们的msp430fr5969.h中找到下面的寄存器定义,这样写的话更方便。

最终代码如下:延时1s中闪烁

好了不说了,一说发现说了好多。

(0)

相关推荐