玩转 ESP32 + Arduino (三) GPIO和串口

玩转 ESP32 + Arduino (三) GPIO和串口

IMG公开课火热来袭,游戏开发者绝不能错过的尖端课堂!
你是否因为游戏画面模糊不清、头疼不已却又不知道如何改变?锁定1月21日在线公开课,技术大佬空降直播间与您共同探讨如何借助硬件光线追踪技术,打造移动端影视级画质!

我用的 ESP32 DEVKIT V1引脚图


一、GPIO

1、初始化GPIO

pinMode(pin, mode)

作用:设置一个引脚(pin)作为GPIO时的I/O模式。

参数:

pin:引脚编号

mode:GPIO的I/O模式,取值有3种

INPUT :作为数字输入

OUTPUT :作为数字输出

INPUT_PULLUP:作为数字输入,且使能引脚的内部上拉电阻

注意:

a、引脚作为PWM输出时,无需先前使用pinMode配置其模式,因为PWM本身就代表了输出的意思。且官方库源代码中可以发现,它已经帮我们配置为输出了。

b、模拟引脚也可以作为数字引脚使用,完全OK。这在数字引脚不够用的情况下非常有用。

2、GPIO数字输出

digitalWrite(pin,value)

作用:设置一个数字输出引脚的输出电平值,HIGH或者LOW。

参数:

pin:引脚编号。此引脚必须在之前使用pinMode设置为OUTPUT模式。

value:2个值

LOW:输出低电平

HIGH:输出高电平

3、GPIO数字输入

int digitalRead(pin)

作用:读取一个数字输入引脚的电平值。

返回:HIGH(高电平)或者LOW(低电平)。

参数:

pin:引脚编号。

示例 : 按键控制灯亮灭

      
      
  1. void setup()
  2. {
  3. pinMode( 2,OUTPUT);
  4. pinMode( 0,INPUT_PULLUP);
  5. }
  6. void loop()
  7. {
  8. if(digitalRead( 0))
  9. {
  10. while(digitalRead( 0));
  11. digitalWrite( 2,!digitalRead( 2));
  12. }
  13. }
4、GPIO模拟输入:analogRead(pin)

注意 : 模拟输入是通过PWM实现的, 所以不需要初始化PIN

analogRead(4)
      
      
5. 模拟信号输入分辨率: analogSetWidth(bit);
bit的值范围
90~511
100~1023
110~2047
12(默认) 0~4095
6. 模拟信号输出 (基于LEDC)

LEDC是基于PWM调制实现模拟输出的.
与arduino uno主板不同, ESP32的PWM模拟是一个个通道 共16个, 通道可以映射到引脚上. 引脚就可以输出PWM信号了.

6.1 设置通道 ledcSetup(channel,freq,bit_num)

参数:

  • channel : LEDC的PWM通道参数,可选0~15
  • freq : 10Hz到40MHz , 但较高的频率精确度低
  • bit_num: 占空比分辨率(可选1~16), 比如bit_num=8 则范围 0~2的8次方 , 也就是0~255

推荐的配置:

频率位深过渡的可用步骤
1220赫兹1665536
2441赫兹1532768
4882赫兹1416384
9765Hz138192
19531赫兹124096
ledcSetup(1,1200,16);
      
      
6.2 通道与引脚映射 ledcAttachPin(pin,channel)
ledcAttachPin(5,1);
      
      

注意: 一个通道可以同时映射多个引脚

6.3 取消引脚的PWM映射 ledcDetachPin(pin)
ledcDetachPin(5);
      
      
6.4 向指定通道写入占空比 ledcWrite(channel,duty)

例: 呼吸灯


      
      
  1. bool add_status = true;
  2. void setup()
  3. {
  4. pinMode( 2,OUTPUT);
  5. ledcSetup( 2, 1200, 8);
  6. ledcAttachPin( 2, 2);
  7. }
  8. void loop()
  9. {
  10. for( int i = 0 ; i< 256; i++)
  11. {
  12. if(add_status)
  13. {
  14. ledcWrite( 2,i);
  15. }
  16. else
  17. {
  18. ledcWrite( 2, 256-i);
  19. }
  20. delay( 5);
  21. }
  22. add_status = !add_status;
  23. }
例子, 全彩呼吸灯

      
      
  1. #include <Arduino.h>
  2. #define LED_R 27
  3. #define LED_G 33
  4. #define LED_B 32
  5. void setup()
  6. {
  7. Serial.begin(115200);
  8. ledcSetup(1, 1200, 8 );
  9. ledcSetup(2, 1200, 8 );
  10. ledcSetup(3, 1200, 8 );
  11. ledcAttachPin(LED_R, 1 );
  12. ledcAttachPin(LED_G, 2 );
  13. ledcAttachPin(LED_B, 3 );
  14. ledcWrite(1, 255 );
  15. ledcWrite(2, 255 );
  16. ledcWrite(3, 255 );
  17. }
  18. void loop()
  19. {
  20. for (int i = 0 ; i < 510 ; i++)
  21. {
  22. if (i >= 0 && i < 255 )
  23. ledcWrite(1, 255 - i);
  24. if (i >= 255 && i < 510 )
  25. ledcWrite(1, i - 255 );
  26. if (i >= 0 && i < 170 )
  27. ledcWrite(2, 85 + i);
  28. if (i >= 170 && i < 425 )
  29. ledcWrite(2, 425 - i);
  30. if (i >= 425 && i < 510 )
  31. ledcWrite(2, i - 425 );
  32. if (i >= 0 && i < 85 )
  33. ledcWrite(3, 85 - i);
  34. if (i >= 85 && i < 340 )
  35. ledcWrite(3, i - 85 );
  36. if (i >= 340 && i < 510 )
  37. ledcWrite(3, 595 - i);
  38. delay(10);
  39. }
  40. }
6.5 向指定通道输出指定频率的音符信号 ledcWriteTone(channel, freq)
6.6 向指定通道输出指定的音符和音阶 ledcWriteNote(channel,note,octava)

参数

  • note : 音符 可选(NOTE_C, NOTE_Cs, NOTE_D, NOTE_Eb, NOTE_C......)
  • octava : 音阶 , 可选0~7
7. 模拟信号输出函数 (基于DAC)

ESP32提供了两个DAC通道, 对应引脚25 , 26. 精度为8位.

dacWrite(pin,value);

  • value取值: 0~255

      
      
  1. void setup()
  2. {
  3. }
  4. void loop()
  5. {
  6. for( int i = 0 ; i< 256; i++)
  7. {
  8. dacWrite( 25,i);
  9. delay( 10);
  10. }
  11. }

二、串口打印 UART

ESP32共有3个UART端口, 其中UART1用于Flash读/写.

串口名Arduino名TXRX
UART0Serialpin1pin3
UART1Serial1pin10pin9
UART2Serial2pin17pin16
1、串口初始化

Serial.begin(speed, config)

  • 参数:
    • speed:波特率,一般取值9600,115200等。
    • config:设置数据位、校验位和停止位。默认SERIAL_8N1表示8个数据位,无校验位,1个停止位。
  • 返回值:无。
2、关闭串口

Serial.end()

  • 描述:禁止串口传输。此时串口Rx和Tx可以作为数字IO引脚使用。
  • 原型:Serial.end()
  • 参数:无。
  • 返回值:无。
3、串口打印

Serial.print()

  • 描述:串口输出数据,写入字符数据到串口。
  • 原型:
    • Serial.print(val)
    • Serial.print(val, format)
  • 参数:
    • val:打印的值,任意数据类型。
    • config:输出的数据格式。BIN(二进制)、OCT(八进制)、DEC(十进制)、HEX(十六进制)。对于浮点数,此参数指定要使用的小数位数。
4、串口输出数据并换行 println() 和 printf()

Serial.println()
Serial.printf()

  • 描述:串口输出数据并换行。
  • 原型:
    • Serial.println(val)
    • Serial.println(val, format)
  • 参数:
    • val:打印的值,任意数据类型。
    • config:输出的数据格式。
  • 返回值:返回写入的字节数。
附: 常用格式字符及转义字符
字符说明
%o八进制整数输出
%d十进制整数输出
%x十六进制整数输出
%f浮点输出,默认6位小数
%c单字符输出
%s字符串输出
\n换行
\r回车
\tTab制表符
5、将二进制数写入串口

Serial.write()

描述
将二进制数据写入串行端口。该数据以字节或一系列字节的形式发送;要发送代表数字数字的字符,请改用print()函数。
句法
*Serial*.write(val)
*Serial*.write(str)
*Serial*.write(buf, len)
参量
*Serial*:串行端口对象。请参阅“ 串行”主页上每个板的可用串行端口列表。
val:要作为单个字节发送的值。
str:作为一系列字节发送的字符串。
buf:要作为一系列字节发送的数组。
len:要从数组发送的字节数。
退货
write()将返回写入的字节数,尽管读取该数字是可选的。资料类型:size_t

6、判断串口缓冲区的状态

Serial.available()

  • 描述:判断串口缓冲区的状态,返回从串口缓冲区读取的字节数。
  • 原型:Serial.available()
  • 参数:无。
  • 返回值:可读取的字节数。
7、读取串口数据

Serial.read()
描述:读取串口数据,一次读一个字符,读完后删除已读数据。

  • 原型:Serial.read()
  • 参数:无。
  • 返回值:返回串口缓存中第一个可读字节,当没有可读数据时返回-1,整数类型。

      
      
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. char rev;
  4. void setup() {
  5. Serial.begin( 115200);
  6. }
  7. void loop() {
  8. if(Serial.available())
  9. {
  10. rev=Serial.read();
  11. Serial.print( "rev=");
  12. Serial.println(rev);
  13. }
  14. }

Serial.readBytes()

  • 描述:从串口读取指定长度的字符到缓存数组。
  • 原型:Serial.readBytes(buffer, length)
  • 参数:
    • buffer:缓存变量。
    • length:设定的读取长度。

返回值:返回存入缓存的字符数。

Serial.readString()

描述

Serial.readString()从串行缓冲区读取字符到字符串。如果超时,该函数将终止。

Serial.readString()Stream实用程序类继承。

句法

*Serial*.readString()

参量

*Serial*:串行端口对象。请参阅“ 串行”主页上每个板的可用串行端口列表。

返回值

一个String从串行读缓冲器

Serial.readStringUntil()

描述
readStringUntil()从串行缓冲区读取字符到字符串。如果超时,该函数将终止(请参见setTimeout())。
Serial.readStringUntil()Stream实用程序类继承。
句法
*Serial*.readStringUntil(terminator)
参量
*Serial*:串行端口对象。请参阅“ 串行”主页上每个板的可用串行端口列表。
terminator:要搜索的字符。允许的数据类型:char
返回值
String从串行缓冲区的整个读取,直到终止符

注意和警告
终止符将从串行缓冲区中丢弃。

Serial.find()

描述
Serial.find()从串行缓冲区读取数据,直到找到目标为止。true如果找到目标,函数将返回false超时。
Serial.find()实用程序类继承。
句法
*Serial*.find(target)
*Serial*.find(target, length)
参量
*Serial*:串行端口对象。请参阅“ 串行”主页上每个板的可用串行端口列表。
target:要搜索的字符串。允许的数据类型:char
length:目标的长度。允许的数据类型:size_t
返回值
资料类型:bool

Serial.findUntil()

描述
Serial.findUntil() 从串行缓冲区读取数据,直到找到给定长度的目标字符串或终止符字符串。
如果找到目标字符串,则该函数返回true;如果超时,则返回false。
Serial.findUntil()Stream实用程序类继承。
句法
*Serial*.findUntil(target, terminal)
参量
*Serial*:串行端口对象。请参阅“ 串行”主页上每个板的可用串行端口列表。
target:要搜索的字符串。允许的数据类型:char
terminal:搜索中的终端字符串。允许的数据类型:char
返回值
资料类型:bool

Serial.parseFloat()

描述
Serial.parseFloat()从串行缓冲区返回第一个有效的浮点数。parseFloat()以不是浮点数的第一个字符终止。如果超时,该函数将终止(请参见Serial.setTimeout())。
Serial.parseFloat()Stream实用程序类继承。
句法
*Serial*.parseFloat()
*Serial*.parseFloat(lookahead)
*Serial*.parseFloat(lookahead, ignore)
参量
*Serial*:串行端口对象。请参阅“ 串行”主页上每个板的可用串行端口列表。
lookahead:用于在流中向前查询浮点数的模式。允许的数据类型:LookaheadMode。允许lookahead值:

  • SKIP_ALL:扫描流中的浮点数时,除负号,小数点或数字以外的所有字符都将被忽略。这是默认模式。
  • SKIP_NONE:任何内容都不会被跳过,除非第一个等待的字符有效,否则流不会被触摸。
  • SKIP_WHITESPACE:仅跳过制表符,空格,换行符和回车符。
    ignore:用于跳过搜索中指示的字符。例如,用于跳过数千个分频器。允许的数据类型:char
    返回值:
    类型:float

Serial.parseInt()

描述
在输入的序列中查找下一个有效整数。如果超时,该函数将终止(请参见Serial.setTimeout())。
Serial.parseInt()Stream实用程序类继承。
尤其是:

  • 如果没有读取到可配置的超时值的字符,或者读取了非数字,则分析停止。
  • 如果在发生超时(请参见Serial.setTimeout())时未读取到有效数字,则返回0;否则返回0。

句法
*Serial*.parseInt()
*Serial*.parseInt(lookahead)
*Serial*.parseInt(lookahead, ignore)
参量
*Serial*:串行端口对象。请参阅“ 串行”主页上每个板的可用串行端口列表。
lookahead:用于在流中向前搜索整数的模式。允许的数据类型:LookaheadMode。允许lookahead值:

  • SKIP_ALL:扫描流中的整数时,将忽略数字或减号以外的所有字符。这是默认模式。
  • SKIP_NONE:任何内容都不会被跳过,除非第一个等待的字符有效,否则流不会被触摸。
  • SKIP_WHITESPACE:仅跳过制表符,空格,换行符和回车符。

ignore:用于跳过搜索中指示的字符。例如,用于跳过数千个分频器。允许的数据类型:char
返回值
下一个有效整数。资料类型:long

8.判断串口是否就绪** Serial

描述

指示指定的串行端口是否已就绪。

在具有本地USB的板上if (Serial)(或if(SerialUSB)在Due上)指示USB CDC串行连接是否打开。对于所有其他板卡和非USB CDC端口,这将始终返回true。

这是在Arduino IDE 1.0.1中引入的。

句法

if (Serial) while (!Serial) 等等

参量

没有

返回值

如果指定的串行端口可用,则返回true。如果在准备就绪之前查询Leonardo的USB CDC串行连接,则仅返回false。类型:bool

9、设置串口超时**

Serial.setTimeout()

描述
Serial.setTimeout()设置等待串行数据的最大毫秒数。默认值为1000毫秒。
Serial.setTimeout()Stream实用程序类继承。
句法
*Serial*.setTimeout(time)
参量
*Serial*:串行端口对象。请参阅“ 串行”主页上每个板的可用串行端口列表。
time:超时时间(以毫秒为单位)。允许的数据类型:long
退货
没有

注意和警告
使用通过*Serial*.setTimeout()以下方式设置的超时值的串行函数:

  • *Serial*.find()
  • *Serial*.findUntil()
  • *Serial*.parseInt()
  • *Serial*.parseFloat()
  • *Serial*.readBytes()
  • *Serial*.readBytesUntil()
  • *Serial*.readString()
  • *Serial*.readStringUntil()

也可以看看


      
      
  1. void setup() {
  2. //Initialize serial and wait for port to open:
  3. Serial.begin( 9600);
  4. while (!Serial) {
  5. ; // wait for serial port to connect. Needed for native USB
  6. }
  7. }
  8. void loop() {
  9. //proceed normally
  10. }

      
      
  1. /*
  2. Serial
  3. 串口通讯实验
  4. */
  5. int incomedate = 0;
  6. void setup() {
  7. Serial.begin( 9600); //设置串口波特率9600
  8. Serial. println( 78, BIN); // "1001110"
  9. Serial. println( 78, OCT); // "116"
  10. Serial. println( 78, DEC); // "78"
  11. Serial. println( 78, HEX); // "4E"
  12. Serial. println( 1.23456, 0); // "1"
  13. Serial. println( 1.23456, 2); // "1.23"
  14. Serial. println( 1.23456, 4); // "1.2346"
  15. Serial. println( 'N'); // "N"
  16. Serial. println( "Hello world."); // "Hello world."
  17. }
  18. void loop() {
  19. if (Serial.available() > 0) //串口接收到数据
  20. {
  21. incomedate = Serial.read(); //获取串口接收到的数据
  22. if (incomedate == 'H')
  23. {
  24. Serial. println( "Good Job!");
  25. }
  26. }
  27. delay( 1000);
  28. }

使用的串口Serial其实是HardwareSerial类的实例化,实例化过程中传入了串口号,实现过程如下:

<think>好的,我现在需要帮助用户将ESP8266与Arduino结合接入小爱语音控制。用户之前已经询问过ESP8266配合语音交互芯片的选择,现在的问题更具体,涉及到小爱同学的接入。我需要先回忆相关知识,小爱同学是小米的智能助手,通常需要通过米家平台进行设备接入。 首先,用户使用的是ESP8266Arduino,所以需要确认如何通过Arduino开发环境来编程ESP8266,并实现与小爱的通信。可能的方法包括使用第方库或者模拟米家设备的协议。常见的方案有使用Blinker库或者通过MIoT协议。 接下来,我需要考虑步骤。用户可能需要注册小米开发者账号,创建产品,获取设备的密钥等信息。然后,在Arduino代码中配置Wi-Fi连接小爱控制的部分。同时,可能需要处理语音指令的解析响应。 另外,用户可能需要硬件方面的连接,比如是否需要额外的模块,比如麦克风或语音识别模块,但根据之前的问题,用户可能已经有一些语音模块,但现在重点是小爱控制,可能更多是作为被控设备,比如通过语音控制ESP8266连接的电器。 需要注意的点包括:网络稳定性、设备认证、协议兼容性。可能的难点在于如何让ESP8266模拟成米家认证的设备,或者通过第方平台中转,比如使用Blinker这样的中间件。 需要推荐的步骤大致是:注册开发者账号,创建智能设备,获取必要的密钥;在Arduino中安装Blinker库或其他支持库;编写代码连接Wi-Fi小爱同学;处理控制指令,比如开关控制,并反馈状态。同时,可能需要测试语音指令的触发响应时间。 可能遇到的问题包括认证失败、网络连接不稳定、指令无法正确解析等,需要提供调试建议,比如检查密钥是否正确,查看网络连接状态,使用串口输出调试信息等。 最后,需要确保回答结构清晰,分步骤说明,并给出示例代码注意事项,确保用户能够逐步实施,同时提醒可能遇到的常见问题解决方法。</think>以下是基于ESP8266+Arduino实现小爱语音控制的详细方案: ### 一、实现原理 通过**Blinker物联网平台**作为中转,将ESP8266虚拟成米家设备,实现步对接: 1. ESP8266 ⇄ Blinker服务器(MQTT协议) 2. Blinker ⇄ 小米IoT平台(官方接口) 3. 小爱同学 ⇄ 小米IoT平台(语音指令交互) --- ### 二、硬件准备 | 组件 | 型号示例 | 数量 | 备注 | |----------------|---------------|------|-----------------------| | ESP8266开发板 | NodeMCU V3 | 1 | 需支持Arduino IDE开发 | | USB数据线 | Micro USB | 1 | 供电+程序烧写 | | 外围设备 | LED/继电器等 | 按需 | 受控设备 | --- ### 、具体实现步骤 #### 步骤1:平台账号注册 1. 访问[Blinker官网](https://diandeng.tech/)注册账号 2. 在小米IoT开发者平台([https://iot.mi.com](https://iot.mi.com))创建产品 - 选择**Wi-Fi设备**类型 - 记录获得的`Product ID``API Key` #### 步骤2:Arduino环境配置 1. 安装开发库: ```arduino // 在IDE中依次选择: // 工具 -> 管理库 -> 搜索安装以下库: - Blinker (v1.3.0+) - ESP8266WiFi (v3.0.0+) ``` 2. 添加设备密钥: ```cpp #define BLINKER_MIOT_LIGHT // 定义设备类型为灯 #define BLINKER_PRINT Serial // 启用调试输出 char auth[] = "blinker分配的密钥"; // 从Blinker APP获取 ``` #### 步骤3:硬件接线示例 ``` NodeMCU引脚配置: D1 → LED控制引脚(GPIO5) D2 → 备用控制引脚(GPIO4) 3V3 → 外设电源正极 GND → 外设电源负极 ``` #### 步骤4:核心代码实现 ```cpp #include <Blinker.h> // 控制回调函数 void miotPowerState(const String &state) { BLINKER_LOG("收到语音指令: ", state); if (state == BLINKER_CMD_ON) { // 小爱说"打开" digitalWrite(LED_BUILTIN, LOW); // 根据电路设计调整电平 BlinkerMIOT.powerState("on"); // 同步状态 } else if (state == BLINKER_CMD_OFF) { digitalWrite(LED_BUILTIN, HIGH); BlinkerMIOT.powerState("off"); } } void setup() { Serial.begin(115200); pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); // 初始关闭 Blinker.begin(auth, WiFi.SSID, WiFi.psk); // 连接WiFiBlinker BlinkerMIOT.attachPowerState(miotPowerState); // 绑定回调 } void loop() { Blinker.run(); // 保持长连接 } ``` --- ### 四、设备绑定流程 1. 手机安装**米家APP****Blinker APP** 2. Blinker APP操作: - 添加设备 → Wi-Fi快连 → 输入热点密码 - 在「智能家居」中绑定小米账号 3. 对小爱同学说: ```bash "发现设备" # 触发自动搜索 "打开/关闭[设备名称]" # 执行控制 ``` --- ### 五、调试技巧 1. **状态监测**: ```cpp // 添加调试代码 BLINKER_LOG("WiFi信号强度: ", WiFi.RSSI()); BLINKER_LOG("剩余内存: ", system_get_free_heap_size()); ``` 2. **常见问题处理**: | 现象 | 排查方法 | 解决方案 | |---------------------|----------------------------|---------------------------| | 设备无法上线 | 查看Blinker APP错误代码 | 检查auth密钥WiFi密码 | | 语音无响应 | 用串口监视器观察指令接收 | 确认回调函数正确绑定 | | 控制延迟高 | `ping diandeng.tech`测延迟 | 更换MQTT服务器区域 | --- ### 六、进阶功能扩展 1. **多设备控制**: ```cpp void miotColor(int32_t color) { // 接收颜色指令 // 解析RGB值:color格式0xRRGGBB uint8_t r = (color >> 16) & 0xFF; uint8_t g = (color >> 8) & 0xFF; uint8_t b = color & 0xFF; analogWrite(R_PIN, r); // PWM调光 } ``` 2. **状态反馈**: ```cpp // 主动上报设备状态 BlinkerMIOT.print("temperature", 25.6); // 上报温度 BlinkerMIOT.print("humidity", 63); // 上报湿度 ``` --- ### 七、功耗优化建议 1. 启用ESP8266深度睡眠: ```cpp ESP.deepSleep(30e6); // 休眠30秒(GPIO16需连接RST) ``` 2. 调整Wi-Fi工作模式: ```cpp WiFi.setSleepMode(WIFI_MODEM_SLEEP); // 启用MODEM睡眠 ``` 通过本方案可实现典型响应时间<1.5秒的语音控制,建议实际部署时使用ESP8266-12F模块以增强稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值