ESP32外设
入门文档
2025-05-28
写在前边
弄这个文档的初衷是为了更快地入门ESP32
GPIO
GPIO有四种常见的工作模式:
输出:可以设置GPIO的高低电平
输入:可以获取外部输入的高低电平信息,一般要设置加上拉电阻或下拉电阻
浮空输出:可以设置GPIO的高低电平,但要在电路外部中增加上拉电阻
开漏输入:可以获取外部输入的高低电平信息,但要在电路外部中增加上拉电阻
GPIO的使用流程:
初始化->设置GPIO工作模式
GPIO初始化
定义结构体->调用API初始化GPIO
①定义结构体
结构体由以下内容组成
②使用API初始化GPIO
GPIO输出
输出的两个参数分别是:
gpio_num:GPIO引脚编号(如GPIO_NUM_2)。
level:电平值(0/1)
这里level非零即为1
GPIO交换矩阵
GPIO交换矩阵的核心作用:
动态信号路由:允许将90%以上的外设信号(如UART、PWM、SPI等)自由映射到 任意可用的GPIO引脚(部分特殊功能引脚除外)。
突破物理限制:解决PCB设计时的引脚冲突问题,例如可将同一外设(如 UART0)的TX和RX分配到不同位置的引脚。
简而言之,可以让任意引脚使用任意的功能。
定时器
PWM
定时器是通道的基础.
通道必须绑定到一个已通过ledc_timer_config配置的定时器。定时器定义了PWM的全局参数(如频率),而通道负责将这一时间基准转化为具体GPIO的输出。
共享性:
一个定时器可被多个通道共享。例如,定时器配置为1kHz频率后,多个通道可基于同一频率输出不同占空比的信号。
参数一致性:
通道的speed_mode必须与绑定的定时器一致,否则PWM信号无法正确生成。
配置流程:配置PWM,绑定通道和GPIO
①配置PWM:创建PWM配置结构体->通过API使用结构体对PWM的定时器进行配置
②绑定:完成通道绑定设置->通过API使用结构体对PWM的定时器进行绑定
创建PWM配置结构体
对PWM进行初始化设置,设置定时器频率、通道,时钟源,翻转频率,分辨率
↓↓ESP32的时钟源类型↓↓
|
时钟源类型 |
频率范围 |
适用模式 |
特点 |
|
APB_CLK |
80MHz(默认) |
高速模式 |
高精度、低抖动 |
|
RTC8M_CLK |
~8MHz(可校准) |
低速模式 |
低功耗、可深度睡眠工作 |
|
REF_TICK |
1MHz |
特殊应用 |
同步系统时钟 |
此处一般为自动
使用API配置PWM
ledc_timer_config用于初始化用到的定时器()
通道初始化
指定配置的通道,及其绑定的定时器与GPIO,并指明定时器频率,中断类型和信号占空比
使用API进行绑定
ledc_channel_config用于初始化ledc输出通道 以及将timer关联起来
这样对应的通道就能输出PWM频率了(上例为On_Board_LED_GPIO这个GPIO接口输出PWM)
计时计数
IIC协议:
注意!注意!新旧I2C协议代码不通用!不兼容!
旧版"driver/i2c.h"
新版"driver/i2c_master.h"
配置流程:写初始化I2C函数,写I2C对寄存器读写函数(用于寄存器初始化函数中),主函数调用I2C初始化函数与寄存器初始化函数
①配置I2C:创建I2C初始化结构体->配置参数->安装I2C驱动
②寄存器读写函数->寄存器初始化函数需要用到寄存器值读写
③在主函数中调用I2C初始化函数与寄存器初始化函数
文件中创建结构体初始化I2C
通过I2C对寄存器值进行读取写入(用于寄存器初始化函数中)
BSP_I2C_NUM依旧是使用的I2C外设编号,SENSOR_ADDR是寄存器的地址,I2C通过地址找到寄存器并进行读写操作。
在主函数中调用初始化函数
ESP_ERROR_CHECK 是一个宏函数,位于 esp-idf 文件中,用于检测执行函数的返回结果,如果没有错误,什么事情都不会发生,如果有错误,会引起单片机重启。使用这个宏函数,需要包含 esp_err.h 头文件。
串口(UART)
使用方法与其他的配置大同小异
使用流程:创建配置结构体->调用结构体进行配置->安装驱动(设置RX/TX缓冲区)->读取/发送
创建配置结构体
| baud_rate | 波特率 | 设置数据传输速率,单位是每秒比特数(bps) |
| data_bits | 数据位 | 定义每个数据包的位数 |
| parity | 校验位 | 错误检测机制,检测单比特错误 |
| stop_bits | 停止位 | 标识数据包结束的位数 |
| flow_ctrl | 流控制 | 防止数据溢出的硬件流控 |
| source_clk | 时钟源 | 选择 UART 的基准时钟源 |
这里对流控制进一步解释(因为我也不会)
流控制的作用:
防止数据溢出:当接收方缓冲区满时,通过流控制信号让发送方暂停传输。
保证传输可靠性:避免高速发送导致低速接收设备无法处理数据。
适应不同硬件性能:协调不同处理速度的设备(如MCU与PC)之间的通信。
硬件流控制(通过物理引脚信号控制数据流):
RTS(RequestToSend):接收方准备好接收数据时,拉高此信号。
CTS(ClearToSend):发送方检测到CTS有效时,才允许发送数据。
调用API配置结构体
这里UART_PORT_NUM是串口号
(ESP32芯片通常包含3个独立的UART硬件控制器,串口0默认串口下载,串口1一般为FLASH的引脚(可通过GPIO交换矩阵更改引脚),串口2常用)
安装UART驱动
串口号-发送缓存大小-接收缓存大小-队列长度-队列句柄(传回来用的)-中断标志(一般使用0,使用默认配置)
读取串口数据
这函数有返回值:如果成功,则返回读取的字节数;失败则返回-1。
串口号-缓冲区-缓冲区大小-等待数据的超时时间 portMAX_DELAY表示无限等待
发送串口数据
串口号-待发送数据的源地址-发送数据的字节数
更改串口引脚(可选)
通过GPIO矩阵,将默认的串口引脚更改。若更改,则需在安装驱动前配置该项。
WiFi
STA模式
STA模式:连接已有的网络,ESP32作为终端设备
使用流程:
总流程:创建并初始化函数->监听设备事件->分情况调用回调函数进行各项初始化和配置
初始化流程:初始化NVS(存储SSID和密码),初始化TCP/IP栈(使用esp_netif_init),初始化事件系统循环(存储系统事件,包括WIFI MQTT BLU等),初始化WIFI,设置事件回调函数并监听事件
初始化NVS,TCP/IP,系统事件循环
初始化WIFI
先定义个WIFI初始化结构体->再创建个设置STA的初始化结构体->调用API进行初始化(WIFI和WIFI设置)->启动WIFI
设置事件回调函数
WIFI事件的回调函数
事件回调函数有以下几个要素:
-
有个能被调用的"注册回调函数的接口"(就是将回调函数与事件进行绑定)
-
有个回调函数(被调用之后产生的动作)
WIFI需要注册多个回调函数:WIFI和网络(IP_EVENT)
这里的事件回调函数,主要是为了判断WIFI的各个事件段该做什么,比如未连接WiFi怎么办,获取ip之后怎么办。
一键配网模式(SmartConfig)
MQTT
基于TCP/IP的低带宽需求报文传输服务
使用流程:
①创建MQTT句柄(通过这个对MQTT进行操作)->创建并调用结构体(存储初始化MQTT的参数)->②->注册回调函数->启用MQTT
②配置事件回调函数,对MQTT各个状态进行反应(对订阅、发布、接收数据等进行操作)
①MQTT基础设置
创建MQTT句柄
这里实际上创建了一个MQTT客户端,名为s_mqtt_client
后续所有对MQTT客户端的操作,都使用s_mqtt_client
创建并填充结构体
调用配置结构体并初始化客户端
注册回调函数
为 MQTT 客户端注册事件回调函数。具体来说:
-
调用 esp_mqtt_client_register_event() 来关联 MQTT 客户端 s_mqtt_client 和事件回调函数aliot_mqtt_event_handler。
-
指定 ESP_EVENT_ANY_ID 表示接收所有类型的 MQTT 事件(例如连接、断开、发布、订阅、接收数据等)。
-
回调函数中可以根据事件类型(event_id)做出相应处理,例如记录日志、修改连接状态或发布配置信息。
-
最后传入 s_mqtt_client 作为用户数据,这样在回调中可以访问到该 MQTT 客户端句柄或相关信息。
启用MQTT
②配置MQTT事件回调函数
可以用这个回调函数直接读取MQTT订阅的数据
配置方式与WIFI大差不差
注:
使用MQTT发送数据
发送流程:
NVS 是 Non-Volatile Storage(非易失性存储)的缩写,是 ESP32 用来持久化保存数据的一种机制。
它类似于"小型文件系统",常用于保存 WiFi 配置、密钥、参数等,即使断电数据也不会丢失。
此处,NVS 主要用于保证系统能正常保存和读取配置信息。
初始化WIFI
传入回调函数,用于通知连接成功事件
监听WIFI连接事件
直到WiFi连接成功后,才启动MQTT连接
发布数据
JSON
JSON是一种规范好的数据格式,本质上就是字符串。用于传输数据信息,基于"键-值对",可以包含对象、数组、字符串、数字、布尔、NULL这六种最基本的数据。
ESP32中可以使用cJSON数据解析器来分析和打包JSON数据,需要调用"cJSON.h"。
JSON的基本格式如下
解析JSON
流程:解析JSON->……>解析JSON->读取键的数据->读取数据的值
解析JSON并保存
本文档中只说明ESP32中的情况
读取JSON中某个键的数据
这里的数据,可以是具体的数值和字符串,也可以是对象。
若JSON层层嵌套,则需层层解析。重复使用cJSON_GetObjectItem,一层一层解析,以下操作也同理
读取获取数据的值
如果要获取数据的值为字符串,则用cJSON_GetStringValue()
如果是数值,则用cJSON_GetNumberValue()
生成JSON
流程:创建cJSON格式的对象->向对象中添加键-值
创建cJSON格式的对象
这里创建了个名为js_obj_tx_humidity的cJSON对象。
向对象中添加键-值
这里向js_obj_tx_humidity这个对象中添加的键-值为"Humidity","%d"
然后向js_obj_tx_humidity这个对象中又添加了一个对象js_obj_sys
WS2812
以下是调用已有配置对WS2812进行驱动
单总线控制的彩色LED灯珠,因为对控制时序比较严格,故使用RMT红外控制。
同GPIO等操作方式,需先使用结构体进行初始化,再使用API通过结构体配置。
Tips:使用"led_strip.h"
使用流程(基于官方Example):
创建结构体(共两个)->调用API进行配置->使用函数配置亮度颜色等参数
结构体创建
先创建LED的配置结构体和被操控的LED对象
再创建RMT的配置结构体
调用API进行配置
使用led_strip_new_rmt_device函数
利用传递进来两个参数(LED和RMT的配置结构体),生成到先前创建的LED对象(led_strip)中
配置LED亮度等参数
对生成的对象(led_strip),进行参数配置;配置后刷新LED状态
这样WS2812就会常亮了
(不基于BLink例程)以下是从RMT驱动开始,驱动WS2812
基于此帖子(【ESP32 IDF】用RMT控制 WS2812 彩色灯带 - 东邪独孤 - 博客园)
DHT11
单总线工作的数字温湿度传感器,工作范围"-20~60摄氏度""5%~90%"
DHT11基于单总线,同样利用RMT红外进行控制(接收数据)。
工作流程:
定义RMT接收用结构体->调用RMT接收通道API->使用队列接收数据->接收完使用回调至接收模式
初始化DHT11
调用rmt接受通道
使用队列接收数据
将RMT读取到的脉冲数据处理为温度和湿度
脉冲信号处理,复制即可
调整脉冲信号以接受DHT11数据
脉冲信号调整部分复制即可
调整后接收数据
LCD液晶显示屏
这里采用液晶屏驱动芯片ST7789,采用SPI通信方式与ESP32连接.
由于esp32的引脚数量少,可以使用寄存器PCA9557,对远程位置上的输入输出控制和状态监控,用于解决微控制器I/O资源不足的问题,并允许通过简单的I2C接口实现复杂的I/O操作。
液晶屏的LCD_CS引脚由IO扩展芯片pca9557控制,所以需要先初始化pca9557,而pca9557是i2c通信芯片,所以又需要先初始化i2c。
初始化PCA8559
首先需要设置PCA9557的工作模式(如输入或输出)。这是通过向特定寄存器写入配置数据完成的。
读写PCA8559
控制PCA9557任意一个单独引脚变高变低
控制PCA9557_LCD_CS输出高低电平
初始化I2C
初始化LCD
使用ESP32中遇到的奇奇怪怪的问题
-
明明添加了"esp_log.h"这种头文件,但是根本识别不到该怎么办?
-
ESP-IDF的路径设置对了吗。
-
需要用"ESP-IDF: 添加 VS Code 配置文件夹"给这个项目添加以下配置文件夹
-
-
编译卡在CMake过不去,但是检查了一圈程序发现没问题
-
删掉build文件夹,再重新编译一下
-
-
明明头文件设置好了,但是头文件中的函数无法调用怎么办?
1)在CMakeLists.txt中,按照格式把需要编译的.C程序添加进去(根据已有的格式设置就行)



Comments | NOTHING