풀업이 된 푸시버튼이 2번 핀에 연결되었다고 가정하자. 이 버튼은 외부에 풀업이 된 상태이기 때문에 안 눌려진 상태에서는 1값이 읽혀지고 눌려지면 0값이 읽힌다. 부저는 11번핀에 연결되었다고 가정한다.


 이 때 버튼이 눌려지는 시점에서 멜로디가 울리도록 하는 프로그램은 다음과 같다. tone()함수는 ISR 내부에서는 정상적으로 동작하기 않기 때문에 인터럽트 기능은 사용할 수 없다는 점에 유의하자.


#include "pitches.h"
#define BUZ 11
#define K 2

void setup() {
 pinMode(K, INPUT);
}

int iBtnPrev = 1; //버튼의 이전 상태값을 저장하는 변수

void loop() {
 int iBtn = digitalRead(K);
 if (iBtn == 0 && iBtnPrev == 1)
   melody();
 iBtnPrev = iBtn;
}

void melody() {
 tone(BUZ, NOTE_C4);
 delay(100);
 tone(BUZ, NOTE_D4);
 delay(100);
 tone(BUZ, NOTE_E4);
 delay(100);
 noTone(BUZ);
}


이 프로그램을 다운로드하면 버튼이 눌리는 순간 ‘도레미’ 멜로디가 울린다.



Posted by 살레시오
,

 아두이노에는 tone()함수가 제공되는데 부저나 스피커로 음을 발생시킬 수 있는 함수이다. 기본 문법은 다음과 같다.


tone(pin, freq [, duration]);


  • pin : 부저나 스피커가 연결된 디지털 핀번호

  • freq : 주파수 (범위 : 31 ~ 65535)

  • duration : (옵션) 음의 발생 시간


여기서 duration은 주파수 지속시간으로서 이 시간이 지난 후에 noTone()함수가 자동으로 호출되는 것과 같은 효과를 낸다.  duration이  생략되면 noTone()함수가 호출될 때까지 음이 계속 발생된다. 예를 들어서 11번 핀에 부저가 연결되었다면 다음과 같이 한다.


tone(11, 262); // ‘도’음 발생
delay(500);
noTone(11);


이 코드는 ‘도’음을 0.5초간 발생시키는데 다음과 같이 할 수 있다.


tone(11, 262, 500);


이렇게 하면 음 발생 직후 다른 작업을 수행할 수 있으며 500ms후에는 내부 인터럽트가 발생하여 음발생이 자동으로 정지된다. 하지만 단음만 생성할 경우에는 상관없지만 연속음을 생성할 경우에는 주의해야 한다.


tone(11, 262, 500); // ‘도’음
tone(11, 294, 500); // ‘레’음
tone(11, 330, 500); // ‘미’음


이렇게 하면 맨 마지막의 ‘미’음만 발생하게 된다. (왜?) 따라서 올바른 동작을 위해서는 다음과 같이 해야 한다.


tone(11, 262); // ‘도’음 발생
delay(500);
tone(11, 294); // ‘레’음 발생
delay(500);
tone(11, 330); // ‘미’음 발생
delay(500);
noTone(11);
tone(11, 262); // ‘도’
delay(500);
tone(11, 294); // ‘레’
delay(500);
tone(11, 330, 500); // ‘미’


tone()함수는 내부적으로 타이머를 사용하므로 다음과 같은 점들을 주의해야 한다.

  • 이 함수를 사용할 경우 3번 11번 핀의 PWM이 정상적으로 동작되지 않는다.

  • 한 번에 하나의 주파수만 발생시킬 수 있으며 여러 핀에 동시에 다른 음을 발생시킬 수 없다.


 특정 음에 해당되는 주파수를 일일이 숫자로 기입하는 것은 가독성 면에서 좋지 않으며 이를 개선하기 위해서 아두이노에서는 음의 주파수만을 모아놓은 “pitches.h”라는 헤더파일을 제공한다. 내용은 다음과 같다.


/*************************************************
* Public Constants
*************************************************/
#define NOTE_B0  31
#define NOTE_C1  33
#define NOTE_CS1 35
#define NOTE_D1  37
#define NOTE_DS1 39
#define NOTE_E1  41
#define NOTE_F1  44
#define NOTE_FS1 46
#define NOTE_G1  49
#define NOTE_GS1 52
#define NOTE_A1  55
#define NOTE_AS1 58
#define NOTE_B1  62
#define NOTE_C2  65
#define NOTE_CS2 69
#define NOTE_D2  73
#define NOTE_DS2 78
#define NOTE_E2  82
#define NOTE_F2  87
#define NOTE_FS2 93
#define NOTE_G2  98
#define NOTE_GS2 104
#define NOTE_A2  110
#define NOTE_AS2 117
#define NOTE_B2  123
#define NOTE_C3  131
#define NOTE_CS3 139
#define NOTE_D3  147
#define NOTE_DS3 156
#define NOTE_E3  165
#define NOTE_F3  175
#define NOTE_FS3 185
#define NOTE_G3  196
#define NOTE_GS3 208
#define NOTE_A3  220
#define NOTE_AS3 233
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_CS4 277
#define NOTE_D4  294
#define NOTE_DS4 311
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_FS4 370
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_AS4 466
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_CS5 554
#define NOTE_D5  587
#define NOTE_DS5 622
#define NOTE_E5  659
#define NOTE_F5  698
#define NOTE_FS5 740
#define NOTE_G5  784
#define NOTE_GS5 831
#define NOTE_A5  880
#define NOTE_AS5 932
#define NOTE_B5  988
#define NOTE_C6  1047
#define NOTE_CS6 1109
#define NOTE_D6  1175
#define NOTE_DS6 1245
#define NOTE_E6  1319
#define NOTE_F6  1397
#define NOTE_FS6 1480
#define NOTE_G6  1568
#define NOTE_GS6 1661
#define NOTE_A6  1760
#define NOTE_AS6 1865
#define NOTE_B6  1976
#define NOTE_C7  2093
#define NOTE_CS7 2217
#define NOTE_D7  2349
#define NOTE_DS7 2489
#define NOTE_E7  2637
#define NOTE_F7  2794
#define NOTE_FS7 2960
#define NOTE_G7  3136
#define NOTE_GS7 3322
#define NOTE_A7  3520
#define NOTE_AS7 3729
#define NOTE_B7  3951
#define NOTE_C8  4186
#define NOTE_CS8 4435
#define NOTE_D8  4699
#define NOTE_DS8 4978


이 헤더파일은 전역 상수 정의로만 이루어져 있으므로 실행 파일의 용량을 증가시키진 않는다. 따라서 이 파일을 폴도에 복사한 후 인클루드시켜서 필요한 주파수를 사용하면 된다.


#include “pitches.h”
tone(11, NOTE_C3, 1000); // 3도 ‘도’음을 1초간 발생
...


이렇게 주파수(숫자) 대신 상수 이름을 사용하면 가독성이 높아지게 된다.




Posted by 살레시오
,

 이번에는 부저(buzzer)를 이용한 실험을 해 보겠다. 부저는 소리를 내는 부품으로서 소리 파형을 만들어서 인가하여야 하는 것과 그냥 전압을 걸면 소리가 나는 두 가지 종류가 있으나 실험의 편의상 후자를 택해서 진행한다.


[그림 1] 부저의 외형


부저는 극성이 있으며 조금 긴 다리가 (+)극이고 짧은 쪽은 (-)이다. 극성에 맞게 전압을 걸면 삐~~ 하는 소리가 발생한다. 아두이노 우노의 11번 핀에 부저의 (+)를 꽂으면 (-)핀은 GND에 들어맞게 되어 있다.


[그리 2] 아두이노의 11번 핀에 부저의 (+)를, GND핀에 (-)를 연결했다.


이렇게 연결했다면 부저를 울리는 것은 LED를 동작시키는 것과 똑같다. 단순히 1초 간격으로 삑삑 거리는 프로그램은 다음과 같이 하면 된다.


#define BUZ 11

void setup() {
    pinMode(BUZ, OUTPUT);
}
void loop() {
    digitalWrite(BUZ, HIGH); // 부저가 울리기 시작한다.
    delay(50);
    digitalWrite(BUZ, LOW); // 부저가 멈춘다
    delay(950);
}


이 예제에서는 부저가 울리는 시간을 50ms로 설정했으므로 짧은 시간 동안 ‘삑’하는 소리가 날 것이다. loop()함수 안에 있으므로 이것이 1초 간격으로 반복된다.


 두 번째 예제로 13번 핀에 물려 있는 LED와 조합해서 동작하도록 해보자. LED는 0.5초마다 한 번씩 켜지고 부저는 1초 마다 한 번씩 울리게 해서 마치 타이머처럼 동작하도록 하는 예제이다.


#define LED 13

#define BUZ 11

void setup() {
    pinMode(LED, OUTPUT);
    pinMode(BUZ, OUTPUT);
}
void loop() {
    digitalWrite(LED, HIGH);
    digitalWrite(BUZ, HIGH);
    delay(50);
    digitalWrite(BUZ, LOW);
    delay(200);
    digitalWrite(LED, LOW);
    delay(250);
    digitalWrite(LED, HIGH);
    delay(250);
    digitalWrite(LED, LOW);
    delay(250);
}



Posted by 살레시오
,