PWM Introduction
- PWM(Pulse Width Modulation) : 펄스의 폭을 조정하는 방식
- 신호의 주기를 조정하는 방식으로, 주로 출력 전압을 제어하거나 디지털/아날로그 통신, 로봇 공학 등에서 사용 (스테퍼 모터나 DC 모터의 제어)
- 디지털 회로에서, 마이크로컨트롤러의 디지털 핀은 논리 0은 0V, 논리 1은 3.3V 또는 1.8V를 의미
- STM32 마이크로컨트롤러의 GPIO 핀)
- 논리 0 → GND, 논리 1 → VCC(3.3V)
- 0V와 3.3V 사이의 출력을 얻으려면 PWM 필요
- STM32 마이크로컨트롤러의 GPIO 핀)
- 주기(period)가 1초인 신호에서, 신호가 50%의 시간 동안은 3.3V로, 나머지 50%는 0V로 유지
- T ON(켜짐 시간) / T OFF(꺼짐 시간) ( Duty cycle : 50%)
- Duty cycle : ON 시간의 비율, 여기서는 평균 전압이 3.3V의 절반인 1.65V
- Duty cycle 을 늘리면, 예를 들어 ON 시간이 75%로 증가하면 평균 전압도 증가
- PWM을 이용해서 Duty cycle을 조절할 수 있음
PWM Exercise
목표 : PWM mode를 사용하여 TIMER2 channel에 대해 PWM signal(25%, 45%, 75%, 90% duty cycle) 생성하기
1) Initialize the TIMER output Compare Time base
HAL_TIM_PWM_init(TIM_HandleTypeDef*htim)
이전 Timer2 초기화 방식과 동일
2) Configure output channel of the timer
HAL_TIM_**PWM**_ConfigChannel(TIM_HandleTypeDef*htim, TIM_**PWM**_InitTypeDef* sConfig, uint32_t Channel)
Duty cycle Configuration
<가정>
- 40% 듀티 사이클 신호를 채널 1에서 생성
- 주기 = 1sec (update events occur every second)
1초의 주기를 얻기 위한 ARR 값 계산
- ARR 값이 10000일 때, 1초의 주기를 생성
40% duty cycle을 위한 pulse value 계산
- 40% 듀티 사이클은 전체 주기의 40%가 ON인 상태이므로, Pulse 값은 ARR 값의 40%
- ⇒ 10000 × 40% = 4000
- Pulse 필드에 4000을 입력하면, 타이머의 카운터가 4000에 도달할 때 출력 신호가 토글
- 90% duty cycle ⇒ Pulse value = 9000
Polarity of signal
극성에 따라 출력 신호의 ON/OFF 상태 달라짐
- Polarity HIGH ⇒ 카운트 값이 CCR1보다 작을 때, 출력 HIGH
- Polarity LOW ⇒ 카운트 값이 CCR1보다 작을 때, 출력 LOW
TIM_HandleTypeDef htimer2;
UART_HandleTypeDef huart2;
int main(void)
{
HAL_Init();
SystemClockConfig();
GPIO_Init();
UART2_Init();
TIMER2_Init();
if(HAL_TIM_PWM_Start(&htimer2, TIM_CHANNEL_1) != HAL_OK) Error_handler();
if(HAL_TIM_PWM_Start(&htimer2, TIM_CHANNEL_2) != HAL_OK) Error_handler();
if(HAL_TIM_PWM_Start(&htimer2, TIM_CHANNEL_3) != HAL_OK) Error_handler();
if(HAL_TIM_PWM_Start(&htimer2, TIM_CHANNEL_4) != HAL_OK) Error_handler();
while(1)
return 0;
}
void TIMER2_Init(void)
{
TIM_OC_InitTypeDef tim2PWM_init;
htimer2.Instance = TIM2;
htimer2.Init.Period = 10000-1;
htimer2.Init.Prescaler = 4999;
if(HAL_TIM_PWM_Init(&htimer2) != HAL_OK)Error_handler();
memset(&tim2PWM_init, 0, sizeof(tim2PWM_init));
tim2PWM_init.OCMode = TIM_OCMODE_PWM1;
tim2PWM_init.OCPolarity = TIM_OCPOLARITY_HIGH;
tim2PWM_init.Pulse = (htimer2.Init.Period * 25) / 100;
if(HAL_TIM_PWM_ConfigChannel(&htimer2, &tim2PWM_init, TIM_CHANNEL_1) != HAL_OK) Error_handler();
tim2PWM_init.Pulse = (htimer2.Init.Period * 45) / 100;
if(HAL_TIM_PWM_ConfigChannel(&htimer2, &tim2PWM_init, TIM_CHANNEL_2) != HAL_OK) Error_handler();
tim2PWM_init.Pulse = (htimer2.Init.Period * 75) / 100;
if(HAL_TIM_PWM_ConfigChannel(&htimer2, &tim2PWM_init, TIM_CHANNEL_3) != HAL_OK) Error_handler();
tim2PWM_init.Pulse = (htimer2.Init.Period * 95) / 100;
if(HAL_TIM_PWM_ConfigChannel(&htimer2, &tim2PWM_init, TIM_CHANNEL_4) != HAL_OK) Error_handler();
}
- msp.c 는 이전에 작성했던 HAL_TIM_OC_MspInit(TIM_HandleTypeDef *htim) 를 HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) 로 함수명만 변경해 주면 됨
LED brightness control using PWM signal
목표 : LED가 어두운 상태에서 점점 밝아졌다가 다시 어두워지는 효과 구현. PWM을 활용하여 LED에 공급되는 평균 전압 조절
- 듀티 사이클 증감 로직 구현
- 초기 듀티 사이클을 0%에서 시작하여 100%까지 증가.
- 이후 다시 0%로 감소하도록 설정.
- CCR1(Capture Compare Register)에 값을 지속적으로 업데이트.
- 코드 구성
- brightness 변수 생성하여 CCR1에 저장.
- HAL_TIM_SET_COMPARE() 함수 사용하여 타이머 핸들, 채널 번호, 비교 값 전달.
- 1ms 지연을 추가하여 프로세서 속도를 조절.
- 하드웨어 및 타이머 주기 고려
- 타이머 주파수: 10MHz, 프로세서 주파수: 50MHz
- CCR1 레지스터는 16비트 값 사용 → uint16_t 적용.
- 주기값(Period) 1ms = 9999 (10,000 - 1).
- PWM 신호 제어 로직
int main(void)
{
uint32_t brightness = 0;
HAL_Init();
SystemClockConfig();
GPIO_Init();
UART2_Init();
TIMER2_Init();
if(HAL_TIM_PWM_Start(&htimer2, TIM_CHANNEL_1) != HAL_OK) Error_handler();
while(1)
{
while(brightness < htimer2.Init.Period)
{
brightness+=10;
__HAL_TIM_SET_COMPARE(&htimer2, TIM_CHANNEL_1, brightness);
HAL_Delay(1);
}
while(brightness > 0)
{
brightness-=10;
__HAL_TIM_SET_COMPARE(&htimer2, TIM_CHANNEL_1, brightness);
HAL_Delay(1);
}
}
return 0;
}
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef tim2OC_ch_gpios;
// 1) Enable the peripheral clock for the timeer2 peripheral
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
// 2) Configure a gpios to behave as timer 2 channel 1, 2, 3, and 4
tim2OC_ch_gpios.Pin = GPIO_PIN_5; // NUCLEO 보드 내부 LED
tim2OC_ch_gpios.Mode = GPIO_MODE_AF_PP;
tim2OC_ch_gpios.Speed = GPIO_SPEED_FREQ_LOW;
tim2OC_ch_gpios.Alternate = GPIO_AF1_TIM2;
HAL_GPIO_Init(GPIOA, &tim2OC_ch_gpios);
// 3) NVIC settings
HAL_NVIC_SetPriority(TIM2_IRQn, 15, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
}
반응형
'ComputerScience & Embedded > NUCLEO & CAN Tranceiver' 카테고리의 다른 글
CAN frame formats / Bus Arbitration (0) | 2025.03.01 |
---|---|
CAN (Controller Area Network) Fundamentals (0) | 2025.03.01 |
Timer’s Output compare unit (0) | 2025.03.01 |
General Purpose Timer : Input Capture Unit (0) | 2025.03.01 |
Timers (Polling mode / Interrupt mode) (0) | 2025.03.01 |