ESP32通过I2C驱动PCA9557IO扩展芯片

2024-06-24 03:18

本文主要是介绍ESP32通过I2C驱动PCA9557IO扩展芯片,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

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 文件修改为:

idf_component_register(SRCS “i2c_example_main.c”“bsp_pca9557.c”
INCLUDE_DIRS “.”)

  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          200000  /*!< 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/W0011 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)  B11110000
#define PCA9557_CONTROL_REG_3 0x03	// Configuration Register        (R/W)  B11111111typedef enum __pinname
{PIN_IO0 = 0, //BIT 0PIN_IO1,	 //BIT 1PIN_IO2,	 //BIT 2PIN_IO3,	 //BIT 3PIN_IO4,	 //BIT 4PIN_IO5,	 //BIT 5PIN_IO6,	 //BIT 6PIN_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 查看打印信息:
在这里插入图片描述


纯手写文章,转载请注明出处,谢谢!
如有任何错误,欢迎留言指正!

这篇关于ESP32通过I2C驱动PCA9557IO扩展芯片的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1089033

相关文章

ESP32 esp-idf esp-adf环境安装及.a库创建与编译

简介 ESP32 功能丰富的 Wi-Fi & 蓝牙 MCU, 适用于多样的物联网应用。使用freertos操作系统。 ESP-IDF 官方物联网开发框架。 ESP-ADF 官方音频开发框架。 文档参照 https://espressif-docs.readthedocs-hosted.com/projects/esp-adf/zh-cn/latest/get-started/index

探索蓝牙协议的奥秘:用ESP32实现高质量蓝牙音频传输

蓝牙(Bluetooth)是一种短距离无线通信技术,广泛应用于各种电子设备之间的数据传输。自1994年由爱立信公司首次提出以来,蓝牙技术已经经历了多个版本的更新和改进。本文将详细介绍蓝牙协议,并通过一个具体的项目——使用ESP32实现蓝牙音频传输,来展示蓝牙协议的实际应用及其优点。 蓝牙协议概述 蓝牙协议栈 蓝牙协议栈是蓝牙技术的核心,定义了蓝牙设备之间如何进行通信。蓝牙协议

iptables(7)扩展模块state

简介         前面文章我们已经介绍了一些扩展模块,如iprange、string、time、connlimit、limit,还有扩展匹配条件如--tcp-flags、icmp。这篇文章我们介绍state扩展模块  state          在 iptables 的上下文中,--state 选项并不是直接关联于一个扩展模块,而是与 iptables 的 state 匹配机制相关,特

【芯片学习】【DDR3】

<xlinx FPGA应用进阶 通用IP核详解和设计开发>读书摘录: 1.      2. 3. 4. 5. 6. 7. 8. 9. 10. 11.

蓝牙ble数传芯片推荐,TD5327A芯片蓝牙5.1—拓达半导体

蓝牙数传芯片TD5327A芯片是一款支持蓝牙BLE的纯数传芯片,蓝牙5.1版本。芯片的亮点在于性能强,除了支持APP端直接对芯片做设置与查询操作,包括直接操作蓝牙芯片自身的IO与PWM口以外,还支持RTC日历功能,可以做各类定时类操作,极大丰富了蓝牙在IOT产品中的应用。此外,在数传应用方面,此芯片支持串口流控功能,提大提高了数据传输的稳定与可靠性。 拓达蓝牙芯片特点: 支持RTC日历功能,超

WDF驱动开发-WDF总线枚举(一)

支持在总线驱动程序中进行 PnP 和电源管理 某些设备永久插入系统,而其他设备可以在系统运行时插入和拔出电源。 总线驱动 必须识别并报告连接到其总线的设备,并且他们必须发现并报告系统中设备的到达和离开情况。 总线驱动程序标识和报告的设备称为总线的 子设备。 标识和报告子设备的过程称为 总线枚举。 在总线枚举期间,总线驱动程序会为其子 设备创建设备对象 。  总线驱动程序本质上是同时处理总线枚

WDF驱动开发-特定于KMDF的技术(一)

这部分的技术是一些零散的记录知识点,它们主要是在WDF框架中特定于KMDF的部分。 将内核模式驱动程序框架和非 PnP 驱动程序配合使用 如果要为不支持 即插即用 (PnP) 的设备编写驱动程序,则驱动程序必须: 在 WDF_DRIVER_CONFIG 结构的 DriverInitFlags 成员中设置 WdfDriverInitNonPnpDriver 标志;提供 EvtDriverUnl

ADD属性驱动架构设计(一)

目录 一、架构设计过程 1.1、架构设计过程 1.1.1、设计目的 1.1.2、质量属性(非功能需求) 1.1.3、核心功能(功能需求) 1.1.4、架构关注 1.1.5、约束条件 1.2、基于设计过程 二、什么是ADD? 三、为什么选择ADD? 四、作用 五、ADD实现步骤 5.1、架构设计目标 5.1.1、系统类型确定  5.1.2、系统阶段确定 5.2、建

lvgl_micropython development for esp32

​​​​​​上一篇博客已经编译源码生成了ESP32C3的固件lvgl_micropy_ESP32_GENERIC_C3-4.bin,这篇博客开发一个界面。 一、开发环境 1、安装开发工具 Windows安装Thonny工具,官网链接:Thonny, Python IDE for beginners。 参考博客:用MicroPython开发ESP32- 用Thonny写程序_esp32用什么

博通5720 windows server 2003 32位网卡驱动和系统

driver for DELL R320 Broadcom 5720 Windows 2003 32bit 本人安装windows server 2003 网卡驱动成功!! 提供方便网盘下载地址博通5720网卡驱动 : http://pan.baidu.com/s/1GQWpw  windows server 2003 ghost 系统: http://pan