Arduino聲控開關-聲波原始碼分析
首先先分析麥克風模組,從最簡單的用法開始.
先將不必要的電路移除,剩下如圖.
麥克風模組接線分別為--->Arduino Nano
1. VCC Vcc
2. 輸出電壓 A0
3. GND GND
撰寫必要的程式
Test-01: 抓出MIC數值
#define MIC A0 // 定義MIC為A0
// Arduino Nano的A0~A7為類比電壓輸入腳
// 而麥克風模組是將類比聲波轉成類比電波
int iADC; // 宣告iADC為全域變數
void setup()
{
Serial.begin(115200); // 設定序列埠的速率為115200
pinMode(MIC, INPUT); // 將Arduino Nano的MIC腳定義為輸入腳
}
void loop()
{
iADC = analogRead(MIC); // 讀取MIC腳位的數值
Serial.print("ADC: "); // 供序列埠監控視窗用
Serial.println(iADC); // 供序列埠監控視窗用
}
|
抓出的數值如下圖
Ardunio Nano的類比轉數位是10bit的,所以數值範圍是0~1023,代表0~5V.
以上圖來說大約落在890~740之間換算電壓就是4.3V~3.6V之間.
嗯,雖然抓出數值了,但.....對這堆數字實在無感!所以決定將它圖形化.
在Arduino IDE中就有數據圖形化的功能了,但....我覺得不太好用!
所以決定改寫一下Arduino GPS時速表 的程式碼.
而Test-01也須加程式碼來輸出數值,可以參考Test-02的部分
讓它變成一個簡單的示波器.
根據這個影片,可以看到聲音會讓MIC輸出如影片中的震幅.
但此麥克風模組有點壓準位不穩的問題.
所以在改寫一下程式來取出平均值.
Test-02: 分析出MIC數值的平均值
#include "SoftwareSerial.h" // 載入軟體序列傳輸函示庫
// 因為Nano本身只有一個Serial傳輸埠
// 所以用SoftwareSerial.h函式庫,來增加傳輸埠
// 傳給示波器用
#define MIC A0 // 定義MIC為A0
// Arduino Nano的A0~A7為類比電壓輸入腳
// 而麥克風模組是將類比聲波轉成類比電波
int iADC; // 宣告iADC為全域變數
float fAvg;
int iAvgBuf30[30];
SoftwareSerial Serial2(3, 4); // 宣告軟體序列傳輸Serial2,使用3,4pin, 聲波
SoftwareSerial Serial3(5, 6); // 宣告軟體序列傳輸Serial3,使用5,6pin, 聲波平均值
void setup()
{
Serial.begin(115200); // 設定序列埠的速率為115200
Serial2.begin(115200); // 設定序列埠的速率為115200
Serial3.begin(115200); // 設定序列埠的速率為115200
pinMode(MIC, INPUT); // 將Arduino Nano的MIC腳定義為輸入腳
for(int i=0;i<30;i++) // 先取出30筆資料,供之後MIC平均用
{
iAvgBuf30[i] = analogRead(MIC); // 讀取MIC腳位的數值
}
}
void loop()
{
// 序列式取值(參考下列詳細說明)
for(int i=0;i<29;i++)
{
iAvgBuf30[i] = iAvgBuf30[i+1];
}
iADC = analogRead(MIC); // 讀取MIC腳位的數值
iAvgBuf30[30-1] = iADC; // 存第30筆資料
// 算出平均值
fAvg = 0;
for (int i = 0; i < 30; i++)
{
fAvg = fAvg + iAvgBuf30[i];
}
fAvg = fAvg / 30.0f; // 30筆資料取平均值
Serial.print("ADC: "); // 供序列埠監控視窗用
Serial.print(iADC); // 供序列埠監控視窗用
Serial.print(" AVG: "); // 供序列埠監控視窗用
Serial.println(fAvg); // 供序列埠監控視窗用
Serial2.println(iADC); // 供Oscilloscop用
Serial3.println(fAvg); // 供Oscilloscop用
}
|
輸出的視頻如下
由影片中可以看出,平均值會落在波型的中央.
就算電壓準位改變,平均值仍是處於波型的中央.
以這平均值為基礎,若聲音越大,則震幅越大.我們可利用這現象來判斷拍手的聲響.
但因為震幅會上下震動不太好判斷,所以我想將負半波反向.
Test-03: 平均值以下數值反向
#include "SoftwareSerial.h" // 載入軟體序列傳輸函示庫
#define MIC A0 // 定義MIC為A0
// Arduino Nano的A0~A7為類比電壓輸入腳
// 而麥克風模組是將類比聲波轉成類比電波
int iADC, iADC2; // 宣告iADC,iADC2為全域變數
float fAvg;
int iAvgBuf30[30];
SoftwareSerial Serial2(3, 4); // 宣告軟體序列傳輸Serial2,使用3,4pin, 聲波
SoftwareSerial Serial3(5, 6); // 宣告軟體序列傳輸Serial3,使用5,6pin, 聲波平均值
SoftwareSerial Serial4(7, 8); // 宣告軟體序列傳輸Serial3,使用5,6pin, 聲波負半周反向
void setup()
{
Serial.begin(115200); // 設定序列埠的速率為115200
Serial2.begin(115200); // 設定序列埠的速率為115200
Serial3.begin(115200); // 設定序列埠的速率為115200
Serial4.begin(115200); // 設定序列埠的速率為115200
pinMode(MIC, INPUT); // 將Arduino Nano的MIC腳定義為輸入腳
for(int i=0;i<30;i++) // 先取出30筆資料,供之後MIC平均用
{
iAvgBuf30[i] = analogRead(MIC); // 讀取MIC腳位的數值
}
}
void loop()
{
// 序列式取值
for(int i=0;i<29;i++)
{
iAvgBuf30[i] = iAvgBuf30[i+1];
}
iADC = analogRead(MIC); // 讀取MIC腳位的數值
iAvgBuf30[30-1] = iADC; // 存30筆資料
// 算出平均值
fAvg = 0;
for (int i = 0; i < 30; i++)
{
fAvg = fAvg + iAvgBuf30[i];
}
fAvg = fAvg / 30.0f; // 30筆資料取平均值
// 將平均值的負端翻正
int iADC2 = abs(iADC-fAvg);
iADC2 = iADC2+fAvg;
Serial.print("ADC: "); // 供序列埠監控視窗用
Serial.print(iADC); // 供序列埠監控視窗用
Serial.print(" AVG: "); // 供序列埠監控視窗用
Serial.print(fAvg); // 供序列埠監控視窗用
Serial.print(" ADC2: "); // 供序列埠監控視窗用
Serial.println(iADC2); // 供序列埠監控視窗用
Serial2.println(iADC); // 供Oscilloscop用
Serial4.println(iADC2); // 供Oscilloscop用
}
|
輸出的影片如下
由影片中可以看出,綠色的聲波,轉成藍色的聲波.這樣一來,僅需比對平均值以上的峰值,
就可以判斷拍手的聲響.
好,接下來將平均值+10,當作拍手聲響的水平標準.
安靜時候的波形如下.
再拍手2下得到以下波形.
這樣乍看之下沒甚麼問題.
但若遇到環境因較吵雜的場所,就可能會有誤動作.
下圖是播放音樂的連續聲響.
這樣就很難判斷是其他聲響,或拍手.
不過,我已經累了.
下次再來聊聊 Arduino 聲控開關 的另一部分,簡易的適應性控制.用來對付吵雜的環境音.
謝謝閱讀....ZZZzzz.
Arduino聲控開關-聲波原始碼分析由Peng Yi Hsing製作,以創用CC 姓名標示-非商業性-禁止改作 3.0 台灣 授權條款釋出。
留言列表