XL9555 芯片使用
XL9555 芯片使用
·
XL9555 芯片使用
XL9555 是一款常用的 I/O 扩展芯片,通过 I²C 接口与主控芯片通信,可以扩展额外的输入输出引脚。以下是 XL9555 芯片的使用方法和注意事项:
芯片介绍
1. XL9555 芯片概述
- 功能:提供 16 个可配置的 GPIO 引脚(8 个 Port 0 和 8 个 Port 1)。
- 通信接口:支持 I²C 通信,默认地址为
0x20
(可通过地址引脚配置)。 - 电源电压:通常为 2.3V 至 5.5V。
- 应用场景:用于需要扩展 GPIO 的嵌入式系统,如按键检测、LED 控制、传感器接口等。
2. 引脚说明
- SCL:I²C 时钟线。
- SDA:I²C 数据线。
- A0, A1, A2:地址配置引脚,用于设置 I²C 设备地址。
- P00-P07:Port 0 的 8 个 GPIO 引脚。
- P10-P17:Port 1 的 8 个 GPIO 引脚。
- RESET:复位引脚(低电平有效)。
- INT:中断输出引脚(可选功能)。
3. I²C 地址配置
XL9555 的 I²C 地址由 A0、A1、A2 引脚的电平决定:
- 默认地址:
0x20
(A0=A1=A2=0)。 - 地址计算公式:
0x20 + (A2 << 2) + (A1 << 1) + A0
。 - 例如:A2=1, A1=0, A0=1,则地址为
0x20 + 4 + 0 + 1 = 0x25
。
4. 寄存器说明
XL9555 通过寄存器配置 GPIO 的状态和方向:
- 输入端口寄存器(Input Port):
0x00
:Port 0 输入状态。0x01
:Port 1 输入状态。
- 输出端口寄存器(Output Port):
0x02
:Port 0 输出状态。0x03
:Port 1 输出状态。
- 配置寄存器(Configuration Register):
0x06
:Port 0 方向配置(0=输出,1=输入)。0x07
:Port 1 方向配置(0=输出,1=输入)。
5. 使用步骤
硬件连接
- 将 XL9555 的 SCL 和 SDA 引脚连接到主控芯片的 I²C 接口。
- 配置 A0、A1、A2 引脚设置 I²C 地址。
- 连接 RESET 引脚(通常上拉至高电平)。
- 将 P00-P07 和 P10-P17 连接到外部设备(如 LED、按键等)。
软件配置
-
初始化 I²C 接口:
- 配置主控芯片的 I²C 时钟频率和引脚。
-
设置 GPIO 方向:
-
向配置寄存器写入数据,设置引脚为输入或输出。
-
示例:将 Port 0 设置为输出,Port 1 设置为输入:
uint8_t config_port0 = 0x00; // Port 0 输出 uint8_t config_port1 = 0xFF; // Port 1 输入 i2c_write(XL9555_ADDR, 0x06, &config_port0, 1); // 配置 Port 0 i2c_write(XL9555_ADDR, 0x07, &config_port1, 1); // 配置 Port 1
-
-
控制 GPIO 输出:
-
向输出端口寄存器写入数据,控制引脚电平。
-
示例:设置 Port 0 的 P00 为高电平:
uint8_t output_port0 = 0x01; // P00 = 1 i2c_write(XL9555_ADDR, 0x02, &output_port0, 1);
-
-
读取 GPIO 输入:
-
从输入端口寄存器读取数据,获取引脚状态。
-
示例:读取 Port 1 的状态:
uint8_t input_port1; i2c_read(XL9555_ADDR, 0x01, &input_port1, 1);
-
6. 示例代码
以下是一个简单的 XL9555 使用示例(基于 Arduino):
#include <Wire.h>
#define XL9555_ADDR 0x20 // 默认地址
void setup() {
Wire.begin();
Serial.begin(9600);
// 配置 Port 0 为输出,Port 1 为输入
i2c_write(XL9555_ADDR, 0x06, 0x00); // Port 0 输出
i2c_write(XL9555_ADDR, 0x07, 0xFF); // Port 1 输入
}
void loop() {
// 设置 Port 0 的 P00 为高电平
i2c_write(XL9555_ADDR, 0x02, 0x01);
// 读取 Port 1 的状态
uint8_t port1_state = i2c_read(XL9555_ADDR, 0x01);
Serial.println(port1_state, BIN);
delay(1000);
}
void i2c_write(uint8_t addr, uint8_t reg, uint8_t data) {
Wire.beginTransmission(addr);
Wire.write(reg);
Wire.write(data);
Wire.endTransmission();
}
uint8_t i2c_read(uint8_t addr, uint8_t reg) {
Wire.beginTransmission(addr);
Wire.write(reg);
Wire.endTransmission();
Wire.requestFrom(addr, 1);
return Wire.read();
}
7. 注意事项
- I²C 上拉电阻:确保 SCL 和 SDA 引脚接上拉电阻(通常 4.7kΩ)。
- 电源滤波:在 VCC 和 GND 之间添加滤波电容(如 0.1μF)。
- 复位信号:上电时确保 RESET 引脚为高电平。
- 地址冲突:避免 I²C 地址与其他设备冲突。
通过以上步骤和代码示例,可以快速上手使用 XL9555 扩展 GPIO,满足项目需求。
在 XL9555 中,中断引脚(INT
)可以用于检测输入引脚的状态变化,从而减少主控芯片的轮询开销。以下是基于 ESP32-IDF 的示例代码,增加了对 XL9555 中断引脚的使用。
1. 硬件连接
- ESP32 与 XL9555 的连接:
- ESP32 GPIO 引脚 -> XL9555 引脚
- SCL (默认 GPIO 22) -> SCL
- SDA (默认 GPIO 21) -> SDA
- GND -> GND
- 3.3V -> VCC
- XL9555 的
INT
引脚 -> ESP32 的 GPIO 引脚(例如 GPIO 4)。
- XL9555 的 A0、A1、A2 引脚接地(默认地址
0x20
)。
2. 代码实现
以下代码演示了如何使用 XL9555 的中断功能来检测输入引脚的状态变化。
#include <stdio.h>
#include "driver/i2c.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#define XL9555_ADDR 0x20 // XL9555 默认地址
#define I2C_MASTER_SCL_IO 22 // I2C 时钟引脚
#define I2C_MASTER_SDA_IO 21 // I2C 数据引脚
#define I2C_MASTER_FREQ_HZ 100000 // I2C 时钟频率
#define I2C_MASTER_PORT I2C_NUM_0 // I2C 端口
#define XL9555_INT_GPIO 4 // XL9555 中断引脚连接的 GPIO
static const char *TAG = "XL9555_INTERRUPT_EXAMPLE";
static QueueHandle_t gpio_evt_queue = NULL;
// I2C 初始化
static void i2c_master_init() {
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_MASTER_SDA_IO,
.scl_io_num = I2C_MASTER_SCL_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
};
i2c_param_config(I2C_MASTER_PORT, &conf);
i2c_driver_install(I2C_MASTER_PORT, conf.mode, 0, 0, 0);
}
// I2C 写数据
static esp_err_t i2c_write(uint8_t reg_addr, uint8_t data) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (XL9555_ADDR << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, reg_addr, true);
i2c_master_write_byte(cmd, data, true);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_PORT, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
// I2C 读数据
static esp_err_t i2c_read(uint8_t reg_addr, uint8_t *data) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (XL9555_ADDR << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, reg_addr, true);
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (XL9555_ADDR << 1) | I2C_MASTER_READ, true);
i2c_master_read_byte(cmd, data, I2C_MASTER_NACK);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_PORT, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
// GPIO 中断处理函数
static void IRAM_ATTR gpio_isr_handler(void *arg) {
uint32_t gpio_num = (uint32_t) arg;
xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}
// 初始化 GPIO 中断
static void gpio_interrupt_init() {
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << XL9555_INT_GPIO),
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_NEGEDGE, // 下降沿触发
};
gpio_config(&io_conf);
gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
gpio_install_isr_service(0);
gpio_isr_handler_add(XL9555_INT_GPIO, gpio_isr_handler, (void *) XL9555_INT_GPIO);
}
void app_main() {
// 初始化 I2C
i2c_master_init();
ESP_LOGI(TAG, "I2C initialized");
// 配置 Port 0 为输出,Port 1 为输入
i2c_write(0x06, 0x00); // Port 0 输出
i2c_write(0x07, 0xFF); // Port 1 输入
ESP_LOGI(TAG, "Port 0 set as output, Port 1 set as input");
// 设置 Port 0 的 P00 为高电平
i2c_write(0x02, 0x01); // P00 = 1
ESP_LOGI(TAG, "Set P00 to HIGH");
// 初始化 GPIO 中断
gpio_interrupt_init();
ESP_LOGI(TAG, "GPIO interrupt initialized");
uint32_t io_num;
while (1) {
if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
ESP_LOGI(TAG, "Interrupt detected on GPIO %d", io_num);
// 读取 Port 1 的状态
uint8_t port1_state;
i2c_read(0x01, &port1_state);
ESP_LOGI(TAG, "Port 1 state: 0x%02X", port1_state);
}
}
}
3. 代码说明
- GPIO 中断初始化:
- 使用
gpio_config
配置中断引脚为输入模式,并设置为下降沿触发。 - 使用
gpio_install_isr_service
和gpio_isr_handler_add
注册中断服务函数。
- 使用
- 中断处理函数:
- 在中断发生时,将 GPIO 编号发送到队列中。
- 主循环:
- 通过队列接收中断事件,并读取 XL9555 的输入状态。
5. 输出结果
- 当 XL9555 的输入引脚状态发生变化时,会触发中断。
- 程序会读取 Port 1 的状态并通过串口输出。
6. 注意事项
- 中断引脚配置:确保 XL9555 的
INT
引脚正确连接到 ESP32 的 GPIO。 - 中断触发方式:根据需求选择上升沿、下降沿或电平触发。
- 去抖动处理:如果输入信号有抖动,可以在硬件或软件中添加去抖动逻辑。
通过以上代码,可以实现 XL9555 的中断功能,减少主控芯片的轮询开销,提高系统效率。

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)