Arduino聲控開關-聲波原始碼分析

首先先分析麥克風模組,從最簡單的用法開始.

先將不必要的電路移除,剩下如圖.

麥克風測試電路.jpg

 

 

麥克風模組接線分別為--->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);              // 供序列埠監控視窗用
}

抓出的數值如下圖

聲波局部資料C1.jpg

Ardunio Nano的類比轉數位是10bit的,所以數值範圍是0~1023,代表0~5V.

以上圖來說大約落在890~740之間換算電壓就是4.3V~3.6V之間.

嗯,雖然抓出數值了,但.....對這堆數字實在無感!所以決定將它圖形化.

在Arduino IDE中就有數據圖形化的功能了,但....我覺得不太好用!

所以決定改寫一下Arduino GPS時速表 的程式碼.

而Test-01也須加程式碼來輸出數值,可以參考Test-02的部分

讓它變成一個簡單的示波器.

示波器-聲波局部資料.jpg

根據這個影片,可以看到聲音會讓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用  
}
 

輸出的視頻如下

由影片中可以看出,平均值會落在波型的中央.

就算電壓準位改變,平均值仍是處於波型的中央.

以這平均值為基礎,若聲音越大,則震幅越大.我們可利用這現象來判斷拍手的聲響.

但因為震幅會上下震動不太好判斷,所以我想將負半波反向.

示波器-聲波反向區域.jpg

 

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用  
}
 

輸出的影片如下

由影片中可以看出,綠色的聲波,轉成藍色的聲波.這樣一來,僅需比對平均值以上的峰值,

就可以判斷拍手的聲響.

示波器-聲波已反向區域.jpg

好,接下來將平均值+10,當作拍手聲響的水平標準.

安靜時候的波形如下.

Arduino聲控開關-聲波原始碼分析

 

再拍手2下得到以下波形.

Arduino聲控開關-聲波原始碼分析

這樣乍看之下沒甚麼問題.

但若遇到環境因較吵雜的場所,就可能會有誤動作.

下圖是播放音樂的連續聲響.

Arduino聲控開關-聲波原始碼分析

這樣就很難判斷是其他聲響,或拍手.

不過,我已經累了.

下次再來聊聊 Arduino 聲控開關 的另一部分,簡易的適應性控制.用來對付吵雜的環境音.

謝謝閱讀....ZZZzzz.

 

創用 CC 授權條款
Arduino聲控開關-聲波原始碼分析Peng Yi Hsing製作,以創用CC 姓名標示-非商業性-禁止改作 3.0 台灣 授權條款釋出。

arrow
arrow

    30sec 發表在 痞客邦 留言(0) 人氣()