본문 바로가기
MCU/STM32

[STM32]에서 PWM Soft Start 구현: 모터와 LED 제어를 위한 부드러운 시작 (Implementing PWM Soft Start in STM32: Smooth Start for Motor and LED Control)

by linuxgo 2025. 8. 21.
반응형

STM32 마이크로컨트롤러를 사용해 PWM 신호(PWM signal)를 생성할 때 Soft Start(소프트 스타트, Soft Start) 기능을 구현하는 방법을 알아보겠습니다 (Let's explore how to implement the Soft Start function when generating PWM signals with an STM32 microcontroller). Soft Start는 PWM 듀티 사이클(PWM duty cycle)을 점진적으로 증가시켜 모터, LED, 전원 공급 장치 등의 부하에서 급격한 전류 변화를 방지합니다 (Soft Start gradually increases the PWM duty cycle to prevent sudden current changes in loads like motors, LEDs, or power supplies). 이 글에서는 STM32CubeMXHAL 라이브러리(HAL library)를 사용한 두 가지 구현 방법(소프트웨어 기반, 타이머 인터럽트 기반)을 상세한 주석이 포함된 예제 코드와 함께 설명합니다 (This article explains two implementation methods—software-based and timer interrupt-based—with example code including detailed comments). 초보자도 쉽게 따라 할 수 있도록 구성했습니다 (It’s structured to be easy for beginners to follow).

키워드 (Keywords): STM32 PWM, Soft Start, 듀티 사이클 (Duty Cycle), 타이머 인터럽트 (Timer Interrupt), STM32CubeMX

Soft Start란? (What is Soft Start?)

Soft Start는 PWM 신호의 듀티 사이클을 0%에서 목표값까지 천천히 증가시켜 부하에 가해지는 충격을 줄이는 기술입니다 (Soft Start is a technique that gradually increases the PWM signal’s duty cycle from 0% to the target value to reduce stress on the load). 모터의 급격한 회전이나 LED의 갑작스러운 밝기 변화를 방지하여 시스템 안정성을 높입니다 (It prevents sudden motor rotation or abrupt LED brightness changes, improving system stability). STM32에서는 **타이머(Timer)**를 활용해 PWM을 생성하고, 소프트웨어 또는 인터럽트를 통해 소프트 스타트(Soft Start)를 구현합니다 (In STM32, PWM is generated using a timer, and Soft Start is implemented via software or interrupts).

구현 방법 (Implementation Methods)

STM32에서 PWM Soft Start를 구현하는 두 가지 실용적인 방법을 소개합니다 (We introduce two practical methods to implement PWM Soft Start in STM32). 각 방법은 STM32CubeMX로 생성한 기본 설정에 쉽게 통합할 수 있습니다 (Each method can be easily integrated with basic settings generated by STM32CubeMX).

방법 1: 소프트웨어 기반 Soft Start (Method 1: Software-Based Soft Start)

이 방법은 메인 루프에서 듀티 사이클(duty cycle)을 점진적으로 증가시키는 간단한 방식입니다 (This method is a simple approach that gradually increases the duty cycle in the main loop). 초보자에게 적합하며, 추가 하드웨어 없이 구현 가능합니다 (It’s suitable for beginners and requires no additional hardware).

구현 단계 (Implementation Steps)

  1. 타이머 PWM 설정 (Timer PWM Setup): STM32의 타이머(예: TIM1)를 PWM 모드로 설정 (Configure an STM32 timer, e.g., TIM1, in PWM mode).
  2. Soft Start 로직 (Soft Start Logic): 듀티 사이클을 0에서 시작해 일정 간격(예: 10ms)으로 증가 (Start the duty cycle at 0 and increase it at regular intervals, e.g., 10ms).
  3. 타이밍 제어 (Timing Control): HAL_Delay()로 간격을 제어(테스트용) (Control intervals with HAL_Delay() for testing).

예제 코드 (Example Code)

#include "stm32f4xx_hal.h"

TIM_HandleTypeDef htim1; // PWM을 생성할 타이머 핸들 (Timer handle for generating PWM)

// 함수 선언 (Function declarations)
void SystemClock_Config(void); // 시스템 클럭 설정 (System clock configuration)
void MX_GPIO_Init(void);      // GPIO 초기화 (GPIO initialization)
void MX_TIM1_Init(void);      // 타이머 1 초기화 (Timer 1 initialization)

int main(void) {
    HAL_Init(); // HAL 라이브러리 초기화 (Initialize HAL library)
    SystemClock_Config(); // 시스템 클럭 설정 (Configure system clock, generated by STM32CubeMX)
    MX_GPIO_Init(); // GPIO 설정 (Configure GPIO)
    MX_TIM1_Init(); // PWM 타이머 설정 (Configure PWM timer)

    // PWM 신호 출력 시작 (TIM1, 채널 1) (Start PWM signal output on TIM1, Channel 1)
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);

    uint32_t duty_cycle = 0;      // 초기 듀티 사이클 (0%) (Initial duty cycle, 0%)
    const uint32_t max_duty = 1000; // 최대 듀티 사이클 (ARR=1000, 100%) (Maximum duty cycle, ARR=1000, 100%)
    const uint32_t increment = 10;  // 한 번에 증가할 듀티 사이클 값 (Duty cycle increment per step)
    const uint32_t delay_ms = 10;   // 증가 간격 (10ms) (Interval between increments, 10ms)

    // Soft Start: 듀티 사이클을 점진적으로 증가 (Soft Start: Gradually increase duty cycle)
    while (duty_cycle < max_duty) {
        // TIM1 채널 1의 CCR 레지스터에 듀티 사이클 값 설정 (Set duty cycle in TIM1 Channel 1 CCR register)
        __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, duty_cycle);
        duty_cycle += increment; // 듀티 사이클 증가 (Increase duty cycle)
        if (duty_cycle > max_duty) duty_cycle = max_duty; // 최대값 제한 (Limit to maximum duty cycle)
        HAL_Delay(delay_ms); // 10ms 대기 (Soft Start 속도 조절) (Wait 10ms to control Soft Start speed)
    }

    // Soft Start 완료 후 목표 듀티 사이클 유지 (Maintain target duty cycle after Soft Start)
    while (1) {
        // 추가 제어 로직 (예: 사용자 입력 처리) (Additional control logic, e.g., handle user input)
    }
}

void MX_TIM1_Init(void) {
    TIM_OC_InitTypeDef sConfigOC = {0}; // 출력 비교(OC) 설정 구조체 (Output Compare configuration structure)

    // TIM1 기본 설정 (TIM1 basic configuration)
    htim1.Instance = TIM1; // 타이머 1 선택 (Select Timer 1)
    htim1.Init.Prescaler = 0; // 프리스케일러 (클럭 분주 없음) (Prescaler, no clock division)
    htim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 업 카운터 모드 (Up-counter mode)
    htim1.Init.Period = 1000; // ARR 값 (PWM 주기, 1000=100%) (ARR value, PWM period, 1000=100%)
    htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 클럭 분주 비활성화 (Clock division disabled)
    HAL_TIM_PWM_Init(&htim1); // PWM 모드로 타이머 초기화 (Initialize timer in PWM mode)

    // PWM 채널 설정 (채널 1) (PWM channel configuration, Channel 1)
    sConfigOC.OCMode = TIM_OCMODE_PWM1; // PWM 모드 1 설정 (Set PWM mode 1)
    sConfigOC.Pulse = 0; // 초기 듀티 사이클 0 (CCR1 값) (Initial duty cycle 0, CCR1 value)
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // 출력 극성: High (Output polarity: High)
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 빠른 모드 비활성화 (Fast mode disabled)
    HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1); // 채널 1에 설정 적용 (Apply settings to Channel 1)
}

주석 설명 (Comment Explanation):

  • 각 변수와 함수 호출에 역할과 목적을 한글과 영어로 설명 (Each variable and function call is explained in Korean and English).
  • htim1.Init.Period와 Pulse 값이 PWM 주기와 듀티 사이클에 미치는 영향을 명확히 기술 (The impact of htim1.Init.Period and Pulse on PWM period and duty cycle is clearly described).
  • HAL_Delay가 테스트용임을 강조 (Emphasized that HAL_Delay is for testing).

방법 2: 타이머 인터럽트를 이용한 Soft Start (Method 2: Timer Interrupt-Based Soft Start)

타이머 인터럽트(Timer interrupt)를 사용하면 메인 루프를 차단하지 않고 Soft Start를 구현할 수 있습니다 (Using a timer interrupt allows Soft Start implementation without blocking the main loop). 실시간 시스템에 적합하며, 주기적인 듀티 사이클 업데이트를 자동화합니다 (It’s suitable for real-time systems and automates periodic duty cycle updates).

구현 단계 (Implementation Steps)

  1. PWM 타이머 설정 (PWM Timer Setup): TIM1을 PWM 모드로 설정 (Configure TIM1 in PWM mode).
  2. 인터럽트 타이머 설정 (Interrupt Timer Setup): TIM2를 사용해 10ms마다 인터럽트 발생 (Use TIM2 to generate interrupts every 10ms).
  3. 인터럽트 핸들러 (Interrupt Handler): 듀티 사이클을 증가시키고 목표값 도달 시 인터럽트 비활성화 (Increase duty cycle and disable interrupt when target is reached).

예제 코드 (Example Code)

#include "stm32f4xx_hal.h"

TIM_HandleTypeDef htim1; // PWM용 타이머 핸들 (Timer handle for PWM)
TIM_HandleTypeDef htim2; // Soft Start용 인터럽트 타이머 핸들 (Timer handle for Soft Start interrupt)

// 함수 선언 (Function declarations)
void SystemClock_Config(void); // 시스템 클럭 설정 (System clock configuration)
void MX_GPIO_Init(void);      // GPIO 초기화 (GPIO initialization)
void MX_TIM1_Init(void);      // PWM 타이머 초기화 (PWM timer initialization)
void MX_TIM2_Init(void);      // 인터럽트 타이머 초기화 (Interrupt timer initialization)

// Soft Start 변수 (Soft Start variables)
uint32_t duty_cycle = 0;        // 현재 듀티 사이클 (0%) (Current duty cycle, 0%)
const uint32_t max_duty = 1000; // 최대 듀티 사이클 (ARR=1000, 100%) (Maximum duty cycle, ARR=1000, 100%)
const uint32_t increment = 10;  // 한 번에 증가할 듀티 사이클 값 (Duty cycle increment per step)

int main(void) {
    HAL_Init(); // HAL 라이브러리 초기화 (Initialize HAL library)
    SystemClock_Config(); // 시스템 클럭 설정 (Configure system clock)
    MX_GPIO_Init(); // GPIO 설정 (Configure GPIO)
    MX_TIM1_Init(); // PWM 타이머 설정 (Configure PWM timer)
    MX_TIM2_Init(); // 인터럽트 타이머 설정 (Configure interrupt timer)

    // PWM 신호 출력 시작 (TIM1, 채널 1) (Start PWM signal output on TIM1, Channel 1)
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
    // Soft Start용 인터럽트 타이머 시작 (Start interrupt timer for Soft Start)
    HAL_TIM_Base_Start_IT(&htim2);

    while (1) {
        // 메인 루프에서 다른 작업 수행 가능 (Perform other tasks in the main loop)
    }
}

void MX_TIM1_Init(void) {
    TIM_OC_InitTypeDef sConfigOC = {0}; // 출력 비교 설정 구조체 (Output Compare configuration structure)

    // TIM1 기본 설정 (PWM용) (TIM1 basic configuration for PWM)
    htim1.Instance = TIM1; // 타이머 1 선택 (Select Timer 1)
    htim1.Init.Prescaler = 0; // 프리스케일러 (클럭 분주 없음) (Prescaler, no clock division)
    htim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 업 카운터 모드 (Up-counter mode)
    htim1.Init.Period = 1000; // ARR 값 (PWM 주기 설정) (ARR value, sets PWM period)
    htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 클럭 분주 비활성화 (Clock division disabled)
    HAL_TIM_PWM_Init(&htim1); // PWM 모드로 타이머 초기화 (Initialize timer in PWM mode)

    // PWM 채널 설정 (채널 1) (PWM channel configuration, Channel 1)
    sConfigOC.OCMode = TIM_OCMODE_PWM1; // PWM 모드 1 설정 (Set PWM mode 1)
    sConfigOC.Pulse = 0; // 초기 듀티 사이클 0 (CCR1 값) (Initial duty cycle 0, CCR1 value)
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // 출력 극성: High (Output polarity: High)
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 빠른 모드 비활성화 (Fast mode disabled)
    HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1); // 채널 1에 설정 적용 (Apply settings to Channel 1)
}

void MX_TIM2_Init(void) {
    // TIM2 기본 설정 (인터럽트용) (TIM2 basic configuration for interrupts)
    htim2.Instance = TIM2; // 타이머 2 선택 (Select Timer 2)
    htim2.Init.Prescaler = 8399; // 프리스케일러 (84MHz에서 10ms 주기 생성) (Prescaler, generates 10ms period at 84MHz)
    htim2.Init.Period = 9999; // 인터럽트 주기 (10ms) (Interrupt period, 10ms)
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP; // 업 카운터 모드 (Up-counter mode)
    HAL_TIM_Base_Init(&htim2); // 기본 타이머 모드로 초기화 (Initialize in basic timer mode)
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    // 타이머 인터럽트 콜백 함수 (Timer interrupt callback function)
    if (htim->Instance == TIM2) { // TIM2 인터럽트인지 확인 (Check if it’s a TIM2 interrupt)
        if (duty_cycle < max_duty) { // 목표 듀티 사이클에 도달하지 않은 경우 (If target duty cycle not reached)
            duty_cycle += increment; // 듀티 사이클 증가 (Increase duty cycle)
            if (duty_cycle > max_duty) duty_cycle = max_duty; // 최대값 제한 (Limit to maximum duty cycle)
            // TIM1 채널 1의 CCR 레지스터에 듀티 사이클 값 설정 (Set duty cycle in TIM1 Channel 1 CCR register)
            __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, duty_cycle);
        } else {
            // 목표 듀티 사이클 도달 시 인터럽트 비활성화 (Disable interrupt when target duty cycle is reached)
            HAL_TIM_Base_Deactivate(&htim2);
        }
    }
}

주석 설명 (Comment Explanation):

  •   각 줄에 한글과 영어로 상세 주석 추가 (Detailed comments added in Korean and English for each line).
  •   타이머 설정과 인터럽트 동작의 기술적 배경 설명 (Explained technical background of timer settings and interrupt operation).
  •   인터럽트 비활성화로 리소스 절약 강조 (Emphasized resource saving by disabling interrupts).

Soft Start 설정 팁 (Soft Start Configuration Tips)

  1. 타이밍 조정 (Timing Adjustment):
    •   Soft Start 시간 (Soft Start Duration): 모터는 100ms1초, LED는 500ms2초로 설정 (Set 100ms–1s for motors, 500ms–2s for LEDs).
    •   increment와 delay_ms(또는 인터럽트 주기)를 조정해 부드러운 변화 구현 (Adjust increment and delay_ms or interrupt period for smooth transitions).
  2. PWM 주파수 (PWM Frequency):
    •   모터: 1kHz~20kHz (Motors: 1kHz–20kHz)
    •   LED: 100Hz~1kHz (LEDs: 100Hz–1kHz)
    •   STM32CubeMX에서 Prescaler와 Period로 주파수 설정 (Set frequency with Prescaler and Period in STM32CubeMX).
  3. 부하 특성 (Load Characteristics):
    •   모터: 과전류 방지를 위해 전류 피드백 모니터링 (Motors: Monitor current feedback to prevent overcurrent).
    •   LED: 로그 스케일로 듀티 사이클 증가 시 자연스러운 밝기 변화 (LEDs: Use logarithmic duty cycle increase for natural brightness changes).
  4. STM32CubeMX 활용 (Using STM32CubeMX):
    •   STM32CubeMX로 타이머 설정을 생성해 초기화 오류 최소화 (Generate timer settings with STM32CubeMX to minimize initialization errors).
    •   예: TIM1을 PWM 모드로, TIM2를 기본 타이머로 설정 (E.g., configure TIM1 for PWM mode and TIM2 as a basic timer).

디버깅 및 테스트 (Debugging and Testing)

  • 오실로스코프 (Oscilloscope): PWM 핀의 듀티 사이클 증가 확인 (Verify duty cycle increase on the PWM pin).
  • UART 디버깅 (UART Debugging): 듀티 사이클 값을 시리얼로 출력 (Output duty cycle values via serial).
  • STM32 모델 (STM32 Model): STM32F4, STM32G4 등 모델별 레지스터 차이 확인 (Check register differences for models like STM32F4, STM32G4).

결론 (Conclusion)

STM32 PWM Soft Start는 모터, LED, 전원 제어에서 시스템 안정성을 높이는 필수 기술입니다 (STM32 PWM Soft Start is an essential technique for improving system stability in motor, LED, and power control). 소프트웨어 기반 방식은 간단하고, 타이머 인터럽트 방식은 실시간 제어에 적합합니다 (The software-based method is simple, while the timer interrupt method is suitable for real-time control). 상세 주석이 포함된 위 코드를 STM32CubeMX 프로젝트에 적용해 보세요 (Apply the above code with detailed comments to your STM32CubeMX project). 

반응형