我们在GPIO和外部中断的基础功能测试的基础上进行定时器功能的测试。在GPIO和外部中断我们实现的按键中断的采集以及LED的控制,在次基础上加入定时器功能会擦出怎么样的火花呢?是的,第一个就是LED的闪烁,在定时器中断中进行LED的翻转。
我们先了解一下MAX78000的定时器:
MAX78000具有32位定时器/计数器/PWM (TMR, LPTMR),通用的32位定时器提供定时、捕获/比较或脉宽调制(PWM)信号的生成。定时器提供以下功能:
●32位向上/向下自动重新加载
●可编程预分频器
●PWM输出产生
●捕获、比较和捕获/比较能力
●外部引脚与GPIO复用,用于定时器输入,时钟门控,或捕获
●计时器输出管脚
●TMR0-TMR3可配置为2 × 16位通用定时器
●定时器中断
MAX78000一共提供6个32位定时器(TMR0、TMR1、TMR2、TMR3、LPTMR0和LPTMR1)。LPTMR0和LPTMR1可以在SLEEP、LOW POWER和MICRO POWER模式下运行。所有计时器都支持I/O功能。请注意,端口的功能可以与其他功能进行复用在GPIO引脚上。(在max78000.h中,6个定时器被描述为MXC_TMR0~MXC_TMR5)。
每一个定时器能够实现的功能如下:
在这里我们就要考虑一下本章节测试需要使用哪个定时器呢?基本定时功能基本上都能实现,那么PWM的展现可能需要与LED相结合。我们首先实现基础定时器功能,通过定时器中断中实现LED的翻转。
基础定时功能:
要想实现LED是连续翻转,我们需要选择定时器为Counter Mode。
为此我们参考例程定时器初始化内容如下:
#define Basic_CLOCK_SOURCE MXC_TMR_8M_CLK
#define Basic_FREQ 2// (Hz)
#define Basic_TIMER MXC_TMR3
void BasicTimerInit()
{
mxc_tmr_cfg_t tmr;
uint32_t periodTicks = MXC_TMR_GetPeriod(Basic_TIMER, Basic_CLOCK_SOURCE, 128, Basic_FREQ);
MXC_TMR_Shutdown(Basic_TIMER);
tmr.pres = TMR_PRES_128;
tmr.mode = TMR_MODE_CONTINUOUS;
tmr.bitMode = TMR_BIT_MODE_16B;
tmr.clock = Basic_CLOCK_SOURCE;
tmr.cmp_cnt = periodTicks; //SystemCoreClock*(1/interval_time);
tmr.pol = 0;
if (MXC_TMR_Init(Basic_TIMER, &tmr, true) != E_NO_ERROR) {
printf("Failed Continuous timer Initialization.\n");
return;
}
MXC_NVIC_SetVector(TMR3_IRQn, BasicTimerHandler);
NVIC_EnableIRQ(TMR3_IRQn);
printf("Continuous timer started.\n");
MXC_TMR_Start(Basic_TIMER);
}
我们创建中断并编写中断程序:
void BasicTimerHandler()
{
MXC_TMR_ClearFlags(Basic_TIMER);
LED_Toggle(LEDSt);
}
以上代码测试开始后出现了异常,我们经过定位发现程序卡在了while (!(tmr->ctrl1 & MXC_F_TMR_REVB_CTRL1_CLKEN_A)),也就是说定时器开启使能失败了,通过
MXC_SYS_IsClockEnabled(MXC_SYS_PERIPH_CLOCK_TMR1)检查时钟发现已经开启了。尝试重新加载例程看一下,同样的问题。、
通过不断的测试目前的的现象更倾向于无限进入中断,都不用开启定时器计数,只要定时器初始化完成就开启潘多拉魔盒,计数就开始乱跳了。进行深层的挖掘发现在tmr_revb.c中的void MXC_TMR_RevB_ConfigGeneric函数(定时器初始化的底层函数)中,如果tmr.bitMode = TMR_BIT_MODE_16B则直接启动中断和定时器,到这里看似已经慢慢的揭开了这个异常的面纱。不过我准备放弃了,另寻途径,既然tmr.bitMode = TMR_BIT_MODE_16B会造成这种不可接受的异常,那么配置TMR_BIT_MODE_16A试一下,修改代码如下:
void BasicTimerInit()
{
mxc_tmr_cfg_t tmr;
uint32_t periodTicks = MXC_TMR_GetPeriod(Basic_TIMER, Basic_CLOCK_SOURCE, 128, Basic_FREQ);
MXC_TMR_Shutdown(Basic_TIMER);
tmr.pres = TMR_PRES_128;
tmr.mode = TMR_MODE_CONTINUOUS;
tmr.bitMode = TMR_BIT_MODE_16A;
tmr.clock = Basic_CLOCK_SOURCE;
tmr.cmp_cnt = periodTicks; //SystemCoreClock*(1/interval_time);
tmr.pol = 0;
if (MXC_TMR_Init(Basic_TIMER, &tmr, false) != E_NO_ERROR) {
printf("Failed Continuous timer Initialization.\n");
return;
}
MXC_NVIC_SetVector(TMR3_IRQn, BasicTimerHandler);
NVIC_EnableIRQ(TMR3_IRQn);
MXC_TMR_EnableInt(Basic_TIMER);
printf("Continuous timer started.\n");
MXC_TMR_Start(Basic_TIMER);
}
柳暗花明啊,这是一个bitMode引发的惨案,不过结果是好,使用TMR_BIT_MODE_16A后,可以正常进入中断了,程序正常运行了,也算达到了预期。
PWM输出功能:
在PWM模式下,定时器使用定时器的输出信号发送PWM输出。计时器首先计数到匹配值存储在TMRn_PWM.pwm寄存器中。在循环结束时,TMRn_CNT值与TMRn_PWM.pwm比较,定时器输出信号切换状态。计时器继续计数,直到到达TMRn_CMP值。
定时器周期在TMRn_CNT = TMRn_CMP之后的fCNT_CLK上升沿结束。计时器外设在计时器周期结束时自动执行以下动作:
•TMRn_CNT复位为0x0000 0001,定时器恢复计数。
•定时器输出信号切换。
•对应的TMRn_INTFL.irq字段设置为1,表示发生了定时器中断事件。
当TMRn_CTRL0.pol = 0,时,定时器输出信号从低开始,到TMRn_CNT值时变为高匹配TMRn_PWM值。定时器输出信号保持高电平,直到TMRn_CNT值达到TMRn_CMP,导致定时器输出信号变低,TMRn_CNT值复位为0x0000 0001。
当TMRn_CTRL0.pol = 1,时,定时器输出信号高起始,当TMRn_CNT值与TMRn_PWM值,定时器输出信号保持低电平,直到TMRn_CNT值达到TMRn_CMP,导致定时器输出信号转高,TMRn_CNT值复位为0x0000 0001。
测试代码如下:
#define PWM_CLOCK_SOURCE MXC_TMR_32K_CLK
#define FREQ 10 // (Hz)
#define DUTY_CYCLE 50 // (%)
#define PWM_TIMER MXC_TMR4
void PWMTimer()
{
mxc_tmr_cfg_t tmr; // to configure timer
unsigned int periodTicks = MXC_TMR_GetPeriod(PWM_TIMER, PWM_CLOCK_SOURCE, 16, FREQ);
unsigned int dutyTicks = periodTicks * DUTY_CYCLE / 100;
MXC_TMR_Shutdown(PWM_TIMER);
tmr.pres = TMR_PRES_16;
tmr.mode = TMR_MODE_PWM;
tmr.bitMode = TMR_BIT_MODE_32;
tmr.clock = PWM_CLOCK_SOURCE;
tmr.cmp_cnt = periodTicks;
tmr.pol = 1;
if (MXC_TMR_Init(PWM_TIMER, &tmr, true) != E_NO_ERROR) {
printf("Failed PWM timer Initialization.\n");
return;
}
if (MXC_TMR_SetPWM(PWM_TIMER, dutyTicks) != E_NO_ERROR) {
printf("Failed TMR_PWMConfig.\n");
return;
}
MXC_TMR_Start(PWM_TIMER);
printf("PWM started.\n\n");
}
效果如下:
精彩视频分享:
串口接收情况(定时器基础定时测试)
定时器基础定时测试效果展示
定时器PWM测试效果展示