KY-270 声音传感器踩坑记录

使用 ESP32 开发板,Arduino 框架

今天折腾了一下 KY-270 声音传感器,遇到了两个坑,记录一下,免得以后又忘了~

电位器阈值太高,怎么拍手都没反应

一开始代码还没写,就想先试试传感器能不能用。我写了个简单的检测数字信号变低电平的代码,结果发现不管怎么拍手都不会触发。而且传感器上的 LED2(显示 DO 口状态的那个灯)一直是常亮的,说明 DO 口根本就没有变化过。

这时候我才觉得不对,查了资料发现可能是出厂的时候阈值被调得太高了。

解决方法:逆时针慢慢转,边转边测试。我大概转了十几二十圈才终于看到变化,调到一个合适的灵敏度,拍手能触发,但平时环境噪音不会误触发。

调的时候可以用串口打印看看状态变化,这样比较好判断。

直接检测低电平不行,得用边沿触发

传感器调好之后,就开始写代码了。一开始我觉得挺简单的,声音传感器嘛,有声音就输出低电平,没声音就是高电平,直接检测低电平就好了呀。

if (digitalRead(ky_do) == LOW) {
    // 有声音,做点什么
}

结果发现完全不行。因为只要检测到一次声音,低电平就会持续一段时间,用这种方式检测的话,一次拍手就会触发好多次,LED 就一直闪个不停,根本没法控制。

后来想明白了,要用边沿触发,也就是检测从高电平到低电平的那个跳变瞬间。这样每次声音出现的时候只会触发一次,不管声音持续多久。

int lastSoundState = HIGH;

void loop() {
    int soundState = digitalRead(ky_do);
    
    // 检测下降沿:上次是高电平,这次变低电平了
    if (lastSoundState == HIGH && soundState == LOW) {
        // 这里就是检测到声音的那一瞬间
        // 做你想做的事
    }
    
    lastSoundState = soundState; // 记住这次的状态,下次循环用
    delay(10);
}

改完之后就好了,每次拍手或者敲桌子只会触发一次,不会一直连击了。

另外说一下,后面用到 SW-420 震动传感器的时候也是同理,都是检测下降沿,方法是一样的。

KY-270 引脚说明

引脚说明
VCC接 3.3V 或 5V
GND接地
AO模拟输出,输出电压随声音大小变化
DO数字输出,超过阈值输出 LOW,否则 HIGH

代码里一般用 DO 引脚就够了,接一个数字输入口就行。

注意事项

  1. 电位器很敏感,调的时候慢慢来,别转太快,转完记得测试一下
  2. AO 和 DO 的区别:AO 是模拟量,可以读到声音的强度;DO 是数字量,只有超过阈值才触发。一般用 DO 就够了
  3. 供电电压:这个模块 3.3V 和 5V 都能用,看你的板子
  4. 环境噪音:如果环境太吵,可能需要把阈值调高一点,不然会一直误触发
  5. 响应时间:传感器本身响应挺快的,但代码里最好加个小延迟防抖,10ms 左右就行

完整代码

#include <Arduino.h>

#define ky_ao       34  // ADC1_CH6 - 模拟输出
#define ky_do       35  // 数字输出
#define led_pin     5

uint8_t led_status;             // LED 状态
int lastSoundState = HIGH;      // 记录上一次的声音状态,初始假设为安静(HIGH)

void setup() {
    Serial.begin(115200);
    pinMode(ky_do, INPUT);
    pinMode(led_pin, OUTPUT);
    digitalWrite(led_pin, led_status); // 初始LED熄灭
    Serial.println("Edge Trigger Test");
}

void loop() {
    int soundState = digitalRead(ky_do);  // 读取当前状态: 0=有声音, 1=安静

    // 检测下降沿:上次是高电平(安静),本次是低电平(有声音)
    if (lastSoundState == HIGH && soundState == LOW) {
        led_status = !led_status;             // 翻转 LED 状态
        digitalWrite(led_pin, led_status);
        Serial.println("Sound Detected! LED Toggled.");
        delay(200); // 一个简单的防抖,忽略紧接着的抖动信号
    }

    lastSoundState = soundState; // 更新状态记录,为下次循环做准备
    delay(10); // 小延迟,让 CPU 休息一下
}

就这些啦,希望能帮到也遇到同样问题的人~