第1章
1.1 1.2 1.3 1.4
通用定时器(Timer)......................................................................................1
Timer总体特性.............................................................................................................1 Timer功能概述.............................................................................................................2 Timer库函数.................................................................................................................3 Timer例程...................................................................................................................11
i
第1章 通用定时器(Timer)
函 数 原 型
void TimerConfigure(unsigned long ulBase, unsigned long ulConfig)
void TimerControlStall(unsigned long ulBase, unsigned long ulTimer, tBoolean bStall) void TimerControlTrigger(unsigned long ulBase, unsigned long ulTimer, tBoolean bEnable) void TimerControlEvent(unsigned long ulBase, unsigned long ulTimer, unsigned long ulEvent) void TimerControlLevel(unsigned long ulBase, unsigned long ulTimer, tBoolean bInvert) void TimerLoadSet(unsigned long ulBase, unsigned long ulTimer, unsigned long ulValue) unsigned long TimerLoadGet(unsigned long ulBase, unsigned long ulTimer) unsigned long TimerValueGet(unsigned long ulBase, unsigned long ulTimer) void TimerEnable(unsigned long ulBase, unsigned long ulTimer) void TimerDisable(unsigned long ulBase, unsigned long ulTimer) void TimerRTCEnable(unsigned long ulBase) void TimerRTCDisable(unsigned long ulBase) void TimerQuiesce(unsigned long ulBase)
void TimerMatchSet(unsigned long ulBase, unsigned long ulTimer, unsigned long ulValue) unsigned long TimerMatchGet(unsigned long ulBase, unsigned long ulTimer)
void TimerPrescaleSet(unsigned long ulBase, unsigned long ulTimer, unsigned long ulValue) unsigned long TimerPrescaleGet(unsigned long ulBase, unsigned long ulTimer) void TimerIntEnable(unsigned long ulBase, unsigned long ulIntFlags) void TimerIntDisable(unsigned long ulBase, unsigned long ulIntFlags) void TimerIntClear(unsigned long ulBase, unsigned long ulIntFlags) unsigned long TimerIntStatus(unsigned long ulBase, tBoolean bMasked)
void TimerIntRegister(unsigned long ulBase, unsigned long ulTimer, void (*pfnHandler)(void)) void TimerIntUnregister(unsigned long ulBase, unsigned long ulTimer)
页码4 5 6 6 6 7 7 7 7 8 8 8 8 9 9 9 9 10 10 10 10 10 11
1.1 Timer总体特性
在Stellaris系列ARM内部通常集成有2~4个通用定时器模块(General-Purpose Timer
Module,GPTM),分别称为Timer0、Timer1、Timer2和Timer3。它们的用法是相同的:每个Timer模块都可以配置为一个32位定时器或一个32位RTC定时器;也可以拆分为两个16位的定时/计数器TimerA和TimerB,它们可以被配置为运行的定时器、事件计数器或PWM。
Timer模块具有非常丰富的功能: z 32位定时器模式:
可编程单次触发(one-shot)定时器 可编程周期(periodic)定时器 实时时钟RTC(Real Time Clock)
软件可控的事件暂停(用于单步调试时暂停计数,RTC模式除外) z 16位定时器模式:
带8位预分频器的通用定时器功能 可编程单次触发(one-shot)定时器
1
可编程周期(periodic)定时器 软件可控的事件暂停 z 16位输入捕获模式:
输入边沿计数捕获 输入边沿定时捕获 z 16位PWM模式:
用法简单的PWM(Pulse-Width Modulation,脉宽调制)模式 可通过软件实现PWM信号周期、占空比、输出反相等的控制
1.2 Timer功能概述
Timer模块的功能在总体上可以分成32位模式和16位模式两大类。在32位模式下,TimerA和TimerB被连在一起形成一个完整的32位计数器,对Timer的各项操作,如装载
而对TimerB初值、运行控制、中断控制等,都用对TimerA的操作作为总体上的32位控制,
的操作无任何效果。在16位模式下,对TimerA的操作仅对TimerA有效,对TimerB的操作仅对TimerB有效,即对两者的操控是完全进行的。
每一个Timer模块对应两个CCP管脚。CCP是“Capture Compare PWM”的缩写,意为“捕获/比较/脉宽调制”。在32位单次触发和周期定时模式下,CCP功能无效(与之复用的GPIO管脚功能仍然正常)。在32位RTC模式下,偶数CCP管脚(CCP0、CCP2、CCP4等)作为RTC时钟源的输入,而奇数CCP管脚(CCP1、CCP3、CCP5等)无效。在16位模式下,计数捕获、定时捕获、PWM功能都会用到CCP管脚,对应关系是:Timer0A对应CCP0、Timer0B对应CCP1,Timer1A对应CCP2、Timer1B对应CCP3,依此类推。
1. 32位单次触发/周期定时器
在这两种模式中,Timer都被配置成一个32位的递减计数器,用法类似,只是单次触发模式只能定时一次,如果需要再次定时则必须重新配置,而周期模式则可以周而复始地定时,除非被关闭。在计数到0x00000000时,可以在软件的控制下触发中断或输出一个内部的单时钟周期脉冲信号,该信号可以用来触发ADC采样。
2. 32位RTC定时器
在该模式中,Timer被配置成一个32位的递增计数器。
在LM3S101/102里,RTC时钟信号从专RTC功能的时钟源来自偶数CCP管脚的输入。门的“32KHz”管脚输入。输入的时钟频率应当为精准的32.768KHz,在芯片内部有一个RTC专用的预分频器,固定为32768分频。因此最终输入到RTC计数器的时钟频率正好是1Hz,即每过1秒钟RTC计数器增1。
RTC计数器从0x00000000开始计满需要232秒,这是个极长的时间,有136年!因此RTC真正的用法是:初始化后不需要更改配置(调整时间或日期时例外),只需要修改匹配寄存器的值,而且要保证匹配值总是超前于当前计数值。每次匹配时可产生中断(如果中断已被使能),据此可以计算出当前的年月日、时分秒以及星期。在中断服务函数里应当重新设置匹配值,并且匹配值仍要超前于当前的计数值。
注意:在实际应用当中一般不会真正采用Timer模块的RTC功能来实现一个低功耗万年历系统,因为芯片一旦出现复位或断电的情况就会清除RTC计数值。取而代之的是冬眠模块(Hibernation Module)的RTC功能,由于采用了后备电池,因此不怕复位和VDD断
2
电,并且功耗很低。
3. 16位单次触发/周期定时器
一个32位的Timer可以被拆分为两个单独运行的16位定时/计数器,每一个都可以被配置成带8位预分频(可选功能)的16位递减计数器。如果使用8位预分频功能,则相当于24位定时器。具体用法跟32位单次触发/周期定时模式类似,不同的是对TimerA和TimerB的操作是分别进行的。
4. 16位输入边沿计数捕获
在该模式中,TimerA或TimerB被配置为能够捕获外部输入脉冲边沿事件的递减计数器。共有3种边沿事件类型:正边沿、负边沿、双边沿。
该模式的工作过程是:设置装载值,并预设一个匹配值(应当小于装载值);计数使能后,在特定的CCP管脚每输入1个脉冲(正边沿、负边沿或双边沿有效),计数值就减1;当计数值与匹配值相等时停止运行并触发中断(如果中断已被使能)。如果需要再次捕获外部脉冲,则要重新进行配置。
5. 16位输入边沿定时捕获
在该模式中,TimerA或TimerB被配置为自由运行的16位递减计数器,允许在输入信号的上升沿或下降沿捕获事件。
该模式的工作过程是:设置装载值(默认为0xFFFF)、捕获边沿类型;计数器被使能后开始自由运行,从装载值开始递减计数,计数到0时重装初值,继续计数;如果从CCP管脚上出现有效的输入脉冲边沿事件,则当前计数值被自动复制到一个特定的寄存器里,该值会一直保存不变,直至遇到下一个有效输入边沿时被刷新。为了能够及时读取捕获到的计数值,应当使能边沿事件捕获中断,并在中断服务函数里读取。
6. 16位PWM
Timer模块还可以用来产生简单的PWM信号。在Stellaris系列ARM众多型号当中,对于片内未集成专用PWM模块的,可以利用Timer模块的16位PWM功能来产生PWM信号,只不过功能较为简单。对于片内已集成专用PWM模块的,但仍然不够用时,则可以从Timer模块借用。
在PWM模式中,TimerA或TimerB被配置为16位的递减计数器,通过设置适当的装载值(决定PWM周期)和匹配值(决定PWM占空比)来自动地产生PWM方波信号从相应的CCP管脚输出。在软件上,还可以控制输出反相,参见函数TimerControlLevel( )。
1.3 Timer库函数
在使用某个Timer模块之前,应当首先将其使能,方法为:
#define SysCtlPeriEnable
SysCtlPeripheralEnable
SysCtlPeriEnable(SYSCTL_PERIPH_TIMERn); // 末尾的n取0、1、2或3
对于RTC、计数捕获、定时捕获、PWM等功能,需要用到相应的CCP管脚作为信号
3
的输入或输出。因此还必须对CCP所在的GPIO端口进行配置。以CCP2为例,假设在PD5管脚上,则配置方法为:
#define CCP2_PERIPH #define CCP2_PORT
SYSCTL_PERIPH_GPIOD GPIO_PORTD_BASE
#define CCP2_PIN GPIO_PIN_5
SysCtlPeripheralEnable(CCP2_PERIPH); // 使能CCP2管脚所在的GPIOD GPIOPinTypeTimer(CCP2_PORT, CCP2_PIN); // 配置CCP2管脚为Timer功能
1. 配置与控制
函数TimerConfigure( )用来配置Timer的工作模式,这些模式包括:32位单次触发定时器、32位周期定时器、32位RTC定时器、16位输入边沿计数捕获、16位输入边沿定时捕获和16位PWM。对16位模式,Timer被拆分为两个的定时/计数器TimerA和TimerB,该函数能够分别对它们进行配置。详见表1.1的描述。
函数TimerControlStall( )可以控制Timer在程序在单步调试时暂停运行,这为用户随时观察相关寄存器的内容提供了方便,否则在单步调试时Timer可能还在飞速运行,从而影响互动的调试效果。但是该函数对32位RTC定时器模式无效,即RTC定时器一旦使能就会地运行,除非被禁止计数。参见表1.2的描述。
函数TimerControlTrigger( )可以控制Timer在单次触发/周期定时器溢出时产生一个内部的单时钟周期脉冲信号,该信号可以用来触发ADC采样。参见表1.3的描述。
函数TimerControlEvent( )用于两种16位输入边沿捕获模式,可以控制有效的输入边沿,输入边沿有3种情况:正边沿、负边沿和双边沿。详见表1.4的描述。
函数TimerControlLevel( )可以控制Timer在16位PWM模式下的方波有效输出电平是高电平还是低电平,即可以控制PWM方波反相输出。参见表1.5的描述。
表1.1 函数TimerConfigure( )
功能 原型
配置Timer模块的工作模式
void TimerConfigure(unsigned long ulBase, unsigned long ulConfig) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3) ulConfig:Timer模块的配置
在32位模式下应当取下列值之一:
TIMER_CFG_32_BIT_OS // 32位单次触发定时器 TIMER_CFG_32_BIT_PER // 32位周期定时器 TIMER_CFG_32_RTC // 32位RTC定时器
在16位模式下,一个32位的Timer被拆分成两个运行的子定时器TimerA和TimerB。
参数
配置TimerA的方法是参数ulConfig先取值TIMER_CFG_16_BIT_PAIR再与下列值之一进行“或运算”的组合形式:
TIMER_CFG_A_ONE_SHOT // TimerA为单次触发定时器 TIMER_CFG_A_PERIODIC // TimerA为周期定时器 TIMER_CFG_A_CAP_COUNT // TimerA为边沿事件计数器 TIMER_CFG_A_CAP_TIME // TimerA为边沿事件定时器
TIMER_CFG_A_PWM
// TimerA为PWM输出
配置TimerB的方法是参数ulConfig先取值TIMER_CFG_16_BIT_PAIR再与下列值之一进行“或运算”的组合形式:
4
TIMER_CFG_B_ONE_SHOT // TimerB为单次触发定时器 TIMER_CFG_B_PERIODIC // TimerB为周期定时器 TIMER_CFG_B_CAP_COUNT // TimerB为边沿事件计数器 TIMER_CFG_B_CAP_TIME // TimerB为边沿事件定时器 TIMER_CFG_B_PWM // TimerB为PWM输出
返回
无
// 配置Timer0为32位单次触发定时器
TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_OS);
// 配置Timer1为32位周期定时器
TimerConfigure(TIMER1_BASE, TIMER_CFG_32_BIT_PER);
// 配置Timer2为32位RTC定时器
TimerConfigure(TIMER2_BASE, TIMER_CFG_32_RTC);
// 在Timer0当中,配置TimerA为单次触发定时器(不配置TimerB)
TimerConfigure(TIMER0_BASE, TIMER_CFG_16_BIT_PAIR | TIMER_CFG_A_ONE_SHOT);
// 在Timer0当中,配置TimerB为周期定时器(不配置TimerA)
TimerConfigure(TIMER0_BASE, TIMER_CFG_16_BIT_PAIR | TIMER_CFG_B_PERIODIC);
示例
// 在Timer0当中,配置TimerA为单次触发定时器,同时配置TimerB为周期定时器 TimerConfigure(TIMER0_BASE, TIMER_CFG_16_BIT_PAIR | TIMER_CFG_A_ONE_SHOT | TIMER_CFG_B_PERIODIC);
// 在Timer1当中,配置TimerA为边沿事件计数器、TimerB为边沿事件定时器 TimerConfigure(TIMER1_BASE, TIMER_CFG_16_BIT_PAIR | TIMER_CFG_A_CAP_COUNT | TIMER_CFG_B_CAP_TIME);
// 在Timer2当中,TimerA、TimerB都配置为PWM输出 TimerConfigure(TIMER2_BASE, TIMER_CFG_16_BIT_PAIR |
TIMER_CFG_A_PWM | TIMER_CFG_B_PWM);
表1.2 函数TimerControlStall( )
功能 原型
控制Timer暂停运行(对32位RTC模式无效)
void TimerControlStall(unsigned long ulBase, unsigned long ulTimer, tBoolean bStall) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3)
参数
ulTimer:指定的Timer,取值TIMER_A、TIMER_B或TIMER_BOTH
在32位模式下只能取值TIMER_A,作为总体上的控制,而取值TIMER_B或TIMER_BOTH都无效。在16位模式下取值TIMER_A只对TimerA有效,取值TIMER_B只对TimerB有效,取
5
值TIMER_BOTH同时对TimerA和TimerB有效。 bStall:如果取值true,则在单步调试模式下暂停计数
返回
无
如果取值false,则在单步调试模式下继续计数
表1.3 函数TimerControlTrigger( )
功能 原型
控制Timer的输出触发功能使能或禁止
void TimerControlTrigger(unsigned long ulBase, unsigned long ulTimer, tBoolean bEnable) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3)
参数
ulTimer:指定的Timer,取值TIMER_A、TIMER_B或TIMER_BOTH bEnable:如果取值true,则使能输出触发
返回
无
如果取值false,则禁止输出触发
表1.4 函数TimerControlEvent( )
功能 原型
控制Timer在捕获模式中的边沿事件类型
void TimerControlEvent(unsigned long ulBase, unsigned long ulTimer, unsigned long ulEvent) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3) ulTimer:指定的Timer,取值TIMER_A、TIMER_B或TIMER_BOTH ulEvent:指定的边沿事件类型,应当取下列值之一:
参数
TIMER_EVENT_POS_EDGE // 正边沿事件 TIMER_EVENT_NEG_EDGE // 负边沿事件
TIMER_EVENT_BOTH_EDGES // 双边沿事件(正边沿和负边沿都有效) 注:在16位输入边沿计数捕获模式下,可以取值3种边沿事件的任何一种,但在16位输入边沿定时模式下仅支持正边沿和负边沿,不能支持双边沿。
返回
无
表1.5 函数TimerControlLevel( )
功能 原型
控制Timer在PWM模式下的有效输出电平
void TimerControlLevel(unsigned long ulBase, unsigned long ulTimer, tBoolean bInvert) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3)
参数
ulTimer:指定的Timer,取值TIMER_A、TIMER_B或TIMER_BOTH bInvert:当取值false时PWM输出为高电平有效(默认)
返回
无
当取值true时输出低电平有效(即输出反相)
2. 计数值的装载与获取
函数TimerLoadSet( )用来设置Timer的装载值。装载寄存器与计数器不同,它是存
在的。在调用TimerEnable( )时会自动把装载值加载到计数器里,以后每输入一个脉冲计数
6
器值就加1或减1(取决于配置的工作模式),而装载寄存器不变。另外,除了单次触发定时器模式以外,在计数器溢出时会自动重新加载装载值。函数TimerLoadGet( )用来获取装载寄存器的值。参见表1.6和表1.7。
函数TimerValueGet( )用来获取当前Timer计数器的值。但在16位输入边沿定时捕获模式里,获取的是捕获寄存器的值,而非计数器值。参见表1.8的描述。
表1.6 函数TimerLoadSet( )
功能 原型
设置Timer的装载值
void TimerLoadSet(unsigned long ulBase, unsigned long ulTimer, unsigned long ulValue) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3)
参数
ulTimer:指定的Timer,取值TIMER_A、TIMER_B或TIMER_BOTH ulValue:32位装载值(32位模式)或16位装载值(16位模式)
返回
无
表1.7 函数TimerLoadGet( )
功能 原型 参数 返回
获取Timer的装载值
unsigned long TimerLoadGet(unsigned long ulBase, unsigned long ulTimer) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3) ulTimer:指定的Timer,取值TIMER_A、TIMER_B或TIMER_BOTH 32位装载值(32位模式)或16位装载值(16位模式)
表1.8 函数TimerValueGet( )
功能 原型 参数 返回
获取当前的Timer计数值(在16位输入边沿定时捕获模式下,获取的是捕获值) unsigned long TimerValueGet(unsigned long ulBase, unsigned long ulTimer) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3) ulTimer:指定的Timer,取值TIMER_A、TIMER_B或TIMER_BOTH 当前Timer计数值(在16位输入边沿定时捕获模式下,返回的是捕获值)
3. 运行控制
函数TimerEnable( )用来使能Timer计数器开始计数,而函数TimerDisable( )用来禁止计数。参见表1.9和表1.10的描述。
在32位RTC定时器模式下,为了能够使RTC开始计数,需要同时调用函数TimerEnable( )和TimerRTCEnable( )。函数TimerRTCEnable( )用于禁止RTC计数时。参见表1.11和表1.12的描述。
调用函数TimerQuiesce( )可以复位Timer模块的所有配置。这为快速停止Timer工作或重新配置Timer为另外的工作模式提供了一种简便的手段。参见表1.13的描述。
表1.9 函数TimerEnable( )
功能 原型
使能Timer计数(即启动Timer)
void TimerEnable(unsigned long ulBase, unsigned long ulTimer)
7
参数 返回
ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3) ulTimer:指定的Timer,取值TIMER_A、TIMER_B或TIMER_BOTH 无
表1.10 函数TimerDisable( )
功能 原型 参数 返回
禁止Timer计数(即关闭Timer)
void TimerDisable(unsigned long ulBase, unsigned long ulTimer)
ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3) ulTimer:指定的Timer,取值TIMER_A、TIMER_B或TIMER_BOTH 无
表1.11 函数TimerRTCEnable( )
功能 原型 参数 返回 说明
使能RTC计数
void TimerRTCEnable(unsigned long ulBase)
ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3) 无
启动RTC时,除了要调用本函数外,还必须要调用函数TimerEnable( )
表1.12 函数TimerRTCDisable( )
功能 原型 参数 返回
禁止RTC计数
void TimerRTCDisable(unsigned long ulBase)
ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3) 无
表1.13 函数TimerQuiesce( )
功能 原型 参数 返回
使Timer进入它的复位状态
void TimerQuiesce(unsigned long ulBase)
ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3) 无
4. 匹配与预分频
函数TimerMatchSet( )和TimerMatchGet( )用来设置和获取Timer匹配寄存器的值。Timer开始运行后,当计数器的值与预设的匹配值相等时可以触发某种动作,如中断、捕获、PWM等。参见表1.14和表1.15的描述。
在Timer的16位单次触发/周期定时器模式下,输入到计数器的脉冲可以先经8位预分频器进行1~256分频,这样,16位的定时器就被扩展成了24位。该功能是可选的,预分频器默认值是0,即不分频。函数TimerPrescaleSet( )和TimerPrescaleGet( )用来设置和获取8位预分频器的值。参见表1.16和表1.17的描述。
8
表1.14 函数TimerMatchSet( )
功能 原型
设置Timer的匹配值
void TimerMatchSet(unsigned long ulBase, unsigned long ulTimer, unsigned long ulValue) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3)
参数
ulTimer:指定的Timer,取值TIMER_A、TIMER_B或TIMER_BOTH ulValue:32位匹配值(32位RTC模式)或16位匹配值(16位模式)
返回
无
表1.15 函数TimerMatchGet( )
功能 原型 参数 返回
获取Timer的匹配值
unsigned long TimerMatchGet(unsigned long ulBase, unsigned long ulTimer) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3) ulTimer:指定的Timer,取值TIMER_A、TIMER_B或TIMER_BOTH 32位匹配值(32位RTC模式)或16位匹配值(16位模式)
表1.16 函数TimerPrescaleSet( )
功能 原型
设置Timer预分频值(仅对16位单次触发/周期定时模式有效)
void TimerPrescaleSet(unsigned long ulBase, unsigned long ulTimer, unsigned long ulValue) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3)
参数
ulTimer:指定的Timer,取值TIMER_A、TIMER_B或TIMER_BOTH
ulValue:8位预分频值(高24位无效),取值0~255,对应的分频数是1~256
返回
无
表1.17 函数TimerPrescaleGet( )
功能 原型 参数 返回
获取Timer预分频值(仅对16位单次触发/周期定时模式有效)
unsigned long TimerPrescaleGet(unsigned long ulBase, unsigned long ulTimer) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3) ulTimer:指定的Timer,取值TIMER_A、TIMER_B或TIMER_BOTH 8位预分频值(高24位总是为0)
5. 中断控制
Timer模块有多个中断源,有超时中断、匹配中断和捕获中断3大类,又细分为7种。函数TimerIntEnable( )和TimerIntDisable( )用来使能或禁止一个或多个Timer中断源。详见表1.18和表1.19的描述。
函数TimerIntClear( )用来清除一个或多个Timer中断状态,函数TimerIntStatus( )用来获取Timer的全部中断状态。在Timer中断服务函数里,这两个函数通常要配合使用。参见表1.20和表1.21的描述。
函数TimerIntRegister( )和TimerIntUnregister( )用来注册和注销Timer的中断服务函数,参见表1.22和表1.23的描述。
9
表1.18 函数TimerIntEnable( )
功能 原型
使能Timer的中断
void TimerIntEnable(unsigned long ulBase, unsigned long ulIntFlags) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3)
ulIntFlags:被使能的中断源,应当取下列值之一或者它们之间的任意“或运算”组合形式: TIMER_TIMA_TIMEOUT // TimerA超时中断
TIMER_CAPA_MATCH // TimerA捕获模式匹配中断
参数
TIMER_CAPA_EVENT // TimerA捕获模式边沿事件中断 TIMER_TIMB_TIMEOUT // TimerB超时中断 TIMER_CAPB_MATCH // TimerB捕获模式匹配中断 TIMER_CAPB_EVENT // TimerB捕获模式边沿事件中断 TIMER_RTC_MATCH // RTC匹配中断
返回
无
表1.19 函数TimerIntDisable( )
功能 原型 参数 返回
禁止Timer的中断
void TimerIntDisable(unsigned long ulBase, unsigned long ulIntFlags) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3) ulIntFlags:被禁止的中断源,取值与表1.18当中的参数ulIntFlags相同 无
表1.20 函数TimerIntClear( )
功能 原型 参数 返回
清除Timer的中断
void TimerIntClear(unsigned long ulBase, unsigned long ulIntFlags) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3) ulIntFlags:被清除的中断源,取值与表1.18当中的参数ulIntFlags相同 无
表1.21 函数TimerIntStatus( )
功能 原型
获取当前Timer的中断状态
unsigned long TimerIntStatus(unsigned long ulBase, tBoolean bMasked) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3)
参数
bMasked:如果需要获取的是原始的中断状态,则取值false
返回
如果需要获取的是屏蔽的中断状态,则取值true
中断状态,数值与表1.18当中的参数ulIntFlags相同
表1.22 函数TimerIntRegister( )
功能 原型
注册一个Timer的中断服务函数
void TimerIntRegister(unsigned long ulBase, unsigned long ulTimer, void (*pfnHandler)(void))
10
ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3)
参数
ulTimer:指定的Timer,取值TIMER_A、TIMER_B或TIMER_BOTH pfnHandler:函数指针,指向Timer中断出现时调用的函数
返回
无
表1.23 函数TimerIntUnregister( )
功能 原型 参数 返回
注销Timer中断服务函数
void TimerIntUnregister(unsigned long ulBase, unsigned long ulTimer) ulBase:Timer模块的基址,取值TIMERn_BASE(n为0、1、2或3) ulTimer:指定的Timer,取值TIMER_A、TIMER_B或TIMER_BOTH 无
1.4 Timer例程
1. 32位单次触发定时
程序清单1.1是Timer模块32位单次触发定时器模式的例子。程序运行后,Timer初始化为32位单次触发定时器,并使能超时中断。在主循环里,当检测到KEY按下时,启动Timer定时1.5秒,同时点亮LED以表示单次定时开始。当Timer倒计时到0时自动停止,并触发超时中断。在中断服务函数里翻转LED亮灭状态,由于原先LED是点亮的,因此结果是LED熄灭。如果再次按下KEY,则再次点亮LED并定时1.5秒,如此反复循环。如果不再按KEY,则LED一直保持熄灭状态,说明Timer是单次触发的,中断不会被触发,因此在中断服务函数里的翻转LED操作也不会被执行到。
程序清单1.1 Timer例程:32位单次触发定时
#include \"systemInit.h\" #include // 定义LED #define LED_PERIPH SYSCTL_PERIPH_GPIOG #define LED_PORT GPIO_PORTG_BASE #define LED_PIN GPIO_PIN_2 // 定义KEY #define KEY_PERIPH SYSCTL_PERIPH_GPIOD #define KEY_PORT GPIO_PORTD_BASE #define KEY_PIN GPIO_PIN_1 // 主函数(程序入口) int main(void) { 11 jtagWait( ); clockInit( ); // 防止JTAG失效,重要! // 时钟初始化:晶振,6MHz = SysCtlPeriEnable(LED_PERIPH); // 使能LED所在的GPIO端口 GPIOPinTypeOut(LED_PORT, LED_PIN); // 设置LED所在的管脚为输出 GPIOPinWrite(LED_PORT, LED_PIN, 1 << 2); // 熄灭LED = SysCtlPeriEnable(SYSCTL_PERIPH_TIMER0); // 使能Timer模块 TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_OS); // 配置Timer为32位单次触发 TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); for (;;) { SysCtlDelay(10 * (TheSysClock / 3000)); // 延时,消除松键抖动 TimerLoadSet(TIMER0_BASE, TIMER_A, 9000000); // 设置Timer初值,定时1.5s TimerEnable(TIMER0_BASE, TIMER_A); // 使能Timer计数 GPIOPinWrite(LED_PORT, LED_PIN, 0x00); // 点亮LED,定时开始 } // TimerA的中断服务函数 void Timer0A_ISR(void) { ulStatus TimerIntStatus(TIMER0_BASE, true); // 获取当前中断状态 TimerIntClear(TIMER0_BASE, ulStatus); // 清除全部中断状态 if (ulStatus & TIMER_TIMA_TIMEOUT) // 如果是超时中断 { ucVal GPIOPinRead(LED_PORT, LED_PIN); // 反转LED GPIOPinWrite(LED_PORT, LED_PIN, ~ucVal); unsigned char ucVal; unsigned long ulStatus; } } while (GPIOPinRead(KEY_PORT, KEY_PIN) == 0x00); // 等待按键抬起 if (GPIOPinRead(KEY_PORT, KEY_PIN) == 0x00) { // 如果复位时按下KEY IntEnable(INT_TIMER0A); IntMasterEnable( ); // 使能Timer超时中断 // 使能Timer中断 // 使能处理器中断 SysCtlPeriEnable(KEY_PERIPH); // 使能KEY所在的GPIO端口 GPIOPinTypeIn(KEY_PORT, KEY_PIN); // 设置KEY所在管脚为输入 SysCtlDelay(10 * (TheSysClock / 3000)); // 延时,消除按键抖动 12 } } 2. 32位周期定时 程序清单1.2是Timer模块32位周期定时器模式的例子。程序运行后,配置Timer为32位周期定时器,定时0.5秒,并使能超时中断。当Timer倒计时到0时,自动重装初值,继续运行,并触发超时中断。在中断服务函数里翻转LED亮灭状态,因此程序运行的最后结果是LED指示灯每秒钟就会闪亮一次。 程序清单1.2 Timer例程:32位周期定时 #include \"systemInit.h\" #include // 定义LED #define LED_PERIPH SYSCTL_PERIPH_GPIOG #define LED_PORT GPIO_PORTG_BASE #define LED_PIN GPIO_PIN_2 // 主函数(程序入口) int main(void) { SysCtlPeriEnable(LED_PERIPH); // 使能LED所在的GPIO端口 GPIOPinTypeOut(LED_PORT, LED_PIN); // 设置LED所在管脚为输出 SysCtlPeriEnable(SYSCTL_PERIPH_TIMER0); // 使能Timer模块 TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_PER); // 配置Timer为32位周期定时器 TimerLoadSet(TIMER0_BASE, TIMER_A, 3000000UL); // 设置Timer初值,定时500ms TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); TimerEnable(TIMER0_BASE, TIMER_A); // 使能Timer计数 for (;;) { } } // 定时器的中断服务函数 IntEnable(INT_TIMER0A); IntMasterEnable( ); // 使能Timer超时中断 // 使能Timer中断 // 使能处理器中断 jtagWait( ); clockInit( ); // 防止JTAG失效,重要! // 时钟初始化:晶振,6MHz 13 void Timer0A_ISR(void) { ulStatus TimerIntStatus(TIMER0_BASE, true); // 读取中断状态 TimerIntClear(TIMER0_BASE, ulStatus); // 清除中断状态,重要! if (ulStatus & TIMER_TIMA_TIMEOUT) // 如果是Timer超时中断 { ucVal GPIOPinRead(LED_PORT, LED_PIN); // 反转LED GPIOPinWrite(LED_PORT, LED_PIN, ~ucVal); } } unsigned char ucVal; unsigned long ulStatus; 3. 32位RTC定时 程序清单1.3是Timer模块32位RTC定时器模式的例子。程序运行后,要求输入RTC初始时间,格式为“hh:mm:ss”,即“时:分:秒”。比如我们输入9:59:45,然后回车 = 产生一次匹配中断。在中断服务函数里,重新设置匹配值,仍然超前1秒钟,计算并显示当前时间。最终我们通过UART会看到不断显示09:59:45、09:59:46、……、09:59:59,接着会进位到10:00:00,并继续运行。 =程序清单1.3已在EasyARM1138开发板上调试通过。由于在该开发板上并没有提供 32.768KHz时钟源,因此我们特意在程序里安排了一个pulseInit( )函数,利用6MHz晶振提供的系统时钟在PF6/CCP1管脚产生一个接近于32.768KHz的PWM方波信号,标称频率为32786.885Hz。实际做实验时,需要短接PF6/CCP1和PF7/CCP4管脚,CCP4是RTC时钟源输入管脚。在其它开发板上,如EasyARM615或EasyARM62,提供有32.768KHz时钟源,则可以不必使用函数pulseInit( )来产生RTC时钟源。 在程序清单1.3里,用到了一个新的头文件 程序清单1.3 Timer例程:32位RTC定时 #include \"systemInit.h\" #include \"uartGetPut.h\" #include 14 #include #define PART_LM3S1138 #include // 在PF6/CCP1管脚产生32786.885Hz方波,为Timer2的RTC功能提供时钟源 void pulseInit(void) { SysCtlPeriEnable(SYSCTL_PERIPH_TIMER0); // 使能TIMER0模块 SysCtlPeriEnable(CCP1_PERIPH); // 使能CCP1所在的GPIO端口 GPIOPinTypeTimer(CCP1_PORT, CCP1_PIN); // 配置相关管脚为Timer功能 TimerConfigure(TIMER0_BASE, TIMER_CFG_16_BIT_PAIR | // 配置TimerB为16位PWM TimerLoadSet(TIMER0_BASE, TIMER_B, 183); // 设置TimerB初值 TimerMatchSet(TIMER0_BASE, TIMER_B, 92); // 设置TimerB匹配值 TimerEnable(TIMER0_BASE, TIMER_B); } // 定时器RTC功能初始化 void timerInitRTC(unsigned long ulVal) { SysCtlPeriEnable(CCP4_PERIPH); // 使能CCP4所在的GPIO端口 GPIOPinTypeTimer(CCP4_PORT, CCP4_PIN); // 配置CCP4管脚为RTC时钟输入 SysCtlPeriEnable(SYSCTL_PERIPH_TIMER2); // 使能Timer模块 TimerConfigure(TIMER2_BASE, TIMER_CFG_32_RTC); // 配置Timer为32位RTC模式 TimerLoadSet(TIMER2_BASE, TIMER_A, ulVal); // 设置RTC计数器初值 TimerMatchSet(TIMER2_BASE, TIMER_A, 1 + ulVal); // 设置RTC匹配值 TimerIntEnable(TIMER2_BASE, TIMER_RTC_MATCH); // 使能RTC匹配中断 TimerRTCEnable(TIMER2_BASE); // 使能RTC计数 TimerEnable(TIMER2_BASE, TIMER_A); // 使能Timer计数 } // 计算并显示RTC时钟 void timerDispRTC(unsigned long ulVal) { char s[40]; IntEnable(INT_TIMER2A); IntMasterEnable( ); // 使能Timer中断 // 使能处理器中断 TIMER_CFG_B_PWM); 15 // 计算并显示小时 // 显示秒钟,并回车换行 } // 主函数(程序入口) int main(void) { ulVal TimerValueGet(TIMER2_BASE, TIMER_A); // 读取当前RTC计时器值 for (;;) { } } timerDispRTC(ulVal); // 显示初始时间 uartPuts(\"Please input the time (hh:mm:ss)\\r\\n\"); // 提示输入时、分、秒 sscanf(s, \"%ld:%ld:%ld\&ulM, &ulS); // 扫描输入时、分、秒 ulVal = 3600 * ulH + 60 * ulM + ulS; timerInitRTC(ulVal); pulseInit( ); // 时分秒转换为1个整数 // RTC初始化 // 开始提供RTC时钟源 uartGets(s, sizeof(s)); // 从UART读取RTC初始时间 jtagWait( ); clockInit( ); uartInit( ); // 防止JTAG失效,重要! // 时钟初始化:晶振,6MHz // UART初始化 unsigned long ulH, ulM, ulS; unsigned long ulVal; if (ulVal < 10) uartPutc('0'); sprintf(s, \"%ld\\r\\n\if (ulVal / 3600 < 10) uartPutc('0'); sprintf(s, \"%ld:\ = ulVal %= 3600; uartPuts(s); = if (ulVal / 60 < 10) uartPutc('0'); sprintf(s, \"%ld:\ulVal %= 60; // 计算并显示分钟 uartPuts(s); uartPuts(s); char s[40]; ulVal % 24 * 60 * 60; // 去掉“天” 16 // Timer2的中断服务函数 void Timer2A_ISR(void) { if (ulStatus & TIMER_RTC_MATCH) { ulVal TimerValueGet(TIMER2_BASE, TIMER_A); // 读取当前RTC计时器值 if (ulVal > 24 * 60 * 60) // 若超过一天,则从0开始 { ulVal 0; = TimerLoadSet(TIMER2_BASE, TIMER_A, 0); // 重新设置RTC计数器初值 = } } = timerDispRTC(ulVal); // 显示当前时间 TimerMatchSet(TIMER2_BASE, TIMER_A, 1 + ulVal); // 重新设置RTC匹配值 } ulStatus = TimerIntStatus(TIMER2_BASE, true); TimerIntClear(TIMER2_BASE, ulStatus); unsigned long ulStatus; unsigned long ulVal; 4. 16位单次触发定时 程序清单1.4是Timer模块16位单次触发定时器模式的例子。该例程实现的功能与32 位单次触发定时的例程(参见程序清单1.1)基本相同,只是多了一个8位预分频器的运用。 程序清单1.4 Timer例程:16位单次触发定时 #include \"systemInit.h\" #include // 定义LED #define LED_PERIPH SYSCTL_PERIPH_GPIOG #define LED_PORT GPIO_PORTG_BASE #define LED_PIN GPIO_PIN_2 // 定义KEY #define KEY_PERIPH SYSCTL_PERIPH_GPIOD #define KEY_PORT GPIO_PORTD_BASE #define KEY_PIN GPIO_PIN_1 17 // 主函数(程序入口) int main(void) { SysCtlPeriEnable(LED_PERIPH); // 使能LED所在的GPIO端口 GPIOPinTypeOut(LED_PORT, LED_PIN); // 设置LED所在的管脚为输出 GPIOPinWrite(LED_PORT, LED_PIN, 1 << 2); // 熄灭LED SysCtlPeriEnable(SYSCTL_PERIPH_TIMER0); // 使能Timer模块 TimerConfigure(TIMER0_BASE, TIMER_CFG_16_BIT_PAIR | // 配置Timer为16位单次触发 TIMER_CFG_A_ONE_SHOT); TimerPrescaleSet(TIMER0_BASE, TIMER_A, 199); // 预先进行200分频 TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); for (;;) { SysCtlDelay(10 * (TheSysClock / 3000)); // 延时,消除松键抖动 TimerLoadSet(TIMER0_BASE, TIMER_A, 45000); // 设置Timer初值,定时1.5s TimerEnable(TIMER0_BASE, TIMER_A); // 使能Timer计数 GPIOPinWrite(LED_PORT, LED_PIN, 0x00); // 点亮LED,定时开始 } // TimerA的中断服务函数 void Timer0A_ISR(void) { unsigned char ucVal; unsigned long ulStatus; } } while (GPIOPinRead(KEY_PORT, KEY_PIN) == 0x00); // 等待按键抬起 if (GPIOPinRead(KEY_PORT, KEY_PIN) == 0x00) { // 如果复位时按下KEY IntEnable(INT_TIMER0A); IntMasterEnable( ); // 使能Timer超时中断 // 使能Timer中断 // 使能处理器中断 SysCtlPeriEnable(KEY_PERIPH); // 使能KEY所在的GPIO端口 GPIOPinTypeIn(KEY_PORT, KEY_PIN); // 设置KEY所在管脚为输入 jtagWait( ); clockInit( ); // 防止JTAG失效,重要! // 时钟初始化:晶振,6MHz SysCtlDelay(10 * (TheSysClock / 3000)); // 延时,消除按键抖动 18 ulStatus TimerIntStatus(TIMER0_BASE, true); // 获取当前中断状态 TimerIntClear(TIMER0_BASE, ulStatus); // 清除中断状态,重要! if (ulStatus & TIMER_TIMA_TIMEOUT) // 如果是超时中断 { ucVal GPIOPinRead(LED_PORT, LED_PIN); // 反转LED GPIOPinWrite(LED_PORT, LED_PIN, ~ucVal); } } 5. 16位周期定时 程序清单1.5是Timer模块16位周期定时器模式的例子。该例程实现的功能与32位周期定时的例程(参见程序清单1.2)基本相同,只是多了一个8位预分频器的运用。 程序清单1.5 Timer例程:16位周期定时 #include \"systemInit.h\" #include // 定义LED #define LED_PERIPH SYSCTL_PERIPH_GPIOG #define LED_PORT GPIO_PORTG_BASE #define LED_PIN GPIO_PIN_2 = // 主函数(程序入口) int main(void) = { SysCtlPeriEnable(LED_PERIPH); // 使能LED所在的GPIO端口 GPIOPinTypeOut(LED_PORT, LED_PIN); // 设置LED所在管脚为输出 SysCtlPeriEnable(SYSCTL_PERIPH_TIMER0); // 使能Timer模块 TimerConfigure(TIMER0_BASE, TIMER_CFG_16_BIT_PAIR | // 配置Timer为16位周期定时器 TIMER_CFG_A_PERIODIC); TimerPrescaleSet(TIMER0_BASE, TIMER_A, 99); TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); IntEnable(INT_TIMER0A); // 使能Timer超时中断 // 使能Timer中断 // 预先进行100分频 TimerLoadSet(TIMER0_BASE, TIMER_A, 30000); // 设置Timer初值,定时500ms jtagWait( ); clockInit( ); // 防止JTAG失效,重要! // 时钟初始化:晶振,6MHz 19 IntMasterEnable( ); // 使能处理器中断 TimerEnable(TIMER0_BASE, TIMER_A); // 使能Timer计数 for (;;) { } } // 定时器的中断服务函数 void Timer0A_ISR(void) { unsigned char ucVal; unsigned long ulStatus; = ulStatus TimerIntStatus(TIMER0_BASE, true); // 读取中断状态 TimerIntClear(TIMER0_BASE, ulStatus); // 清除中断状态,重要! = if (ulStatus & TIMER_TIMA_TIMEOUT) // 如果是Timer超时中断 { ucVal GPIOPinRead(LED_PORT, LED_PIN); // 反转LED GPIOPinWrite(LED_PORT, LED_PIN, ~ucVal); } } 6. 16位输入边沿计数捕获 程序清单1.6是Timer模块16位输入边沿计数捕获模式的例子。在程序中,利用函数pulseInit( )产生10KHz的PWM方波,为边沿计数捕获模式提供时钟源。在EasyARM1138开发板上做实验时,需要短接PF6/CCP1和PF7/CCP4管脚。程序移植到其它开发板,如EasyARM615或EasyARM62,可以利用32.768KHz振荡器作为输入时钟源。 程序运行后,配置Timer为16位输入边沿计数捕获模式,设置计数初值和匹配值。启动Timer计数后,每从CCP4管脚输入一个脉冲,计数值就减1,直到与匹配值相当时停止计数,并触发计数捕获中断。在中断服务函数里重新配置Timer,并翻转LED。 程序清单1.6 Timer例程:16位输入边沿计数捕获 #include \"systemInit.h\" #include // 定义LED #define LED_PERIPH SYSCTL_PERIPH_GPIOG #define LED_PORT GPIO_PORTG_BASE #define LED_PIN GPIO_PIN_2 20 #define PART_LM3S1138 #include // 在CCP1管脚产生10KHz方波,为Timer2的16位输入边沿计数捕获功能提供时钟源 void pulseInit(void) { SysCtlPeriEnable(SYSCTL_PERIPH_TIMER0); // 使能TIMER0模块 SysCtlPeriEnable(CCP1_PERIPH); // 使能CCP1所在的GPIO端口 GPIOPinTypeTimer(CCP1_PORT, CCP1_PIN); // 配置相关管脚为Timer功能 TimerConfigure(TIMER0_BASE, TIMER_CFG_16_BIT_PAIR | // 配置TimerB为16位PWM TimerLoadSet(TIMER0_BASE, TIMER_B, 600); // 设置TimerB初值 TimerMatchSet(TIMER0_BASE, TIMER_B, 300); // 设置TimerB匹配值 TimerEnable(TIMER0_BASE, TIMER_B); } // 定时器16位输入边沿计数捕获功能初始化 void timerInitCapCount(void) { SysCtlPeriEnable(SYSCTL_PERIPH_TIMER2); // 使能Timer模块 SysCtlPeriEnable(CCP4_PERIPH); // 使能CCP4所在的GPIO端口 GPIOPinTypeTimer(CCP4_PORT, CCP4_PIN); // 配置CCP4管脚为脉冲输入 TimerConfigure(TIMER2_BASE, TIMER_CFG_16_BIT_PAIR | // 配置Timer为16位事件计数器 TIMER_CFG_A_CAP_COUNT); TimerControlEvent(TIMER2_BASE, // 控制TimerA捕获CCP负边沿 TimerLoadSet(TIMER2_BASE, TIMER_A, 40000); // 设置计数器初值 TimerMatchSet(TIMER2_BASE, TIMER_A, 35000); // 设置事件计数匹配值 TimerIntEnable(TIMER2_BASE, TIMER_CAPA_MATCH); // 使能TimerA捕获匹配中断 TimerEnable(TIMER2_BASE, TIMER_A); // 使能Timer计数 } // 主函数(程序入口) IntEnable(INT_TIMER2A); IntMasterEnable( ); // 使能Timer中断 // 使能处理器中断 TIMER_A, TIMER_EVENT_NEG_EDGE); TIMER_CFG_B_PWM); 21 int main(void) { SysCtlPeriEnable(LED_PERIPH); // 使能LED所在的GPIO端口 GPIOPinTypeOut(LED_PORT, LED_PIN); // 设置LED所在管脚为输出 = pulseInit( ); timerInitCapCount( ); // Timer初始化:16位计数捕获 for (;;) { = } } // Timer2的中断服务函数 void Timer2A_ISR(void) { ulStatus TimerIntStatus(TIMER2_BASE, true); // 读取当前中断状态 TimerIntClear(TIMER2_BASE, ulStatus); // 清除中断状态,重要! if (ulStatus & TIMER_CAPA_MATCH) // 若是TimerA捕获匹配中断 { TimerLoadSet(TIMER2_BASE, TIMER_A, 40000); // 重新设置计数器初值 TimerEnable(TIMER2_BASE, TIMER_A); // TimerA已停止,重新使能 ucVal GPIOPinRead(LED_PORT, LED_PIN); // 反转LED GPIOPinWrite(LED_PORT, LED_PIN, ~ucVal); } } unsigned long ulStatus; unsigned char ucVal; jtagWait( ); clockInit( ); // 防止JTAG失效,重要! // 时钟初始化:晶振,6MHz 7. 16位输入边沿定时捕获 程序清单1.7是Timer模块16位输入边沿定时捕获模式的例子。同样采用pulseInit( )函数来产生捕获用的时钟源,频率为1KHz。在EasyARM1138开发板上做实验时,需要短接PF6/CCP1和PF7/CCP4管脚。 程序运行后,配置Timer模块为16位输入边沿定时捕获模式。函数pulseMeasure( )利用捕获功能测量输入到CCP4管脚的脉冲频率,结果通过UART显示。 22 程序清单1.7 Timer例程:16位输入边沿定时捕获 #include \"systemInit.h\" #include \"uartGetPut.h\" #include #define PART_LM3S1138 #include // 在CCP1管脚产生1KHz方波,为Timer2的16位输入边沿定时捕获功能提供时钟源 void pulseInit(void) { SysCtlPeriEnable(SYSCTL_PERIPH_TIMER0); // 使能TIMER0模块 SysCtlPeriEnable(CCP1_PERIPH); // 使能CCP1所在的GPIO端口 GPIOPinTypeTimer(CCP1_PORT, CCP1_PIN); // 配置相关管脚为Timer功能 TimerConfigure(TIMER0_BASE, TIMER_CFG_16_BIT_PAIR | // 配置TimerB为16位PWM TimerLoadSet(TIMER0_BASE, TIMER_B, 6000); // 设置TimerB初值 TimerMatchSet(TIMER0_BASE, TIMER_B, 3000); // 设置TimerB匹配值 TimerEnable(TIMER0_BASE, TIMER_B); } // 定时器16位输入边沿定时捕获功能初始化 void timerInitCapTime(void) { SysCtlPeriEnable(SYSCTL_PERIPH_TIMER2); // 使能Timer模块 SysCtlPeriEnable(CCP4_PERIPH); // 使能CCP4所在的GPIO端口 GPIOPinTypeTimer(CCP4_PORT, CCP4_PIN); // 配置CCP4管脚为脉冲输入 TimerConfigure(TIMER2_BASE, TIMER_CFG_16_BIT_PAIR | // 配置Timer为16位事件定时器 TimerControlEvent(TIMER2_BASE, // 控制TimerA捕获CCP正边沿 TimerControlStall(TIMER2_BASE, TIMER_A, true); // 允许在调试时暂停定时器计数 TimerIntEnable(TIMER2_BASE, TIMER_CAPA_EVENT); } 23 IntEnable(INT_TIMER2A); IntMasterEnable( ); // 使能TimerA事件捕获中断 // 使能TimerA中断 // 使能处理器中断 TIMER_A, TIMER_EVENT_POS_EDGE); TIMER_CFG_A_CAP_TIME); TIMER_CFG_B_PWM); // 定义捕获标志 volatile tBoolean CAP_Flag = false; // 测量输入脉冲频率并显示 void pulseMeasure(void) { unsigned short i; TimerLoadSet(TIMER2_BASE, TIMER_A, 0xFFFF); // 设置计数器初值 TimerEnable(TIMER2_BASE, TIMER_A); // 使能Timer计数 CAP_Flag = false; // 清除捕获标志 usVal[i] TimerValueGet(TIMER2_BASE, TIMER_A); // 读取捕获值 } TimerDisable(TIMER2_BASE, TIMER_A); // 禁止Timer计数 } // 主函数(程序入口) int main(void) { for (;;) { pulseMeasure( ); } // Timer2的中断服务函数 void Timer2A_ISR(void) SysCtlDelay(1500 * (TheSysClock / 3000)); } jtagWait( ); clockInit( ); uartInit( ); // 防止JTAG失效,重要! // 时钟初始化:晶振,6MHz // UART初始化 // Timer初始化:16位定时捕获 sprintf(s, \"%d Hz\\r\\n\ // 输出测定的脉冲频率 uartPuts(s); for (i = 0; i < 2; i++) while (!CAP_Flag); = // 等待捕获输入脉冲 { unsigned short usVal[2]; char s[40]; pulseInit( ); timerInitCapTime( ); 24 { ulStatus TimerIntStatus(TIMER2_BASE, true); // 读取当前中断状态 TimerIntClear(TIMER2_BASE, ulStatus); // 清除中断状态,重要! if (ulStatus & TIMER_CAPA_EVENT) // 若是TimerA事件捕获中断 { } CAP_Flag = true; // 置位捕获标志 } unsigned long ulStatus; 8. 16位PWM 程序清单1.8是Timer模块16位PWM模式的例子。程序运行后,配置Timer工作在双16位PWM模式下,设置的装载值决定PWM周期,设置的匹配值决定PWM占空比。最终PWM方波信号从TimerA和TimerB对应的两个CCP管脚输出。 程序清单1.8 Timer例程:16位PWM #include \"systemInit.h\" #include #define PART_LM3S1138 #include // Timer初始化为16位PWM模式 =void timerInitPWM(void) { SysCtlPeriEnable(SYSCTL_PERIPH_TIMER1); // 使能Timer模块 SysCtlPeriEnable(CCP2_PERIPH); // 使能CCP2所在的GPIO端口 GPIOPinTypeTimer(CCP2_PORT, CCP2_PIN); // 配置CCP2管脚为PWM输出 SysCtlPeriEnable(CCP3_PERIPH); // 使能CCP3所在的GPIO端口 GPIOPinTypeTimer(CCP3_PORT, CCP3_PIN); // 配置CCP3管脚为PWM输出 TimerConfigure(TIMER1_BASE, TIMER_CFG_16_BIT_PAIR | // 配置Timer为双16位PWM TimerControlLevel(TIMER1_BASE, TIMER_BOTH, true); // 控制PWM输出反相 TimerLoadSet(TIMER1_BASE, TIMER_BOTH, 6000); // 设置TimerBoth初值 TimerMatchSet(TIMER1_BASE, TIMER_A, 3000); // 设置TimerA的PWM匹配值 TimerMatchSet(TIMER1_BASE, TIMER_B, 2000); // 设置TimerB的PWM匹配值 TimerEnable(TIMER1_BASE, TIMER_BOTH); // 使能Timer计数,PWM开始输出 } TIMER_CFG_A_PWM | TIMER_CFG_B_PWM); 25 // 主函数(程序入口) int main(void) { for (;;) { } } jtagWait( ); clockInit( ); // 防止JTAG失效,重要! // 时钟初始化:晶振,6MHz // Timer的PWM功能初始化 timerInitPWM( ); 9. Timer PWM应用:蜂鸣器发声 如图1.1所示,为EasyARM1138开发板上的蜂鸣器驱动电路。蜂鸣器类型是交流蜂鸣器,也称无源蜂鸣器,需要输入一列方波才能鸣响,发声频率等于驱动方波的频率。 程序清单1.9是Timer模块16位PWM模式的一个应用,可以驱动交流蜂鸣器发声,运行后蜂鸣器以不同的频率叫两声。 程序清单1.10和程序清单1.11是蜂鸣器的驱动程序,仅有3个驱动函数,用起来很简捷:蜂鸣器初始化函数buzzerInit( );蜂鸣器发声函数buzzerSound( ),能发出指定频率的响声;蜂鸣器静音函数buzzerQuiet( )。 5VD41N4148BZ1BUZZERABR2675ΩPG4/CCP3R242.2kΩR2510kΩQ18050GND 图1.1 蜂鸣器驱动电路 程序清单1.9 Timer PWM应用:蜂鸣器发声 #include \"systemInit.h\" #include \"buzzer.h\" // 主函数(程序入口) 26 int main(void) { buzzerSound(1500); // 蜂鸣器发出1500Hz声音 SysCtlDelay(400 * (TheSysClock / 3000)); // 延时约400ms buzzerSound(2000); // 蜂鸣器发出2000Hz声音 SysCtlDelay(800 * (TheSysClock / 3000)); // 延时约800ms buzzerQuiet( ); // 蜂鸣器静音 for (;;) { } } jtagWait( ); clockInit( ); buzzerInit( ); // 防止JTAG失效,重要! // 时钟初始化:晶振,6MHz // 蜂鸣器初始化 程序清单1.10 蜂鸣器驱动头文件buzzer.h #ifndef __BUZZER_H__ #define __BUZZER_H__ // 蜂鸣器初始化 extern void buzzerInit(void); // 蜂鸣器发出指定频率的声音 extern void buzzerSound(unsigned short usFreq); // 蜂鸣器停止发声 extern void buzzerQuiet(void); #endif // __BUZZER_H__ 程序清单1.11 蜂鸣器驱动C文件buzzer.c #include \"buzzer.h\" #include 27 #define PART_LM3S1138 #include #define SysCtlPeriEnable #define GPIOPinTypeOut = // 声明全局的系统时钟变量 extern unsigned long TheSysClock; // 蜂鸣器初始化 void buzzerInit(void) { SysCtlPeriEnable(SYSCTL_PERIPH_TIMER1); // 使能TIMER1模块 SysCtlPeriEnable(CCP3_PERIPH); // 使能CCP3所在的GPIO端口 GPIOPinTypeTimer(CCP3_PORT, CCP3_PIN); // 设置相关管脚为Timer功能 TimerConfigure(TIMER1_BASE, TIMER_CFG_16_BIT_PAIR | // 配置TimerB为16位PWM } // 蜂鸣器发出指定频率的声音 // usFreq是发声频率,取值 (系统时钟/65536)+1 ~ 20000,单位:Hz void buzzerSound(unsigned short usFreq) { if ((usFreq <= TheSysClock / 65536UL) || (usFreq > 20000)) { buzzerQuiet( ); } else { GPIOPinTypeTimer(CCP3_PORT, CCP3_PIN); // 设置相关管脚为Timer功能 ulVal TheSysClock / usFreq; TimerLoadSet(TIMER1_BASE, TIMER_B, ulVal); // 设置TimerB初值 TimerMatchSet(TIMER1_BASE, TIMER_B, ulVal / 2); // 设置TimerB匹配值 TimerEnable(TIMER1_BASE, TIMER_B); // 使能TimerB计数 } } // 蜂鸣器停止发声 void buzzerQuiet(void) { TimerDisable(TIMER1_BASE, TIMER_B); // 禁止TimerB计数 unsigned long ulVal; TIMER_CFG_B_PWM); SysCtlPeripheralEnable GPIOPinTypeGPIOOutput 28 GPIOPinTypeOut(CCP3_PORT, CCP3_PIN); // 配置CCP3管脚为GPIO输出 GPIOPinWrite(CCP3_PORT, CCP3_PIN, 0x00); // 使CCP3管脚输出低电平 } 10. Timer PWM应用:蜂鸣器演奏乐曲 程序清单1.12是Timer模块16位PWM模式的一个应用,能驱动交流蜂鸣器演奏一首动听的乐曲《化蝶》,乐谱参见图1.2。程序清单1.13和程序清单1.14是演奏乐曲的驱动程序\"music.h\"和\"music.c\"。 图1.2 乐谱《化蝶》 简谱是大众化的音乐记谱方式,比较容易理解和掌握。我们可以把一首乐谱(score)看成是由若干个基本的音符(note)单元组成。一个音符由音名和时值组成。音名就是低音、中音、高音的1234567(唱作do re mi fa sol la si),其本质是音符的发声频率。在头文件\"music.h\"里,用L1~L7、M1~M7、H1~H7定义了低音、中音、高音所对应的发声频率。时值是音符的发声时间长短,有全音符、二分音符、四分音符……等等。音符可以后缀一个“符点”,表示时值增加1/2,特殊地,二分音符加符点时用“-”代替圆点。参见表1.24的描述。 表1.24 常见简谱音符示例 音 符 5――― 5- 5 55 5―― 5. 5.名 称 相 对 时 值 全音符 T 二分音符 T/2 四分音符 T/4 八分音符 T/8 十六分音符 T/16 符点二分音符 T/2+T/4 符点四分音符 T/4+T/8 符点八分音符 T/8+T/16 29 在头文件\"music.h\"里定义有一个音符结构体tNote,有两个数据成员:音名mName和时值mTime。在C文件\"music.c\"里定义有一个tNote型常量数表MyScore[ ],用来保存实际乐谱转换成tNote格式的数据。有了上述一点点乐谱基础知识,我们就可以很方便地编辑这个数表了。比如音符“3”转换为“{L3, T/4}”,音符“3.”转换为“{M3, T/4+T/8}”,等等。.在程序清单1.14里,已经在数表MyScore[ ]里给出了乐谱《化蝶》开头一部分音符转换结果,其余部分请感兴趣的读者补充完整。 程序清单1.12 Timer PWM应用:蜂鸣器演奏乐曲 #include \"systemInit.h\" #include \"buzzer.h\" #include \"music.h\" // 主函数(程序入口) int main(void) { for (;;) { } musicPlay( ); SysCtlDelay(4000 * (TheSysClock / 3000)); jtagWait( ); clockInit( ); buzzerInit( ); // 防止JTAG失效,重要! // 时钟初始化:晶振,6MHz // 蜂鸣器初始化 } 程序清单1.13 乐曲演奏头文件music.h #ifndef __MUSIC_H__ #define __MUSIC_H__ // 定义低音音名(数值单位:Hz) #define L1 #define L2 #define L3 #define L4 #define L5 #define L6 #define L7 #define M1 #define M2 #define M3 #define M4 262 294 330 349 392 440 494 523 587 659 698 // c // d // e // f // g // a1 // b1 // c1 // d1 // e1 // f1 // 定义中音音名 30 #define M5 #define M6 #define M7 #define H1 #define H2 #define H3 #define H4 #define H5 #define H6 #define H7 784 880 988 1047 1175 1319 1397 1568 1760 1976 // g1 // a2 // b2 // c2 // d2 // e2 // f2 // g2 // a3 // b3 // 定义高音音名 // 定义时值单位,决定演奏速度(数值单位:ms) #define T 3600 // 定义音符结构 typedef struct { short mName; // 音名:取值L1~L7、M1~M7、H1~H7分别表示低音、中音、高音的 // 演奏乐曲 extern void musicPlay(void); #endif // __MUSIC_H__ // 1234567,取值0表示休止符 // 二分音符、四分音符、八分音符…,取值0表示演奏结束 short mTime; // 时值:取值T、T/2、T/4、T/8、T/16、T/32分别表示全音符、 }tNote; 程序清单1.14 乐曲演奏C文件music.c #include \"music.h\" #include \"buzzer.h\" #include \"systemInit.h\" // 定义乐曲:《化蝶》(梁祝) const tNote MyScore[ ] = { {L3, T/4}, {L5, T/8+T/16}, {L6, T/16}, {M1, T/8+T/16}, {M2, T/16}, {L6, T/16}, 31 {M1, T/16}, {L5, T/8}, {M5, T/8+T/16}, {H1, T/16}, {M6, T/16}, {M5, T/16}, {M3, T/16}, {M5, T/16}, {M2, T/2}, // 省略后续乐曲数据,请感兴趣的读者补充完整 }; // 演奏乐曲 void musicPlay(void) { for (;;) { buzzerSound(MyScore[i].mName); SysCtlDelay(MyScore[i].mTime * (TheSysClock / 3000)); i++; buzzerQuiet( ); SysCtlDelay(10 * (TheSysClock / 3000)); } } if (MyScore[i].mTime == 0) break; short i = 0; { 0, 0} // 结束 32 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- yrrf.cn 版权所有 赣ICP备2024042794号-2
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务