본문 바로가기
Arduino&RasberryPi/Arduino Uno

14. Arduino - 압전 부저 회로 구성 및 코드

by Rosmary 2019. 11. 9.
728x90
반응형

1. 압전 부저 회로의 구성

 

압전 부저의 회로 구성은, 압전 부저의 작동 원리에 비하면 매우 간단하다. 압전 소자는 LED처럼 방향성을 지니지 않기 때문에, 양 끝 단자들 중 어떤 것이라도 GND나 전원 공급 핀에 연결할 수 있기 때문이다.

 

필자는 1년 전에 구입한 고장난 알람 시계를 분해한 뒤, 해당 제품 안에 내장되어 있던 압전 부저를 이용해 회로를 구성했다. 압전 부저와 연결된 선의 피복을 벗기고, 구리선을 깔끔하게 말아 Arduino 핀에 연결함으로써, 회로를 완성시켰다. 부저와 연결한 핀의 번호는 각각 11번과 GND이다.

 

 

 

회로는 매우 단순한데, 그에 반해 코드 작성은 약간 복잡하다. 아무래도 압전 부저의 동작과 큰 관련이 있다보니, 내용이 복잡할 수밖에 없다. 천천히 살펴보자.

 

***  C 언어의 "for 문", "while 문" 그리고 함수와 배열에 대한 지식이 있다면 코드를 이해가 수월하다. 

 

 

 

2. 소리 발생을 위한 코드

 

(1) 아날로그 신호를 이용한 압전 부저 작동 코드

 

압전 부저의 경우, 주기적인 HIGH/LOW 신호에 의해 부저 내 막이 진동하면서 소리가 발생한다고 했다. 그렇다면, PWD 핀을 통해 analogWrite() 함수 인자를 127로 설정해주면 소리가 발생할 것이다. 아날로그 신호에서 줄 수 있는 최대 인자 값이 255이기 때문에, 이 값의 절반인 127을 함수 인자로 설정해준다면, HIGH/LOW 신호가 동일한 간격으로 발생하게 된다. (Analog 핀에서 PWD에 대한 자세한 내용을 확인할 수 있다)

 

다음의 코드를 Arduino에 밀어넣고 실행해보자.

 

=================================

int analog_buzz_pin = 11;

void setup() {
  // put your setup code here, to run once:
  pinMode(analog_buzz_pin, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:

  analogWrite(analog_buzz_pin, 255/2);

}

=================================

 

 

 

 

지속적으로 하나의 음이 발생하는 것을 확인할 수 있다. analogWrite() 함수 인자가 255나 0만 아니라면, 소리는 발생한다. 하지만, 127을 중심으로, 인자값이 축에서 멀어질수록, 소리가 점차 작아지게 된다. 무슨 말이냐 하면, analogWrite() 함수로, 소리의 크기(볼륨)를 조절할 수는 있지만, 소리의 높낮이(음)는 조절할 수 없다는 말이다.

 

 

따라서, 압전 부저로 음계를 정확하게 표현하기 위해서는 디지털 신호를 이용하는 코드를 작성해야 한다.

 

 

 

(2) 디지털 신호를 이용한 압전 부저 작동 코드, delayMicroseconds()

 

디지털 신호로 매우 짧은 주기동안 부저에 HIGH/LOW값을 전달하면, 부저는 진동하며 음을 발생시킨다고 했다. 따라서 코드는 다음과 같이 작동하면, 소리가 발생한다. 

 

=================================

 

int digital_buzz_pin = 11;
int delay_time = 1;

void setup() {
  // put your setup code here, to run once:
  pinMode(analog_buzz_pin, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:

  digitalWrite(digital_buzz_pin, 1);
  delay(delay_time);
  digitalWrite(digital_buzz_pin, 0);
  delay(delay_time);
}

 

================================

 

위의 코드는, 11번 핀으로 1 ms(0.001초) 마다 HIGH/LOW 신호를 부저에 전송하는 코드다. 따라서,

 

==============================

주파수 = 1초 /  (1번 진동에 걸리는 시간)

         =  1초 /  ( 0.002초 )

         =  1000 / 2 

         =  500 Hz

==============================

 

500Hz의 소리가 발생하게 된다. 

 

하지만, 여기서 문제가 발생한다. 코드에서 delay() 함수만 사용하게 될 경우, 1번 진동에 걸린 시간을 0.002초 이하로 떨어뜨릴 수 있는 방법이 전무하다. 다른 말로 바꾸자면, delay() 함수를 사용하면, 500Hz 이상의 소리를 발생시키는 것이 불가능하다는 말이다. 지난 포스팅에서 대부분의 음계가 400Hz 이상의 주파수 대역대에 있었음을 생각해본다면, delay() 함수만으로 의미있는 멜로디를 만드는 것이 매우 어렵다는 것을 알 수 있다.

 

따라서, 압전 부저 동작을 위한 디지털 신호 코드를 작성할 때에는, delay() 함수 대신 delayMicroseconds() 라는 함수를 사용한다. 이 함수는 delay() 함수와 유사하나, 함수 인자값이 밀리세컨드(ms)가 아니라 마이크로세컨드(µs)로 작성된다는 차이점이 있다. 즉, delayMicroseconds(1000)은, 0.0000001초 동안 delay를 진행하라는 의미가 된다.

 

해당 코드의 delay() 함수를 모두, delayMicroseconds() 함수로 변경한 뒤, 프로그램을 실행해보자. 그럼 이전과 달리, 매우 높은(마치 초음파처럼 들리는) 음의 소리가 발생하는 것을 알 수 있다. 해당 소리의 주파수는 1 / (0.000002) 이므로, 500000 Hz가 된다.

 

 

이제 이 코드를 이용해, 4음계 "도레미파솔라시" 음을 차례대로 출력해보려고 한다. 해당 주파수에 맞는 delayMicroseconds() 함수 인자 값은 다음과 같다.

 

=========================================

C =>   1초  /  (262Hz * 2) =  0.001908  =>  1908

D =>  1초  /  (294Hz * 2) = 0.001700 =>  1700

E  =>  1초 /  (330Hz * 2) = 0.001515 =>  1515

F   =>  1432,  G =>  1276,  A = 1136,  B = 1012

=========================================

 

이 인자값을 특정 배열에 집어 넣어, for 문을 통해 순서대로 돌려, 음을 출력하는 코드를 작성할 것이며, 해당 코드의 내용은 다음과 같다.

 

==============================================

 

int digital_buzz_pin = 11;
int delay_array[] = {1908, 1700, 1515, 1432, 1276, 1136, 1012};

void setup() {
  // put your setup code here, to run once:
  pinMode(digital_buzz_pin, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:

  for(int number=0; number < 7; number++)
  {
    for(int count=1; count<100; count++)
    {
      digitalWrite(digital_buzz_pin, 1);
      delayMicroseconds(delay_array[number]);
      digitalWrite(digital_buzz_pin, 0);
      delayMicroseconds(delay_array[number]);
    }

  delay(1000);
  }

}

 

=========================================

 

 

 

 

이 코드를 Arduino에 밀어넣어 실행해보면, 주기적으로 "도레미파솔라시" 소리가 반복적으로 출력되는 것을 알 수 있다.

그런데... 도레미파솔라시처럼 단순한 음계도, 위와 같은 방식으로 코드를 작성하는 것은 상당히 번거로운 작업이다. 그래서 Arduino 에서는 mtone() 이라는 함수를 만들어, 압전 부저의 음을 조금 더 쉽게 출력할 수 있도록 설계해 놓았다.

 

 

 

3. tone() 함수를 이용한 음의 출력

 

tone() 함수는 3개의 인자를 가지며, 포맷은 다음과 같다.

 

===================================

tone( Pin#,  주파수,  지속 시간(ms) )

===================================

 

세 개의 인자는 모두 정수형 자료형이다. 굳이 알아도 되는 내용은 아니지만, 궁금하신 분들을 위해 정보를 추가하자면, tone() 함수의 내부 구성은 다음과 같다.

 

======================================

void tone() (int pn, int hz, unsigned long tm)

{

    unsigned long process_time = millis();

    unsigned long ns =  500000 / hz

    while(millis() - process_time < tm)

    {

        digitalWrite(pn, 1);

        delayMicroseconds(ns);

        digitalWrite(pn, 0);

        delayMicroseconds(ns);

    }

}

=======================================

 

tone()함수를 이용해, 4음계 "도레미파솔라시"를 출력하는 코드는 다음과 같다.

 

=======================================

int digital_buzz_pin = 11;

void setup() {
  // put your setup code here, to run once:
  pinMode(digital_buzz_pin, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:

  tone(digital_buzz_pin, 262, 200);
  delay(100);
  tone(digital_buzz_pin, 294, 200);
  delay(100);
  tone(digital_buzz_pin, 330, 200);
  delay(100);
  tone(digital_buzz_pin, 349, 200);
  delay(100);
  tone(digital_buzz_pin, 392, 200);
  delay(100);
  tone(digital_buzz_pin, 440, 200);
  delay(100);
  tone(digital_buzz_pin, 494, 200);
  delay(1000);
  
}

====================================

 

실행 결과로 출력되는 소리가... 마치 카스 온라인의 카지노 맵에 들어온 것 같은 기분이다.

 

 

 

 

 

PS:  날씨가 추워지니, 점점 겨울의 향기가 진하게 다가온다. 심심해서 압전 부저로 캐롤 한 곡을 만들어 보았다.

 

 

 

 

FIN.

 

 

 

반응형

댓글