Timers in STM32
Timers in STM32 microcontrollers are versatile peripherals that can count input clock signals and trigger interrupts when the count reaches a predetermined value. The timer's time base unit consists of a 16-bit counter, prescaler, and auto-reload register, enabling maximum timing periods of 59.65 seconds with a 72MHz clock. Beyond basic timing functions, STM32 timers offer multiple advanced features including clock source selection, input capture, output comparison, encoder interface, and master-slave trigger modes.
STM32 timers are categorized into three types based on complexity and application scenarios: advanced timers, general-purpose timers, and basic timers.
Timer Interrupt Implementation
The counter frequency is calculated as: CK_CNT = CK_PSC / (PSC + 1)
#include "stm32f10x.h"
void Timer_Init(void)
{
// Enable clock for TIM2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// Configure timer to use internal clock
TIM_InternalClockConfig(TIM2);
// Timer base configuration
TIM_TimeBaseInitTypeDef timerConfig;
timerConfig.TIM_ClockDivision = TIM_CKD_DIV1;
timerConfig.TIM_CounterMode = TIM_CounterMode_Up;
timerConfig.TIM_Period = 9999; // Auto-reload value
timerConfig.TIM_Prescaler = 7199; // Prescaler value
timerConfig.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &timerConfig);
// Clear update flag and enable update interrupt
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
// Configure NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef nvicConfig;
nvicConfig.NVIC_IRQChannel = TIM2_IRQn;
nvicConfig.NVIC_IRQChannelCmd = ENABLE;
nvicConfig.NVIC_IRQChannelPreemptionPriority = 2;
nvicConfig.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&nvicConfig);
// Start timer
TIM_Cmd(TIM2, ENABLE);
}
// Timer interrupt handler
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
// User code to execute in interrupt
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
Output Compare for PWM Generation
Output Compare (OC) functionality allows the timer to control output levels by comparing the counter value (CNT) with the capture/compare register (CCR) value. This feature is commonly used to generate PWM (Pulse Width Modulation) signals with specific frequencies and duty cycles.
Each advanced and general-purpose timer includes four output compare channels. The first three channels of advanced timers additionally feature dead-time generation and complementary output capabilities.
PWM (Pulse Width Modulation) is a technique that uses pulse width modulation to simulate analog quantities in systems with inertia, widely used in motor speed control applications.
PWM parameters:
- Frequency = 1 / TS
- Duty cycle = TON / TS
- Resolution = Step size of duty cycle changes
PWM frequency calculation: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
PWM duty cycle calculation: Duty = CCR / (ARR + 1)
PWM resolution calculation: Reso = 1 / (ARR + 1)
#include "stm32f10x.h"
void PWM_Init(void)
{
// Enable clock for TIM2 and GPIOA
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// Configure PA0 as alternate function output
GPIO_InitTypeDef gpioConfig;
gpioConfig.GPIO_Mode = GPIO_Mode_AF_PP;
gpioConfig.GPIO_Pin = GPIO_Pin_0;
gpioConfig.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpioConfig);
// Configure timer for internal clock
TIM_InternalClockConfig(TIM2);
// Timer base configuration
TIM_TimeBaseInitTypeDef timerConfig;
timerConfig.TIM_ClockDivision = TIM_CKD_DIV1;
timerConfig.TIM_CounterMode = TIM_CounterMode_Up;
timerConfig.TIM_Period = 99; // Auto-reload value (ARR)
timerConfig.TIM_Prescaler = 719; // Prescaler value (PSC)
timerConfig.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &timerConfig);
// Output compare configuration for PWM mode 1
TIM_OCInitTypeDef ocConfig;
TIM_OCStructInit(&ocConfig);
ocConfig.TIM_OCMode = TIM_OCMode_PWM1;
ocConfig.TIM_OCPolarity = TIM_OCPolarity_High;
ocConfig.TIM_OutputState = TIM_OutputState_Enable;
ocConfig.TIM_Pulse = 0; // Capture/compare value (CCR)
TIM_OC1Init(TIM2, &ocConfig);
// Enable timer
TIM_Cmd(TIM2, ENABLE);
}
// Function to update PWM duty cycle
void PWM_SetDutyCycle(uint16_t compareValue)
{
TIM_SetCompare1(TIM2, compareValue);
}
Servo Motor Control
A servo motor is a device that controls output angles based on the duty cycle of an input PWM signal. The required input PWM signal has a period of 20ms, with the high-level duration ranging from 0.5ms to 2.5ms.
For servo motor control, a 20ms period base pulse is typically needed. The high-level portion of this pulse (0.5ms-2.5ms) serves as the angle control signal. For a 180-degree servo, the relationship between pulse width and angle is as follows:
- 0.5ms pulse width = 0 degrees
- 1.0ms pulse width = 45 degrees
- 1.5ms pulse width = 90 degrees
- 2.0ms pulse width = 135 degrees
- 2.5ms pulse width = 180 degrees
DC Motor Control
A DC motor converts electrical energy into mechanical energy. It has two terminals; when connected with proper polarity, the motor rotates in one direction, and when polarity is reversed, it rotates in the opposite direction. Since DC motors are high-power devices, GPIO pins cannot drive them directly. A motor driver circuits required for operation. The TB6612 is a dual H-bridge DC motor driver chip capable of driving two DC motors while controlling their speed and direction.
Input Capture
Input Capture (IC) mode allows the timer to capture the counter value (CNT) and store it in the capture/compare register (CCR) when a specified edge transition occurs on the input pin. This functionality is useful for measuring PWM frequency, duty cycle, pulse intervals, and pulse duration.
Each advanced and general-purpose timer includes four input capture channels. The timers can be configured in PWMI mode to simultaneously measure frequency and duty cycle. When combined with master-slave trigger mode, hardware-based automatic measurement can be achieved.