Embedded

ARM Cortex M4 core - (6) PWM을 활용한 주파수 변형 (악보연주)

MiddleJo 2024. 9. 4. 20:46

PWM.zip
10.04MB

목차

1. 배경

2. 보드 구성 및 소스코드

3. 실습결과

 

 

1. 배경

 

칩 설계를 공부하다 보니, 모터 제어가 필요한 경우가 있었습니다.

모터 제어 등에서 진동수 혹은 주기를 다룰 때는 PWM이 필요합니다.

 

 

 

이번에는 PWM과 Buzzer를 이용해 노래를 연주해보려고 합니다.

 

 

 

 

 

 

2. 보드 구성 및 소스코드

이번에도 역시 다른 분석 없이 PWM의 이론을 테스트할 것이기 때문에,

Board Select 방식으로 진행하겠습니다.

 

 

 

- 보드 세팅

 

 

 

- TIMER 세팅

 

 

Prescaler는 설정하기 나름입니다.

결과적으로 원하는 주파수만 계산할 수 있으면 됩니다.

 

 

 

- PV

/* USER CODE BEGIN PV */
#define c 261.63
#define c_sharp 277.18
#define d 293.66
#define d_sharp 311.13
#define e 329.63
#define f 349.23
#define f_sharp 369.99
#define g 392.00
#define g_sharp 415.30
#define a 440.00
#define a_sharp 466.16
#define b 493.88

#define C 523.25
#define C_SHARP 554.37
#define D 587.33
#define D_SHARP 622.25
#define E 659.25
#define F 698.46
#define F_SHARP 739.99
#define G 783.99
#define G_SHARP 830.61
#define A 880.00
#define A_SHARP 932.33
#define B 987.77
#define REST 0

float melody[] = {E       , D_SHARP, E      , D_SHARP, E      , b      , D      , C      ,
		a      , REST   , c      , e      , a      , b      , REST   ,
		e      , g_sharp, b      , C      , REST   , e      ,
		E       , D_SHARP, E      , D_SHARP, E      , b      , D      , C      ,
		a      , REST   , c      , e      , a      , b      , REST   , e      , C      , b      , a     };
int beats[] = 	 {200     , 200    , 200    , 200    , 200    , 200    , 200    , 200    ,
		400    , 200    , 200    , 200    , 200    , 400    , 200    ,
		200    , 200    , 200    , 400    , 200    , 200    ,
		200     , 200    , 200    , 200    , 200    , 200    , 200    , 200    ,
		400    , 200    , 200    , 200    , 200    , 400    , 200    , 200    , 200    , 200    , 800   };
int melody_size = sizeof(melody) / sizeof(melody[0]);

/* USER CODE END PV */

 

저는 "엘리제를 위하여" 곡의 일부를 연주하기 위해 melody를 구성하였습니다.

각 음들의 주파수 값들은 변수로 정의되어 있고,

beats는 그 음을 얼마나 유지할 것인지를 담고 있습니다.

 

 

 

- Main

 

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_ETH_Init();
  MX_USART3_UART_Init();
  MX_USB_OTG_FS_PCD_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    for (int i = 0; i < melody_size; i++) {
      float frequency = melody[i];
      uint16_t value = (uint16_t)((1000000 / frequency) - 1); // ARR 계산
      TIM3->ARR = value;
      TIM3->CCR3 = value / 2; // 듀티 사이클 50%

      HAL_Delay(beats[i]);
    }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

 

첫 음의 주파수를 가져와 ARR과 CCR을 계산하고,

부저는 해당 음을 내게 됩니다.

beats에 담긴 길이동안 음이 지속되고,

loop에 의해 노래가 연주됩니다.

 

 

3. 실습결과

 

 

기계음이라 어색하긴 하지만, 연주가 잘 됨을 확인할 수 있습니다.