본문 바로가기
임베디드/STM32

21. [STM32] Timer - PWM

by fuhehe 2025. 1. 10.

이번 시간에는 Timer의 PWM기능에 대해 알아보자.

PWM은 일정 주기의 디지털 신호의 출력일 일정 비율로 쪼개 아날로그 신호처럼 동작하게 하는 방식이다. 서보 모터, 전력제어, 통신등 다양한 곳에 사용된다.

 

 

 

  • 본 블로그는 STM32를 소프트웨어 엔지니어 관점에서 바라본 블로그입니다. 따라서 회로등의 전자공학 관련 내용은 사실과 다를 수 있습니다.
  • 본 블로그에서 사용된 MCU 및 개발보드는 다음과 같습니다.
    1. NUCLEO-F429ZI (STM32F429ZIT LQFP144)
    2. NUCLEO-F439ZI (STM32F439ZIT LQFP144)

 

 

 

1. 준비물

이번장에서는 3개의 예제를 준비했다. 3개 예제별로 필요한 부품은 다음과 같다.

  • LED 1개, LED보호용 저항 1개
  • SG90 서보모터 1개
  • 스피커 1개

 

2. PWM의 정의

PWM은 Pulse Width Modulation의 약자로 우리말로 하면 펄스폭 변조라고 한다.

타이머의 카운터가 ARR에 도달하는 구간을 1개 주기로 볼 때 PWM은 이 1개 타이머 주기내에서 TIMx_CCRn에 지정된 값에 따라 Low/High상태를 변경되게 하는 방법이다.

그리고 TIMx_CCRn에 입력하는 값을 듀티비(Duty ratio)라고 하는데 ARR값을 기준으로 몇%단위로 상태를 변경할 지를 지정한다.

이때 TIMx_CCMR1레지스터의 OC1M값에 따라 PWM mode1과 PWM mode2 두가지 방법으로 설정이 가능한데 의미는 각각 다음과 같다.

  • PWM mode 1 : TIMx_CNT값이 TIMx_CCRn보다 작은 경우 HIGH, 큰 경우 LOW로 전환.(타이머의 Counter Mode가 Up인 경우)
  • PWM mode 2 : TIMx_CNT값이 TIMx_CCRn보다 작은 경우 LOW,  큰 경우 HIGH로 전환.(타이머의 Counter Mode가 Up인 경우)

 

다음 그림은 타이머의 Counter Mode가 각각 Up, Down, Center align mode일때의 펄스 모양이다.(PWM mode 1일때)

[Counter Mode : Up]
[Counter Mode : Down]
[Counter Mode : Center Aligned]

 

Up counting모드이고 ARR이 8-1일때 CCR은 4로 설정해야 듀티비가 50%가 된다. 습관적으로 CCR값에도 4-1과 같이 -1을 해주면 안된다.

CNT가 0, 1, 2, 3일 때는 High, 4가 되는 순간 Low로 되어서 4, 5, 6, 7동안 Low상태를 유지하기 때문이다.

이와는 달리 Down counting모드일 때는 4로 설정해 버리면 위 그림과 같이 7, 6, 5일때는 Low이고 4, 3, 2, 1, 0일때는 High상태가 되어 50%듀티비가 나오지 않는다. 이때는 3으로 설정해야 50%가 된다.

위의 그림과 같이  Counter Mode에 따라 CNT와 CCR값의 관계를 잘 생각해서 값을 설정해야 한다.

 

 

실제 출력을 확인하기 위해 아래와 같이 STM32F429/439에서 TIM3을

  • APB1 : 84MHz
  • Prescaler : 8400-1
  • ARR : 500-1

로 설정하고 TIM3_CCR1을 각각 250(듀티비 50%), 350(듀티비 70%)으로 설정했다.

아래는 출력 결과이다.(PWM Mode 1)

[듀티비 50%]
[듀티비 70%]

 

 

보는바와 같이 기본적으로 타이머는 50ms마다 동작하는데 50ms를 다시 TIM3_CCR1의 값에 따라 첫번째는 50%씩 해서 25ms는 High, 25ms는 Low상태이고, 두번째는 70%로 35ms는 High, 15ms는 Low상태가 반복된다.

 

이런 펄스출력을 LED등에 인가하게 되면 LED는 지정된 속도로 On/Off를 반복하게 되는데 이때 듀티비가 크면 On되는 시간이 길어져 LED가 밝아지는거 처럼 보이고, 듀티비가 작으면 Off되는 시간이 길어져 LED가 어두워지는 것처럼 보인다. 

아날로그 회로인 경우 전압을 조절해서 LED 밝기를 조절할 수 있지만 디지털 회로의 경우 상태가 High/Low상태만 가질 수 있고 전압은 고정되므로 이런 방식으로 밝기를 조절해야 하는 것이다.

 

따라서 PWM은 디지털 회로에서 아날로그 회로를 흉내낼 수 있는 방법이라고 생각할 수 있다. 

 

 

3. PWM 관련 HAL 함수

PWM과 관련된 HAL함수는 다음과 같다.

  • HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
  • HAL_TIM_PWM_Stop(TIM_HandleTypeDef *htim, uint32_t Channel)
  • HAL_TIM_PWM_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel)
  • HAL_TIM_PWM_Stop_IT(TIM_HandleTypeDef *htim, uint32_t Channel)

각각 PWM을 시작하고 종료하는 함수이다.

여기서 보면 _IT 접미사가 붙은게 있고 안붙은게 있는데 HAL라이브러리 명명규칙에 따라 이 접미사는 인터럽트여부를 의미한다.

인터럽트 필요없이 지정된 핀으로 PWM신호만 출력하려면 HAL_TIM_PWM_Start()를, 인터럽트까지 사용해야 하는 경우에는 HAL_TIM_PWM_Start_IT()를 사용하면 된다.

PWM자체 인터럽트를 소스에서 사용하기 위해서는 아래의 콜백함수를 재정의해서 사용하면 된다.

__weak void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)

 

 

 

 

 

4. LED밝기 조절하기

PWM의 동작을 눈으로 확인하기 위해 실제 LED를 붙여서 테스트를 진행해보자.

사람에 따라 차이는 있지만 청각과 달리 시각은 일반적으로 120Hz이상 되는 변화는 인지할 수 없다. (모니터 주사율이나 게임등에서 화면을 갱신하는 프레임수등도 120Hz이상되면 대부분의 사람은 인지할 수 없다.)

따라서 120Hz이상의 PWM신호에서 듀티비를 다르게 주면 사람이 깜박인다는 인지없이 LED의 밝기를 조절할 수 있다.

 

TIMx_CCRn값은 타이머 동작중에도 변경가능하므로 값을 높였다 줄였다 해보자.

 

먼저 TIM3의 설정을 다음과 같이 한다.

[TIM3 PWM설정]

 

TIM3의 Channel1을 PWM Generation CH1로 설정해서 PWM신호를 PA6핀을 통해 출력하도록 한다.

그리고 Prescaler를 840-1, ARR을 400-1로 설정하는데 이렇게 설정하면 타이머는 4ms마다 동작하게 된다. 목적이 120Hz이상되는 신호를 발생시키는 것이므로 120Hz=8.33..ms 라서 4ms정도면 테스트하는데 충분히 짧은 시간이다.

그리고 PWM의 Mode를 PWM mode 1로 설정했다.

PWM의 Pulse(16bit value)라고 되어 있는 항목이 TIMx_CCRn에 들어갈 값이다.

초기값을 0으로 지정했으므로 이 값을 수정하지 않는다면 신호는 계속 Low상태가 된다.

이 값은 타이머 자체의 인터럽트를 통해 S/W로 수정할 것이다. 따라서 아래와 같이 NVIC Settings탭에서 TIM3의 인터럽트를 활성화시켜야 한다.

그리고 GPIO Settings 탭에서 보는것과 같이 TIM3의 Channel1에 연결된 PA6을 통해 신호를 출력한다.

[TIM3의 인터럽트, GPIO]

저장한 뒤 다음과 같이 소스를 작성하자.

#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdbool.h>
/* USER CODE END Includes */


TIM_HandleTypeDef htim3;

bool gbDir = false;

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if(htim->Instance == TIM3)
  {
    if(htim->Instance->CCR1 == htim->Instance->ARR || htim->Instance->CCR1 == 0)
    	gbDir = !gbDir;
    
    if(gbDir)
    	htim->Instance->CCR1++;
    else
    	htim->Instance->CCR1--;
  }
}


int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM3_Init();  
  /* USER CODE BEGIN 2 */    
  HAL_TIM_Base_Start_IT(&htim3);			// TIM3자체의 인터럽트 발생을 위해
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);	// TIM3의 Ch1을 PWM으로 설정


  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */
}

 

타이머가 4ms주기 이므로 이 시간마다 CCR값을 증가시키다 CCR값이 ARR에 지정한 값과 같아지면 다시 감소시키고, CCR이 0이 되면 다시 증가하는 동작을 반복한다.

CCR값에 따라 듀티비가 달라지므로 LED는 밝아졌다 어두워졌다를 반복하게 된다.

 

그리고 출력핀에 LED가 아니라 DC모터등을 달면 모터의 속도 조절 용도로도 사용할 수 있다.

 

 

5. 서보 모터 제어하기

이번에는 PWM신호로 서보 모터를 구동해보자.

서보모터는 아두이노에서 많이 사용하는 SG90모터를 사용하였다.

우선 SG90의 데이터 시트를 보면 아래와 같다.

[SG90 Datasheet]

타이머의 주기는 20ms(50Hz)이고 이 중 1~2ms의 듀티사이클로 모터의 각도를 지정한다.

왼쪽에 기재된 대로 듀티사이클이 1.5ms이면 0도, 2ms이면 90도, 1ms이면 -90도로 회전한다.

이번 예제에서도 TIM3을 사용할 것이므로 PA6출력핀을 Orange색 선에 연결하고 보드의 5V선을 Red, GND를 Brown에 연결한다.

모터의 PWM입력신호는 4.8V(~5V)로 되어 있는데 STM32의 출력은 3.3V이다. 하지만 3.3V를 인가해도 문제가 없으므로 그대로 사용하도록 하겠다. (레벨 쉬프터를 연결해서 동작시켜 봤지만 3.3V를 바로 인가한것과 차이는 없었다.)

 

TIM3의 설정을 아래와 같이 하자.

[TIM3 설정]

 

TIM3의 Prescaler는 84-1, ARR은 20000-1로 설정하면 타이머의 기본주기는 20ms(50Hz)가 된다.

그리고 PWM의 Pulse(CCR)를 디폴트로 1500으로 줬는데 이 값은 PWN의 듀티사이클을 1.5m로 설정해서 각도를 0으로 설정하겠다는 의미다.

Prescaler값이 84-1이므로 타이머의 CNT는 0.000001초(1MHz) 단위로 증가한다.

따라서 CCR값이 1000이면 0.001초, 1500이면 0.0015초, 2000이면 0.002초가 되므로 데이터시트대로 설정이 가능하다.

 

설정후 코딩을 다음과 같이하자.

#define MIN_CCR				1000
#define MAX_CCR				2500

TIM_HandleTypeDef htim3;


/* USER CODE BEGIN 0 */
float gfUnitPerDegree = 0.f;

void MoveMotor(int8_t degree)
{
  float f = (float)(degree + 90) * gfUnitPerDegree;

  htim3.Instance->CCR1 = (uint16_t)f + MIN_CCR;
}

/* USER CODE END 0 */

int main(void)
{
  HAL_Init();

  /* USER CODE BEGIN Init */
  gfUnitPerDegree = (float)(MAX_CCR - MIN_CCR) / 180.f;
  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */  
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    HAL_Delay(5000);	  
    MoveMotor(90);
	  
    HAL_Delay(2000);	  
    MoveMotor(-90);

    HAL_Delay(2000);	  
    MoveMotor(0);
  }
  /* USER CODE END 3 */
}

 

우선 main함수 시작시 전역변수 gfUnitPerDegree값을 계산한다. 이 값은 각도 1도당 CCR값이 얼마나 증가해야 하는지를 설정하는 값이다. 모터가 -90~90도까지 총 180도 회전 가능하고 CCR에 설정하는 값은 1000(1ms)~2000(2ms)까지 1000개의 값을 가질 수 있으므로 각도 1도당 CCR값은 1000/180 = 5.555556이 된다. 즉 CCR값이 1500이면 0도, 1500+ 5.555556이면 1도, 1500+(5.555556X2)면 2도가 된다.

 

실행하면 CCR 최초 설정값이 1500이므로 모터는 0도에 위치하고 5초 대기한다.

그리고 90도 방향으로 회전후 2초 대기, -90도 방향으로 회전후2초대기, 다시 0도 위치하고 5초대기를 반복한다.

 

제일 위에 define문으로 CCR 최소값과 최대값을 설정해놨는데 이건 데이터시트대로 듀티사이클을 지정하면 데이터시트대로 회전하질 않아서이다. (실제는 지정된 각도보다 작게 회전한다. 다른 사이트에서도 이런 현상을 적어놓은걸 보면 모터자체의 문제인듯 하다.)

실제로 가동범위를 180도 회전 시킬려면 MIN_CCR을 850, MAX_CCR을 2450정도로 지정해야 비슷하게 동작한다. 따라서 정확한 각도가 필요할 경우 이 값을 조정해서 사용하기 바란다. (85, 2450은 정확한 각도를 실측할 수 없어 눈대중으로 측정한 값이다.)

 

실제 0도, -90, 90의 듀티비를 찍어보면 아래와 같이 정확히 출력되므로 설정이나 소스의 문제는 아닌듯 하다.

 

[0도 : 듀티사이클 1.5ms(CCR=1500)]
[-90도 : 듀티사이클 1ms(CCR=1000)]
[90도 : 듀티사이클 2ms(CCR=2000)]

 

 

 

6. 스피커를 통해 음악 출력하기

마지막으로 PWM을 이용해 스피커로 음악을 연주해보자.

우선 소리는 진동이고 이 진동이 공기를 매질로 해서 우리 귀에 도달하게 된다. 따라서 PWM으로 일정한 진동을 줘서 이 진동을 스피커로 출력하면 소리가 되는 것이다.

이때 우리가 아는 특정음은 고유 주파수가 있다. 예를들어 악기 튜닝의 기본이 되는 가온 라 음의 주파수는 440Hz이다.

각 옥타브별 음의 주파수는 구글에서 "음계 주파수" 라고 검색해보면 나오므로 각자 검색해보라.

이번 예제에서는 모든 음을 선언하지는 않았고 3,4 옥타브음 24개만 정의하였다.

 

음을 출력할 때는 ARR값을 실시간으로 변경하면서 음의 주파수대로 조정을 해야 하고 이때 PWM의 듀티비는 50%고정이다.

즉 84MHz상의 타이머에서 Prescaler를 84-1로 설정했을때 가온 라음인 440Hz를 출력하기 위해서는 ARR값을 (84000000 / 84) / 440 = 2272.7272.. 로 입력해야 한다. 이때 소수점까지의 설정은 안되므로 정수만 사용하도록 하겠다. (어차피 이정도 차이는 인식하기 어렵다.)

ARR이 2272이므로 듀티비를 50%로 맞출려면 CCR의 값은 2272 / 2 = 1136으로 설정하면 된다.

 

TIM3을 사용할 것이므로 출력 PA6과 GND에 스피커를 연결하고 아래와 같이 설정하자.

[TIM3의 설정]

초기 ARR값이 지정되어 있지만 최초 ARR값은 MAX값 65535를 지정해도 된다.

 

코딩은 다음과 같다.

#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#define BPM		120
/* USER CODE END Includes */

TIM_HandleTypeDef htim3;

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
// 3, 4옥타브의 각 음계 주파수 설정.(소숫점은 처리하지 않음)
// 음이름뒤에 S가 붙은건 Sharp이다.
// 즉, C4는 4옥타브 도, CS4는 4옥타브 C#
typedef enum {
	Mute = 0,
	C3 = 131, CS3 = 139, D3 = 147, DS3 = 156, E3 = 165, F3 = 175, FS3 = 185, G3 = 196, GS3 = 208, A3 = 220, AS3 = 233, B3 = 247,
	C4 = 262, CS4 = 277, D4 = 294, DS4 = 311, E4 = 330, F4 = 349, FS4 = 370, G4 = 392, GS4 = 415, A4 = 440, AS4 = 466, B4 = 494
} Notes;

// 음표의 길이 선언
// 이 enum은 아래의 gaDuration배열의 첨자로 사용됨
typedef enum {
	DUR1 = 0,	// 온음표
	DUR2,		// 2분음표
	DUR4,		// 4분음표
	DUR8,		// 8분음표
	DUR16,		// 16분음표
	DUR32,		// 32분음표
	DUR64		// 64분음표
} Duration;

// 악보용 구조체
// 악보의 음표갯수만큼 이 구조체를 배열로 선언해서 사용.
typedef struct _tagMusicStruct
{
	Notes note;				// 각 음의 주파수를 가지고 있는 Notes enum
	Duration duration;		// 각 음의 길이(Duration enum)
} MusicStruct;

// ARR값을 계산하기 위한 TIM3의 CNT증가속도
uint32_t tm = 84000000 / 84;

// 온음표, 2분음표, 4분음표 등의 실제 길이(ms단위)
// main함수에서 초기화됨
uint32_t gaDuration[7] = {0,};

// 실제 음 연주
void playSound(MusicStruct music)
{
	if(music.note == Mute)
	{	// Mute인 경우 음을 제거후 리턴
		htim3.Instance->CCR1 = 0;
		return;
	}

	htim3.Instance->ARR = (uint32_t)(tm / music.note);
	htim3.Instance->CCR1 = htim3.Instance->ARR / 2;		// 듀티비 50%

	// PWM신호 생성후 음표길이 만큼 Delay
	uint32_t delay = gaDuration[music.duration];
	HAL_Delay(delay);
}
/* USER CODE END 0 */



int main(void)
{

  /* USER CODE BEGIN 1 */
  MusicStruct mute = {Mute, 0};		// Mute설정

  // 실제 악보
  MusicStruct music[] = {
		  {G4, DUR8},		// 4옥타브 솔, 8분음표
		  {G4, DUR8},
		  {A4, DUR8},		// 4옥타브 라, 8분음표
		  {A4, DUR8},
		  {G4, DUR8},
		  {G4, DUR8},
		  {E4, DUR4},		// 4옥타브 미, 4분음표
		  {G4, DUR8},
		  {G4, DUR8},
		  {E4, DUR8},
		  {E4, DUR8},
		  {D4, DUR2},

		  {G4, DUR8},
		  {G4, DUR8},
		  {A4, DUR8},
		  {A4, DUR8},
		  {G4, DUR8},
		  {G4, DUR8},
		  {E4, DUR4},
		  {G4, DUR8},
		  {E4, DUR8},
		  {D4, DUR8},
		  {E4, DUR8},
		  {C4, DUR2},
  };

  int i = 0;
  int nNoteLen = sizeof(music) / sizeof(MusicStruct);		// 악보 배열 길이(24개)
  
  // 지정된 BPM기준으로 각 음표의 길이(ms단위) 계산.
  uint32_t uiDur4 = 60000 / BPM;

  gaDuration[DUR1] = uiDur4 * 4;
  gaDuration[DUR2] = uiDur4 * 2;
  gaDuration[DUR4] = uiDur4;
  gaDuration[DUR8] = uiDur4 / 2;
  gaDuration[DUR16] = uiDur4 / 4;
  gaDuration[DUR32] = uiDur4 / 8;
  gaDuration[DUR64] = uiDur4 / 16;





  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);	// TIM3 PWM시작
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    for(i = 0;  i < nNoteLen; i++)		// 악보의 음 갯수만큼 루프
    {
    	playSound(music[i]);	// 음 출력

    	playSound(mute);		// 음간의분리를 위해 10ms만큼 Mute
    	HAL_Delay(10);
    }

    playSound(mute);
    HAL_Delay(1000);
  }
  /* USER CODE END 3 */
}

 

실행해보면 학교종이 땡땡땡(이게 제목이 맞나?)이 연주된다.

우선 제일 위에 define문으로 곡의 빠르기를 설정하는 BPM이 있다. 이 값이 높을수록 속도가 빨라진다.

 

그리고 Notes라는 enum문이 나오는데 이게 각 음계 주파수이다. 현재 3, 4옥타브 음만 정의되어 있다. 소스에서 C4라고 지정하면 4옥타브 도, E3이라고 지정하면 3옥타브 미 음이 출력된다.

그 아래로 Duration enum이 나오는데 이 enum은 그 아래의 gaDuration[] 배열의 첨자로 사용된다. 각각 온음표, 2분음표, 4분음표, 8분음표, 16분음표, 32분음표, 64분음표 정의이고 HAL_Delay()의 매개변수로 사용되므로 단위가 ms이다.

 

그 밑으로 MusicStruct구조체가 나오는데 한개의 음과 길이를 쌍으로 가지고 있다. 즉 note에는 Notes enum값을, duration에는 Duration enum값을 지정해서 하나의 Note에 대해 음과 길이를 지정하도록 했다.

메인함수에서 악보를 정의하기 위해 이 구조체를 배열로 선언하여 각각의 음표를 선언했다.

 

playSound()함수는 입력된 MusicStruct구조체에 따라 ARR값을 지정하고 ARR값의 절반을 CCR1에 지정해 듀티비를 50%로 맞춘다. 이렇게 하면 스피커로 음이 출력되고 Duration시간동안 잠시 Delay를 수행한 뒤 리턴한다.

 

main()함수에서는 악보를 선언한 뒤 각 음표의 길이를 선언하기 위해 define문으로 선언한 BPM기준(60BPM=1분당 60개의 박자,  4/4박자이면 1분당 60개의 4분음표 연주)에 따라 각 음표의 실제 길이를 지정한다.

 

while()문 에서는 악보의 길이만큼 각 음을 연주한다. 이때 음표 연주때마다 10ms만큼 Mute시켜 각 음간의 사이를 분리하도록 했다.(그렇게 하지 않으면 실제 연주에서 타이/슬러 표기와 같이 음이 연결되어 솔솔라라 와 같이 8분음표 두개가 연속으로 나오면 연결되어 4분음표처럼 들린다.)

 

 

7. 마무리

이번 시간에는 타이머의 PWM기능에 대해 알아보았다.

Output Compare에서 사용되던 TIMx_CCRn 레지스터는 PWM에서 듀티비를 설정하는 용도로 사용되고 이 CCR을 설정해서 PWM신호를 만들어 내서 여러가지 작업을 해보았다.

이것들 외에도 동기화를 통해 복수의 PWM신호를 만들어내서 활용하는 법등 활용도가 많지만 내용이 길어져 이 정도로만 정리하고자 한다.

 

PWM은 정말 많은 곳에 사용되고 있으므로 위에서 설명한 TIMx_CNT, TIMx_CCRn의 관계를 잘 따져보면서 차근차근 공부해보자.

 

'임베디드 > STM32' 카테고리의 다른 글

20. [STM32] Timer - Output Compare  (0) 2025.01.06
19. [STM32] Timer의 기초  (0) 2024.11.19
18. [STM32] Clock  (0) 2024.11.14
17. [STM32] Power - PVD  (0) 2024.11.08
16. [STM32] Power - Backup Domain Access  (0) 2024.11.07