Using STM32 HAL and register-level methods
Generating PWM (Pulse Width Modulation) on an STM32 microcontroller involves configuring a timer (TIM) peripheral to produce a variable-duty-cycle signal. Below is a step-by-step guide using STM32 HAL and register-level methods.
1. PWM Generation Using STM32 HAL (CubeMX)
(A) CubeMX Setup
Enable Timer (e.g.,
TIM1,TIM2, etc.) in PWM mode.Configure Channel (e.g.,
CH1,CH2) as PWM Generation.Set:
Prescaler (
PSC) – Divides the timer clock.Auto-Reload Register (
ARR) – Sets PWM frequency.Pulse (
CCR) – Sets duty cycle.
(B) Code Implementation
#include "stm32f4xx_hal.h" TIM_HandleTypeDef htim2; void PWM_Init() { TIM_OC_InitTypeDef sConfigOC = {0}; htim2.Instance = TIM2; htim2.Init.Prescaler = 84 - 1; // PSC = 84 → 1 MHz clock (if APB1 = 84 MHz) htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 1000 - 1; // ARR = 1000 → 1 kHz PWM htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&htim2); sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 500; // 50% duty (500/1000) sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); // Start PWM } int main() { HAL_Init(); SystemClock_Config(); // Ensure clock is configured (e.g., APB1 = 84 MHz) PWM_Init(); while (1) { // Adjust duty cycle dynamically __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 750); // 75% duty HAL_Delay(1000); __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 250); // 25% duty HAL_Delay(1000); } }
2. Register-Level PWM Setup (No HAL)
For better performance, configure registers directly:
void PWM_Init_Registers() { // Enable TIM2 clock (APB1) RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // Configure TIM2 for PWM TIM2->PSC = 84 - 1; // Prescaler → 1 MHz clock TIM2->ARR = 1000 - 1; // Auto-reload → 1 kHz frequency TIM2->CCR1 = 500; // 50% duty cycle (CCR1 = Channel 1) // PWM Mode 1 (OC1M = 110) TIM2->CCMR1 |= TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1; TIM2->CCER |= TIM_CCER_CC1E; // Enable output TIM2->CR1 |= TIM_CR1_CEN; // Start timer } int main() { PWM_Init_Registers(); while (1) { TIM2->CCR1 = 750; // 75% duty for (volatile int i = 0; i < 1000000; i++); TIM2->CCR1 = 250; // 25% duty for (volatile int i = 0; i < 1000000; i++); } }
3. Key Formulas
(A) PWM Frequency
Example:
(APB1 clock)
→ Timer clock =
→
(B) Duty Cycle
Example:
, → 50% duty
→ 75% duty
4. Applications
Motor Control (DC, Servo, BLDC)
LED Dimming
Audio Generation (Class D Amplifiers)
Power Converters (Buck/Boost)
5. Debugging Tips
Check Clock Settings: Ensure
APB1/APB2clocks are correct.Use Logic Analyzer: Verify PWM frequency/duty cycle.
Adjust Dead Time (for complementary PWM in advanced timers like
TIM1).
Summary Table
| Parameter | Role | Example Values |
|---|---|---|
| PSC | Divides input clock | 84-1 (for 1 MHz) |
| ARR | Sets PWM period (frequency) | 1000-1 → 1 kHz |
| CCR | Sets duty cycle | 500 → 50% duty |
| OC Mode | PWM mode (1 or 2) | TIM_OCMODE_PWM1 |

评论
发表评论