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

相关文章

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

Spring框架5 - 容器的扩展功能 (ApplicationContext)

private static ApplicationContext applicationContext;static {applicationContext = new ClassPathXmlApplicationContext("bean.xml");} BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与 BeanF

PHP7扩展开发之数组处理

前言 这次,我们将演示如何在PHP扩展中如何对数组进行处理。要实现的PHP代码如下: <?phpfunction array_concat ($arr, $prefix) {foreach($arr as $key => $val) {if (isset($prefix[$key]) && is_string($val) && is_string($prefix[$key])) {$arr[

PHP7扩展开发之字符串处理

前言 这次,我们来看看字符串在PHP扩展里面如何处理。 示例代码如下: <?phpfunction str_concat($prefix, $string) {$len = strlen($prefix);$substr = substr($string, 0, $len);if ($substr != $prefix) {return $prefix." ".$string;} else

PHP7扩展开发之类型处理

前言 这次,我们将演示如何在PHP扩展中如何对类型进行一些操作。如,判断变量类型。要实现的PHP代码如下: <?phpfunction get_size ($value) {if (is_string($value)) {return "string size is ". strlen($value);} else if (is_array($value)) {return "array si

PHP7扩展开发之依赖其他扩展

前言 有的时候,我们的扩展要依赖其他扩展。比如,我们PHP的mysqli扩展就依赖mysqlnd扩展。这中情况下,我们怎么使用其他扩展呢?这个就是本文讲述的内容。 我们新建立一个扩展,名字叫 demo_dep , 依赖之前的say扩展。 在demo_dep扩展中,我们实现demo_say方法。这个方法调用say扩展的say方法。 代码 基础代码 确保say扩展的头文件正确安装到了php

PHP7扩展开发之函数方式使用lib库

前言 首先说下什么是lib库。lib库就是一个提供特定功能的一个文件。可以把它看成是PHP的一个文件,这个文件提供一些函数方法。只是这个lib库是用c或者c++写的。 使用lib库的场景。一些软件已经提供了lib库,我们就没必要再重复实现一次。如,原先的mysql扩展,就是使用mysql官方的lib库进行的封装。 在本文,我们将建立一个简单的lib库,并在扩展中进行封装调用。 代码 基础

PHP7扩展开发之对象方式使用lib库

前言 上一篇文章,我们使用的是函数方式调用lib库。这篇文章我们将使用对象的方式调用lib库。调用代码如下: <?php $hello = new hello(); $result = $hello->get(); var_dump($result); ?> 我们将在扩展中实现hello类。hello类中将依赖lib库。 代码 基础代码 这个扩展,我们将在say扩展上增加相关代码。sa