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)。