【PCA9555详细学习及代码】 您所在的位置:网站首页 25X40芯片作用 【PCA9555详细学习及代码】

【PCA9555详细学习及代码】

2024-07-09 18:24| 来源: 网络整理| 查看: 265

PCA9555详细学习及代码 PCA9555芯片介绍PCA9555详细学习PCA9555代码实例 本文参考 https://blog.csdn.net/TheOneZn/article/details/122723644 https://blog.csdn.net/LH_SMD/article/details/121354625

PCA9555芯片介绍

PCA9555是一款16位通用输入/输出(GPIO)扩展器,具有中断和弱上拉电阻,适用于I2c总线/SMBus应用。它具有以下特点: 1.PCA9555由两个8位配置(输入或输出选择),输入端口,输出端口和极性反转(高电平有效或低电平有效运行)寄存器组成。 2.在加电时I /O被配置为输入,系统主控制器可以通过写入I /O配置位将I /O启动为输入或输出。 3.每一个输入或者输出的数据被保存在相应的输入或者输出寄存器内。 4.输入端口寄存器的极性可借助极性反转寄存器进行转换。 5.所有寄存器都可由系统主控器读取。 芯片引脚及功能描述: 在这里插入图片描述 在这里插入图片描述

PCA9555详细学习

1.INT引脚功能:当任何输入状态与其对应的状态不同时,PCA9555开漏中断(INT)引脚输出(只对被配置为输入模式的引脚产生反应),用于向单片机指示输入状态已更改。INT可以连接到微控制器的中断输入端,通过在这条线发送中断信号给单片机,如果端口上有传入数据,远程I/O可以通知微控制器,而不必通过通信I2C总线。因此PCA9555可以保持一个简单的从设备。

2.PCA9555芯片采用iic的方式进行通信,其地址如下: 其前四位为固定位,后三位A0,A1,A2为可编程位,用于设置地址。从地址的最后一位定义了要执行的操作(读或写)。高(1)表示读操作,低(0)表示写操作。 芯片地址图

3.控制寄存器和命令字节 当地址位正确应答之后,主机应该发送一个控制字节,控制字节将会存PCA9555的控制寄存器中,其中B0,B1,B2三位,将会定义操作以及内部的寄存器(输入、输出、极性反转或配置),控制寄存器能被读以及写,控制字节只有写的时候才发送。一旦发送了一个命令字节,被寻址的寄存器将继续被读访问,直到已发送新的命令字节。command其实就相当于相应的控制寄存器地址,比如000就是访问input port0的寄存器 在这里插入图片描述

4.PCA9555芯片具有四种内部寄存器:

输入寄存器:输入端口寄存器(寄存器0和1)反映引脚的传入逻辑电平,而不管是否 引脚由配置寄存器定义为输入或输出。它只作用于读操作。写入这些寄存器没有作用。默认值X由外部应用的逻辑级别决定。在进行读操作之前,发送一个带有命令字节的写传输,以指示I2C设备接下来将访问输入端口寄存器。 在这里插入图片描述

输出寄存器:输出端口寄存器(寄存器2和3)显示定义为输出的引脚的传出逻辑电 配置寄存器。这个寄存器中的位值对定义为输入的引脚没有影响。反过来,从这里读寄存器反映控制输出选择的触发器中的值,而不是实际引脚值。 在这里插入图片描述

极性反转寄存器:极性反转寄存器(寄存器4和5)允许定义为输入的引脚极性反转 配置寄存器。向该寄存器里某一位写入1,表明该引脚在输入状态的时候输入极性会反转,写入0则不起作用。 在这里插入图片描述

配置寄存器:配置寄存器(寄存器6和7)配置I/O引脚的方向。如果这个寄存器中的位是设置为1,对应的端口引脚作为高阻抗输出驱动器的输入启用。如果在这一点寄存器清除为0,相应的端口引脚作为输出启用。 在这里插入图片描述

5.通过上面的介绍,PCA9555的功能应该有所了解了,下面来看下然后使用这个芯片:

例1:主机发送从设备地址,从设备地址匹配,从设备发送ack,主机接收应答后发生命令字节,比如发送0x02,等待从机应答后,即可向输出寄存器写入数据改变拓展IO引脚输出。如果命令直接写入的配置寄存器的地址,则可配置IO口的输入输出状态。(在写入输出状态前因先将IO口通过配置寄存器设置为输出状态)

例2:主机发送从设备地址(主要此时起始信号为读写位为写状态,因为等下得得写入命令字节),从设备地址匹配,从设备发送ack,主机发送命令字节,接收应答后,重新发送设备地址(此时起始信号为读写位为读取状态),等待应答主机即可读取从机发送过来得数据。

在这里插入图片描述

PCA9555代码实例

头文件:

#ifndef USER_APP_PCA9555_H_ #define USER_APP_PCA9555_H_ #include "stm32f4xx_ll_gpio.h" /***************************************************IIC 驱动部门**********************************************************/ #define IIC_SCL_GPIO_PORT GPIOB #define IIC_SCL_GPIO_PIN LL_GPIO_PIN_7 #define IIC_SDA_GPIO_PORT GPIOB #define IIC_SDA_GPIO_PIN LL_GPIO_PIN_8 #define IIC_SCL_SET_GPIO_OUTPUT_STATUS(status) if(status == 1) LL_GPIO_SetOutputPin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN);\ else if(status == 0) LL_GPIO_ResetOutputPin(IIC_SCL_GPIO_PORT,IIC_SCL_GPIO_PIN); #define IIC_SDA_SET_GPIO_OUTPUT_STATUS(status) if(status == 1) LL_GPIO_SetOutputPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN);\ else if(status == 0) LL_GPIO_ResetOutputPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN); #define IIC_SDA_GET_GPIO_INPUT_STATUS LL_GPIO_IsInputPinSet(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN) void IIC_gpio_init(void); void IIC_start(void); void IIC_stop(void); uint8_t IIC_wait_ack(void); void IIC_ack(void); void IIC_nack(void); void IIC_send_byte(uint8_t txd); void IIC_send_byte(uint8_t txd); uint8_t IIC_read_byte(unsigned char ack); /***********************************************************IIC 驱动 END**********************************************************************/ /************************************************************PCA9555 驱动***********************************************************/ #define SUCCESS 0 #define ERROR 1 #define SLAVE_ADDR0 0x40 #define HOST_WRITE_COMMAND 0x00 #define HOST_READ_COMMAND 0x01 #define INPUT_PORT_REGISTER0 0x00 /* 输入端口寄存器0,负责IO00-IO07 */ #define INPUT_PORT_REGISTER1 0x01 /* 输入端口寄存器1,负责IO10-IO17 */ #define OUTPUT_PORT_REGISTER0 0x02 /* 输入端口寄存器0,负责IO00-IO07 */ #define OUTPUT_PORT_REGISTER1 0x03 /* 输入端口寄存器1,负责IO10-IO17 */ #define POLARITY_INVERSION_PORT_REGISTER0 0x04 /* 极性反转端口寄存器0,负责IO00-IO07 */ #define POLARITY_INVERSION_PORT_REGISTER1 0x05 /* 极性反转端口寄存器1,负责IO10-IO17 */ #define CONFIG_PORT_REGISTER0 0x06 /* 输入端口寄存器0,负责IO00-IO07 */ #define CONFIG_PORT_REGISTER1 0x07 /* 输入端口寄存器1,负责IO10-IO17 */ #define GPIO_PORT0 0 #define GPIO_PORT1 1 #define GPIO_0 0x01 #define GPIO_1 0x02 #define GPIO_2 0x04 #define GPIO_3 0x08 #define GPIO_4 0x10 #define GPIO_5 0x20 #define GPIO_6 0x40 #define GPIO_7 0x80 #define PCA9555_WAIT_IS_RETURN_SUCCESS(flag, tips) if(flag != SUCCESS)\ { \ printf("%s", tips); \ return ERROR;\ } void pca9555_init(void); void pca9555_read_wtite_test(void); void pca9555_set_output_mode_all(uint8_t slave_num, uint8_t gpio_port); void pca9555_set_output_mode(uint8_t slave_num, uint8_t gpio_port, uint8_t gpio_num); void pca9555_set_input_mode_all(uint8_t slave_num, uint8_t gpio_port); void pca9555_set_gpio_output_status(uint8_t slave_num, uint8_t gpio_port, uint8_t gpio_num, uint8_t status); void pca9555_set_input_mode(uint8_t slave_num, uint8_t gpio_port, uint8_t gpio_num); void pca9555_set_input_mode_all(uint8_t slave_num, uint8_t gpio_port); void pca9555_set_output_mode_all(uint8_t slave_num, uint8_t gpio_port); uint8_t pca9555_get_gpio_status(uint8_t slave_num, uint8_t gpio_port, uint8_t gpio_num); uint8_t pca9555_read_byte(uint8_t slave_num, uint8_t addr, uint8_t read_register_data, uint8_t *read_data); uint8_t pca9555_write_byte(uint8_t addr, uint8_t command, uint8_t write_register_data); #endif /* USER_APP_PCA9555_H_ */

源文件:

#include "hardware/pca9555.h" #include "main.h" #include "hardware/timer.h" #include void IIC_gpio_init(void) { LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOC); /* 使能GPIO时钟 */ LL_GPIO_SetPinMode(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, LL_GPIO_MODE_OUTPUT);//设置为推挽输出,初始化高电平 LL_GPIO_SetPinOutputType(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN,LL_GPIO_OUTPUT_PUSHPULL);//设置为推挽输出 LL_GPIO_SetOutputPin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN); LL_GPIO_SetPinMode(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, LL_GPIO_MODE_OUTPUT);//设置为推挽输出,初始化高电平 LL_GPIO_SetPinOutputType(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN,LL_GPIO_OUTPUT_PUSHPULL); LL_GPIO_SetOutputPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN); } static void IIC_SDA_set_output(void) { LL_GPIO_SetPinMode(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, LL_GPIO_MODE_OUTPUT); LL_GPIO_SetPinOutputType(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, LL_GPIO_OUTPUT_PUSHPULL); LL_GPIO_SetOutputPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN); } static void IIC_SDA_set_input(void) { LL_GPIO_SetPinMode(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, LL_GPIO_MODE_INPUT); LL_GPIO_SetPinPull(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, LL_GPIO_PULL_UP); } //产生IIC起始信号 void IIC_start(void) { IIC_SDA_set_output(); //sda线输出 IIC_SDA_SET_GPIO_OUTPUT_STATUS(1); IIC_SCL_SET_GPIO_OUTPUT_STATUS(1); //sl_udelay_wait(6); delay_us(6); IIC_SDA_SET_GPIO_OUTPUT_STATUS(0);//START:when CLK is high,DATA change form high to low //sl_udelay_wait(6); delay_us(6); IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);//钳住I2C总线,准备发送或接收数据 } //产生IIC停止信号 void IIC_stop(void) { IIC_SDA_set_output();//sda线输出 IIC_SCL_SET_GPIO_OUTPUT_STATUS(0); IIC_SDA_SET_GPIO_OUTPUT_STATUS(0);//STOP:when CLK is high DATA change form low to high //sl_udelay_wait(6); delay_us(6); IIC_SCL_SET_GPIO_OUTPUT_STATUS(1); IIC_SDA_SET_GPIO_OUTPUT_STATUS(1);//发送I2C总线结束信号 //sl_udelay_wait(6); delay_us(6); } //等待应答信号到来 //返回值:1,接收应答失败 // 0,接收应答成功 uint8_t IIC_wait_ack(void) { uint8_t ucErrTime=0; IIC_SDA_set_input(); //SDA设置为输入 IIC_SDA_SET_GPIO_OUTPUT_STATUS(1); //sl_udelay_wait(1); delay_us(1); IIC_SCL_SET_GPIO_OUTPUT_STATUS(1); //sl_udelay_wait(1); delay_us(1); while(IIC_SDA_GET_GPIO_INPUT_STATUS) { ucErrTime++; //sl_udelay_wait(1); delay_us(1); if(ucErrTime>250) { IIC_stop(); printf("return 1\r\n"); return 1; } } IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);//时钟输出0 return 0; } //产生ACK应答 void IIC_ack(void) { IIC_SCL_SET_GPIO_OUTPUT_STATUS(0); IIC_SDA_set_output(); IIC_SDA_SET_GPIO_OUTPUT_STATUS(1); //sl_udelay_wait(5); delay_us(5); IIC_SCL_SET_GPIO_OUTPUT_STATUS(1); //sl_udelay_wait(5); delay_us(5); IIC_SCL_SET_GPIO_OUTPUT_STATUS(0); } //不产生ACK应答 void IIC_nack(void) { IIC_SCL_SET_GPIO_OUTPUT_STATUS(0); IIC_SDA_set_output(); IIC_SDA_SET_GPIO_OUTPUT_STATUS(1); //sl_udelay_wait(5); delay_us(5); IIC_SCL_SET_GPIO_OUTPUT_STATUS(1); //sl_udelay_wait(5); delay_us(5); IIC_SCL_SET_GPIO_OUTPUT_STATUS(0); } //IIC发送一个字节(高位先发) //返回从机有无应答 //1,有应答 //0,无应答 void IIC_send_byte(uint8_t txd) { uint8_t t; IIC_SDA_set_output(); IIC_SCL_SET_GPIO_OUTPUT_STATUS(0);//拉低时钟开始数据传输 for(t=0;t unsigned char i,receive=0; IIC_SDA_set_input();//SDA设置为输入 for(i=0;i IIC_gpio_init(); } //pca9555写寄存器值 uint8_t pca9555_write_byte(uint8_t addr, uint8_t command, uint8_t write_register_data) { uint8_t ret = 1; IIC_start(); IIC_send_byte(addr); //写从机地址 ret = IIC_wait_ack(); PCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n"); IIC_send_byte(command); //写要写的寄存器地址 ret = IIC_wait_ack(); PCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n"); IIC_send_byte(write_register_data);//写入数据 ret = IIC_wait_ack(); PCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n"); IIC_stop(); delay_us(10000); return SUCCESS; } /* * pca9555读取寄存器值 * * addr 读取地址 * read_register_data 要读取的寄存器 * read_data 读取数据存放地址 * * * 返回值:读取成功返回SUCCESS 失败返回ERROR * * */ uint8_t pca9555_read_byte(uint8_t slave_num, uint8_t addr, uint8_t read_register_data, uint8_t *read_data) { uint8_t ret = 0; IIC_start(); IIC_send_byte(slave_num); // 写入从机地址 ret = IIC_wait_ack(); PCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n"); IIC_send_byte(read_register_data); //写入要读取的寄存器地址 ret = IIC_wait_ack(); PCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n"); IIC_start(); /* 开始接收数据 */ IIC_send_byte(addr); //发送从机地址并设置为读取 ret = IIC_wait_ack(); PCA9555_WAIT_IS_RETURN_SUCCESS(ret, "[ERROR] wait slave ack error!\r\n"); *read_data = IIC_read_byte(0); IIC_stop(); return SUCCESS; } /* * 设置指定GPIO的模式 * * slave_num 需要操作的从机设备 * gpio_port gpio端口 端口0/1 * gpio_num 哪一个GPIO * * 返回值:void * */ void pca9555_set_output_mode(uint8_t slave_num, uint8_t gpio_port, uint8_t gpio_num) { uint8_t register_original_data = 0; if(gpio_port > 1 || gpio_num > 0x80) return; if(gpio_port == 0) { pca9555_read_byte(slave_num, slave_num | HOST_READ_COMMAND, CONFIG_PORT_REGISTER0, ®ister_original_data);//读取原来的设置 pca9555_write_byte(slave_num | HOST_WRITE_COMMAND, CONFIG_PORT_REGISTER0, register_original_data & (~gpio_num));//在不影响原来设置的情况下修改配置寄存器的设置 } else if(gpio_port == 1) { pca9555_read_byte(slave_num, slave_num | HOST_READ_COMMAND, CONFIG_PORT_REGISTER1, ®ister_original_data); pca9555_write_byte( slave_num | HOST_WRITE_COMMAND, CONFIG_PORT_REGISTER1, register_original_data & (~gpio_num)); } } void pca9555_set_output_mode_all(uint8_t slave_num, uint8_t gpio_port) { uint8_t register_original_data = 0x00; if(gpio_port > 1) return; if(gpio_port == 0) { pca9555_write_byte(slave_num | HOST_WRITE_COMMAND, CONFIG_PORT_REGISTER0, register_original_data); } else if(gpio_port == 1) { pca9555_write_byte( slave_num | HOST_WRITE_COMMAND, CONFIG_PORT_REGISTER1, register_original_data); } } /* * 设置GPIO为输入模式 * * slave_num 需要操作的从机设备 * gpio_port gpio端口 端口0/1 * gpio_num 哪一个GPIO * * 返回值:void **/ void pca9555_set_input_mode(uint8_t slave_num, uint8_t gpio_port, uint8_t gpio_num) { uint8_t register_original_data = 0; if(gpio_port > 1 || gpio_num > 0x80) return; if(gpio_port == 0) { pca9555_read_byte(slave_num, slave_num | HOST_READ_COMMAND, CONFIG_PORT_REGISTER0, ®ister_original_data); pca9555_write_byte(slave_num | HOST_WRITE_COMMAND, CONFIG_PORT_REGISTER0, register_original_data | gpio_num); } else if(gpio_port == 1) { pca9555_read_byte(slave_num, slave_num | HOST_READ_COMMAND, CONFIG_PORT_REGISTER1, ®ister_original_data); pca9555_write_byte(slave_num | HOST_WRITE_COMMAND, CONFIG_PORT_REGISTER1, register_original_data | gpio_num);//参考的文章里给的代码这里使用的是&,但其实这里应该用|才对啊,不然另外7个全变0了 } } void pca9555_set_input_mode_all(uint8_t slave_num, uint8_t gpio_port) { uint8_t register_original_data = 0xff; if(gpio_port > 1 ) return; if(gpio_port == 0) { pca9555_write_byte(slave_num | HOST_WRITE_COMMAND, CONFIG_PORT_REGISTER0, register_original_data); } else if(gpio_port == 1) { pca9555_write_byte(slave_num | HOST_WRITE_COMMAND, CONFIG_PORT_REGISTER1, register_original_data); } } /* * 设置GPIO输出状态 * * slave_num 需要操作的从机设备 * gpio_port gpio端口 端口0/1 * gpio_num 哪一个GPIO * status 输出状态 * * 返回值:void **/ void pca9555_set_gpio_output_status(uint8_t slave_num, uint8_t gpio_port, uint8_t gpio_num, uint8_t status) { uint8_t register_original_data = 0; if(gpio_port > 1 || gpio_num > 0x80) return; if(gpio_port == 0) { pca9555_read_byte(slave_num, slave_num | HOST_READ_COMMAND, OUTPUT_PORT_REGISTER0, ®ister_original_data); if(status == 1) { pca9555_write_byte(slave_num | HOST_WRITE_COMMAND, OUTPUT_PORT_REGISTER0, register_original_data | gpio_num); } else { pca9555_write_byte(slave_num | HOST_WRITE_COMMAND, OUTPUT_PORT_REGISTER0, register_original_data & (~gpio_num)); } } else if(gpio_port == 1) { pca9555_read_byte(slave_num, slave_num | HOST_READ_COMMAND, OUTPUT_PORT_REGISTER1, ®ister_original_data); if(status == 1) { pca9555_write_byte(slave_num | HOST_WRITE_COMMAND, OUTPUT_PORT_REGISTER1, register_original_data | gpio_num); } else { pca9555_write_byte(slave_num | HOST_WRITE_COMMAND, OUTPUT_PORT_REGISTER1, register_original_data & (~gpio_num)); } } } /* * 获取GPIO状态 * * slave_num 需要操作的从机设备 * gpio_port gpio端口 端口0/1 * gpio_num 哪一个GPIO * * 返回值:GPIO状态 **/ uint8_t pca9555_get_gpio_status(uint8_t slave_num, uint8_t gpio_port, uint8_t gpio_num) { uint8_t register_original_data = 0; uint8_t gpio_status = 0; if(gpio_port > 1 || gpio_num > 0x80) { printf("[ERROR] gpio_port > 1 || gpio_num > 0x80\r\n"); return 2; } if(gpio_port == 0) { pca9555_read_byte(slave_num, slave_num | HOST_READ_COMMAND, INPUT_PORT_REGISTER0, ®ister_original_data); } else if(gpio_port == 1) { pca9555_read_byte(slave_num, slave_num | HOST_READ_COMMAND, INPUT_PORT_REGISTER1, ®ister_original_data); } switch(gpio_num) { case 0x01: gpio_status = register_original_data & gpio_num;break; case 0x02: gpio_status = (register_original_data & gpio_num) >> 1;break; case 0x04: gpio_status = (register_original_data & gpio_num) >> 2;break; case 0x08: gpio_status = (register_original_data & gpio_num) >> 3;break; case 0x10: gpio_status = (register_original_data & gpio_num) >> 4;break; case 0x20: gpio_status = (register_original_data & gpio_num) >> 5;break; case 0x40: gpio_status = (register_original_data & gpio_num) >> 6;break; case 0x80: gpio_status = (register_original_data & gpio_num) >> 7;break; default: printf("[ERROR] gpio error!\r\n"); } return gpio_status; }

注: PCA9555采用IIC通信,协议中涉及的延时函数务必保证精确。 上面代码可直接运行在STM32单片机中,只需要对以下两部点进行修改即可 ①GPIO输入输出设置 ②精确到us级别的延时函数



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有