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

  1. Enable Timer (e.g., TIM1TIM2, etc.) in PWM mode.

  2. Configure Channel (e.g., CH1CH2) as PWM Generation.

  3. Set:

    • Prescaler (PSC) – Divides the timer clock.

    • Auto-Reload Register (ARR) – Sets PWM frequency.

    • Pulse (CCR) – Sets duty cycle.

(B) Code Implementation

c
#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:

c
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

fPWM=fTIM(PSC+1)×(ARR+1)
  • Example:

    • fTIM=84 MHz (APB1 clock)

    • PSC=841 → Timer clock = 1 MHz

    • ARR=10001 → fPWM=1 MHz1000=1 kHz

(B) Duty Cycle

Duty Cycle (%)=(CCRARR+1)×100
  • Example:

    • CCR=500ARR=999 → 50% duty

    • CCR=750 → 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/APB2 clocks are correct.

  • Use Logic Analyzer: Verify PWM frequency/duty cycle.

  • Adjust Dead Time (for complementary PWM in advanced timers like TIM1).


Summary Table

ParameterRoleExample Values
PSCDivides input clock84-1 (for 1 MHz)
ARRSets PWM period (frequency)1000-1 → 1 kHz
CCRSets duty cycle500 → 50% duty
OC ModePWM mode (1 or 2)TIM_OCMODE_PWM1

评论

此博客中的热门博文

Detailed Explanation of STM32 HAL Library Clock System

How to remove write protection of STM32 chip?

How do you set up ADC (Analog-to-Digital Converter) in STM32?