### 4.4.6 语音控制风扇系统

#### 4.4.6.1 简介

夏天来了，风扇成了家里或农场里的“小救星”。但每次手动调节风速，是不是觉得有点麻烦？想象一下，只需动动嘴，风扇就乖乖听话，那该多方便！语音控制风扇，真的是懒人福音！无需动手，只需口头指令，就能轻松实现开关、调节风速等功能。

想象一下，回家一进门，喊一声类似于“打开风扇”等命令词，立刻就能感受到凉风拂面；感觉风速小，喊一声类似于“风大一点”等命令词，又能感受到凉风变大；感觉风速大了需要风速小点，喊一声类似于“风小一点”等命令词，立马能感受到凉风变小；需要外出出门时，喊一声类似于“关闭风扇”等命令词，风扇立刻就能停止。

这种便捷性，对于行动不便者或大农场主来说，更是大大提升了生活质量。

![Img](../media/cout5.jpg)

语音控制风扇系统是通过组合智能语音模块和电机模块，实现对农场里的温度进行语音智能调节。

#### 4.4.6.2 接线图

- **电机模块的IN-引脚连接到io18，IN+引脚连接到io19**

- **智能语音模块的TXD引脚连接到io5，RXD引脚连接到io23**

⚠️ **特别注意：智慧农场已经组装好了，这里不需要把超声波传感器、舵机和智能语音模块拆下来又重新组装和接线，这里再次提供接线图，是为了方便您编写代码！**

![Img](../media/couj64.png)

------

#### 4.4.6.3 代码流程图

![Img](../media/flo5.png)

------

#### 4.4.6.4 实验代码

代码文件在`Arduino_代码`文件夹中，代码文件为`4_4_6_Voice-Control-Fan-System`，如下图所示：

![Img](../media/couj026-1.png)

鼠标双击`4_4_6_Voice-Control-Fan-System.ino`即可在Arduino IDE中打开。

```c++
/*
 * 文件名 : Voice-Control-Fan-System
 * 功能   : 结合智能语音模块和电机模拟农场语音调控风扇系统
 * 编译IDE：ARDUINO 2.3.6
 * 作者   : https://www.keyesrobot.cn/
*/

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

// 定义引脚常量
const int RX_PIN = 23;  // 引脚 GPIO23 为 RX
const int TX_PIN = 5;  // 引脚 GPIO5 为 TX
const int MotorPin1 = 19; // (IN+)
const int MotorPin2 = 18; // (IN-)

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

// 定义变量
volatile int yuyin;

// 串口发送消息最大长度
#define UART_SEND_MAX      32
#define UART_MSG_HEAD_LEN  2
#define UART_MSG_FOOT_LEN  2

// 串口发送消息号
#define U_MSG_bozhensgshu      1
#define U_MSG_boxiaoshu      2
#define U_MSG_bobao1      3
#define U_MSG_bobao2      4
#define U_MSG_bobao3      5
#define U_MSG_bobao4      6
#define U_MSG_bobao5      7
#define U_MSG_bobao6      8
#define U_MSG_bobao7      9
#define U_MSG_bobao8      10
#define U_MSG_bobao9      11
#define U_MSG_bobao10      12
#define U_MSG_bobao11      13
#define U_MSG_bobao12      14
#define U_MSG_bobao13      15
#define U_MSG_bobao14      16
#define U_MSG_bobao15      17
#define U_MSG_bobao16      18
#define U_MSG_bobao17      19
#define U_MSG_bobao18      20

// 串口消息参数类型
typedef union {
  double d_double;
  int d_int;
  unsigned char d_ucs[8];
  char d_char;
  unsigned char d_uchar;
  unsigned long d_long;
  short d_short;
  float d_float;}uart_param_t;

// 串口发送函数实现
void _uart_send_impl(unsigned char* buff, int len) {
  // TODO: 调用项目实际的串口发送函数
  for(int i=0;i<len;i++){
    mySerial.write (*buff++);
  }
}

// 串口通信消息尾
const unsigned char g_uart_send_foot[] = {
  0x55, 0xaa
};

// 十六位整数转32位整数
void _int16_to_int32(uart_param_t* param) {
  if (sizeof(int) >= 4)
    return;
  unsigned long value = param->d_long;
  unsigned long sign = (value >> 15) & 1;
  unsigned long v = value;
  if (sign)
    v = 0xFFFF0000 | value;
  uart_param_t p;  p.d_long = v;
  param->d_ucs[0] = p.d_ucs[0];
  param->d_ucs[1] = p.d_ucs[1];
  param->d_ucs[2] = p.d_ucs[2];
  param->d_ucs[3] = p.d_ucs[3];
}

// 浮点数转双精度
void _float_to_double(uart_param_t* param) {
  if (sizeof(int) >= 4)
    return;
  unsigned long value = param->d_long;
  unsigned long sign = value >> 31;
  unsigned long M = value & 0x007FFFFF;
  unsigned long e =  ((value >> 23 ) & 0xFF) - 127 + 1023;
  uart_param_t p0, p1;
  p1.d_long = ((sign & 1) << 31) | ((e & 0x7FF) << 20) | (M >> 3);
  param->d_ucs[0] = p0.d_ucs[0];
  param->d_ucs[1] = p0.d_ucs[1];
  param->d_ucs[2] = p0.d_ucs[2];
  param->d_ucs[3] = p0.d_ucs[3];
  param->d_ucs[4] = p1.d_ucs[0];
  param->d_ucs[5] = p1.d_ucs[1];
  param->d_ucs[6] = p1.d_ucs[2];
  param->d_ucs[7] = p1.d_ucs[3];
}

// 串口通信消息头
const unsigned char g_uart_send_head[] = {
  0xaa, 0x55
};

void setup(){
  Serial.begin(9600); // 硬件串口（与电脑通信）
  mySerial.begin(9600); // 软件串口（与外设通信）
  yuyin = 0; // 定义变量yuyin初始值为0
  pinMode(MotorPin1,OUTPUT); // 设置MotorPin1(IN+)引脚为输出模式
  pinMode(MotorPin2,OUTPUT); // 设置MotorPin2(IN-)引脚为输出模式
}

void loop(){
  if (mySerial.available() > 0) { // 接收语音控制模块的外设数据(命令参数)
    yuyin = mySerial.read();  // 将接收到的外设数据(命令参数)进行赋值
    Serial.println(yuyin);  // 串口打印接收到的外设数据(命令参数)
    if (yuyin == 5) { // 接收到的外设数据(命令参数)为5, 打开风扇, 风速为100
      yuyin = 0;  // 清除识别结果
      delay(2000);
      analogWrite(MotorPin1, 100);
      analogWrite(MotorPin2, 0);
    }
    if (yuyin == 7) { // 接收到的外设数据(命令参数)为7, 风大一点, 风速为200
      yuyin = 0;
      delay(2000);
      analogWrite(MotorPin1, 200);
      analogWrite(MotorPin2, 0);
    }
    if (yuyin == 8) { // 接收到的外设数据(命令参数)为8, 风小一点, 风速为100
      yuyin = 0;
      delay(2000);
      analogWrite(MotorPin1, 100);
      analogWrite(MotorPin2, 0);
    }
    if (yuyin == 6) { // 接收到的外设数据(命令参数)为6, 关闭风扇
      yuyin = 0;
      delay(2000);
      analogWrite(MotorPin1, 0);
      analogWrite(MotorPin2, 0);
    }
  }
}
```

#### 4.4.6.5 实验结果

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

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

智能语音模块唤醒后，对着麦克风说：“打开风扇” 或 “请开风扇” 或 “开风扇” 等命令词时，喇叭播放对应的回复语 “已为您打开风扇”，同时风扇转动。

对着麦克风说：“风大一点” 或 “大一点” 等命令词时，喇叭播放对应的回复语 “风速已增加”，同时风扇转速加快。

对着麦克风说 “风小一点” 或 “小一点” 等命令词时，喇叭播放对应的回复语 “风速已减弱”，同时风扇转速减慢。

对着麦克风说：“关闭风扇” 或 “请关风扇” 或 “关风扇” 或 “关上风扇” 等命令词时，喇叭播放对应的回复语 “已为您关闭风扇”，同时风扇不转。

![Img](../media/Voice-Control-Fan-System.gif)