2018年3月13日 星期二

利用光敏電阻控制蜂鳴器

作者:王一哲
日期:2016/9/13



所需元件



  1. 光敏電阻 1 個
  2. 10 kΩ 電阻 1 個
  3. 蜂鳴器或喇叭 1 個
  4. 麵包板1塊
  5. Arduino Uno 開發板 1 塊
  6. 麵包板連接線數條

線路圖

實際的裝置照片(連接蜂鳴器)

實際的裝置照片(連接喇叭)

控制蜂鳴器或喇叭發出指定頻率的聲音



方法1:由頻率算出蜂鳴器發聲、不發聲的持續時間



/* 實驗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));
}

這是最直接但不方便的方法,由於聲音頻率較高,延遲時間極短,必須以μs(百萬分之1秒)為單位,算式如下
float dt = 1./(float(frequency)*2.)*1000000.;

延遲時間則寫為
delayMicroseconds(int(dt));


方法2:使用內建函數tone



/* 實驗3-2:指定無源蜂鳴器發聲頻率           *
 *          使用tone                          *
 * 日期:Sep. 8, 2016                         *
 * 作者:王一哲                               */

int buzzerPin = 3;

void setup() {
    pinMode(buzzerPin, OUTPUT);
    Serial.begin(9600);
}

void loop() {
    tone(buzzerPin, 262); //31Hz ~ 4978Hz
}


Arduino有內建的聲音函數tone,但要將蜂鳴器的正極接腳接在支援PWM的腳位3或11,詳細的說明請參考Arduino的說明文件。寫法如下
tone(pin, 頻率)   或   tone(pin, 頻率, 持續時間)


利用光敏電阻控制蜂鳴器



這裡所使用的光敏電阻是最常見、最便宜的規格,當光敏電阻照到光時電阻值減少,沒照到光時則電阻值增加,範圍約為 2 kΩ ~ 980 kΩ。若將光敏電阻串聯 1 個 10 kΩ 的固定電阻,兩端接上 +5 V 的電壓,就是一個簡單的分壓電路。由於我將 +5 V 先接到光敏電阻再接到固定電阻,當光敏電阻照到光時電阻值減少,固定電阻分到的電壓增加;反之則降低。我們可以先寫一個最簡單的程式來測試一下。
/* 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);
}


當我們確定光敏電阻及蜂鳴器都能正常運作後,就能將兩個部分結合起來,利用光敏電阻照光的程度控制蜂鳴器的發聲頻率。
/* 實驗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);
}


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//Arduino/librarieshome//sketchbook/libraries

接下來在程式碼的開頭只要加上 #include 即可引用。之前我為了某次研習寫了一個小程式,當盒蓋打開時讓蜂鳴器或喇叭演奏一小段曲子,當時就是利用了 pitches.h,有興趣的同學可以參考。
/* 實驗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);
}



HackMD 版本連結:https://hackmd.io/@yizhewang/SJCyNPOVN

沒有留言:

張貼留言