
目錄
1. 超聲波模塊的測距原理
2. 超聲波模塊如何與Arduino開發板連接
3. 先從測距開始
4. 如何將超聲波改造成聲控開關
5. 再加一個超聲波開關
在本文最后有完整的視頻講解
玩Arduino、樹莓派的同學應該很熟悉超聲波模塊,這個東西不貴(通常在5到10元之間),作用有限,在網上搜索,99%的應用場景都是測量距離,剩下的場景就是一些沒什么用的小玩應,例如,將兩個超聲波模塊相對,利用超聲波玩懸浮,其實沒啥大用,本文就給大家提供一個新的思路,只用10幾行代碼,就可以將超聲波模塊改成一個聲控開關,用來控制LED以及任何復雜的電子設備,我還利用了這個功能制作了一個基于鴻蒙的“救命SOS”游戲,后面我會寫文章來介紹,現在還是先回到本文的主題上來,
先來體驗一下基于超聲波模塊的聲控開關:
【Arduino實驗室】超聲波只能測距?隔空操控LED聽說過嗎?見證奇跡的時刻!
1. 超聲波模塊的測距原理
可能有的讀者不太熟悉超聲波模塊,為了不讓大家看的一頭霧水,先來看一下超聲波模塊的樣子,看起來很萌,有兩個像眼睛一樣的東西,還有4個針式的管腳,

當然,這個模塊發出的超聲波很弱,肯定不會像對付浩克那樣強的超聲波,否則我也不會有命在這里寫文章了!

超聲波模塊測距的原理其實很簡單,與測量地球到月亮的距離類似,只是前者使用的是超聲波,后者使用的是激光,超聲波模塊利用了聲波在空氣中傳播速度是340米/秒這一特性(這是一個固定值,就像光的傳播速度約等于30萬千米/秒一樣),然后測量出從發出超聲波到接收到回傳超聲波的時間(就是往返的時間),然后再除以2,就是超聲波從A點到B點所需的時間,如果這個值是1000毫秒,那么A到B的距離就是340米,如果是100毫秒,就是34米,以此類推,當然,超聲波與激光不同,距離不能太遠,一般最多也就測量個幾十米,再遠可能就不準了,
超聲波模塊的兩個像眼睛一樣的東西,一個負責發射超聲波,另外一個負責接識訓傳的超聲波,一旦開始發射超聲波,就自動啟動計時器,接收到回傳的超聲波就會停止計時,然后通過相應的管腳讀取計時器中的時間,經過計算,就可以得到特定單位(米、厘米、毫米)的距離了,下圖是超聲波發射和接收的時序圖,最下面的輸出回響信號的時序圖凸起的部位,左邊設定為高電平,這時等待超聲波回傳,當接收到回傳的超聲波后,右邊就變成低電平,回傳計時器的時間,其實我們需要的時間就是凸起的部位處于高電平的時間(也就是說,超聲波模塊的某個管腳處于高電平的時間),

2. 超聲波模塊如何與Arduino開發板連接
一圖頂千言,還是看圖說話吧!

這是超聲波模塊與Arduino開發板的連接圖,同時還有一個LED與Arduino開發板相連,其實這里的LED與超聲波模塊沒有任何關系,只是通過由超聲波模塊改裝的聲控開關來控制LED,
超聲波模塊有如下4個管腳:
(1)VCC:接Arduino開發板的5v管腳
(2)Trig:發射超聲波的管腳,需要接在數字管腳上,本例接在10號管腳,當10號管腳處于高電平時發射超聲波
(3)Echo:接收超聲波的關鍵,需要接在數字管腳上,本例接在9號管腳,當9號管腳處于高電平時,會等待超聲波回傳,如果接收到超聲波,9號管腳就會自動變成低電平,這時會回傳計時器中的時間(超聲波的往返時間)
(4)GND:接Arduino開發板的GND管腳(接地)
LED很簡單,正極接到7號數字管腳,負極接地(GND)
本例將5V接到了面包板上,所以可以將VCC直接接到面包板上,
如果大家不了解面包板的用法,可以看這個視頻:
【Arduino實驗室】無需撰寫一行代碼,用按鍵控制LED,Arduino初學者入門首選
3. 先從測距開始
還是先上代碼吧!
void loop() {
digitalWrite(trigPin, LOW);
delayMicroseconds(5);
// 發射超聲波
digitalWrite(trigPin, HIGH);
delayMicroseconds(5);
// 這個distance就是距離,超聲波回傳時,pulseIn函式會回傳計時器的時間,單位:微秒
int distance = pulseIn(echoPin, HIGH) * 340 / 2 / 1000
delay(40);
}
這段測距代碼一共就6行,其實就是先設定trip管腳低電平,然后再設定高電平,讓超聲波模塊發射超聲波,然后通過pulseIn函式將echo管腳設定高電平,等待超聲波的回傳,如果回傳,pulseIn函式會回傳時間(單位:微秒),本例計算得到的distance的單位是毫米,
看看,是不是很簡單呢?
4. 如何將超聲波改造成聲控開關
測距很容易理解,那么如果將超聲波模塊變成聲控開關呢?其實也并不復雜,這里用了一個技巧和一個狀態機的演算法,一共也就十幾行代碼,
測量距離肯定有遠近,如300毫米和600毫米肯定是有差距的,肉眼也是可見的,也可以感知到,而這里的聲控開關,其實并不是你要大喊一聲:芝麻開門,超聲波你也發不出,也聽不見,這里的聲控是指讓超聲波感知你的存在,

從前面的視頻可以看出,將手在超聲波模塊前滑動,如果手正好在超聲波模塊的前面,那么測量的距離肯定要小于手不在超聲波模塊前的距離,其實這就是一個二值邏輯,利用測量距離的變化,可以判斷手是否在超聲波模塊的前面,因此,這里需要設定一個閾值,如果測量的距離小于這個閾值,說明手在超聲波模塊的前面,如果大于這個閾值,說明手沒在超聲波模塊的前面,
不過這里還有一個問題,由于loop函式是不斷回圈的,所以如果你的手一直在超聲波模塊的前面,那么就會一直觸發“開”這個動作,因此需要使用狀態機來屏蔽這種情況,也就是說,只有上一個狀態是“關”時,才會檢測當前狀態是否為“開”,完整的實作代碼如下:
// 單超聲波實作
#include <SoftwareSerial.h>
#define LED 7
int trigPin = 10; // 發射管腳
int echoPin = 9; // 接收管腳
int distance = 0;
int state = 0; // 用于控制狀態機的狀態
bool led_state = false; // false:滅 true:亮
void setup() {
pinMode(LED, OUTPUT);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
digitalWrite(LED, LOW);
Serial.begin(9600);
while (!Serial) {
}
Serial.println("hello world!");
}
void loop() {
digitalWrite(trigPin, LOW);
delayMicroseconds(5);
digitalWrite(trigPin, HIGH);
delayMicroseconds(5);
distance = pulseIn(echoPin, HIGH) * 340 / 2 / 1000;
// 狀態:關
if (state == 0) {
// 判斷距離是否小于300毫米
if (distance < 300) {
state = 1; // 如果小于300毫米,說明手正好在超聲波模塊起那么,將狀態設定為開
}
} else if (state == 1) { // 狀態:開
// 如果距離大于等于300毫米,說明手不在超聲波模塊前面,狀態設定為關
if (distance >= 300 ) {
state = 0;
// 當手不在超聲波模塊前面時,根據LED當前的狀態,決定是關閉LEd,還是點亮LED
if(led_state) {
led_state = false;
digitalWrite(LED, LOW);
} else {
led_state = true;
digitalWrite(LED, HIGH);
}
}
}
delay(40);
}
5. 再加一個超聲波開關
如果嫌不過癮,可以再加一個超聲波開關,連接方式同上,控制兩個超聲波開關的代碼如下:
#include <SoftwareSerial.h>
#define LED1 8
#define LED2 7
int trigPin1 = 10; // 發射管腳
int echoPin1 = 9; // 接收管腳
int trigPin2 = 13; // 發射管腳
int echoPin2 = 12; // 接收管腳
int distance = 0;
int state1 = 0;
int state2 = 0;
bool led_state1 = false; // false:滅 true:亮
bool led_state2 = false; // false:滅 true:亮
void setup() {
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(trigPin1, OUTPUT);
pinMode(echoPin1, INPUT);
pinMode(trigPin2, OUTPUT);
pinMode(echoPin2, INPUT);
digitalWrite(LED1, LOW);
digitalWrite(LED2, LOW);
Serial.begin(9600);
while (!Serial) {
}
Serial.println("hello world!");
}
void loop() {
// 處理第1個超聲波開關
digitalWrite(trigPin1, LOW); // 高電平發射超聲波, 但要先設定為低電平, 就像打開燈,需要先關閉燈,才能打開
delayMicroseconds(5);
digitalWrite(trigPin1, HIGH);
delayMicroseconds(5);
distance = pulseIn(echoPin1, HIGH) * 340 / 2 / 1000;
if (state1 == 0) {
if (distance < 300) {
state1 = 1;
}
} else if (state1 == 1) {
if (distance > 300 ) {
state1 = 0;
if(led_state1) {
led_state1 = false;
digitalWrite(LED1, LOW);
} else {
led_state1 = true;
digitalWrite(LED1, HIGH);
}
}
}
// 處理第2個超聲波開關
digitalWrite(trigPin2, LOW); // 高電平發射超聲波, 但要先設定為低電平, 就像打開燈,需要先關閉燈,才能打開
delayMicroseconds(5);
digitalWrite(trigPin2, HIGH);
delayMicroseconds(5);
distance = pulseIn(echoPin2, HIGH) * 340 / 2 / 1000;
if (state2 == 0) {
if (distance < 300) {
state2 = 1;
}
} else if (state2 == 1) {
if (distance > 300 ) {
state2 = 0;
if(led_state2) {
led_state2 = false;
digitalWrite(LED2, LOW);
} else {
led_state2 = true;
digitalWrite(LED2, HIGH);
}
}
}
delay(40);
}
這段代碼通過一個數字管腳控制多個LED,兩個數字管腳控制兩組LED,所以首先需要將面包板與數字管腳連接,然后這些LED連接到面包板上,如下圖所示,ok,現在可以盡情滴玩耍了,
下面是本文的視頻講解:
【硬核】老程式員教你一招,讓超聲波模塊秒變聲控開關!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/271461.html
標籤:其他
