stm32定时器级联(一个定时器作为另一个的预分频器
在网上找了许多代码看了许多资料,都没有找到理想的,有些不是用标准库的,有些只写出了想法并没有具体的操作,经过多次修改笔者终于成功运行。
该代码的实现功能是:TIM2和TIM3的级联,TIM2用内部时钟源,每秒产生一个中断(执行NUM1++)和更新事件(作为TRGO输出到TIM3),TIM3以触发输入为时钟,每传来两次信号后进入中断(执行NUM2++)
Timer.c
#include "stm32f10x.h" // Device header
void Timer_Init(void)
{
/*
TIM2
*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 10000-1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200-1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//打开更新中断
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);//设置更新事件,触发输出
/*
TIM3
*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_SelectInputTrigger(TIM3, TIM_TS_ITR1);//TIM3的触发输入
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_External1);//选择TIM3的从模式
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 2-1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 1-1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
/*
NVIC
*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStrucutre;
NVIC_InitStrucutre.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStrucutre.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStrucutre.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStrucutre.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStrucutre);
NVIC_InitStrucutre.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStrucutre.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStrucutre.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStrucutre.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_InitStrucutre);
TIM_Cmd(TIM2, ENABLE);
TIM_Cmd(TIM3, ENABLE);
}
Timer.h
#ifndef __TIMER_H_
#define __TIMER_H_
void Timer_Init(void);
#endif
main.c
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "Timer.h"
uint16_t Num1, Num2;
int main(void)
{
OLED_Init();
Timer_Init();
while (1)
{
OLED_ShowString(1, 1, "NUM1:");
OLED_ShowNum(1, 6, Num1 ,5);
OLED_ShowString(2, 1, "NUM2:");
OLED_ShowNum(2, 6, Num2 ,5);
}
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
Num1++;
TIM_ClearFlag(TIM2, TIM_IT_Update);
}
}
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)
{
Num2++;
TIM_ClearFlag(TIM3, TIM_IT_Update);
}
}
先看看手册中给出的方法:
可以归结为一下几点:
①配置TIM1为主模式,配置内部时钟,时基单元,产生的更新事件映射到TRGO口。
②配置TIM2为从模式,从ITRx引脚输入时钟,设置外部时钟模式,设置时基单元。
③开启TIM1和TIM2。
几点感悟:
①主从模式并不是需要配套使用的,可以只有TIM3的从模式,这也算是笔者学习的一个误区,自以为主从模式是配套的,有主就得有从。
②从其他时钟触发输入选择的时钟模式,应该由TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_External1)函数确定,不应该设置外部时钟模式1(TIM_ETRClockMode1Config)。笔者产生这个误会来自下图。实际上应该看下图。
③定时器的更新中断和更新事件可以同时允许。
附上定时器框图和定时器的内部连接: