03_GPIO输入_按键控制RGB
GPIO 输入按键控制 RGB学习目标在 GPIO 输出基础上加入输入形成“读取按键—判断边沿—更新状态—控制 RGB”的最小交互系统。按键引脚按键GPIOKEY1GPIO2KEY2GPIO45KEY3GPIO46实际有效电平和上下拉方式必须结合原理图确认。教程中通过gpio_get_level()读取状态再在软件中判断按下与释放。初始化输入引脚gpio_config_tio{.pin_bit_mask(1ULLKEY_1_PIN)|(1ULLKEY_2_PIN)|(1ULLKEY_3_PIN),.modeGPIO_MODE_INPUT,.pull_up_enGPIO_PULLUP_ENABLE,.pull_down_enGPIO_PULLDOWN_DISABLE,.intr_typeGPIO_INTR_DISABLE,};ESP_ERROR_CHECK(gpio_config(io));封装后的接口可以保持简单voidkey_init(void);intkey_get_level(gpio_num_tkey_pin);轮询与边沿判断如果只判断“现在是否按下”主循环每跑一次都会触发动作。更合理的方法是保存上一次电平只在状态发生变化时处理if(nowPRESSEDlastRELEASED){// 一次新的按下事件}lastnow;这种写法本质上是在软件里检测边沿。它比单纯检测电平更适合“按一下切换一次颜色”的需求。消抖机械按键在按下和释放瞬间会抖动几毫秒内可能出现多次高低变化。最简单的软件消抖方式是检测到可能按下延时 1020 ms再读一次状态仍然一致才确认等待释放避免长按重复触发。轮询周期不宜太长否则按键感觉迟钝也不宜毫无延时地死循环读取否则白白占用 CPU。主程序状态设计可以让三个按键分别切换 R、G、B 三个位color^RGB_COLOR_RED;// 翻转红色位rgb_set_color(color);异或非常适合“开/关切换”原来为 0 就变 1原来为 1 就变 0。这样三个按键能组合出 8 种状态。我的理解输入系统真正困难的不是“读到 0 或 1”而是判断这个 0 或 1代表什么事件。电平、边沿、长按、双击其实是不同层次的抽象。教程先用轮询建立直觉后面触摸章节再用中断提高响应效率。易错点上拉、下拉配置与外部电路冲突。把 GPIO45、GPIO46 等特殊引脚用于其他用途前没有查看芯片/开发板限制。没有消抖一次按下被识别成多次。在按下分支中持续阻塞导致其他功能无法运行。忘记保存上次状态导致长按时颜色高速切换。新手实操三个按键分别切换 R、G、B第 1 步以上一章工程为基础复制02_gpio_rgb为新工程并删除复制后的build目录或者创建新工程后复制rgb_set组件。不要复制旧sdkconfig后忘记目标芯片进入新工程先确认idf.py set-target esp32s3mkdircomponents idf.py-Ccomponents create-component key_set第 2 步定义按键接口components/key_set/include/key_set.h#pragmaonce#includedriver/gpio.h#defineKEY_1_PINGPIO_NUM_2#defineKEY_2_PINGPIO_NUM_45#defineKEY_3_PINGPIO_NUM_46voidkey_init(void);intkey_get_level(gpio_num_tpin);第 3 步初始化输入 GPIOcomponents/key_set/key_set.c#includekey_set.h#includeesp_err.hvoidkey_init(void){gpio_config_tcfg{.pin_bit_mask(1ULLKEY_1_PIN)|(1ULLKEY_2_PIN)|(1ULLKEY_3_PIN),.modeGPIO_MODE_INPUT,.pull_up_enGPIO_PULLUP_ENABLE,.pull_down_enGPIO_PULLDOWN_DISABLE,.intr_typeGPIO_INTR_DISABLE,};ESP_ERROR_CHECK(gpio_config(cfg));}intkey_get_level(gpio_num_tpin){returngpio_get_level(pin);}key_set/CMakeLists.txt使用REQUIRES esp_driver_gpio。如果教程板原理图已经提供外部上下拉应按电路修改内部上下拉配置。第 4 步先打印原始电平不要一开始就写复杂控制逻辑。先在主程序里每 200 ms 打印三个电平确认松开和按下分别是什么值ESP_LOGI(KEY,%d %d %d,key_get_level(KEY_1_PIN),key_get_level(KEY_2_PIN),key_get_level(KEY_3_PIN));教程接法通常是松开为 1、按下为 0。若实测相反后续PRESSED_LEVEL应改为 1。第 5 步加入按下沿和消抖#definePRESSED_LEVEL0staticboolkey_pressed(gpio_num_tpin,int*last){intnowgpio_get_level(pin);bool pressed(nowPRESSED_LEVEL*last!PRESSED_LEVEL);if(pressed){vTaskDelay(pdMS_TO_TICKS(15));pressedgpio_get_level(pin)PRESSED_LEVEL;}*lastnow;returnpressed;}这是适合入门实验的简单消抖。正式项目若有多键、长按和双击需求建议使用统一按键扫描任务和状态机。第 6 步组合 RGB 状态在app_main()中保存uint8_t color三个按键分别异或一个颜色位if(key_pressed(KEY_1_PIN,last1))color^RGB_COLOR_RED;if(key_pressed(KEY_2_PIN,last2))color^RGB_COLOR_GREEN;if(key_pressed(KEY_3_PIN,last3))color^RGB_COLOR_BLUE;rgb_set_color(color);vTaskDelay(pdMS_TO_TICKS(10));初始化时将last1/2/3读取为当前电平避免设备启动时误判一次按下。第 7 步编译与故障排查烧录后每按一次按键对应颜色通道应切换开关多个通道可以组合颜色。若一次按下切换多次把消抖延时适当增加到 2030 ms并确认循环中存在短延时。若某个键永远为同一电平检查引脚定义、焊接和上下拉。