### 第14课 语音照明系统

#### 14.1 项目介绍

本教程将先为您详细介绍智能语音模块的工作原理、引脚功能、电路连接方法以及如何通过微控制器（如ESP32）来控制。然后使用智能语音模块来控制LED，实现自动化语音控制LED亮灭及亮度改变。

#### 14.2 模块相关资料

![](media/SU-03T.png)

**智能语音模块：** 语音识别采用了离线语音识别芯片MUS516P6，该芯片采用 32bit RSIC 架构内核，并加入了专门针对信号处理和语音识别所需要的 DSP指令集，支持浮点运算的 FPU 运算单元，以及 FFT 加速器。智能语音模块通过串口通信的方式实现与主机的交互，最多支持150条语音指令，可在用户平台上自主定制语音指令和固件，命令词可任意修改，开发简单，不需要写代码。自带固件下载芯片，只需数据线即可完成固件下载。支持语音调节音量、学习唤醒词，识别灵敏且准确率高。


**技术参数：**

- 工作电压：3.3V~5.5V
- 负载：LDO输出3.3V，外部负载不能超过150MA
- 供电及待机：500MA/60MA
- 硬件: 10个IO口 / 1路uart(串口) / 5个ADC / 2个PWM / 1路I2S / 1路SPI / 1路I2C
- 音频输出：1路MONO功放输出接口
- 语音指令：70条（最大支持150条）
- FLASH: 2M
- 喇叭功率：8欧1W
- 支持语言：默认固件支持中文（也可自行生成英文）
- 工作温度：0~80℃
- 尺寸：47.73mm*23.93mm
- 重量：8.96g

#### 14.3 固件导入

⚠️ **特别提醒：** 智能语音模块在出厂时，已经导入好了默认语音固件，不需要再重复导入。如果你发现语音固件流失了或者想导入你自己的语音固件，请参照链接：[语音固件制作说明](https://www.keyesrobot.cn/projects/KE4084/zh-cn/latest/) 中的说明。

⚠️ **特别提醒：** 我们提供的语音固件，包括默认的语音命令词和语音播报，想了解请参照链接：[默认语音固件](https://www.keyesrobot.cn/projects/KE4084/zh-cn/latest/)，可以看到一些默认语音命令词和语音播报等内容，请认真查看。

#### 14.4 实验组件

|![](media/esp32.png)|![](media/yellow-led2.png)|![](media/SU-03T-1.png)|
|-|-|-|
|ESP32 Plus主板 *1|黄色LED模块 *1|智能语音模块 *1|
|![](media/3p.png)|![](media/4p.png) |![](media/usb.png)|
|3P线 *1|4P线 *1|USB线 *1|

#### 14.5 接线图

智能语音模块和黄色LED模块的控制引脚：

|黄色LED（S引脚）|io12|
|-|-|
|智能语音模块（TXD引脚）|io16|
|智能语音模块（RXD引脚）|io27|

⚠️ **特别注意：智能家居已经组装好了，这里不需要把智能语音模块和黄色LED模块拆下来又重新组装和接线，这里再次提供接线图，是为了方便您编写代码！**

![](media/pjt16.png)

#### 14.6 语音命令的实验代码1

⚠️ **特别注意：** 上传代码前要添加库文件，库文件存放在`Arduino_库文件`文件夹中名为`EspSoftwareSerial.zip`。

唤醒智能语音模模块，读取语音命令词和播报语


```c++
/*
 * 项目 : voice-command
 * 描述 : 通过语音控制模块读取对应命令
 * 编译IDE：ARDUINO IDE
 * 作者 : http//www.keyes-robot.com
*/

//导入相关库文件
#include <SoftwareSerial.h>

// 定义引脚常量
const int RX_PIN = 27; // 引脚 GPIO27 为 RX
const int TX_PIN = 16; // 引脚 GPIO16 为 TX

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

void setup() {
  Serial.begin(9600); // 硬件串口（与电脑通信）
  mySerial.begin(9600); // 软件串口（与外设通信）
  Serial.println("System initialized");
}

void loop() {
  if (mySerial.available()) { // 接收语音控制模块的外设数据(命令参数)
    int yuyin = mySerial.read(); // 将接收到的外设数据(命令参数)进行赋值      
    mySerial.println(yuyin); // 软串口打印收到的外设数据(命令参数)
    Serial.println(yuyin); // 硬串口打印收到的外设数据(命令参数)
  }
}
```

#### 14.7 实验结果1

按照接线图接好线，外接电源，选择好正确的开发板板型（ESP32 Dev Module）和 适当的串口端口（COMxx），然后单击按钮![](media/cou0.png)上传代码，上传代码成功后，设置串口波特率为9600。

![](media/WASZ2.jpg)

对着智能语音模块上的麦克风，使用唤醒词 “你好，小智” 或 “小智小智” 来唤醒智能语音模块，同时喇叭播放回复语 “有什么可以帮到您”；接下来即可通过串口打印窗口查看智能语音模块接收到语音命令词所对应的命令参数 等。

智能语音模块唤醒后，对着麦克风说：“打开台灯” 或 “请开灯” 或 “开灯” 或 “打开灯” 或 “我回来了”等命令词时，串口打印命令参数 “1”，同时喇叭播放对应的回复语 “已为您打开照明”；

对着麦克风说：“关闭台灯” 或 “请关灯” 或 “关灯” 或 “睡觉了” 或 “关上灯” 或 “我出去了”等命令词时，串口打印命令参数 “2”，同时喇叭播放对应的回复语 “已为您关闭照明”。

对着麦克风说：“调亮一点” 或 “亮一点”等命令词时，串口打印命令参数 “3”，同时喇叭播放对应的回复语 “灯光已调亮”；

对着智能语音模块上的麦克风说 “调暗一点” 或 “暗一点”等命令词时，串口打印命令参数 “4”，同时喇叭播放对应的回复语 “灯光已调暗”；

其他的这里就不一一分别陈述，请查看下面所列的语音命令词语音播报指令，所对应的命令参数和信息号：

默认的语音命令词和语音播报等等，请参照链接： [默认语音固件](https://www.keyesrobot.cn/projects/KE4084/zh-cn/latest/)

![](media/voice-value.png)

#### 14.8 代码流程图

![](media/project14.png)

#### 14.9 语音照明系统的实验代码2

```c++
/*
 * 项目: voice-control-led
 * 描述: 智能语音模块控制LED来模拟智能照明系统
 * 编译IDE：ARDUINO IDE
 * 作者: http//www.keyes-robot.com
*/

//导入相关库文件
#include <SoftwareSerial.h>

// 定义引脚常量
const int RX_PIN = 27; // 引脚 GPIO27 为 RX
const int TX_PIN = 16; // 引脚 GPIO16 为 TX
const int LED_PIN = 12; // 定义LED的GPIO引脚

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

// LED亮度等级
const int LED_OFF = 0;
const int LED_DIM = 50;
const int LED_MEDIUM = 150;
const int LED_BRIGHT = 255;

void setup() {
  Serial.begin(9600); // 硬件串口（与电脑通信）
  mySerial.begin(9600); // 软件串口（与外设通信）
  pinMode(LED_PIN, OUTPUT); // 设置LED引脚为输出模式
}

void loop() { 
  if (mySerial.available()) { // 接收语音控制模块的外设数据
    int yuyin = mySerial.read(); // 将接收到的外设数据进行赋值   
    switch(yuyin) { //进行判断
      case 1: analogWrite(LED_PIN, LED_MEDIUM); break; // 接收到的数据为1,打开灯,灯的亮度为150
      case 2: analogWrite(LED_PIN, LED_OFF); break; // 接收到的数据为2,关闭灯
      case 3: analogWrite(LED_PIN, LED_BRIGHT); break; // 接收到的数据为3,灯的亮度为最亮
      case 4: analogWrite(LED_PIN, LED_DIM); break; // 接收到的数据为4,灯的亮度为暗
      default: break;
    }
    mySerial.println(yuyin);
    Serial.println(yuyin);
  }
}
```

#### 14.10 实验结果2

按照接线图接好线，外接电源，选择好正确的开发板板型（ESP32 Dev Module）和 适当的串口端口（COMxx），然后单击按钮![](media/cou0.png)上传代码。上传代码成功后，通过智能语音模块来控制LED。

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

智能语音模块唤醒后，对着麦克风说：“打开台灯” 或 “请开灯” 或 “开灯” 或 “打开灯” 或 “我回来了” 等命令词时，喇叭播放对应的回复语 “已为您打开照明”，同时LED点亮；

对着麦克风说：“调亮一点” 或 “亮一点” 等命令词时，喇叭播放对应的回复语 “灯光已调亮”，同时LED变亮；

对着麦克风说：“调暗一点” 或 “暗一点” 等命令词时，喇叭播放对应的回复语 “灯光已调暗”，同时LED变暗；

对着麦克风说：“关闭台灯” 或 “请关灯” 或 “关灯” 或 “睡觉了” 或 “关上灯” 或 “我出去了”等命令词时，喇叭播放对应的回复语 “已为您关闭照明”，同时LED熄灭。

![Img](../../media/image-14.gif)

#### 14.11 代码说明

（1）. 通过调用软串口库`SoftwareSerial.h`，您可以轻松使用软串口来驱动智能语音模块。SoftwareSerial 是Arduino平台提供的软件模拟串口通信库，通过编程将数字引脚模拟为串口通信引脚，用于扩展硬件串口不足时的多设备通信需求，但存在同时只能监听一个端口的限制‌。
 
```c++                  
#include <SoftwareSerial.h>
```

- ‌核心功能与限制‌

    - ‌基本用途‌：SoftwareSerial库允许在Arduino开发板上将任意数字引脚模拟为软串口的RX（接收）和TX（发送）引脚，解决硬件串口数量不足的问题。
    
    - ‌关键限制‌：
        同一时间只能有一个SoftwareSerial实例处于监听状态，需通过listen()函数切换。‌‌
        不支持同时收发数据，且不同开发板（如UNO、Mega、ESP32等）的兼容引脚不同。‌‌
        波特率建议不超过57600bps以保证稳定性。‌‌

- ‌使用方法‌

    - ‌初始化‌：需包含头文件#include <SoftwareSerial.h>，并通过构造函数指定RX/TX引脚（如SoftwareSerial mySerial(27, 16)。‌‌
    
    - ‌常用函数‌：
        - begin()设置波特率，read()/write()进行数据读写，print()/println()格式化输出。‌‌
        - isListening()检查监听状态，overflow()检测缓冲区溢出。‌

- ‌多设备通信解决方案‌

    - 通过动态调用listen()切换监听端口，可实现多个软串口的分时复用（需注意数据丢失风险）。例如：‌‌

```c++
portOne.listen(); // 监听第一个端口
delay(10); // 短暂接收数据
portTwo.listen(); // 切换至第二个端口
```

更多详细解释请参考官方链接：[SoftwareSerial Library | Arduino Documentation](https://docs.arduino.cc/learn/built-in-libraries/software-serial/?queryID=f43d3e5f9455c28430e512244d0319f0)

（2）. 定义智能语音模块的软串口引脚。

```c++
const int RX_PIN = 27; // 引脚 GPIO27为 RX
const int TX_PIN = 16; // 引脚 GPIO16为 TX

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

（3）. 定义硬件串口（与电脑通信）和 软件串口（与外设通信，比如：智能语音模块）。

```c++
Serial.begin(9600); // 硬件串口（与电脑通信）
mySerial.begin(9600); // 软件串口（与外设通信）
```

（4）. 接收智能语音模块的外设数据，并且将将接收到的外设数据进行赋值，然后通过软硬串口打印出对应的数据命令。

```c++
void loop() {
  if (mySerial.available()) { // 接收智能语音模块的外设数据
    int command = mySerial.read(); // 将接收到的外设数据进行赋值      
    mySerial.println(command);
    Serial.println(command);
  }
}
```


