ESP32 - ESP-IDF 实战:AW9523 16路IO扩展与256级调光驱动详解

张开发
2026/4/17 10:28:58 15 分钟阅读

分享文章

ESP32 - ESP-IDF 实战:AW9523 16路IO扩展与256级调光驱动详解
1. ESP32的IO扩展困境与AW9523的破局之道做ESP32开发的朋友应该都深有体会这颗芯片虽然性能强大但GPIO资源实在捉襟见肘。我去年做一个智能家居中控项目时光是LED指示灯、按键输入、传感器接口就把所有GPIO用完了更别提还要接显示屏。这时候外扩IO芯片就成了必选项。市面上常见的IO扩展芯片主要有TCA9554、XL9555、PCA9557这几款我都实际用过。TCA9554虽然乐鑫官方提供了驱动但只有8个IO而且淘宝上基本都是翻新货我买过三次有两批是坏的。XL9555的16路IO很诱人但零售渠道价格虚高。PCA9557算是折中选择但同样只有8路IO。直到发现AW9523这个宝藏芯片所有问题迎刃而解。1块钱左右的价格16路IO每路驱动能力高达37mA最惊艳的是支持256级线性调光。这意味着它不仅能当普通GPIO用还能直接驱动LED实现专业级调光效果省去了额外的PWM驱动电路。2. AW9523硬件设计要点2.1 典型电路连接AW9523采用I2C接口硬件连接非常简单。这是我的参考设计VDD接3.3V注意虽然芯片支持5V但ESP32的GPIO是3.3V电平SDA接ESP32的GPIO17SCL接GPIO18ADDR引脚决定I2C地址接地为0x58接VDD为0x5B所有GPIO口都内置了上拉电阻硬件设计时可以省去外部上拉特别注意P0端口的工作模式选择推挽模式适合直接驱动LED无需外接电阻开漏模式需要外接上拉电阻适合电平转换场景2.2 电流配置技巧AW9523最强大的功能就是可编程电流输出。通过CTRL寄存器的D1:D0位可以设置四个档位的最大电流0037mA默认0127.75mA1018.5mA119.25mA实际使用中要注意普通LED的极限电流通常是20mA建议设置为18.5mA档驱动多个LED时要注意总功耗不超过芯片限制调光精度会随最大电流设置而变化需要权衡亮度和精度3. ESP-IDF驱动开发详解3.1 I2C初始化先来看基础通信部分的实现。ESP-IDF的I2C驱动已经封装得很好我们只需要配置参数esp_err_t aw9523_i2c_init(void) { int i2c_master_port AW9523_I2C_MASTER_NUM; i2c_config_t conf { .mode I2C_MODE_MASTER, .sda_io_num AW9523_SDA_IO, .scl_io_num AW9523_SCL_IO, .sda_pullup_en GPIO_PULLUP_ENABLE, .scl_pullup_en GPIO_PULLUP_ENABLE, .master.clk_speed AW9523_I2C_MASTER_FREQ_HZ, }; i2c_param_config(i2c_master_port, conf); return i2c_driver_install(i2c_master_port, conf.mode, AW9523_I2C_MASTER_RX_BUF_DISABLE, AW9523_I2C_MASTER_TX_BUF_DISABLE, 0); }这里有个坑要注意ESP32的I2C引脚内部上拉电阻约40kΩ在长距离传输时可能不够建议在硬件设计时预留外部上拉电阻位置。3.2 寄存器操作基础所有功能都是通过读写寄存器实现的基础读写函数如下esp_err_t aw9523_reg_read(uint8_t reg_addr, uint8_t *data, size_t len) { return i2c_master_write_read_device(AW9523_I2C_MASTER_NUM, AW9523_I2C_ADDR, reg_addr, 1, data, len, AW9523_I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); } esp_err_t aw9523_reg_write_byte(uint8_t reg_addr, uint8_t data) { uint8_t write_buf[2] {reg_addr, data}; return i2c_master_write_to_device(AW9523_I2C_MASTER_NUM, AW9523_I2C_ADDR, write_buf, sizeof(write_buf), AW9523_I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); }调试时建议先读取芯片ID0x23验证通信是否正常uint8_t aw9523_read_ID(void) { uint8_t data 0x00; esp_err_t ret aw9523_reg_read(AW9523_REG_ID, data, sizeof(data)); if (ret ! ESP_OK) { ESP_LOGE(TAG, Read ID failed); } return data; }4. 高级功能开发实战4.1 GPIO模式应用配置P1端口为GPIO输出模式// 设置P1为GPIO模式 aw9523_set_port_gpio_or_led(AW9523_PORT_1, 0xFF); // 配置为输出模式 aw9523_set_port_inout(AW9523_PORT_1, 0x00); // 输出交替高低电平 aw9523_set_port_level(AW9523_PORT_1, 0xAA); // 10101010GPIO输入模式同样简单// 设置P0_0为输入模式 aw9523_set_pin_inout(AW9523_PORT_0, AW9523_PX_0, AW9523_MODE_IN); // 读取输入状态 uint8_t p0_state aw9523_read_level(AW9523_PORT_0); if(p0_state 0x01) { ESP_LOGI(TAG, P0_0 is high); }4.2 LED调光实战AW9523最强大的功能就是256级线性调光。实现呼吸灯效果void led_breath_task(void *arg) { aw9523_set_port_gpio_or_led(AW9523_PORT_0, 0x00); // LED模式 aw9523_set_led_max_current(AW9523_CURR_18_5M); // 设置18.5mA最大电流 uint8_t duty 0; int8_t step 1; while(1) { aw9523_set_port_duty(AW9523_PORT_0, duty); duty step; if(duty 0 || duty 255) step -step; vTaskDelay(10 / portTICK_PERIOD_MS); } }更精细的单LED控制// 设置P0_1引脚LED亮度为50% aw9523_set_pin_duty(AW9523_PORT_0, AW9523_PX_1, 128); // 渐变熄灭P0_2 for(int i255; i0; i--) { aw9523_set_pin_duty(AW9523_PORT_0, AW9523_PX_2, i); vTaskDelay(5 / portTICK_PERIOD_MS); }5. 常见问题与调试技巧5.1 I2C通信失败排查首先用逻辑分析仪抓取I2C波形确认是否有起始信号检查地址是否正确默认0x5B测量SCL/SDA电压确保是3.3V电平尝试降低I2C频率如100kHz检查上拉电阻通常4.7kΩ5.2 LED亮度异常处理确认最大电流设置寄存器CTRL的值检查LED极性是否正确阴极接AW9523测量实际电流是否与预期相符长时间大电流工作要注意散热5.3 电源设计建议当驱动多个LED时建议单独给AW9523供电电源输入端加100μF以上电容稳压每个LED引脚建议加10Ω电阻限流即使芯片有限流功能大电流场景下PCB走线要足够宽6. 进阶应用案例6.1 智能背光控制用AW9523驱动LCD背光实现自动亮度调节void backlight_control_task(void *arg) { // 初始化光传感器和AW9523 light_sensor_init(); aw9523_init(); while(1) { float lux read_light_sensor(); uint8_t duty calculate_duty(lux); // 根据光照计算亮度值 aw9523_set_port_duty(AW9523_PORT_0, duty); vTaskDelay(1000 / portTICK_PERIOD_MS); } }6.2 多路LED矩阵控制利用16路IO实现8x8 LED矩阵控制void led_matrix_display() { // 行扫描列数据驱动 uint8_t pattern[8] {0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18}; while(1) { for(int row0; row8; row) { // 设置当前行导通P1端口 aw9523_set_port_level(AW9523_PORT_1, 1row); // 输出列数据P0端口 aw9523_set_port_level(AW9523_PORT_0, pattern[row]); vTaskDelay(2 / portTICK_PERIOD_MS); } } }6.3 组合按键检测利用中断功能实现低功耗按键检测void key_interrupt_handler() { uint8_t p1_state aw9523_read_level(AW9523_PORT_1); // 解码按键状态 // ... } void key_init() { // 配置P1端口为输入中断使能 aw9523_set_port_inout(AW9523_PORT_1, 0xFF); aw9523_set_port_interrupt(AW9523_PORT_1, 0x00); // 在ESP32上配置GPIO中断 gpio_set_intr_type(AW9523_INT_PIN, GPIO_INTR_NEGEDGE); gpio_isr_handler_add(AW9523_INT_PIN, key_interrupt_handler, NULL); }

更多文章