Giới thiệu
Timer là thành phần ngoại vi quan trọng của vi điều khiển. Thông thường mỗi vi điều khiển đều có vài timer phục vụ cho nhiều mục đích khác nhau, chẳng hạn như làm bộ đếm, tạo xung PWM, đo tín hiệu đầu vào…
STM32F407VG có 14 timer, bao gồm 2 timer cao cấp (TIM1/TIM8), 10 timer đa dụng, 2 timer cơ bản. Các tính chất cơ bản của chúng được liệt kê ở bảng dưới.

Timer | Type | Resolution | Prescaler | Channels | MAX INTERFACE CLOCK | MAX TIMER CLOCK* | APB |
---|---|---|---|---|---|---|---|
TIM1, TIM8 | Advanced | 16bit | 16bit | 4 | SysClk/2 | SysClk | 2 |
TIM2, TIM5 | General purpose | 32bit | 16bit | 4 | SysClk/4 | SysClk, SysClk/2 | 1 |
TIM3, TIM4 | General purpose | 16bit | 16bit | 4 | SysClk/4 | SysClk, SysClk/2 | 1 |
TIM9 | General purpose | 16bit | 16bit | 2 | SysClk/2 | SysClk | 2 |
TIM10, TIM11 | General purpose | 16bit | 16bit | 1 | SysClk/2 | SysClk | 2 |
TIM12 | General purpose | 16bit | 16bit | 2 | SysClk/4 | SysClk, SysClk/2 | 1 |
TIM13, TIM14 | General purpose | 16bit | 16bit | 1 | SysClk/4 | SysClk, SysClk/2 | 1 |
TIM6, TIM7 | Basic | 16bit | 16bit | 0 | SysClk/4 | SysClk, SysClk/2 | 1 |
Các chế độ hoạt động của Timer:
- Input capture
- Output compare
- PWM generation (Edge- and Center-aligned modes)
- One-pulse mode output
Để sử dụng timer ở chế độ định thời, các bước sau cần được thiết lập:
1. Bật TIM clock bằng cách gọi hàm RCC_APBxPeriphClockCmd(RCC_APBxPeriph_TIMx, ENABLE);
2. Thiết lập các thành phần của struct TIM_TimeBaseInitStruct bằng các tham số cần thiết
3. Gọi hàm TIM_TimeBaseInit(TIMx, &TIM_TimeBaseInitStruct) để thiết lập cấu hình tương ứng cho timer
4. Bật NVIC nếu cần khởi tạo việc cập nhật ngắt
5. Cho phép ngắt tương ứng xảy ra bằng cách gọi hàm TIM_ITConfig(TIMx, TIM_IT_Update)
6. Gọi hàm TIM_Cmd(ENABLE) để bật TIM counter.
Dưới đây là các tham số để thiết lập cấu hình cho timer:
TIM_Period: Period có nghĩa là chu kỳ của timer (không phải là chu kỳ của 1 xung clock timer). Ví dụ một chu kỳ gồm 1000 xung clock mà mỗi xung clock = 1us ta sẽ được period là 1ms. Cần trừ đi cho 1 là vì hệ thống đếm bắt đầu từ 0.
TIM_Prescaler : Tham số TIM_Prescaler hiểu đơn giản như một bộ chia tần số.
TIM_Prescaler = ((SystemCoreClock/n)/Ftim_cnt)-1
Trong đó:
SystemCoreClock/n: tần số clock timer (xem bảng trên)
Ftim_cnt: tần số đếm của timer
TIM_CounterMode: Thiết lập mode cho timer là đếm lên, đếm xuống hay đếm lên/xuống. Nếu chọn mode đếm tăng (đếm lên) có nghĩa là mỗi xung nhịp timer, bộ đếm counter sẽ tự tăng lên một giá trị theo chiều dương cho đến khi nào bằng giá trị period sẽ đếm lại từ đầu, người ta thường gọi trường hợp này là tràn bộ đếm. Có thể cấu hình để khi tràn bộ đếm sẽ có ngắt xảy ra.


Ví dụ
Ở ví dụ đầu tiên chúng ta sử dụng TIM2 cho mục đích tạo hàm delay.

#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_tim.h"
#include "misc.h"
void INTTIM_Config(void);
void GPIO_Config(void);
int main(void)
{
SystemInit();
GPIO_Config();
INTTIM_Config();
while(1)
{
}
}
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
GPIO_ToggleBits(GPIOD,GPIO_Pin_13);
}
}
void GPIO_Config(void)
{
GPIO_InitTypeDef gpio_struct;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
gpio_struct.GPIO_Pin = GPIO_Pin_13;
gpio_struct.GPIO_Mode = GPIO_Mode_OUT;
gpio_struct.GPIO_OType = GPIO_OType_PP;
gpio_struct.GPIO_PuPd = GPIO_PuPd_NOPULL;
gpio_struct.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOD, &gpio_struct);
}
void INTTIM_Config(void)
{
NVIC_InitTypeDef nvic_struct;
nvic_struct.NVIC_IRQChannel = TIM2_IRQn;
nvic_struct.NVIC_IRQChannelPreemptionPriority = 0;
nvic_struct.NVIC_IRQChannelSubPriority = 1;
nvic_struct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_struct);
TIM_TimeBaseInitTypeDef tim_struct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
tim_struct.TIM_Period = 1000000-1;
tim_struct.TIM_Prescaler = (uint16_t)(SystemCoreClock/2/1000000)-1;
tim_struct.TIM_ClockDivision = 0;
tim_struct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &tim_struct);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE);
}