【MSP430趣谈之七】库函数的定时器使用
这次我们要讲一下单片机中非常重要的一个外设,定时器。
怎么说呢,定时器和闹钟差不多吧,功能和闹钟类似。实现定时的功能,当然这只是他其中的一个功能,他还可以完成很多其他的功能,我们这次就来看看他到底有什么神奇的地方。
还是那份文档,哪份我就不再说了。打开找到定时器的章节。
我们看到这里有三个定时器的章节,其实都是类似的,只是说相对而言他的功能会有些不同,本质上还是想他的名字及一样,定时器定时器,就是定时嘛!
这里我们重点讲一下Timer_A,之后我们再说下这三个的不同。
另外我们来说下为什么需要定时器哈!不知道大家还记得吗,我们说过单片机是死脑筋的,就一条程序语句一条程序语句的执行下来,没有什么情况的话,他就是一根筋的执行下来,其实这个和我们之前中断说道的一样,定时器可以通过对时钟进行计数,能够在固定的时间内完成一个中断,打断单片机的死脑筋。接下来我们看看该如何实现。
上次我们使用了Grace进行配置时钟,方便大家理解时钟那块,同样Grace也可以用来配置定时器,但是这里我们就不用Grace这个工具了,为什么呢?因为他的工具虽然形象但是不能帮助我们真正学到东西,而且并不是所有的单片机的编译环境提供了这样好的开发方式,也不建议大家一直使用这个工具,这里我们就使用之前的开发方式进行开发,我们采用库开发的形式,但是我们会讲到寄存器的相关配置。
对于定时器来讲,基本功能的话就是定时作用,到达一定执行什么样的动作,也就是我们可以产生一个定时器中断。另外我们可以利用定时器输出PWM波。另外还可以进行输入捕获的功能。
对于TimerA的计数模式有四种。如图说明,分别是:
1.停止暂停定时器
2.向上计数模式
3.连续模式
4.向上或向下模式
下面我们来解释下这四个模式具体是怎么样的。
向上计数模式中是这样的,我们定时器是16位的,所以最大值就是0FFFFh,所以在纵坐标上我们有这样一个标志,后面的h表示我们这个数值是以16进制的方式。那现在我们如果设置了TAxCCR0这个寄存器的值,那他的计数就会从0开始,计数到TAxCCR0的计数值之后,就返回0开始继续计数。
连续计数模式,就是一直从零开始计数到0FFFFh。在返回0继续计数。
从图上我们可以明显看出区别了,向上向下计数模式是从零向上数,然后倒着数下来而不是数到TAxCCR0之后直接变成零再继续数。
另外一种模式,停止模式,就是定时器计数停止,也就没有什么意义了,这里不再讨论了。
定时器相对而言还是比较复杂的,怎么说呢?我们这样子的三言两语是没有办法讲清楚的,可能需要一个很大的章节才可以把中间的条条道道讲明白,所以这里我们不深入讲。把我们要用到的东西讲明白给大家,其他的一些功能应该对于大家需要使用到的时候在去查看使用方法即可,也相信如果我们讲到的东西大家能够自己明白领会的话,相信大家再去学习其他的模块也相对容易一点。
我们将使用TIMA来实现两个功能,一个是定时中断点亮LED,另外一个是实现定时器的PWM输出。
现在我们来实现定时器中断。找到我们的库函数参考手册。
MSP430FR5xx_6xx_DriverLib_Users_Guide-2_21_00_08
在我们的第五讲中的附件的库函数中有个doc文件夹下面可以找到。
在第三十章中我们找到所有的函数名列表,单击每个函数可以调到具体的函数定义。
所先第一步,我们初始化向上计数模式,单击这个函数得到它的函数定义,以及相关形参的选择说明。
我们发现我们并不明白很多东西的定义,就比如说baseadress,那我们来看下该如何来使用CCS帮助自己来填写这些东西,具体怎么做我们看下。
这里我们使用第六讲中时钟配置的工程,在上次中我们一进配置好了时钟,这样我们更好判断我们的定时时间。要记住一点就是定时器要保证定时的准确性,他的时钟源是十分重要的,所以我们直接利用了上次的工程,时钟配置为16M.
在上图中我们看到,对TIMA的时钟来源我们看到总共有四个,TAxCLK和INCLK是由外部输入的,ACLK和SMCLK则是我们上次说到的那两个时钟源输入。我们所配置的大小是SMCLK是16M,ACLK是32.768K。
建立工程,添加我们的库文件,这里不再说明具体的操作了。
上面的baseadress是在哪里定义的呢?我们找到一个头文件叫做hw_memmap.h
那么这个文件是在哪里被包括进来的呢?在timer_a.c中我们可以看到,它在这里被包含进来了。
这样我们就知道到了第一参量是什么了,baseaddress对应的是TIMER_A0_BASE。这里有一个条件编译,我们解释一下这个的用法。他可以实现说代码的适用性。假设说我写一小段代码。
#ifdef MSP430
a = 0;
#endif
#ifdef MSP430FR5969
a = 1;
#endif
此时的话如果我定义一个#define MSP430,,那么我得到的值a就为0,相反的话我定义一个#define MSP430FR5969的话得到的a的值就是1.
这里的话我们不在说这个是在哪里定义的了,右键__MSP430_HAS_T0A3__选择open declaration。大家自己试下就知道了。
现在我们来找一下第二个参量的填写,我们右键Timer_A_initUpModeParam然后open declaration。(快捷方式就是按住Ctrl然后点击Timer_A_initUpModeParam即可)
看到它是一个结构体的定义,太长了我截图不下来。可以看到大部分都是注释,所以相对来说还是比较好理解的,我们看下该如何使用。
上面就是总的程序了,记得要#include
我的编译器出现了一个问题
还没有解决,也希望有知道的小伙伴能够帮忙解决一下。
如果我找到解决方法我会在下次告诉大家如何解决这个问题。
这里我觉得是我的Grace有问题,但是没找到具体是配置上的问题,还是说软件本身的问题。仔细查看了下是没有办法生成Grace.lib这个文件
下次我们将认真的讲到系统时钟的库函数配置方法。
谢谢。
补充:
上面的代码我写错了一句。
Timer_A_initUpModeStucture.timerInterruptEnable_TAIE= TIMER_A_TAIE_INTERRUPT_ENABLE;
这一句使能的中断和我们想象中的中断不一样,我们想要的中断是计数到和CCR0设置的值为50000时产生中断,但是实际中我们发现并不是这样,我们将上面的代码编译过后下载进去,发现LED虽然亮了,但是它并不闪烁,而且在仿真过程中我们还进入了一个IntFault()这样的一个函数,这里我们就需要搞明白说上面这一个语句设置的什么中断。
对于TIMER_A来讲有两个中断,我们可以在数据手册的定时器那个章节中找到:
一个是CCIFG所产生的CCIE中断,另外一个是有TAIFG所产生的TAIE中断,这两个中断是有所区别的,具体如下:
TAIE 和CCIE指的是不同事件。TAIE指TAR 计数器溢出,从65535 到0 的变化,由TAIFG 引起的。CCIE指捕获到相应信号(捕获模式下);定时时间到(比较模式下)。由CCIFG引起的。两个中断的中断向量不一样,TAIFG 一般进TIMER_A1_VECTOR;CCIFG 的话要看用的是哪个定时器如果是CCR0 的话就进TIMER_A0_VECTOR,如果是CCR1,CCR2……则进TIMER_A1_VECTOR。
蓝色字眼这是我们使用到的中断,所以这里我们要进行修改开启CCR0的中断,关闭TAIFG中断。修改为下面这句话:
Timer_A_initUpModeStucture.captureCompareInterruptEnable_CCR0_CCIE |= TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE;
此时再次下载进去就可以看到LED闪烁了。
同时我们在上面看到我们需要使用到一个中断向量,那么这个中断向量指的是什么呢?
中断向量,指的意思是我们的中断程序的入口地址,那么这个地址在哪里定义的呢?我们找到,在msp430fr5969.h里面有定义这些地址:
在这里定义了FR5969中所有的中断向量,当然也有的地方会说到这是一个中断向量表,都是指同一个东西,就是所有中断入口地址的定义。
那我们要怎么理解这个呢?
我们从下面这个图中可以更好的理解这个过程。
可能有些地方不够严谨,希望大家可以明白这个具体的意思是怎么样的。
谢谢大家的支持!!!
更多内容及附件下载请点击下方阅读原文。
欢迎观看