
之前已经装好了环境并且跑通了第一个项目现在开始点亮LED灯再通过多个LED灯实现流水灯的效果。1. 实验准备1.1 硬件准备名称数量说明ESP32-P4 开发板1 块本教程使用 GPIO4、GPIO5、GPIO6 三个引脚三色 LED 模块1 个4 个引脚G、Y、R、GND丝印顺序可能不同以实际为准杜邦线母对母3 根红、黄、黑各一根方便对照接线表线材的颜色不影响使用不同颜色可以避免接错线USB Type-C 数据线1 根必须是能传数据的线只能充电的线烧录会失败使用数据线连接主板和电脑主板可以被识别就证明数据线是可以传输数据的电脑1 台Windows 10 / 11已装好 ESP-IDF 与 VS Code三色 LED 模块内部已经自带限流电阻不用自己再串电阻。如果你用的是单独一颗裸 LED就必须串一个 220Ω1kΩ 的电阻否则会烧坏 LED 或引脚。1.2 软件准备不需要新装任何东西直接复用第 1 课的环境如何还没有搭建环境可以参照第一课【ESP32入门】Windows 下 ESP-IDF V6.1 环境搭建上EIM 离线安装 VS Code 配置 驱动安装_eim-gui-windows-x64-CSDN博客)1.3 基础概念1.3.1 GPIO 是什么GPIO General Purpose Input/Output通用输入输出引脚。把它想成芯片身上的一个个小水龙头你可以让它出水输出高电平3.3V——这就是输出模式也可以让它关水输出低电平0V还可以反过来感受外面有没有水压输入模式比如读按键。ESP32-P4 有几十个这样的引脚开发板边缘的丝印GPIO4、GPIO5、GPIO0就是它们的名字。本课我们只用到最简单的用法让引脚输出电压去点亮 LED。1.3.2 高电平、低电平与 LED 亮灭LED 是发光二极管有正极长脚 / 模块上标注的那一端和负极。电流只能从正极流向负极一旦流过去它就发光。所以让 LED 亮起来的完整条件是——电流要走一个圈高电平1引脚输出 3.3V和 GND 之间有电压差电流流过灯亮低电平0引脚输出 0V两端没有电压差没有电流灯灭。这就是为什么接线表里必须有一根黑色线接 GND。没有 GND电流回不去灯怎么都不会亮也就是说在要电路可以正常工作就必须形成环路即有出必有进。1.3.3 LED模块的两种接线方式LED 共阴 / 共阳的区别只在公共端接电源地(GND)还是电源正(VCC)由此决定 IO 输出高电平还是低电平点亮。在编写代码时如果发现LED高电平无法点亮输出低电平可以点亮则这个模块就是共阳极的了两者区别我们可以参照下图。2. 案例一点亮一颗 LED常亮现在我们开始让灯亮起来。灯亮了说明接线、端口、烧录全都正常后面再出问题就只可能是代码。2.1 接线断电拔掉 USB状态下接线在更改硬件接线时断电可以避免硬件短路损坏图中线路颜色接到开发板接到 LED 模块作用红色线GPIO4R红色 LED给红灯供电黄色线GPIO5Y黄色 LED给黄灯供电黑色线GNDGND共地电流回路必需本实验一暂时只用红色线GPIO4 → R和黑色线GND。黄色线Y和绿色线 G这一课不用先放着。图上 LED 模块的丝印从上到下是G / Y / R / GND不同批次模块的丝印顺序可能不一样以字母为准R 对应红色灯Y 对应黄色灯G对应绿色灯 GND 接地。2.2 打开工程使用课程提供的LED_Blink工程压缩包解压到纯英文路径下用 VS Code 直接打开工程文件夹也可以。LED_Blink项目下载2.3 代码解释#includedriver/gpio.h引入 GPIO 驱动这样才认识gpio_config等函数相当于这是一个工具箱gpio_config等函数相当于扳手、锤子。我们不拿出工具箱就用不了里面的扳手一样。#defineLED1_GPIOGPIO_NUM_4// 给 GPIO4 起个外号叫 LED1_GPIO这里是全局定义将主板的GPIO4用LED1_GPIO来代替好处就是之后我们修改引脚只要修改这一个位置就行在程序中我们会将GPIO4设置为高电平让LED亮起也会设置低电平让LED熄灭如果我们现在希望修改LED的控制引脚为GPIO5使用全局定义的方法我们只要这个语句GPIO_NUM_4换为GPIO_NUM_5就行如果不写则一行而是之间都写GPIO_NUM_4此时就要修改很多位置了。gpio_config_tio_conf{// 先填一张配置表.pin_bit_mask(1ULLLED1_GPIO),// 选择要配置哪个引脚.modeGPIO_MODE_OUTPUT,// 设为输出模式要往外送电.pull_up_enGPIO_PULLUP_DISABLE,// 不用内部上拉.pull_down_enGPIO_PULLDOWN_DISABLE,// 不用内部下拉.intr_typeGPIO_INTR_DISABLE,// 不用中断};这部分是对引脚进行配置.pin_bit_mask (1ULL LED1_GPIO),决定我们使用哪个引脚这里我们使用LED1_GPIO也就是我们前面定义的GPIO4).mode GPIO_MODE_OUTPUT,这里决定引脚的模式为输出模式ESP32向外输出高低电平信号信号是发出去的所以为输出模式gpio_config(io_conf);前面我们将引脚配置好了这里就提交使用gpio_set_level(LED1_GPIO,1);// 输出高电平 3.3V灯亮这里用于控制引脚电平的输出其中LED1_GPIO就是我们配置的引脚1就是高电平也就是GPIO4输出3.3V电压另外如果使用0就是低电平GPIO4此时输出电压为0V。2.4 编译、烧录、看效果把 USB 线插到开发板的FUSB 口调试 / 下载口不是 HUSB另一端插电脑。看 VS Code 底部工具栏③ 位置选择正确的 COM 口插拔一次看哪个出现的通常就是它④ 位置确认为esp32p4。点击底部的⚒ 编译Build等待右下角提示Build complete。第一次编译要花几分钟。点击⚡ 烧录Flash弹出烧录方式时选UART等待Flash done。看板子红色 LED 常亮。灯亮了实验一成功。如果想让板子立刻运行新程序烧录完成后按一下板子上的RST / EN复位键多数情况下烧录会自动复位。2.5 问题排查烧录代码后如果LED不亮首先需要检查接线是否正确比如IO引脚是否接错GND是否没接另外也可能我们使用的模块是共阳极的需要低电平才能点亮此时我们可以把gpio_set_level(LED1_GPIO, 1)改成0再烧录一次在修改完代码后如果烧录没有按照代码编写逻辑变化还是维持旧代码功能首先检查代码修改后是否保存第二代码修改后一定先 ⚒ 编译再 ⚡ 烧录。3. 案例二用 delay() 实现流水灯效果实现了一个灯常亮后我们现在使用3个LED灯让其依次亮灭实现流水灯的效果当然也可以更多的LED灯效果会更加好。流水灯就是按特定的顺序和时间间隔依次点亮和点亮利用人眼的视觉暂留效果产生多个像流水连续移动的动态视觉错觉。3.1打开工程使用课程提供的led_chaser工程压缩包解压到纯英文路径下用 VS Code 直接打开工程文件夹也可以。led_chaser项目下载3.2 代码#includefreertos/FreeRTOS.h#includefreertos/task.h//前两行引入 FreeRTOS 的头文件提供延时函数 vTaskDelay的调用#includestdint.h//提供了 uint32_t 这类“标准尺寸”的数据类型后面定义延时函数时会用到。和前一个代码一样这里也相当于提供工具箱其中前两行引入 FreeRTOS 的头文件提供延时函数 vTaskDelay的调用第三行为uint32_t类型提供定义。#defineLED_NUM3#defineLED1_GPIOGPIO_NUM_4这里同样是全局定义。LED_NUM表示灯的总数好处是以后如果增加到 5 盏灯只要把3改成5、再多定义几个引脚外号程序里其他地方一个字都不用改——因为后面所有循环都是围绕LED_NUM自动展开的。staticconstgpio_num_tled_pins[LED_NUM]{LED1_GPIO,LED2_GPIO,LED3_GPIO};这里定义了一个数组在后续流水灯实现时我们将借助这个数组实现LED的切换如下gpio_set_level(led_pins[i],0);gpio_set_level(led_pins[index],1);当然也可也不定义数组但是此时我们就需要每一个灯定义一个变量如下gpio_num_tled1GPIO_NUM_4;gpio_num_tled2GPIO_NUM_5;gpio_num_tled3GPIO_NUM_6;另外此时的led1、led2、led3作为3个新名字其中的123不能再使用循环中的i代替实现LED的切换故每一个灯都需要单独写一行这里我们只使用3个灯代码相对较短但是有时为了流水灯效果更佳我们可能使用10个甚至20个LED那这种情况下就只能使用数组的方式了。staticvoiddelay(uint32_tms)// 自己组装一个定时器{vTaskDelay(pdMS_TO_TICKS(ms));}ESP-IDF 里没有现成的delay(ms)函数只有比较繁琐的vTaskDelay(pdMS_TO_TICKS(ms))。所以这里我们自己封装了一个外面看起来就是一个简单好用的delay使用delay(ms)其实是调用内部复杂的写法。注意vTaskDelay在延时期间会让 CPU 去干别的事是“先歇一会儿有活随时叫我”而不是傻站着空等这样系统不会因为长时间空转而出问题。voidapp_main(void){gpio_config_tio_conf{.pin_bit_mask(1ULLLED1_GPIO)|(1ULLLED2_GPIO)|(1ULLLED3_GPIO),.modeGPIO_MODE_OUTPUT,// 设为输出模式要往外送电.pull_up_enGPIO_PULLUP_DISABLE,// 不用内部上拉.pull_down_enGPIO_PULLDOWN_DISABLE,// 不用内部下拉.intr_typeGPIO_INTR_DISABLE,// 不用中断};gpio_config(io_conf);.pin_bit_mask (1ULL LED1_GPIO) | (1ULL LED2_GPIO) | (1ULL LED3_GPIO),这里和案例一一样只是增加了两个引脚其中|为按位或。intindex0;// 记录当前轮到第几盏灯while(1){// 死循环让流水一直流下去for(inti0;iLED_NUM;i){gpio_set_level(led_pins[i],0);// 第一步先把所有灯全部熄灭}gpio_set_level(led_pins[index],1);// 第二步只点亮名单上第 index 盏灯index(index1)%LED_NUM;// 第三步轮到下一盏delay(500);// 第四步停 500 毫秒再继续}}这里实现了LED的依次点亮和熄灭LED的切换就是通过前面数组实现的实现流程如图。3.3 现象上传代码后可以看到红绿黄3个LED灯依次亮起熄灭由于视觉暂留效果可以看出LED灯具备流水效果。3.4 问题排查如果增加更多灯LED不亮了这是因为LED数量的增加会带来更多的电源消耗单片机不足以维持大量LED的工作如果需要控制多颗LED灯建议通过独立电源模块供电只有主板供电情况下建议不要超过10颗。4. 小结4.1 总结在后续GPIO的应用中比如继电器开关、电机模块的驱动等我们均可以参照以下架构图进行配置。5. 参考文档ESP-IDF 编程指南中文GPIO 驱动 API 说明