반응형

https://youtube.com/live/QPbT5pfgztc

[STM32#07] TIM3의 ARR와 CCR을 설정하고 PWM출력을 해서 부저(buzzer) 사운드 재생하는 방법 알아보기!(녹칸다 내맘대로 STM32)

심심한녹칸다의 내맘대로 STM32시리즈이다!

STM32시리즈의 모든 자료는 구글 슬라이드에 작성하고 모두에게 공유되어있음!
https://docs.google.com/presentation/d/1myA5iYbjuKsLWLqtRLKAiRfwUwvqB1d1RGjiMIIgp3I/edit?slide=id.g39f7ee2e2d4_1_0#slide=id.g39f7ee2e2d4_1_0

이번편은 녹칸다의 STM32쉴드에 붙어있는 부저를 작동시켜보도록 하자!

1.STM32에서 구조체와 포인터타입의 구조체에 대해서 차이를 알수있는 예시를 보이시오!

/* USER CODE BEGIN 2 */
 char buff[50];
 typedef struct{
 	uint16_t num1;
 	int32_t num2;
 }Mystruct;
 //Mystruct type의 구조체를 s1이라는 이름으로 만들겠다!
 Mystruct s1;
 //Mystruct type의 구조체의 주소를 담는 포인터를 생성한다!
 Mystruct *s2;
 //s2에다가 s1의 주소를 넣겠다!
 //s2는 s1을 참조하게된다!
 s2 = &s1;
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //s1의 멤버인 num1에 10이라는 값을 대입하겠다!
	  s1.num1 = 10;
	  s1.num2 = 20;
	  sprintf(buff,"CASE1 num1=%d, num2=%d\n",s1.num1,s1.num2);
	  HAL_UART_Transmit(&huart2, buff, strlen(buff), 100);
	  HAL_Delay(1000);
	  //s2를 통해서 s1의 num1의 값을 30으로 바꾸고, num2의 값을 40으로 바꾼다!
	  (*s2).num1 = 30;
	  (*s2).num2 = 40;
	  sprintf(buff,"CASE2 num1=%d, num2=%d\n",s1.num1,s1.num2);
	  HAL_UART_Transmit(&huart2, buff, strlen(buff), 100);
	  HAL_Delay(1000);
	  s2->num1 = 50;
	  s2->num2 = 60;
	  sprintf(buff,"CASE3 num1=%d, num2=%d\n",s1.num1,s1.num2);
	  HAL_UART_Transmit(&huart2, buff, strlen(buff), 100);
	  HAL_Delay(1000);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


2.IOC를 설정해서 부저에 1초 간격으로 440hz의 부저음이 발생할 수 있도록 하시오!(PWM은 제일 처음 1회 호출하는 코드가 있다)

/* USER CODE BEGIN 0 */
static void Tone(uint32_t Frequency)
{
   TIM3->ARR = (1000000UL / Frequency) - 1; //주파수
   TIM3->CCR3 = (TIM3->ARR >> 1); //듀티비 50%
}
/* USER CODE END 0 */
//중략
/* USER CODE BEGIN 2 */
 //TIM3_CH3의 PWM기능을 활성화하겠습니다!
 HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);
 //주파수값을 440hz로 설정한다
 Tone(440);
 //시작하면 일단 부저는 끈상태라
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 0);
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //부저의 소리를 재생한다!(1초)
	  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 1);
	  HAL_Delay(1000);
	  //부저의 소리를 끈다!(1초)
	  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 0);
	  HAL_Delay(1000);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


3.녹칸다가 쉴드에 붙혀놓은 8개의 버튼이 있다! 8개의 버튼을 도,레,미,파,솔,라,시,도까지를 버튼을 누를때 소리가 나오도록 하시오!(피아노 만들기)

/* USER CODE BEGIN 0 */
static void Tone(uint32_t Frequency)
{
   TIM3->ARR = (1000000UL / Frequency) - 1; //주파수
   TIM3->CCR3 = (TIM3->ARR >> 1); //듀티비 50%
}
#define NOTE_C6  1047 //도
#define NOTE_D6  1175 //레
#define NOTE_E6  1319 //미
#define NOTE_F6  1397 //파
#define NOTE_G6  1568 //솔
#define NOTE_A6  1760 //라
#define NOTE_B6  1976 //시
#define NOTE_C7  2093 //도

/* USER CODE END 0 */
//중략
/* USER CODE BEGIN 2 */
 //TIM3_CH3의 PWM기능을 활성화하겠습니다!
 HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);
 //시작하면 일단 부저는 끈상태라
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 0);
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == 0){
		  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 1);
		  Tone(NOTE_C6);


	  }else if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8) == 0){
		  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 1);
		  Tone(NOTE_D6);
	  }else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2) == 0){
		  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 1);
		  Tone(NOTE_E6);
	  }else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6) == 0){
		  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 1);
		  Tone(NOTE_F6);
	  }else if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_5) == 0){
		  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 1);
		  Tone(NOTE_G6);
	  }else if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_7) == 0){
		  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 1);
		  Tone(NOTE_A6);
	  }else if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11) == 0){
		  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 1);
		  Tone(NOTE_B6);
	  }else if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12) == 0){
		  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 1);
		  Tone(NOTE_C7);
	  }else{
		  //소리를 끈다
		  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 0);
	  }
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


4.로터리엔코더를 이용해서 로터리엔코더의 회전이 감지되면 감지될때마다 아주 짧은 비프음을 발생시키시오!(시계 6옥타브미, 반시계는 6옥타브솔,로터리엔코더눌려지면 7옥타브도)

/* USER CODE BEGIN 0 */
static void Tone(uint32_t Frequency)
{
   TIM3->ARR = (1000000UL / Frequency) - 1; //주파수
   TIM3->CCR3 = (TIM3->ARR >> 1); //듀티비 50%
}
#define NOTE_C6  1047 //도
#define NOTE_D6  1175 //레
#define NOTE_E6  1319 //미
#define NOTE_F6  1397 //파
#define NOTE_G6  1568 //솔
#define NOTE_A6  1760 //라
#define NOTE_B6  1976 //시
#define NOTE_C7  2093 //도

/* USER CODE END 0 */
//중략
/* USER CODE BEGIN 2 */
 //TIM3_CH3의 PWM기능을 활성화하겠습니다!
 HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);
 //시작하면 일단 부저는 끈상태라
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 0);
 uint8_t old_sensor_A  = 1;
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */


while (1)
 {
	  uint8_t sensor_A = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11); //A값
	  if(sensor_A == 0 && old_sensor_A == 1){
		  //falling edge
		  uint8_t sensor_B = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12); //B값
		  if(sensor_B == 0){
			  //시계
			  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 1);
			  Tone(NOTE_E6);
			  HAL_Delay(100);
			  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 0);
		  }else{
			  //반시계
			  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 1);
			  Tone(NOTE_G6);
			  HAL_Delay(100);
			  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 0);
		  }
	  }
	  old_sensor_A = sensor_A;
	  //PC7이 눌려지면 7옥타브 도 음이 재생된다!
	  if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_7) == 0){
		  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 1);
		  Tone(NOTE_C7);
	  }else{
		  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 0);
	  }
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


5.PA0에 연결된 가변저항을 이용해서 부저의 피치를 6옥타브도부터 7옥타브 도까지를 설정하는데, 버튼1인 PB1을 누르면 부저가 재생되고, 버튼2인 PA8을 누르면 부저가 재생되지 않도록 하시오!

/* USER CODE BEGIN 0 */
static void Tone(uint32_t Frequency)
{
   TIM3->ARR = (1000000UL / Frequency) - 1; //주파수
   TIM3->CCR3 = (TIM3->ARR >> 1); //듀티비 50%
}
#define NOTE_C6  1047 //도
#define NOTE_D6  1175 //레
#define NOTE_E6  1319 //미
#define NOTE_F6  1397 //파
#define NOTE_G6  1568 //솔
#define NOTE_A6  1760 //라
#define NOTE_B6  1976 //시
#define NOTE_C7  2093 //도

/* USER CODE END 0 */
//중략
/* USER CODE BEGIN 2 */
 //TIM3_CH3의 PWM기능을 활성화하겠습니다!
 HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);
 HAL_ADC_Start(&hadc1); //딱 한번만 호출
 uint16_t adc_value0 = 0;
 //시작하면 일단 부저는 끈상태라
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 0);
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */



while (1)
 {
	  //PB1을 누르면 부저의 소리가 난다
	  if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == 0){
		  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 1);
	  }
	  //PA8을 누르면 부저의 소리가 꺼진다
	  if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8) == 0){
		  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 0);
	  }
	  //측정할때마다 호출
	  if(HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK)
	  {
		  // 값 처리
		  adc_value0 = HAL_ADC_GetValue(&hadc1); //0~4095
		  //NOTE_C6 1047 ~ NOTE_C7 2094
		  adc_value0 = NOTE_C6+(NOTE_C7-NOTE_C6)*(adc_value0/4095.0);
		  Tone(adc_value0);
	  }
	  HAL_Delay(100);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


6.예제5에서 했던 가변저항측정값을 CDS측정값으로 바꾸고, 빛의 세기에 따라서 음높이가 달라지는 예시를 구현하시오!

/* USER CODE BEGIN 0 */
static void Tone(uint32_t Frequency)
{
   TIM3->ARR = (1000000UL / Frequency) - 1; //주파수
   TIM3->CCR3 = (TIM3->ARR >> 1); //듀티비 50%
}
#define NOTE_C6  1047 //도
#define NOTE_D6  1175 //레
#define NOTE_E6  1319 //미
#define NOTE_F6  1397 //파
#define NOTE_G6  1568 //솔
#define NOTE_A6  1760 //라
#define NOTE_B6  1976 //시
#define NOTE_C7  2093 //도

/* USER CODE END 0 */
//중략
/* USER CODE BEGIN 2 */
 //TIM3_CH3의 PWM기능을 활성화하겠습니다!
 HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);
 HAL_ADC_Start(&hadc1); //딱 한번만 호출
 uint16_t adc_value0 = 0;
 //시작하면 일단 부저는 끈상태라
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 0);
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */



while (1)
 {
	  //PB1을 누르면 부저의 소리가 난다
	  if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == 0){
		  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 1);
	  }
	  //PA8을 누르면 부저의 소리가 꺼진다
	  if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8) == 0){
		  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 0);
	  }
	  //측정할때마다 호출
	  if(HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK)
	  {
		  // 값 처리
		  adc_value0 = HAL_ADC_GetValue(&hadc1); //0~4095
		  //NOTE_C6 1047 ~ NOTE_C7 2094
		  adc_value0 = NOTE_C6+(NOTE_C7-NOTE_C6)*(adc_value0/4095.0);
		  Tone(adc_value0);
	  }
	  HAL_Delay(100);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }

7.PA1에 연결된 CDS의 아날로그 값을 측정해서 녹칸다가 센서를 손으로 가리면 부저의 소리가 발생하고 안가리면 소리가 안나도록 하시오!

/* USER CODE BEGIN 0 */
static void Tone(uint32_t Frequency)
{
   TIM3->ARR = (1000000UL / Frequency) - 1; //주파수
   TIM3->CCR3 = (TIM3->ARR >> 1); //듀티비 50%
}
#define NOTE_C6  1047 //도
#define NOTE_D6  1175 //레
#define NOTE_E6  1319 //미
#define NOTE_F6  1397 //파
#define NOTE_G6  1568 //솔
#define NOTE_A6  1760 //라
#define NOTE_B6  1976 //시
#define NOTE_C7  2093 //도

/* USER CODE END 0 */
//중략
/* USER CODE BEGIN 2 */
 //TIM3_CH3의 PWM기능을 활성화하겠습니다!
 HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);
 HAL_ADC_Start(&hadc1); //딱 한번만 호출
 uint16_t adc_value0 = 0;
 //시작하면 일단 부저는 끈상태라
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 0);
 Tone(NOTE_G6);
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */




while (1)
 {
	  //측정할때마다 호출
	  if(HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK)
	  {
		  // 값 처리
		  adc_value0 = HAL_ADC_GetValue(&hadc1); //0~4095
		  //측정값이 1000보다 크면 부저에 소리가 안나고
		  //그게 아니라면 소리가 난다
		  if(adc_value0 > 1000){
			  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 0);
		  }else{
			  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 1);
		  }
	  }
	  HAL_Delay(100);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


8.로터리엔코더를 돌리면 세탁메뉴가 변경되는데 LED8개중에 1개가 선택되는것으로 시각화한다! 그리고 로터리엔코더의 스위치를 누르면 실행이 되었다는 의미로 세탁 완료음을 부저로 재생하시오! 그리고 로터리엔코더가 회전할때 회전하는 사운드도 추가하시오!

/* USER CODE BEGIN 0 */
static void Tone(uint32_t Frequency)
{
   TIM3->ARR = (1000000UL / Frequency) - 1; //주파수
   TIM3->CCR3 = (TIM3->ARR >> 1); //듀티비 50%
}
#define NOTE_C6  1047 //도
#define NOTE_D6  1175 //레
#define NOTE_E6  1319 //미
#define NOTE_F6  1397 //파
#define NOTE_G6  1568 //솔
#define NOTE_A6  1760 //라
#define NOTE_B6  1976 //시
#define NOTE_C7  2093 //도
#define NOTE_D7  2349 //레
void play_melody(){
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2,1);
	  Tone(NOTE_G6);
	  HAL_Delay(500);
	  Tone(NOTE_C7);
	  HAL_Delay(500/3);
	  Tone(NOTE_B6);
	  HAL_Delay(500/3);
	  Tone(NOTE_A6);
	  HAL_Delay(500/3);
	  Tone(NOTE_G6);
	  HAL_Delay(500);
	  Tone(NOTE_E6);
	  HAL_Delay(500);
	  //파솔라 레미파 미 솔
	  Tone(NOTE_F6);
	  HAL_Delay(500/3);

	  Tone(NOTE_G6);
	  HAL_Delay(500/3);
	  Tone(NOTE_A6);
	  HAL_Delay(500/3);
	  Tone(NOTE_D6);
	  HAL_Delay(500/3);
	  Tone(NOTE_E6);
	  HAL_Delay(500/3);
	  Tone(NOTE_F6);
	  HAL_Delay(500/3);
	  Tone(NOTE_E6);
	  HAL_Delay(500);
	  Tone(NOTE_G6);
	  HAL_Delay(500);
	  //
	  Tone(NOTE_G6);
	  HAL_Delay(500);
	  Tone(NOTE_C7);
	  HAL_Delay(500/3);
	  Tone(NOTE_B6);
	  HAL_Delay(500/3);
	  Tone(NOTE_A6);
	  HAL_Delay(500/3);
	  Tone(NOTE_G6);
	  HAL_Delay(500);
	  Tone(NOTE_C7);
	  HAL_Delay(500);
	  //도레도 시라시 도~
	  Tone(NOTE_C7);
	  HAL_Delay(500/3);
	  Tone(NOTE_D7);
	  HAL_Delay(500/3);
	  Tone(NOTE_C7);
	  HAL_Delay(500/3);
	  Tone(NOTE_B6);
	  HAL_Delay(500/3);

	  Tone(NOTE_A6);
	  HAL_Delay(500/3);
	  Tone(NOTE_B6);
	  HAL_Delay(500/3);
	  Tone(NOTE_C7);
	  HAL_Delay(1000);
	  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2,0);
}
GPIO_TypeDef *mygroup[] = {GPIOB,GPIOB,GPIOB,GPIOB,GPIOB,GPIOB,GPIOC,GPIOB};
uint16_t mypin[] = {GPIO_PIN_3,GPIO_PIN_13,GPIO_PIN_5,GPIO_PIN_14,GPIO_PIN_4,GPIO_PIN_15,GPIO_PIN_4,GPIO_PIN_7};
void set_led(int num){
	//LED의 상태 업데이트 현재 켜져야하는 LED는 CNT번째꺼
	  for(int i = 0;i<8;i++){
		  if(i == num){
			  HAL_GPIO_WritePin(mygroup[i],mypin[i],GPIO_PIN_SET);
		  }else{
			  HAL_GPIO_WritePin(mygroup[i],mypin[i],GPIO_PIN_RESET);
		  }
	  }
	  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2,1);
	  Tone(NOTE_G6);
	  HAL_Delay(100);
	  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2,0);
}
/* USER CODE END 0 */


/* USER CODE BEGIN 2 */
 //TIM3_CH3의 PWM기능을 활성화하겠습니다!
 HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);
 //시작하면 일단 부저는 끈상태라
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, 0);
 uint8_t old_A = 0;
 int cnt = 0;
   //시작하자마자 일단 12시방향의 LED는 1개 켜고 출발한다!
 HAL_GPIO_WritePin(mygroup[0],mypin[0],GPIO_PIN_SET);
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //PA11의 상승엣지가 발생했을때
	  uint8_t now_A = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11);
	  if(old_A == 0 && now_A == 1){
		  //PA12의 값을 측정해서 LOW면 시계, HIGH면 반시계
		  uint8_t now_B = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12);
		  if(now_B){
			 //반시계
			  cnt--;
			  if(cnt < 0) cnt = 7;
			  set_led(cnt);

		  }else{
			 //시계
			  cnt++;
			  if(cnt > 7) cnt = 0;
			  set_led(cnt);
		  }
	  }
	  old_A = now_A;
	  //PC7을 누르면 세탁기 완료 사운드가 재생된다
	  if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_7) == 0){
		  play_melody();
	  }
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }
반응형
Posted by 덕력킹
,