# Arduino 教學 5:利用光敏電阻控制蜂鳴器 > 作者:王一哲 > 日期:2016/9/13 ## 所需元件 1. 光敏電阻1個 2. 10kΩ電阻1個 3. 蜂鳴器或喇叭1個 4. 麵包板1塊 5. Arduino Uno開發板1塊 6. 麵包板連接線數條 <img height="100%" width="100%" src="https://i.imgur.com/VB0I1UV.png" style="display: block; margin-left: auto; margin-right: auto;"/> <div style="text-align:center">線路圖</div> </br> <img height="100%" width="100%" src="https://i.imgur.com/f0cjb3E.jpg" style="display: block; margin-left: auto; margin-right: auto;"/> <div style="text-align:center">實際的裝置照片(連接蜂鳴器)</div> </br> <img height="100%" width="100%" src="https://i.imgur.com/8ORTUQV.jpg" style="display: block; margin-left: auto; margin-right: auto;"/> <div style="text-align:center">實際的裝置照片(連接喇叭)</div> </br> ## 控制蜂鳴器或喇叭發出指定頻率的聲音 ### 方法1:由頻率算出蜂鳴器發聲、不發聲的持續時間 ```c= /* 實驗3-1:指定無源蜂鳴器發聲頻率 * * 不使用tone * * 日期:Sep. 8, 2016 * * 作者:王一哲 */ int buzzerPin = 3; int frequency = 262; // 31 Hz ~ 4978 Hz float dt = 1./(float(frequency)*2.)*1000000.; //由頻率換算延遲時間,單位為microsecond void setup() { pinMode(buzzerPin, OUTPUT); Serial.begin(9600); Serial.println(dt); } void loop() { digitalWrite(buzzerPin, HIGH); delayMicroseconds(int(dt)); digitalWrite(buzzerPin, LOW); delayMicroseconds(int(dt)); } ``` </br> 這是最直接但不方便的方法,由於聲音頻率較高,延遲時間極短,必須以μs(百萬分之1秒)為單位,算式如下 ```c float dt = 1./(float(frequency)*2.)*1000000.; ``` 延遲時間則寫為 ```c delayMicroseconds(int(dt)); ``` </br> ### 方法2:使用內建函數tone ```c= /* 實驗3-2:指定無源蜂鳴器發聲頻率 * * 使用tone * * 日期:Sep. 8, 2016 * * 作者:王一哲 */ int buzzerPin = 3; void setup() { pinMode(buzzerPin, OUTPUT); Serial.begin(9600); } void loop() { tone(buzzerPin, 262); //31Hz ~ 4978Hz } ``` </br> Arduino有內建的聲音函數tone,但要將蜂鳴器的正極接腳接在支援PWM的腳位3或11,詳細的說明請參考Arduino的說明文件。寫法如下 ```c tone(pin, 頻率) 或 tone(pin, 頻率, 持續時間) ``` </br> ## 利用光敏電阻控制蜂鳴器 這裡所使用的光敏電阻是最常見、最便宜的規格,當光敏電阻照到光時電阻值減少,沒照到光時則電阻值增加,範圍約為2kΩ ~ 980kΩ。若將光敏電阻串聯1個10kΩ的固定電阻,兩端接上+5V的電壓,就是一個簡單的分壓電路。由於我將+5V先接到光敏電阻再接到固定電阻,當光敏電阻照到光時電阻值減少,固定電阻分到的電壓增加;反之則降低。我們可以先寫一個最簡單的程式來測試一下。 ```c= /* 3-5:利用光敏電阻的分壓電路 * * 日期:Sep. 8, 2016 * * 作者:王一哲 */ int potPin = 0; //定義讀取電壓值的接腳 int val = 0 ; //定義讀取數值暫存用的變數 //光敏電阻範圍約2kOhm ~ 980kOhm //串聯10kOhm固定電阻 void setup() { pinMode(potPin, INPUT); //定義讀取電壓值的接腳為輸入 Serial.begin(9600); } void loop() { val = analogRead(potPin); //val = 0 ~ 1023 Serial.println(val); } ``` </br> 當我們確定光敏電阻及蜂鳴器都能正常運作後,就能將兩個部分結合起來,利用光敏電阻照光的程度控制蜂鳴器的發聲頻率。 ```c= /* 實驗3-6:光敏電阻控制無源蜂鳴器發聲頻率 * * 日期:Sep. 8, 2016 * * 作者:王一哲 */ int buzzerPin = 3; //定義連接蜂鳴器的接腳 int potPin = 0; //定義讀取電壓值的接腳 int val = 0 ; //定義讀取數值暫存用的變數 int frequency; //發聲頻率,31Hz ~ 4978Hz //光敏電阻範圍約2kOhm ~ 980kOhm //串聯10kOhm固定電阻 void setup() { pinMode(buzzerPin, OUTPUT); pinMode(potPin, INPUT); //定義讀取電壓值的接腳為輸入 Serial.begin(9600); } void loop() { val = analogRead(potPin); frequency = map(val, 200, 1000, 31, 4978); tone(buzzerPin, frequency, 200); Serial.print("val = "); Serial.print(val); Serial.print(" frequency = "); Serial.println(frequency); } ``` </br> ## pitches.h及演奏曲子 由於每個音高會對應到特定的頻率,但這些頻率並不好記,因此就有熱心人士將兩者對應的關係寫成 **pitches.h** ,我們可以從Arduino官網上找到(https://www.arduino.cc/en/Tutorial/ToneMelody)。開啟文字編輯器,將該頁面的內容複製、貼上,存成 pitches.h ,再建立一個名為 pitches 的新資料夾,將 pitches.h 移到資料夾內,最後將資料夾移到Arduino開發程式的資料夾內即可。可能的路徑為 1. Windows環境 **C:\\Program Files (x86)\\Arduino\\libraries\\** 2. Linux環境 **home/<user name>/Arduino/libraries 或 home/<user name>/sketchbook/libraries** 接下來在程式碼的開頭只要加上 ```#include "pitches.h"``` 即可引用。之前我為了某次研習寫了一個小程式,當盒蓋打開時讓蜂鳴器或喇叭演奏一小段曲子,當時就是利用了 pitches.h,有興趣的同學可以參考。 ```c= /* 實驗3-4(示範用):用無源蜂鳴器演奏曲子 * * 使用pitches.h * * 日期:Sep. 8, 2016 * * 作者:王一哲 */ #include "pitches.h" #define NOTE_ 0 int buzzerPin = 3; //設定曲子 int tempo = 30; //每分鐘幾拍 float dt = 1000.0*60.0/float(tempo); //換算1拍的時間長度單位為ms //The prelude of Final Fantasy 3 int melody[]={NOTE_AS3, NOTE_C3, NOTE_D3, NOTE_F3, NOTE_AS3, NOTE_C4, NOTE_D4, NOTE_F4, NOTE_AS4, NOTE_C5, NOTE_D5, NOTE_F5, NOTE_AS5, NOTE_C6, NOTE_D6, NOTE_F6, NOTE_AS6, NOTE_F6, NOTE_D6, NOTE_C6, NOTE_AS5, NOTE_F5, NOTE_D5, NOTE_C5, NOTE_AS4, NOTE_F4, NOTE_D4, NOTE_C4, NOTE_AS3, NOTE_F3, NOTE_D3, NOTE_C3, NOTE_F3, NOTE_A3, NOTE_AS3, NOTE_D3, NOTE_F3, NOTE_A3, NOTE_AS3, NOTE_D4, NOTE_G4, NOTE_A4, NOTE_AS4, NOTE_D5, NOTE_G5, NOTE_A5, NOTE_AS5, NOTE_D6}; int noteDurations[] = {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; // 計算陣列長度,sizeof 是回傳陣列所佔的 bytes 而非長度,要算出真正的長度要再除以 sizeof(DataType) int arrayLen = sizeof(melody)/sizeof(int); // 設定函數,讀陣列 melody 及 noteDrations 並輸入到 tone void play(int *melody, int *noteDurations) { for(int i=0; i < arrayLen; i++) { int noteDuration = int(dt/float(noteDurations[i])); Serial.print(melody[i]); Serial.println(noteDurations[i]); tone(buzzerPin, melody[i], noteDuration); int pauseBetweenNotes = int(noteDuration * 1.30); delay(pauseBetweenNotes); noTone(buzzerPin); } } void setup() { pinMode(buzzerPin, OUTPUT); Serial.begin(9600); } void loop() { play(melody, noteDurations); noTone(buzzerPin); delay(2000); } ``` </br> --- ###### tags:`Arduino`