ESP32通过I2C驱动PCA9557IO扩展芯片

ESP32通过I2C驱动PCA9557IO扩展芯片前言 ESP32 自带的 IO 管脚比较有限 这个时候我们就需要使用一些 IO 扩展芯片扩展我们的 IO 今天就介绍一款使用 I2C 接口扩展 8 个 IO 的芯片 PCA9557 PCA 9557 芯片介绍 PCA9557 是一款硅 CMOS 电路 为 SMBus 和 I C 总线应用提供并行输入 输出扩展 PCA9557 由 8 位输入端口寄存器

大家好,我是讯享网,很高兴认识大家。

前言

ESP32自带的IO管脚比较有限,这个时候我们就需要使用一些IO扩展芯片扩展我们的IO,今天就介绍一款使用I2C接口扩展8个IO的芯片 PCA9557

PCA 9557芯片介绍

PCA9557是一款硅CMOS电路,为SMBus和I²C总线应用提供并行输入/输出扩展。PCA9557由8位输入端口寄存器、8位输出端口寄存器和I²C总线/SMBus接口组成。具有低电流消耗和高阻抗开漏输出引脚IO0。
通过写入I/O配置寄存器,系统主器件可将PCA9557的I/O用作输入或输出。通过写入高电平有效的极性反转寄存器,系统主器件还可反转PCA9557输入。最后,通过在复位输入中加入低电平,系统主器件可在超时时使PCA9557复位。
上电复位会将寄存器设为其默认状态并初始化I²C总线/SMBus状态机。1引脚可引发相同的复位/初始化而无需使部件断电。
原理图如下:
pca9557原理图
讯享网

代码编写

在 i2c_self_test的例程上修改

  1. 在 i2c_self_test–main文件夹下创建 bsp_pca9557.c和bsp_pca9557.h文件
    增加pca文件

增加文件后,然后将 CMakeList.txt 文件修改为:

  1. 根据 pca9557 数据手册上读写的要求,编写pca9557读写寄存器的函数,并在读写寄存器函数的基础上封装设置IO,读取IO的函数,具体如下:
  • bsp_pca9557.c
#include "bsp_pca9557.h" #include <stdio.h> #include "esp_log.h" #include "driver/i2c.h" #define PCA9557_I2C_MASTER_SCL_IO 2 /*!< gpio number for I2C master clock */ #define PCA9557_I2C_MASTER_SDA_IO 15 /*!< gpio number for I2C master data */ #define PCA9557_I2C_MASTER_NUM I2C_NUM_1 /*!< I2C port number for master dev */ #define PCA9557_I2C_MASTER_FREQ_HZ /*!< I2C master clock frequency */ #define PCA9557_I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ #define PCA9557_I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ /* * 名 称: bsp_Pca9557Init * 功 能: PCA9577 I2C初始化函数 * 入口参数: 无 * 出口参数: 无 * 作  者: Roger-WY * 创建日期: 2021-05-08 * 修 改: * 修改日期: * 备 注: */ esp_err_t bsp_Pca9557Init(void) { 
    int i2c_master_port = PCA9557_I2C_MASTER_NUM; i2c_config_t conf; conf.mode = I2C_MODE_MASTER; conf.sda_io_num = PCA9557_I2C_MASTER_SDA_IO; conf.sda_pullup_en = GPIO_PULLUP_ENABLE; conf.scl_io_num = PCA9557_I2C_MASTER_SCL_IO; conf.scl_pullup_en = GPIO_PULLUP_ENABLE; conf.master.clk_speed = PCA9557_I2C_MASTER_FREQ_HZ; i2c_param_config(i2c_master_port, &conf); return i2c_driver_install(i2c_master_port, conf.mode, PCA9557_I2C_MASTER_RX_BUF_DISABLE, PCA9557_I2C_MASTER_TX_BUF_DISABLE, 0); } /* * 名 称: bsp_Pca9557WriterReg * 功 能: PCA9577 写寄存器 * 入口参数: u8I2cSlaveAddr : PCA9557的I2C地址 u8Cmd : 命令寄存器 u8Value : 写入寄存器的值 * 出口参数: esp_err_t * 作  者: Roger-WY * 创建日期: 2021-05-08 * 修 改: * 修改日期: * 备 注: */ esp_err_t bsp_Pca9557WriterReg(uint8_t u8I2cSlaveAddr,uint8_t u8Cmd,uint8_t u8Value) { 
    i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (u8I2cSlaveAddr << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN); i2c_master_write_byte(cmd, u8Cmd, ACK_CHECK_EN); i2c_master_write_byte(cmd, u8Value, ACK_CHECK_EN); i2c_master_stop(cmd); esp_err_t ret = i2c_master_cmd_begin(PCA9557_I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS); i2c_cmd_link_delete(cmd); return ret; } /* * 名 称: bsp_Pca9557ReadReg * 功 能: PCA9577 读寄存器 * 入口参数: u8I2cSlaveAddr : PCA9557的I2C地址 u8Cmd : 命令寄存器 pBuff : 寄存器值的缓存数组指针 u8Cnt : 读取的寄存器个数 * 出口参数: esp_err_t * 作  者: Roger-WY * 创建日期: 2021-05-08 * 修 改: * 修改日期: * 备 注: */ esp_err_t bsp_Pca9557ReadReg(uint8_t u8I2cSlaveAddr,uint8_t u8Cmd,uint8_t *pBuff,uint8_t u8Cnt) { 
    esp_err_t ret ; i2c_cmd_handle_t wr_cmd = i2c_cmd_link_create(); i2c_master_start(wr_cmd); i2c_master_write_byte(wr_cmd, (u8I2cSlaveAddr << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN); i2c_master_write_byte(wr_cmd, u8Cmd, ACK_CHECK_EN); i2c_master_stop(wr_cmd); ret = i2c_master_cmd_begin(PCA9557_I2C_MASTER_NUM, wr_cmd, 1000 / portTICK_RATE_MS); i2c_cmd_link_delete(wr_cmd); if (ret != ESP_OK) { 
    return ret; } //vTaskDelay(30 / portTICK_RATE_MS); i2c_cmd_handle_t rd_cmd = i2c_cmd_link_create(); i2c_master_start(rd_cmd); i2c_master_write_byte(rd_cmd, (u8I2cSlaveAddr << 1) | I2C_MASTER_READ, ACK_CHECK_EN); i2c_master_read(rd_cmd, pBuff, u8Cnt, I2C_MASTER_LAST_NACK); i2c_master_stop(rd_cmd); ret = i2c_master_cmd_begin(PCA9557_I2C_MASTER_NUM, rd_cmd, 1000 / portTICK_RATE_MS); i2c_cmd_link_delete(rd_cmd); return ret; } /* * 名 称: bsp_PcaSetIoDirection * 功 能: PCA9577 设置IO方向 * 入口参数: pinx : pin脚名称 newMode : 输入或者输出 * 出口参数: esp_err_t * 作  者: Roger-WY * 创建日期: 2021-05-08 * 修 改: * 修改日期: * 备 注: */ esp_err_t bsp_PcaSetIoDirection(snPinName_t pinx,snPinMode_t newMode) { 
    esp_err_t ret ; uint8_t current_mode = 0; ret = bsp_Pca9557ReadReg(PCA9557_I2C_SLAVE_ADDR, PCA9557_CONTROL_REG_3, &current_mode, 1); if (ret != ESP_OK) { 
    return ret; } if(newMode == IO_OUTPUT) { 
    current_mode &= ~(1 << pinx); } else { 
    current_mode |= (1 << pinx); } ret = bsp_Pca9557WriterReg(PCA9557_I2C_SLAVE_ADDR, PCA9557_CONTROL_REG_3, current_mode); return ret; } /* * 名 称: bsp_PcaSetIoStatus * 功 能: PCA9577 设置IO状态 * 入口参数: pinx : pin脚名称 snPinState_t : 高电平或者低电平 * 出口参数: esp_err_t * 作  者: Roger-WY * 创建日期: 2021-05-08 * 修 改: * 修改日期: * 备 注: */ esp_err_t bsp_PcaSetIoStatus(snPinName_t pinx,snPinState_t newState) { 
    esp_err_t ret ; uint8_t current_state = 0; ret = bsp_Pca9557ReadReg(PCA9557_I2C_SLAVE_ADDR, PCA9557_CONTROL_REG_1, &current_state, 1); if (ret != ESP_OK) { 
    return ret; } if(newState == IO_LOW) { 
    current_state &= ~(1 << pinx); } else { 
    current_state |= (1 << pinx); } ret = bsp_Pca9557WriterReg(PCA9557_I2C_SLAVE_ADDR, PCA9557_CONTROL_REG_1, current_state); return ret; } /* * 名 称: bsp_PcaSetInputPolarity * 功 能: PCA9577 设置IO输入的极性是否翻转 * 入口参数: pinx : pin脚名称 newPolarity : 极性是否翻转 * 出口参数: esp_err_t * 作  者: Roger-WY * 创建日期: 2021-05-08 * 修 改: * 修改日期: * 备 注:默认bit0-bit3极性不翻转 bit4-bit7极性翻转 */ esp_err_t bsp_PcaSetInputPolarity(snPinName_t pinx,snPinPolarity_t newPolarity) { 
    esp_err_t ret ; uint8_t current_state = 0; ret = bsp_Pca9557ReadReg(PCA9557_I2C_SLAVE_ADDR, PCA9557_CONTROL_REG_2, &current_state, 1); if (ret != ESP_OK) { 
    return ret; } if(newPolarity == IO_NON_INVERTED) { 
    current_state &= ~(1 << pinx); } else { 
    current_state |= (1 << pinx); } ret = bsp_Pca9557WriterReg(PCA9557_I2C_SLAVE_ADDR, PCA9557_CONTROL_REG_2, current_state); return ret; } /* * 名 称: bsp_PcaGetIoStatus * 功 能: PCA9577 设置IO输入的状态 * 入口参数: pinx : pin脚名称 * 出口参数: snPinState_t 引脚的电平(0/1) * 作  者: Roger-WY * 创建日期: 2021-05-08 * 修 改: * 修改日期: * 备 注:注意是否在极性翻转寄存器中设置了翻转极性!!! */ snPinState_t bsp_PcaGetIoStatus(snPinName_t pinx) { 
    esp_err_t ret ; uint8_t current_state = 0; ret = bsp_Pca9557ReadReg(PCA9557_I2C_SLAVE_ADDR, PCA9557_CONTROL_REG_0, &current_state, 1); if(ret == ESP_OK) { 
    if(current_state & (1 << pinx)) { 
    return IO_HIGH; } else { 
    return IO_LOW; } } else { 
    return IO_UNKNOW; //返回未知状态 } } 

讯享网
  • bsp_pca9557.h
讯享网#ifndef __BSP_PCA9557_H__ #define __BSP_PCA9557_H__ #include "esp_err.h" #define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/ #define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */ #define ACK_VAL 0x0 /*!< I2C ack value */ #define NACK_VAL 0x1 /*!< I2C nack value */ /* 0011 A2 A1 A0 R/W 0011 0 0 0 X // w: 0x30 r:0x31 (0x18 << 1) 真实使用i2c地址 ((PCA9557_I2C_SLAVE_ADDR << 1) | R/W) */ #define PCA9557_I2C_SLAVE_ADDR 0x18 //(0001 1 A2 A1 A0) /* 控制寄存器 (CMD)*/ #define PCA9557_CONTROL_REG_0 0x00 // Input Port Register (R) BXXXXXXXX (Default) #define PCA9557_CONTROL_REG_1 0x01 // Output Port Register (R/W) B00000000 #define PCA9557_CONTROL_REG_2 0x02 // Polarity Inversion Register (R/W) B #define PCA9557_CONTROL_REG_3 0x03 // Configuration Register (R/W) B typedef enum __pinname { 
    PIN_IO0 = 0, //BIT 0 PIN_IO1, //BIT 1 PIN_IO2, //BIT 2 PIN_IO3, //BIT 3 PIN_IO4, //BIT 4 PIN_IO5, //BIT 5 PIN_IO6, //BIT 6 PIN_IO7, //BIT 7 } snPinName_t; typedef enum __pinstate { 
    IO_LOW = 0, IO_HIGH = 1, IO_UNKNOW, } snPinState_t; typedef enum __pinmode { 
    IO_OUTPUT = 0, IO_INPUT = 1 } snPinMode_t; typedef enum __pinpolarity{ 
    IO_NON_INVERTED = 0, IO_INVERTED = 1 } snPinPolarity_t; /* 外部函数引用 */ esp_err_t bsp_Pca9557Init(void); esp_err_t bsp_PcaSetIoDirection(snPinName_t pinx, snPinMode_t newMode); esp_err_t bsp_PcaSetIoStatus(snPinName_t pinx, snPinState_t newState); esp_err_t bsp_PcaSetInputPolarity(snPinName_t pinx, snPinPolarity_t newPolarity); snPinState_t bsp_PcaGetIoStatus(snPinName_t pinx); #endif 
  1. 屏蔽例程自带的i2c自身读取的例程,编写测试pca9557的函数
/* 每隔 10s 翻转一次 IO0-IO6 的状态,并读取一次 IO7 的输入电平*/ void pca9557_test_task(void *arg) { 
    esp_err_t ret ; snPinState_t state = IO_LOW; snPinState_t pin7state = IO_LOW; while (1) { 
    printf("PCA9557 IO0-IO6 SET %d!\n",state); for (uint8_t i = 0; i <= 6; i++) { 
    ret = bsp_PcaSetIoStatus(i, state); printf("set io state ret:%d\n",ret); } if(state == IO_LOW) { 
    state = IO_HIGH; } else { 
    state = IO_LOW; } pin7state = bsp_PcaGetIoStatus(PIN_IO7); printf("pin7state:%d\n",pin7state); vTaskDelay((10000) / portTICK_RATE_MS); } } void app_main(void) { 
    esp_err_t ret ; //print_mux = xSemaphoreCreateMutex(); //ESP_ERROR_CHECK(i2c_slave_init()); //ESP_ERROR_CHECK(i2c_master_init()); //xTaskCreate(i2c_test_task, "i2c_test_task_0", 1024 * 2, (void *)0, 10, NULL); //xTaskCreate(i2c_test_task, "i2c_test_task_1", 1024 * 2, (void *)1, 10, NULL); printf("PCA9557 IC Test!\n"); bsp_Pca9557Init(); printf("PCA9557 SET IO DIRECTION IO0-IO6 IS OUTPUT/IO7 IS INPUT!\n"); ret=bsp_PcaSetIoDirection(PIN_IO0,IO_OUTPUT); printf("IO0 set dir is %d\n",ret); ret=bsp_PcaSetIoDirection(PIN_IO1, IO_OUTPUT); printf("IO1 set dir is %d\n",ret); ret=bsp_PcaSetIoDirection(PIN_IO2,IO_OUTPUT); printf("IO2 set dir is %d\n",ret); ret=bsp_PcaSetIoDirection(PIN_IO3,IO_OUTPUT); printf("IO3 set is %d\n",ret); ret=bsp_PcaSetIoDirection(PIN_IO4,IO_OUTPUT); printf("IO4 set dir is %d\n",ret); ret=bsp_PcaSetIoDirection(PIN_IO5,IO_OUTPUT); printf("IO5 set dir is %d\n",ret); ret=bsp_PcaSetIoDirection(PIN_IO6,IO_OUTPUT); printf("IO6 set dir is %d\n",ret); ret=bsp_PcaSetIoDirection(PIN_IO7,IO_INPUT); printf("IO7 set dir is %d\n",ret); /* 设置IO7的输入电平极性翻转 */ bsp_PcaSetInputPolarity(PIN_IO7, IO_NON_INVERTED); xTaskCreate(pca9557_test_task, "pca9557_test_task", 1024 * 2, (void *)1, 10, NULL); } 

实验结果

编译下载程序后,可通过 Monitor 查看打印信息:
在这里插入图片描述


小讯
上一篇 2025-02-15 07:47
下一篇 2025-02-10 23:39

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/118604.html