TIM概述
外设定时器除了和系统定时器一样具有基本定时功能外,还具有PWM(Pulse width modulation)输出的功能,stm32f4的外设定时器非常多,一 共有14个,分为2个高级控制定时器、10 个通用定时器 和 2 个基本定时器:
1.高级控制定时器(TIM1和TIM8),挂载到APB2:具有16位定时器功能,具有4通道、输入捕获、PWM输出高级控制功能;
2.通用定时器(TIM2到TIM5),挂载到APB1:具有16或32位定时功能,具有4通道、输入捕获、PWM输出控制功能;
通用定时器(TIM9到TIM14),挂载到AP1或APB2:具有16位定时功能,具有2通道、输入捕获、PWM输出控制功能;
3.基本定时器(TIM6和TIM7),挂载到APB1:具有16位定时功能。
定时计算
对于TIM的外设定时器的时钟频率,需要注意参考手册RCC章节中如下两句话
STM32F405xx/07xx 和 STM32F415xx/17xx 的定时器时钟频率由硬件自动设置。分为两种
情况:
1. 如果APB预分频器为1,定时器时钟频率等于APB域的频率。
2. 否则,等于APB域的频率的两倍 (×2)。
而在函数SetSysClock中可以看到,APB1=1/4 x AHB,APB2=1/2 x AHB,也就是挂载在APB下的TIM,其时钟频率为对应的APB时钟频率的两倍,而外设TIM也不会对所得到时钟频率进行再次分频才使用,而是直接使用。但是在使用PWM输出/比较或定时功能时需要使用预分频器对其分频,从TIM的框图中可以看出:
实验程序1
通过原理图发现LED4的引脚连接了TIM14的通道1,便可以通过TIM14通道1实现呼吸灯。
led.c
#include "stm32f4xx.h"
#include "common.h"
#include "led.h"
void breathinglight_init()
{
GPIO_InitTypeDef GPIO_InitStructure ;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
//初始化对应端口的引脚
GPIO_InitStructure.GPIO_Pin = LED_PIN_4;//指定第9根引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF ;//配置为复用模式
GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz ;//配置引脚的响应时间=1/50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP ;//推挽的输出模式,增加输出电流和灌电流的能力
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//不使能内部上下拉电阻
GPIO_Init(LED_PORT2,&GPIO_InitStructure);
//将LED4的引脚连接到TIM14
GPIO_PinAFConfig(LED_PORT2, LED4_PinSource, GPIO_AF_TIM14);
//配置TIM14的相关参数:计数值(决定定时时间)、分频值
//TIM14的硬件时钟频率=AHBCLK/4*2=APB1CLK*2=84000000Hz
//设置预分频器为8400:84000000/8400
//只要进行10000次计数,就是1秒时间的到达,也就是1Hz的频率输出
TIM_TimeBaseStructure.TIM_Period = 10000/200-1;//如:计数值10000/100-1,决定了输出频率为100Hz,计数值为10000/50-1,频率为50Hz
TIM_TimeBaseStructure.TIM_Prescaler = 8400-1;//预分频,也就是第一次分频,当前8400分频,就是84MHz/8400
TIM_TimeBaseStructure.TIM_ClockDivision = 0;//时钟分频,也称之二次分频这个F407是不支持的,因此该参数是不会生效的
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//就是从0开始计数,然后计数到TIM_Period
TIM_TimeBaseInit(TIM14, &TIM_TimeBaseStructure);
//占空比的配置
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//工作在PWM1模式,当计时器值小于比较器设定值时则输出脚此时输出有效电位。
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //脉冲的输出开关,当前是输出脉冲
TIM_OCInitStructure.TIM_Pulse = 25;//这个值是决定了占空比,配置比较值,现在的输出占空比为50%
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//有效电平为高电平
//TIM14的通道1配置
TIM_OC1Init(TIM14, &TIM_OCInitStructure);
//使能定时器14工作
TIM_Cmd(TIM14, ENABLE);
}
led_test.c
#include "led_test.h"
#include "sys_tick.h"
void breathinglight_test()
{
uint32_t pwm = 50;
uint32_t flag = 0;
while(1)
{
//设置TIM14的通道1比较值为20,亮度高
if (0 == flag)
{
TIM_SetCompare1(TIM14, pwm);//设置TIM14通道1的比较值
pwm = pwm - 1;
if (pwm <= 0)
{
flag = 1;
}
}
delay_ms(50);
if (1 == flag)
{
TIM_SetCompare1(TIM14,l);
pwm = pwm + 1;
if (pwm >= 50)
{
flag = 0;
}
}
}
}
main.c
#include "hwconf.h"
#include "led.h"
#include "led_test.h"
int main()
{
init_board(); //初始化相关时钟
breathinglight_init();
breathinglight_test();
}
实验程序2
使用TIM3的定时器中断功能实现LED4闪烁。
tim.c
#include "stm32f4xx.h"
#include "tim.h"
void tim3_init()
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
NVIC_InitTypeDef NVIC_InitStruct;
TIM_TimeBaseStruct.TIM_Period = 10000/2-1;//计数值5000-1,决定了定时时间500ms,即频率为2Hz
TIM_TimeBaseStruct.TIM_Prescaler = 8400-1;//预分频,也就是第一次分频,当前8400分频,就是84MHz/8400
TIM_TimeBaseStruct.TIM_ClockDivision = 0;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStruct);
//配置TIM3的中断触发方式:时间更新中断
TIM_ITConfig(TIM3,TIM_IT_Update , ENABLE);
//配置TIM3的优先级
NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
//使能定时器3工作
TIM_Cmd(TIM3, ENABLE);
}
main.c
#include "hwconf.h"
#include "common.h"
#include "led.h"
#include "tim.h"
void main()
{
init_board();//初始化相关时钟
led4_init();//初始化LED4
tim3_init();
}
void TIM3_IRQHandler(void)
{
//检测是否超时时间到达
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)
{
FLASH_LED4;
//清空标志位,告诉CPU当前数据接收完毕,可以响应新的中断请求
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
}
}
以上的程序都是基于作者本人之前工程模板,和文件进行编写的,有需要可以参考我之前的stm32相关随笔。
总结
1.注意区分不同类型的TIM;
2.TIM的输出频率计数有些复杂,需要谨慎计算;
3.注意PWM占空比的计算:假设高电平有效,比较器值/(计数器值+1)。