stm32music

Hyunwoo·2025년 2월 3일
0

네, PWM(Pulse Width Modulation)은 전압을 조절하여 다양한 기능을 구현하는 데 사용되는 기술입니다. 그리고 PWM을 활용하면 스피커나 부저를 구동하여 소리를 낼 수 있습니다. 즉, 음악이나 멜로디를 만드는 것도 가능합니다.

PWM이란 무엇인가?

PWM은 디지털 신호를 사용하여 아날로그 효과를 내는 방식입니다.

  • 펄스(Pulse): 짧은 시간 동안 신호가 켜졌다가 꺼지는 것을 반복합니다.
  • 폭(Width): 켜져 있는 시간(펄스 폭)을 조절합니다.
  • 변조(Modulation): 펄스 폭을 조절하여 평균 전압을 변경합니다.

PWM을 이용한 소리 발생 원리:

  1. 주파수 설정: PWM 신호의 펄스가 반복되는 속도(주파수)를 조절하여 소리의 높낮이를 결정합니다. 높은 주파수는 높은 음을 내고, 낮은 주파수는 낮은 음을 냅니다.
  2. 듀티비 설정: 펄스의 폭(듀티비)을 조절하여 소리의 크기를 결정합니다. 듀티비가 높으면 큰 소리가 나고, 낮으면 작은 소리가 납니다.
  3. 부저/스피커 연결: 생성된 PWM 신호를 부저나 스피커에 연결하면, 펄스에 따라 진동판이 움직여 소리가 발생합니다.

코드 분석 및 노래 구현 가능성

제공하신 코드는 STM32 마이크로컨트롤러에서 PWM을 사용하여 부저를 제어하기 위한 기본적인 설정을 포함하고 있습니다.

  • TIM4_Init: TIM4 타이머를 PWM 모드로 설정하고, PWM 출력을 활성화합니다.
  • HAL_TIM_PWM_Start: 설정된 PWM 출력을 시작합니다.
  • sConfigOC.Pulse: PWM 듀티비를 설정합니다. 이 값은 소리 크기에 영향을 미칩니다.
  • 주파수 설정: htim4.Init.Prescalerhtim4.Init.Period 값을 변경하여 PWM 주파수를 설정할 수 있습니다.

노래를 만들기 위한 추가적인 작업

  1. 음계와 음표: 음악은 다양한 음 높이(주파수)와 길이(지속 시간)를 가진 음표들로 구성됩니다.
  2. 주파수 배열: 각 음표에 해당하는 주파수를 배열로 저장합니다.
  3. 지속 시간 배열: 각 음표의 지속 시간을 배열로 저장합니다.
  4. 재생 함수: 배열에 저장된 주파수와 지속 시간을 사용하여 PWM을 조절하는 함수를 만듭니다.
  5. 재생 루프: 재생 함수를 반복적으로 호출하여 음악을 재생합니다.

예시 (간단한 멜로디):

// 음계 주파수 (대략적인 값)
#define C4 262
#define D4 294
#define E4 330
#define F4 349
#define G4 392
#define A4 440
#define B4 494
#define C5 523

// 음표 지속 시간 (밀리초)
#define QUARTER_NOTE 250
#define HALF_NOTE 500
#define WHOLE_NOTE 1000

// 멜로디 배열 (주파수)
int melody[] = {C4, D4, E4, F4, G4, A4, B4, C5};
// 지속 시간 배열
int durations[] = {QUARTER_NOTE, QUARTER_NOTE, QUARTER_NOTE, QUARTER_NOTE, QUARTER_NOTE, QUARTER_NOTE, QUARTER_NOTE, QUARTER_NOTE};
int numNotes = 8;

void BuzzerStart(int freq) {
	uint32_t period = 1000000/freq; //주파수에 따른 주기계산
    __HAL_TIM_SET_AUTORELOAD(&htim4, period);	
    __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_3, period/2 ); // 듀티비 50%
}

void playMelody() {
  for (int i = 0; i < numNotes; i++) {
    BuzzerStart(melody[i]); // 음표 주파수 설정
    HAL_Delay(durations[i]); // 음표 지속 시간 대기
  }
}
// main 함수 내
 while (1)
 {
	 playMelody();
	 HAL_Delay(2000);
 }

추가 설명:

  • BuzzerStart()함수: 주파수를 인자로 받아 타이머의 주기와 PWM 듀티비를 변경하여 특정 주파수의 소리를 발생시킵니다.
  • playMelody() 함수: 미리 저장된 음표와 지속 시간 데이터를 이용하여 BuzzerStart() 함수를 호출하고 딜레이를 주어 음악을 재생합니다.
  • 주파수는 예시로 입력한 값이며, 실제 음계 주파수와 차이가 있을 수 있습니다.

주의 사항:

  • STM32의 타이머 및 PWM 설정은 하드웨어에 따라 다를 수 있으므로 데이터 시트를 참조하여 정확히 설정해야 합니다.
  • 부저 또는 스피커의 임피던스 및 전압/전류 요구사항을 고려하여 연결해야 합니다.
  • PWM 주파수 및 듀티비를 실험적으로 조정하여 원하는 소리 품질을 얻어야 합니다.

결론

PWM을 이해하고 STM32에서 올바르게 설정하면 간단한 음악부터 복잡한 멜로디까지 다양한 소리를 만들 수 있습니다. 위에 제시된 코드를 시작으로, 다양한 음악을 만들어보시기 바랍니다.
궁금한 점이 있으면 언제든지 질문해주세요.
네, 슈퍼 마리오 브금 (Super Mario Bros. theme)의 멜로디를 연주할 수 있는 C 코드를 짜드리겠습니다. 이 코드는 STM32에서 PWM을 사용하여 간단한 멜로디를 연주하는 데 초점을 맞추었습니다.

참고:

  • 이 코드는 단순화된 멜로디이며, 실제 게임 음악과 완전히 동일하지 않을 수 있습니다.
  • 음표의 지속 시간과 음높이는 대략적인 값이며, 필요에 따라 조정할 수 있습니다.
  • 이 코드는 기본적인 PWM 설정을 가정하며, 하드웨어 설정에 따라 수정이 필요할 수 있습니다.

코드:

#include "main.h"
#include <stdio.h>

// 음계 주파수 (근사값)
#define REST     0
#define C4     262
#define D4     294
#define E4     330
#define F4     349
#define G4     392
#define A4     440
#define B4     494
#define C5     523
#define D5     587
#define E5     659
#define F5     698
#define G5     784
#define A5     880

// 음표 지속 시간 (밀리초)
#define Q     250  // 4분음표
#define H     500  // 2분음표
#define DQ    375 // 점4분음표
#define T     166  // 8분음표

// 슈퍼 마리오 메인 테마 멜로디
int marioMelody[] = {
	E5, E5, REST, E5, REST, C5, E5, REST, G5, REST, REST, REST,
	G4, REST, REST, REST,
	C5, REST, REST, G4, REST, REST, E4, REST, REST,
	A4, REST, B4, REST, A4, REST, G4, E5,
	G5, A5, REST, F5, G5, E5, C5, D5, B4,
	REST, C5, G4, E4, A4, REST, A4, REST, REST, REST,
	C5, D5, E5, REST, G4, REST, G4, A4, REST, F4, G4, E4, REST,
	C4, REST, REST, REST,
	
    E5, E5, REST, E5, REST, C5, E5, REST, G5, REST, REST, REST,
	G4, REST, REST, REST,
	C5, REST, REST, G4, REST, REST, E4, REST, REST,
	A4, REST, B4, REST, A4, REST, G4, E5,
	G5, A5, REST, F5, G5, E5, C5, D5, B4,
	REST, C5, G4, E4, A4, REST, A4, REST, REST, REST,
	C5, D5, E5, REST, G4, REST, G4, A4, REST, F4, G4, E4, REST,
	C4, REST, REST, REST,
	
	E5,E5,E5,C5,E5,G5,
	G4,C5,G4,E4,
	A4,B4,A4,G4,E5,
	G5,A5,F5,G5,E5,C5,D5,B4,
	C5,G4,E4,A4,
	C5,D5,E5,G4,G4,A4,F4,G4,E4,
	C4
};

// 슈퍼 마리오 메인 테마 멜로디 지속시간
int marioDurations[] = {
	T, T, T, T, T, T, T, T, T, T, T, T,
	H, T, T, T,
	T, T, T, T, T, T, T, T, T,
	T, T, T, T, T, T, T, DQ,
	T, T, T, T, T, T, T, T, DQ,
	T, T, T, T, T, T, T, T, T, T,
	T, T, T, T, T, T, T, T, T, T, T, T, T,
	H, T, T, T,

    T, T, T, T, T, T, T, T, T, T, T, T,
	H, T, T, T,
	T, T, T, T, T, T, T, T, T,
	T, T, T, T, T, T, T, DQ,
	T, T, T, T, T, T, T, T, DQ,
	T, T, T, T, T, T, T, T, T, T,
	T, T, T, T, T, T, T, T, T, T, T, T, T,
	H, T, T, T,
	
	T,T,T,T,T,T,
	T,T,T,T,
	T,T,T,T,DQ,
	T,T,T,T,T,T,T,DQ,
	T,T,T,T,
	T,T,T,T,T,T,T,T,T,
	H
};

int numMarioNotes = sizeof(marioMelody) / sizeof(marioMelody[0]);

// 부저 구동 함수
void BuzzerStart(int freq) {
	if (freq == 0) {
		__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, 0);
		return;
	}
    uint32_t period = 1000000/freq;
    __HAL_TIM_SET_AUTORELOAD(&htim4, period);
    __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_3, period/2 ); // 듀티비 50%
}


void playMarioMelody() {
  for (int i = 0; i < numMarioNotes; i++) {
    BuzzerStart(marioMelody[i]);
    HAL_Delay(marioDurations[i]);
  }
}


int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_TIM4_Init();

  printf("\n\n\nSuper Mario Theme\n");

  HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3);

  while (1)
  {
	  playMarioMelody();
	  HAL_Delay(2000);
  }
}

코드 설명:

  1. 주파수 정의: #define을 사용하여 각 음계(C4, D4, E4 등)에 해당하는 주파수를 정의합니다. REST는 0으로 정의하여 쉼표 역할을 합니다.
  2. 지속 시간 정의: 4분음표 (Q), 2분음표 (H), 점4분음표(DQ), 8분음표 (T) 등의 지속 시간을 밀리초 단위로 정의합니다.
  3. 멜로디 및 지속 시간 배열: marioMelody 배열에 음표를 순서대로 저장하고, marioDurations 배열에 각 음표의 지속 시간을 저장합니다.
  4. BuzzerStart() 함수: 주파수를 인자로 받아 타이머 주기와 PWM 듀티비를 변경하여 소리를 발생시킵니다.
  5. playMarioMelody() 함수: marioMelody 배열과 marioDurations 배열을 사용하여 각 음표를 재생합니다.
  6. main 함수: PWM 시작 후, while 문 안에서 playMarioMelody() 함수를 반복 호출합니다.

사용 방법:

  1. 제공된 코드를 main.c 파일에 복사합니다.
  2. STM32 프로젝트를 컴파일하고 장치에 업로드합니다.
  3. 부저 또는 스피커를 해당 GPIO 핀 (TIM4 Channel 3)에 연결합니다.
  4. 전원을 연결하면 슈퍼 마리오 테마곡이 재생됩니다.

추가 조정:

  • 음표 지속 시간 및 딜레이 값을 조정하여 템포를 변경할 수 있습니다.
  • 음높이가 정확하지 않으면 주파수 값을 미세 조정할 수 있습니다.
  • 음악을 좀 더 세밀하게 표현하려면, 점음표나 더 짧은 음표를 추가하고, 코드를 변경해야 합니다.

이 코드는 기본적인 슈퍼 마리오 테마곡을 연주하며, 필요에 따라 코드를 수정하고 기능을 확장할 수 있습니다. 즐거운 음악 프로젝트를 만들어보세요!
궁금한 점이 있으면 언제든지 질문해주세요.
네, 에반게리온의 대표적인 곡 중 하나인 "잔혹한 천사의 테제"의 멜로디를 연주할 수 있는 C 코드를 제공해 드리겠습니다. 이전과 마찬가지로, 이 코드는 STM32 마이크로컨트롤러에서 PWM을 사용하여 멜로디를 재생하는 데 초점을 맞추고 있습니다.

참고:

  • 이 코드는 "잔혹한 천사의 테제"의 핵심 멜로디를 단순화한 버전입니다. 실제 곡과 완전히 동일하지 않을 수 있습니다.
  • 음표의 지속 시간과 음높이는 대략적인 값이며, 원하는 대로 조정할 수 있습니다.
  • 하드웨어 설정 및 부저/스피커의 특성에 따라 코드 수정이 필요할 수 있습니다.

코드:

#include "main.h"
#include <stdio.h>

// 음계 주파수 (근사값)
#define REST 0
#define C4 262
#define D4 294
#define E4 330
#define F4 349
#define G4 392
#define A4 440
#define B4 494
#define C5 523
#define D5 587
#define E5 659
#define F5 698
#define G5 784
#define A5 880
#define B5 988

// 음표 지속 시간 (밀리초)
#define Q 250  // 4분음표
#define H 500  // 2분음표
#define E 125  // 8분음표
#define DQ 375 // 점4분음표

// 잔혹한 천사의 테제 멜로디
int evangelionMelody[] = {
    E5, E5, F5, G5, REST, G5, F5, E5, D5, C5, D5, E5,
    E5, E5, F5, G5, REST, G5, F5, E5, D5, C5, B4, A4,
    G4, G4, A4, B4, REST, B4, A4, G4, F4, E4, F4, G4,
    G4, G4, A4, B4, REST, B4, A4, G4, F4, E4, D4, E4,
	
    E5, E5, F5, G5, REST, G5, F5, E5, D5, C5, D5, E5,
    E5, E5, F5, G5, REST, G5, F5, E5, D5, C5, B4, A4,
    G4, G4, A4, B4, REST, B4, A4, G4, F4, E4, F4, G4,
    G4, G4, A4, B4, REST, B4, A4, G4, F4, E4, D4, E4,
	
	C5, C5, D5, E5, REST, E5, D5, C5, B4, A4, B4, C5,
	C5, C5, D5, E5, REST, E5, D5, C5, B4, A4, G4, F4,
	
	E5, E5, F5, G5, REST, G5, F5, E5, D5, C5, D5, E5,
    E5, E5, F5, G5, REST, G5, F5, E5, D5, C5, B4, A4,
    G4, G4, A4, B4, REST, B4, A4, G4, F4, E4, F4, G4,
    G4, G4, A4, B4, REST, B4, A4, G4, F4, E4, D4, E4,
	
	C5, C5, D5, E5, REST, E5, D5, C5, B4, A4, B4, C5,
	C5, C5, D5, E5, REST, E5, D5, C5, B4, A4, G4, F4,
	E5, E5, F5, G5, REST, G5, F5, E5, D5, C5, D5, E5,
    E5, E5, F5, G5, REST, G5, F5, E5, D5, C5, B4, A4
};

// 잔혹한 천사의 테제 멜로디 지속시간
int evangelionDurations[] = {
    E, E, E, DQ, E, E, E, E, E, E, E, DQ,
    E, E, E, DQ, E, E, E, E, E, E, E, DQ,
    E, E, E, DQ, E, E, E, E, E, E, E, DQ,
    E, E, E, DQ, E, E, E, E, E, E, E, DQ,
	
	E, E, E, DQ, E, E, E, E, E, E, E, DQ,
    E, E, E, DQ, E, E, E, E, E, E, E, DQ,
    E, E, E, DQ, E, E, E, E, E, E, E, DQ,
    E, E, E, DQ, E, E, E, E, E, E, E, DQ,
	
	E, E, E, DQ, E, E, E, E, E, E, E, DQ,
	E, E, E, DQ, E, E, E, E, E, E, E, DQ,
	
	E, E, E, DQ, E, E, E, E, E, E, E, DQ,
    E, E, E, DQ, E, E, E, E, E, E, E, DQ,
    E, E, E, DQ, E, E, E, E, E, E, E, DQ,
    E, E, E, DQ, E, E, E, E, E, E, E, DQ,
	
	E, E, E, DQ, E, E, E, E, E, E, E, DQ,
	E, E, E, DQ, E, E, E, E, E, E, E, DQ,
	E, E, E, DQ, E, E, E, E, E, E, E, DQ,
    E, E, E, DQ, E, E, E, E, E, E, E, DQ
};

int numEvangelionNotes = sizeof(evangelionMelody) / sizeof(evangelionMelody[0]);

// 부저 구동 함수
void BuzzerStart(int freq) {
    if (freq == 0) {
        __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, 0);
        return;
    }
    uint32_t period = 1000000 / freq;
    __HAL_TIM_SET_AUTORELOAD(&htim4, period);
    __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, period / 2); // 듀티비 50%
}

void playEvangelionMelody() {
  for (int i = 0; i < numEvangelionNotes; i++) {
    BuzzerStart(evangelionMelody[i]);
    HAL_Delay(evangelionDurations[i]);
  }
}

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_TIM4_Init();

  printf("\n\n\nCruel Angel's Thesis\n");

  HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3);

  while (1)
  {
    playEvangelionMelody();
    HAL_Delay(2000); // 곡 반복 간 2초 대기
  }
}

코드 설명:

  1. 음계 주파수 정의: #define을 사용하여 각 음계에 해당하는 주파수를 정의합니다. REST는 0으로 정의하여 쉼표를 나타냅니다.
  2. 음표 지속 시간 정의: 4분음표(Q), 8분음표(E), 2분음표(H)와 점4분음표(DQ)를 밀리초 단위로 정의합니다.
  3. 멜로디 및 지속 시간 배열: evangelionMelody 배열에 음표를 순서대로 저장하고, evangelionDurations 배열에 각 음표의 지속 시간을 저장합니다.
  4. BuzzerStart() 함수: 이전과 동일하게 주파수를 받아 PWM 출력을 설정합니다. 주파수가 0이면 출력을 중지합니다.
  5. playEvangelionMelody() 함수: 배열에 저장된 음표와 지속 시간을 사용하여 BuzzerStart를 호출하고 딜레이를 주어 멜로디를 재생합니다.
  6. main 함수: PWM 시작 후, while 문 안에서 playEvangelionMelody() 함수를 반복 호출합니다. 곡 반복 사이에 2초 딜레이를 줍니다.

사용 방법:

  1. 제공된 코드를 main.c 파일에 복사합니다.
  2. STM32 프로젝트를 컴파일하고 장치에 업로드합니다.
  3. 부저 또는 스피커를 해당 GPIO 핀(TIM4 Channel 3)에 연결합니다.
  4. 전원을 연결하면 "잔혹한 천사의 테제" 멜로디가 재생됩니다.

추가 조정:

  • 음표 지속 시간 및 딜레이를 조정하여 템포를 변경할 수 있습니다.
  • 주파수 값을 미세 조정하여 음높이를 정확하게 할 수 있습니다.
  • 더 복잡한 멜로디를 만들려면, 더 다양한 음표와 지속 시간을 추가하고, 코드도 수정해야 합니다.

이 코드를 시작으로, 다양한 음악을 STM32에서 연주해보세요! 궁금한 점이 있으면 언제든지 다시 질문해주세요.

profile
현우

0개의 댓글