第12课 语音动感世界#

12.1 项目介绍#

在前面的教程中,已经了解过SK6812 RGB灯模块、智能语音模块和无源蜂鸣器的工作原理和应用。

在本项目中,使用智能语音模块来控制SK6812 RGB灯模块和无源蜂鸣器,实现自动化语音控制多彩灯光及蜂鸣器发出鸣叫声与播放美妙音乐。

12.2 流程图#

project15

12.3 实验代码#

// 导入相关库文件
#include <SoftwareSerial.h>
#include <BuzzerESP32.h> 
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h> // 需要 16 MHz Adafruit Trinket
#endif

// 定义引脚常量
const int RX_PIN = 25;   // 引脚 GPIO25 为 RX
const int TX_PIN = 26;   // 引脚 GPIO26 为 TX
const int LED_PIN = 4;  // SK6812 RGB模块引脚
const int LED_COUNT = 4; // 新像素数

BuzzerESP32 buzzer(19); // 初始化GPIO19的蜂鸣器

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

SoftwareSerial mySerial(RX_PIN, TX_PIN); // 定义软件串口引脚(RX, TX)

// 定义变量用于存储从语音模块接收到的控制码
volatile int Voice_Control = 0;  // 初始化为0,确保首次判断时不触发任何指令

void setup() {
  Serial.begin(9600); // 硬件串口(与电脑通信)
  mySerial.begin(9600); // 软件串口(与外设通信)

  #if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
    clock_prescale_set(clock_div_1);
  #endif

  strip.begin();           // 初始化新像素条
  strip.show();            // 关闭所有像素
  strip.setBrightness(100); // 设置亮度(最大255)
}

void loop() { 
  if (mySerial.available()) { // 检查软串口是否有来自语音模块的数据可读
    Voice_Control = mySerial.read(); // 从软串口读取多个字节的数据
    Serial.println(Voice_Control); // 将接收到的数据通过硬件串口输出到串口监视器,便于调试   
  }
  switch(Voice_Control) { // 根据接收到的指令数值,执行相应操作进行判断
    case 11: birthday(); break;  // 接收到的数据为11,播放音乐
    case 12: buzzer.playTone(0, 0); break;  // 接收到的数据为12,关闭蜂鸣器
    case 13: colorWipe(strip.Color(255, 0, 0), 50); break;  // 接收到的数据为13,打开红灯   
    case 14: colorWipe(strip.Color(0, 0, 0), 50); break;   // 接收到的数据为14,关闭红灯
    case 15: colorWipe(strip.Color(0, 255, 0), 50); break; // 接收到的数据为15,打开绿灯
    case 16: colorWipe(strip.Color(0, 0, 0), 50); break;   // 接收到的数据为16,关闭绿灯
    case 17: colorWipe(strip.Color(0, 0, 255), 50); break; // 接收到的数据为17,打开蓝灯
    case 18: colorWipe(strip.Color(0, 0, 0), 50); break;   // 接收到的数据为18,关闭蓝灯
    case 36: theaterChaseRainbow(50); break; // 接收到的数据为36,打开彩灯,彩虹增强型追逐型
    case 37: colorWipe(strip.Color(0, 0, 0), 50); break;   // 接收到的数据为37,关闭彩灯
    case 38: buzzer.playTone(784, 250);  break;   // 接收到的数据为37,打开蜂鸣器
    case 39: buzzer.playTone(0, 0); break;   // 接收到的数据为37,关闭蜂鸣器
  }
  // 清除指令,避免重复执行
  Voice_Control = 0;
}

// 用一种颜色填充灯带
void colorWipe(uint32_t color, int wait) {
  for(int i=0; i<strip.numPixels(); i++) { 
    strip.setPixelColor(i, color); // 设置像素颜色
    strip.show();                  // 更新灯带
    delay(wait);                   // 暂停
  }
}

// 彩虹增强剧院帐篷。在帧之间传递延迟时间(毫秒)。
void theaterChaseRainbow(int wait) {
  int firstPixelHue = 0;     // 第一个像素以红色开始(色调0)
  for(int a=0; a<30; a++) {  // 重复30次...
    for(int b=0; b<3; b++) { //  ‘b’从0到2...
      strip.clear();         //  将RAM中的所有像素设置为0(关闭)
      // “c”从“b”开始计数,以3为增量到条带的末尾…
      for(int c=b; c<strip.numPixels(); c += 3) {
        // 像素‘c’的色调被偏移一定的量,
        // 使色轮沿着条带的长度(strip. numpixels()步骤)完整旋转一次(范围65536):
        int hue = firstPixelHue + c * 65536L / strip.numPixels();
        uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
        strip.setPixelColor(c, color); // 设置像素c的值为color
      }
      strip.show();                // 用新内容更新条带
      delay(wait);                 // 暂停一会儿
      firstPixelHue += 65536 / 90; // 一个周期的色轮超过90帧
    }
  }
}

void birthday() {
  // 演奏生日旋律 - 参数为(频率,持续时间)
  buzzer.playTone(294, 250);  // D4
  buzzer.playTone(440, 250);  // A4
  buzzer.playTone(392, 250);  // G4
  buzzer.playTone(532, 250);  // C5  
  buzzer.playTone(494, 250);  // B4
  buzzer.playTone(392, 250);  // G4
  buzzer.playTone(440, 250);  // A4
  buzzer.playTone(392, 250);  // G4
  buzzer.playTone(587, 250);  // D5
  buzzer.playTone(532, 250);  // C5  
  buzzer.playTone(392, 250);  // G4
  buzzer.playTone(784, 250);  // G5
  buzzer.playTone(659, 250);  // E5
  buzzer.playTone(532, 250);  // C5  
  buzzer.playTone(494, 250);  // B4
  buzzer.playTone(440, 250);  // A4
  buzzer.playTone(698, 250);  // F5
  buzzer.playTone(659, 250);  // E5
  buzzer.playTone(532, 250);  // C5  
  buzzer.playTone(587, 250);  // D5
  buzzer.playTone(532, 500);  // C5   - 长时
  buzzer.playTone(0, 0);      // 关闭蜂鸣器
}

12.4 实验结果#

外接电源,选择好正确的开发板板型(ESP32 Dev Module)和 适当的串口端口(COMxx),然后单击cou0按钮上传代码。代码上传成功后,通过智能语音模块来控制无源蜂鸣器和SK6812 RGB灯。

对着智能语音模块上的麦克风,使用唤醒词 “你好,小智” 或 “小智小智” 来唤醒智能语音模块,同时喇叭播放回复语 “有什么可以帮到您”;

智能语音模块唤醒后,对着麦克风说:“播放音乐” 等命令词时,喇叭播放对应的回复语 “已为您播放音乐”,同时蜂鸣器播放音乐;

对着麦克风说:“关闭音乐” 等命令词时,喇叭播放对应的回复语 “已为您停止音乐”,同时蜂鸣器停止播放音乐;

对着麦克风说:“打开红灯” 等命令词时,喇叭播放对应的回复语 “已为您打开红灯”,同时SK6812 RGB灯亮红色灯;

对着麦克风说:“关闭红灯” 等命令词时,喇叭播放对应的回复语 “已为您关闭红灯”,同时SK6812 RGB灯熄灭;

对着麦克风说:“打开绿灯” 等命令词时,喇叭播放对应的回复语 “已为您打开绿灯”,同时SK6812 RGB灯亮绿色灯;

对着麦克风说:“关闭绿灯” 等命令词时,喇叭播放对应的回复语 “已为您关闭绿灯”,同时SK6812 RGB灯熄灭;

对着麦克风说:“打开蓝灯” 等命令词时,喇叭播放对应的回复语 “已为您打开蓝灯”,同时SK6812 RGB灯亮蓝色灯;

对着麦克风说:“关闭蓝灯” 等命令词时,喇叭播放对应的回复语 “已为您关闭蓝灯”,同时SK6812 RGB灯熄灭;

对着麦克风说:“打开彩灯” 等命令词时,喇叭播放对应的回复语 “已为您打开彩灯”,同时SK6812 RGB灯亮彩色灯;

对着麦克风说:“关闭彩灯” 等命令词时,喇叭播放对应的回复语 “已为您关闭彩灯”,同时SK6812 RGB灯熄灭;

对着麦克风说:“打开蜂鸣器” 或 “蜂鸣器开始鸣叫”等命令词时,喇叭播放对应的回复语 “已打开蜂鸣器”,同时蜂鸣器开始鸣叫;

对着麦克风说:“关闭蜂鸣器” 或 “蜂鸣器停止鸣叫” 等命令词时,喇叭播放对应的回复语 “已关闭蜂鸣器”,同时蜂鸣器停止鸣叫。