【物联网】老程序教你一招,10行代码让超声波模块秒变声控开关

   日期:2021-04-01     浏览:118    评论:0    
核心提示:超声波只能用来测距吗?你out了,看哥教你如何只用10行代码将超声波模块改装成声控开关,perfect!

 

目录

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,现在可以尽情滴玩耍了。

 

下面是本文的视频讲解:

【硬核】老程序员教你一招,让超声波模块秒变声控开关!

 

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
更多>相关资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服