I/O扩展器IC

一、前言

由于单片机资源不足,第一次使用IO扩展器,顺便记录下来使用心得,网上查询资料很少,使用的人不多,基本都得照着手册去手搓,搞底层难啊.

需要扩展的IO需求不是很复杂,也不是用来在驱动总线信号,就是扩展为IO,有输入和输出控制即可,之前总用移位寄存器74HC595去扩展IO输出控制,但是需要输入的时候,还是得用专用的IO扩展芯片了。

目录

一、前言

二、环境

三、正文

1.PCA9555PW

2.PCA9505DGG

四、结语


注意:PCA9555PW和PCA9505是默认带内部100k上拉电阻的,在作为输入的情况下一般不是很适合,因为输入为空时只能检测出高电平,再有就是上拉输入和输出电压与VCC相同,这里根据使用场合合理分配使用对应芯片

PCA9505所有通道带100K内部上拉,上拉电源为VCC,PCA9506不带内部上拉,输出为VCC电压

PCA9555所有通道带100K内部上拉,上拉电源为VCC,PCA9535不带内部上拉,输出为VCC电压

DI模式建议要加下拉电阻,否则浮空信号读取为1

二、环境

stm32驱动

windows

三、正文

1.PCA9555PW

此款芯片具有16路IO扩展,分为2组8位IO通道,每一个通道都可以单独设置为输入或者是输出模式,功能很强大。

下面是官方手册介绍:

PCA9555是一款24引脚CMOS器件,为12c总线/SMBus应用提供16位通用并行输入/输出(GPIO)扩展,旨在增强NXP半导体家族的i2c总线I/O扩展器。这些改进包括更高的驱动能力、5 V VO容限、更低的电源电流、单独的l/O配置和更小的封装。当ACPI电源开关、传感器、按钮、led、风扇等需要额外的I/O时,I/O扩展器提供了一个简单的解决方案。PCA9555由两个8位配置(输入或输出选择)组成;输入,输出和极性反转(活动高或活动低操作)寄存器。系统主机可以通过写入I/O配置位来启用I/O作为输入或输出。每个输入或输出的数据保存在相应的输入或输出寄存器中。读寄存器的极性可以用极性反转寄存器反转。所有的寄存器都可以被系统主机读取。虽然引脚对引脚和l2c总线地址与PCF8575兼容,但由于增强,需要对软件进行更改,并在应用笔记AN469中进行了讨论。当任何输入状态与其相应的输入端口寄存器状态不同时,PCA9555开漏中断输出被激活,并用于向系统主机指示输入状态已经改变。上电复位将寄存器设置为其默认值并初始化设备状态机。三个硬件引脚(AO, A1, A2)改变固定的i2c总线地址,允许多达8个设备共享相同的12c总线/SMBus。PCA9555的固定i2c总线地址与PCA9554相同,允许多达8个这些设备以任何组合共享相同的12c总线/SMBus。

架构图如下:

芯片原理图管脚如下:

但是常用的很好买到的还是PCA9555PW

下面是我测试画的测试板原理图:

控制引脚SDA和SCLK给3.3V上拉,INT中断引脚虽然也加了上拉,但是没有连接到STM32上,没使用中断触发,使用轮询读取得方式,如果需要中断触发自行扩展,电源5V驱动,这样在IO输出或者输入浮空的情况下,都是有5V电平。

如果电源给3.3V,那么输出的IO也是3.3V电平。

这里我使用的是2个芯片在一条IIC总线上,通过设置芯片不同的地址,总共就是可以驱动32路IO了

此芯片一条总线最大支持8个芯片,最多控制IO数量也就是16*8=128个,还是很香的。

芯片驱动首先要配置IO模式,是输出还是输入,默认全部IO是输入模式,需要配置寄存器06去修改对应IO的模式,在输出模式下也可以读取IO状态,输出模式也可以强行将高低电平反向提供,在输入寄存器读取数据仍然会改变,但是这里建议尽量不要这样操作,不正规操作芯片容易对芯片的寿命大打折扣,还是输出就是输出使用,输入就是输入使用。

在读写数据时,他的寄存器读出数据时反向的,如1~8的IO数据是8~1,9~16的数据是16~9

不过对于我们搞程序的来说这都是小事情了

寄存器如下:

#define  PCA9555_SLA             (0x40 >> 1)                 //  定义PAC9555的器件地址    
#define  PCA9555_REG_IN0         0x00                        //  定义输入寄存器0地址    
#define  PCA9555_REG_IN1         0x01                        //  定义输入寄存器1地址    
#define  PCA9555_REG_OUT0        0x02                        //  定义输出寄存器0地址    
#define  PCA9555_REG_OUT1        0x03                        //  定义输出寄存器1地址    
#define  PCA9555_REG_POL0        0x04                        //  定义极性反转寄存器0地址    
#define  PCA9555_REG_POL1        0x05                        //  定义极性反转寄存器1地址 
#define  PCA9555_REG_CFG0        0x06                        //  定义方向配置寄存器0地址    
#define  PCA9555_REG_CFG1        0x07                        //  定义方向配置寄存器1地址      
#define  PCA9555_DEVICE_ADDR     0x40                        //  定义PCA9555地址 

核心代码如下:


//PCA9555驱动

//写pca9555第一层,最底层驱动
void IIC_Write_Pca9555(unsigned char addr,unsigned char reg_addr,unsigned char low_byte,unsigned char high_byte)
{
	  IIC_Start();
	  IIC_Write_Byte(addr & 0xfe);
	  IIC_Ack();
	  IIC_Write_Byte(reg_addr);
	  IIC_Ack();
	  IIC_Write_Byte(low_byte);
	  IIC_Ack();
	  IIC_Write_Byte(high_byte);
	  IIC_Ack();
	  IIC_Stop();
}
//读pca9555第一层,最底层驱动
void IIC_Read_Pca9555(unsigned char addr,unsigned char reg_addr,unsigned char* pBuffer,unsigned int num)
{
	  IIC_Start();
	  IIC_Write_Byte(addr & 0xfe);
	  IIC_Ack();
	  IIC_Write_Byte(reg_addr);
	  IIC_Ack();

	  IIC_Start();
	  IIC_Write_Byte(addr | 0x01);
	  IIC_Ack();
	  while (num){
		  *pBuffer = IIC_Read_Byte();
			if (num == 1){
				IIC_Send_NoAck();
			}
			else{ 
				IIC_Send_Ack();
			}	
			pBuffer++;
			num--;
	  }
	  IIC_Stop();
}
/*********************************************************
//pca9555初始化
  配置输入/输出模式,PCA9555_REG_CFG0和PCA9555_REG_CFG1配置谁都可以,采用最后配置的模式
	16个通道每个都可以配置输入/输出(这里我默认整个芯片使用一种模式,需要不同IO不同模式修改配置数据0xXX即可)
  输入模式下不可设置输出,输出模式下可以监测输入(建议输出模式下不要强行输入)
*********************************************************/
void PCA9555_Init(void)
{           
		IIC_PORT_INIT();//IIC初始化

		IIC_Write_Pca9555(PCA9555_ADDR1,PCA9555_REG_CFG0,0x00,0x00);//配置模式:输出
		IIC_Write_Pca9555(PCA9555_ADDR2,PCA9555_REG_CFG0,0x00,0x00);//配置模式:输出
		PCA9555_Set_All(0);
	
//		IIC_Write_Pca9555(PCA9555_ADDR1,PCA9555_REG_CFG0,0xff,0xff);//配置模式:输入
//		IIC_Write_Pca9555(PCA9555_ADDR2,PCA9555_REG_CFG0,0xff,0xff);//配置模式:输入

}
/*********************************************************
//写pca9555第二层驱动,可辅助逻辑不破坏最底层驱动
  addr    芯片地址,0x40表示第一个芯片地址
  data_L  写入芯片的前八位数据
  data_H  写入芯片的前后位数据
*********************************************************/
void PCA9555_writedata(unsigned char addr,unsigned char data_L,unsigned char data_H)
{                        
		IIC_Write_Pca9555(addr,PCA9555_REG_OUT0,data_L,data_H);//	PCA9555_REG_OUT0 输出寄存器0地址    
}

/*********************************************************
//读pca9555第二层驱动,可辅助逻辑不破坏最底层驱动
  addr     芯片地址,0x40表示第一个芯片地址
  pBuffer  读出芯片的数据
*********************************************************/
void PCA9555_readdata(unsigned char addr,unsigned char* pBuffer)
{
		IIC_Read_Pca9555(addr,PCA9555_REG_IN0,pBuffer,2);//2为读出芯片数据组数,9555为2组   
}

/*********************************************************
//设置某一通道IO高低输出
  num    控制的IO序号
  value  控制的IO输出状态 0:低电平 1:高电平
*********************************************************/
void PCA9555_Set_One_Value(unsigned char num,unsigned char value)
{
	 if(num >0 && num <17){//第一个芯片IO1-16控制
		 if(num <9){
				if(value)pca9555writedata[0] |= 0x01<<(num - 1);//赋值位高
				else pca9555writedata[0] &= ~(0x01<<(num - 1));//赋值位低
			}
			else{
				if(value)pca9555writedata[1] |= 0x01<<(num - 9);//赋值位高
				else pca9555writedata[1] &= ~(0x01<<(num - 9));//赋值位低
			}
			PCA9555_writedata(PCA9555_ADDR1,pca9555writedata[0],pca9555writedata[1]);
	 }
	 else if(num >16 && num <33){//第二个芯片IO1-16控制,使用更多IO以此类推,最多支持0x000~0x111 共8个芯片串联,共128个IO,如果不够可以使用PCA9505,40个IO,最多串联320个IO
	 		if(num <25){
				if(value)pca9555writedata[2] |= 0x01<<(num - 17);//赋值位高
				else pca9555writedata[2] &= ~(0x01<<(num - 17));//赋值位低
			}
			else{
				if(value)pca9555writedata[3] |= 0x01<<(num - 25);//赋值位高
				else pca9555writedata[3] &= ~(0x01<<(num - 25));//赋值位低
			}	
			PCA9555_writedata(PCA9555_ADDR2,pca9555writedata[2],pca9555writedata[3]);
	 }
	 else{//超出芯片控制
	 		//error
	 }
}

/*********************************************************
//设置所有输出
  value  控制的IO输出状态 0:全部输出低 1:全部输出高
*********************************************************/
void PCA9555_Set_All(unsigned char value)
{
		int i;
		for(i=0;i<4;i++){
			if(value==0)
				pca9555writedata[i]=0;
			else
				pca9555writedata[i]=0xff;
		}
		PCA9555_writedata(PCA9555_ADDR1,pca9555writedata[0],pca9555writedata[1]);
		PCA9555_writedata(PCA9555_ADDR2,pca9555writedata[2],pca9555writedata[3]);
}

/*********************************************************
//读取所有输入
  pca9555readdata1  芯片1数据,分2组
  pca9555readdata2  芯片2数据,分2组
*********************************************************/
void PCA9555_Read_All(void)
{
	PCA9555_readdata(PCA9555_ADDR1,pca9555readdata1);
	PCA9555_readdata(PCA9555_ADDR2,pca9555readdata2);

}

如果需要测试程序源代码和手册以及测试板图纸的可以这里下载,搬砖也是不容易的~你懂得^_^

测试结果:

	void PCA9555_Init(void)
{           
		IIC_PORT_INIT();//IIC初始化

		IIC_Write_Pca9555(PCA9555_ADDR1,PCA9555_REG_CFG0,0x00,0x00);//配置模式:输出
		IIC_Write_Pca9555(PCA9555_ADDR2,PCA9555_REG_CFG0,0x00,0x00);//配置模式:输出
		PCA9555_Set_All(0);
//		IIC_Write_Pca9555(PCA9555_ADDR1,PCA9555_REG_CFG0,0xff,0xff);//配置模式:输入
//		IIC_Write_Pca9555(PCA9555_ADDR2,PCA9555_REG_CFG0,0xff,0xff);//配置模式:输入

    PCA9555_Set_One_Value(1,1);
	PCA9555_Set_One_Value(8,1);
	PCA9555_Set_One_Value(15,1);
	PCA9555_Set_One_Value(30,1);

	PCA9555_Set_All(0);
	
	PCA9555_Set_One_Value(5,1);
	PCA9555_Set_One_Value(16,1);
	PCA9555_Set_One_Value(17,1);
	PCA9555_Set_One_Value(24,1);
	PCA9555_Set_One_Value(31,1);
}

通过以上代码,在初始化之后分别设置了1、8、15、30通道高电平,随后马上复位电平归零,又设置了5、16、17、24、31输出高电平,使用万用表测试所有通道得出结果与预设值相同,这些通道全部均为高电平,且电平与芯片供电电源电平一致(手册说电源要在2.3~5.5V之间,我测试使用3.3V和5V均正常)

此时通过定时器读取寄存器函数,读出输出通道数据如下:

第一个芯片读取寄存器8~1数据为0x10,    即00010000

第一个芯片读取寄存器16~9数据为0x80,  即10000000

第二个芯片读取寄存器24~17数据为0x81,即10000001

第二个芯片读取寄存器32~25数据为0x40,即01000000

解读后输出高得分别是5、16、17、24、31,与预设值相同。

测试输入时默认全为0xff,即全部有内部上拉,给某个IO为低电平时对应数值会根据逻辑改变。

测试到此基本就算是结束了,如有问题欢迎评论和留言,大家共同探讨,共同解决。

2.PCA9505DGG

这一款芯片驱动基本上与PCA9555相同,但是又有不同之处,控制上引脚多了OE输出使能控制引脚,多了RESET芯片复位引脚,寄存器上多了MSK中断配置寄存器,IO数量上扩展成了5组,共40个IO,地址还是A2 A1 A0三个,总线最多支持挂载8个芯片共320路IO控制,非常nice了

手册介绍如下:

PCA9505/PCA9506提供40位并行输入/输出(I/O)端口扩展,用于组织在5个8 I/O银行的2c总线应用程序。在5 V供电电压下,输出能够输出10 mA和15 mA,总封装负载为600 mA,可以直接驱动40个led。40个I/O端口中的任何一个都可以配置为输入或输出。输出端口是图腾柱,它们的逻辑状态在确认时发生变化(银行更改)。PCA9505与PCA9506相同,除了它在所有I/ o上包括100个kΩ内部上拉电阻。PCA9506不包括I/ o上的内部上拉,以减少作为输出或输入由推挽驱动器驱动时的功耗。该设备可以配置为使每个输入端口被屏蔽,以防止在其状态改变时产生中断,并使I/O数据逻辑状态在系统主机读取时被反转。漏极开路中断(INT)输出引脚允许监控输入引脚,并且每次在一个或几个输入端口发生变化时都断言(除非被屏蔽)。输出使能(OE)引脚3-状态任何I/O选择作为输出,可以用作闪烁或调暗led (PWM频率> 80hz和改变占空比)的输入信号。内部Power-On Reset (POR)或hardware Reset (Reset)引脚将40个I/ o初始化为输入。三个地址选择引脚配置8个从地址之一。PCA9506提供56引脚TSSOP和HVQFN封装,而PCA9505仅提供TSSOP封装。它们都指定在-40°C到+85°C的工业温度范围内。

架构图如下:

芯片引脚图如下:

我测试的原理图:

其中设备地址还是同PCA9555一样控制

控制引脚上多出的RESET功能是为芯片复位,这个基本接个上拉就行,就是整个设备断电才会复位,如果需要单片机复位同事复位芯片,那么就要驱动这个引脚在初始化前给个低电平保持一段时间在给高电平。PS:我的使用场合与PCA9555相同,都是设备一起上电直接配置好模式,无需芯片单独反复复位操作,且PCA9555也无复位控制,所以PCA9505也不用控制复位,大家按需配置。

控制引脚多出的OE是比较重要的,在输出模式下要将OE引脚拉低,再能真正的使能控制输出,否则引脚在3态状态保护,下面是我配置输出并将OE引脚在定时器500ms高低电平转换测试结果。可以看见输出模式下读取的数据一直是使能和失能切换的(至于失能下为何数据全是0xff看后文)

手册OE引脚说明:活动LOW输出使能引脚允许同时启用或禁用所有I/ o。当低电平应用到OE引脚时,配置为输出的所有I/ o都被启用,并且在各自的OP寄存器中编程的逻辑值应用到引脚。当一个高电平被应用到OE引脚时,所有配置为输出的I/ o都是3状态的。对于需要LED闪烁亮度控制的应用,该引脚可以通过在OE引脚上施加高频PWM信号来控制亮度。led可以使用输出端口寄存器闪烁,也可以使用OE引脚上的PWM信号调暗,从而通过调整占空比来控制亮度。

中断引脚就没什么好说的了,还是当电平改变时就会触发中断,这个芯片的升级之处就是这个中断触发不触发是可以配置的,是每一个IO都可以配置哦。

下面说明一下寄存器,寄存器总共分为如下5种:

IP:输入端口寄存器(5个寄存器)

OP:输出端口寄存器(5个寄存器)

Pl:极性反转寄存器(5个寄存器)

IOC: I/O配置寄存器(5个寄存器)

MSK:屏蔽中断寄存器(5个寄存器)

IP手册原文介绍:这些寄存器是只读的。它们反映端口引脚的传入逻辑电平,而不管该引脚是由l/O配置寄存器定义为输入还是输出。如果Pl寄存器中对应的Px[y]位被设置为逻辑0,或者如果PI寄存器中对应的Px[y]位被设置为逻辑1,则反向输入逻辑电平。对这些寄存器的写入没有效果。

OP手册原文介绍:这些寄存器反映由I/O配置寄存器定义为输出的引脚的输出逻辑电平。这些寄存器中的位值对定义为输入的引脚没有影响。反过来,从这些寄存器读取反映控制输出选择的触发器中的值,而不是实际的引脚值。Ox[y]=0: IOx_y=0,如果IOx_y定义为输出(Cx[y]在IOC寄存器=0)。Ox[y] = 1: IOx_y= 1,如果IOx_y定义为输出(Cx[y]在IOC寄存器= 0)。式中“x”为银行编号(0 ~ 4);“y”为位(0 ~ 7)。

PI手册原文介绍:这些寄存器允许反转相应输入端口寄存器的极性。Px[y]= 0:保留相应的输入端口寄存器数据极性。Px[y]= 1:对应的输入端口寄存器数据极性倒置。式中“x”为银行编号(0 ~ 4);“Y”为比特数(0 ~ 7)。

IOC手册原文介绍:这些寄存器配置I/O引脚的方向。Cx[y] = 0:对应端口引脚为输出。Cx[y] = 1:对应的端口引脚为输入。式中“x”为银行编号(0 ~ 4);“y”为位(0 ~ 7)。

MSK手册原文介绍:由于配置为输入的I/O引脚发生变化,这些寄存器屏蔽了中断。“x”为银行号(0 ~ 4);“y”为位数(0 ~ 7)。Mx[y] = 0:如果IOx_y被定义为输入,则I/O端的电平改变将产生中断(IOC 寄存器中的 Cx[y] = 1)。Mx[y] = 1:如果IOx_y定义为输入(IOC register = 1中的Cx[y]),则输入端口的电平变化不会产生中断。

寄存器总共如下:

#define PCA9505_IP					0x00
#define PCA9505_IP0					0x00
#define PCA9505_IP1					0x01
#define PCA9505_IP2					0x02
#define PCA9505_IP3					0x03
#define PCA9505_IP4					0x04
#define PCA9505_OP					0x08
#define PCA9505_OP0					0x08
#define PCA9505_OP1					0x09
#define PCA9505_OP2					0x0A
#define PCA9505_OP3					0x0B
#define PCA9505_OP4					0x0C
#define PCA9505_PI					0x10
#define PCA9505_PI0					0x10
#define PCA9505_PI1					0x11
#define PCA9505_PI2					0x12
#define PCA9505_PI3					0x13
#define PCA9505_PI4					0x14
#define PCA9505_IOC					0x18
#define PCA9505_IOC0				0x18
#define PCA9505_IOC1				0x19
#define PCA9505_IOC2				0x1A
#define PCA9505_IOC3				0x1B
#define PCA9505_IOC4				0x1C
#define PCA9505_MSK					0x20
#define PCA9505_MSK0				0x20
#define PCA9505_MSK1				0x21
#define PCA9505_MSK2				0x22
#define PCA9505_MSK3				0x23
#define PCA9505_MSK4				0x24

核心代码如下:


//PCA9505驱动

//写pca9505第一层,最底层驱动
void IIC_Write_Pca9505(unsigned char addr,unsigned char reg_addr,unsigned char byte)
{
	  IIC_Start1();
	  IIC_Write_Byte1(addr & 0xfe);
	  IIC_Ack1();
	  IIC_Write_Byte1(reg_addr);
	  IIC_Ack1();
	  IIC_Write_Byte1(byte);
		IIC_Ack1();
	  IIC_Stop1();
}
//读pca9505第一层,最底层驱动
void IIC_Read_Pca9505(unsigned char addr,unsigned char reg_addr,unsigned char* pBuffer)
{
	  IIC_Start1();
	  IIC_Write_Byte1(addr & 0xfe);
	  IIC_Ack1();
	  IIC_Write_Byte1(reg_addr);
	  IIC_Ack1();

	  IIC_Start1();
	  IIC_Write_Byte1(addr | 0x01);
	  IIC_Ack1();
	 	
		*pBuffer = IIC_Read_Byte1();
		IIC_Send_NoAck1();
		//IIC_Send_Ack1();
		//pBuffer++;
	  
	  IIC_Stop1();
}
/*********************************************************
//pca9505初始化
  配置输入/输出模式,PCA9505_REG_CFG0和PCA9505_REG_CFG1配置谁都可以,采用最后配置的模式
	16个通道每个都可以配置输入/输出(这里我默认整个芯片使用一种模式,需要不同IO不同模式修改配置数据0xXX即可)
  输入模式下不可设置输出,输出模式下可以监测输入(建议输出模式下不要强行输入)
*********************************************************/
void PCA9505_Init(void)
{           
		IIC_PORT_INIT1();//IIC初始化

		//输出配置
//		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_IOC0,0x00);//配置模式:输出
//		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_IOC1,0x00);//配置模式:输出
//		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_IOC2,0x00);//配置模式:输出
//		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_IOC3,0x00);//配置模式:输出
//		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_IOC4,0x00);//配置模式:输出
//	  OE9505_LOW;//OE使能输出模式
//		delay_ms(10);
//		PCA9505_Set_All(0); //配置所有输出0
	
		//输入配置
		//输入模式必须配置
		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_IOC0,0xff);//配置模式:输入
		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_IOC1,0xff);//配置模式:输入
		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_IOC2,0xff);//配置模式:输入
		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_IOC3,0xff);//配置模式:输入
		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_IOC4,0xff);//配置模式:输入
		//输入模式选择性配置
//		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_PI0,0xff);//配置模式:输入极性反转,还是默认上拉,但是读取数据数值反转,ff读为00,给低电平0变1,不配置默认0不反转极性
//		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_PI1,0xff);//配置模式:输入极性反转,还是默认上拉,但是读取数据数值反转,ff读为00,给低电平0变1,不配置默认0不反转极性
//		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_PI2,0xff);//配置模式:输入极性反转,还是默认上拉,但是读取数据数值反转,ff读为00,给低电平0变1,不配置默认0不反转极性
//		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_PI3,0xff);//配置模式:输入极性反转,还是默认上拉,但是读取数据数值反转,ff读为00,给低电平0变1,不配置默认0不反转极性
//		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_PI4,0xff);//配置模式:输入极性反转,还是默认上拉,但是读取数据数值反转,ff读为00,给低电平0变1,不配置默认0不反转极性
		//输入模式选择性配置
//		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_MSK0,0x00);//配置模式:输入模式电平改变产生中断,不配置默认1不产生中断
//		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_MSK1,0x00);//配置模式:输入模式电平改变产生中断,不配置默认1不产生中断
//		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_MSK2,0x00);//配置模式:输入模式电平改变产生中断,不配置默认1不产生中断
//		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_MSK3,0x00);//配置模式:输入模式电平改变产生中断,不配置默认1不产生中断
//		IIC_Write_Pca9505(PCA9505_ADDR1,PCA9505_MSK4,0x00);//配置模式:输入模式电平改变产生中断,不配置默认1不产生中断

}
/*********************************************************
//写pca9505第二层驱动,可辅助逻辑不破坏最底层驱动
  addr    芯片地址,0x40表示第一个芯片地址
  data_x  写入芯片的数据
*********************************************************/
void PCA9505_writedata(unsigned char addr,unsigned char data_1,unsigned char data_2,unsigned char data_3,unsigned char data_4,unsigned char data_5)
{                        
		IIC_Write_Pca9505(addr,PCA9505_OP0,data_1);//	PCA9505_OP0 输出寄存器0地址    
		IIC_Write_Pca9505(addr,PCA9505_OP1,data_2);//	PCA9505_OP1 输出寄存器1地址    
		IIC_Write_Pca9505(addr,PCA9505_OP2,data_3);//	PCA9505_OP2 输出寄存器2地址    
		IIC_Write_Pca9505(addr,PCA9505_OP3,data_4);//	PCA9505_OP3 输出寄存器3地址    
		IIC_Write_Pca9505(addr,PCA9505_OP4,data_5);//	PCA9505_OP4 输出寄存器4地址    
}
/*********************************************************
//读pca9505第二层驱动,可辅助逻辑不破坏最底层驱动
  addr     芯片地址,0x40表示第一个芯片地址
  pBuffer  读出芯片的数据
*********************************************************/
void PCA9505_readdata(unsigned char addr,unsigned char* pBuffer1,unsigned char* pBuffer2,unsigned char* pBuffer3,unsigned char* pBuffer4,unsigned char* pBuffer5)
{
		IIC_Read_Pca9505(addr,PCA9505_IP0,pBuffer1);//PCA9505_IP0 读出芯片寄存器0地址数据组数
		IIC_Read_Pca9505(addr,PCA9505_IP1,pBuffer2);//PCA9505_IP1 读出芯片寄存器1地址数据组数
		IIC_Read_Pca9505(addr,PCA9505_IP2,pBuffer3);//PCA9505_IP2 读出芯片寄存器2地址数据组数
		IIC_Read_Pca9505(addr,PCA9505_IP3,pBuffer4);//PCA9505_IP3 读出芯片寄存器3地址数据组数
		IIC_Read_Pca9505(addr,PCA9505_IP4,pBuffer5);//PCA9505_IP4 读出芯片寄存器4地址数据组数
}
/*********************************************************
//设置某一通道IO高低输出
  num    控制的IO序号
  value  控制的IO输出状态 0:低电平 1:高电平
*********************************************************/
void PCA9505_Set_One_Value(unsigned char num,unsigned char value)
{
	 if(num >0 && num <41){//第一个芯片IO1-16控制
		  if(num <9){
				if(value)pca9505writedata[0] |= 0x01<<(num - 1);//赋值位高
				else pca9505writedata[0] &= ~(0x01<<(num - 1));//赋值位低
			}
			else if(num <17){
				if(value)pca9505writedata[1] |= 0x01<<(num - 9);//赋值位高
				else pca9505writedata[1] &= ~(0x01<<(num - 9));//赋值位低
			}
			else if(num <25){
				if(value)pca9505writedata[2] |= 0x01<<(num - 17);//赋值位高
				else pca9505writedata[2] &= ~(0x01<<(num - 17));//赋值位低
			}
			else if(num <33){
				if(value)pca9505writedata[3] |= 0x01<<(num - 25);//赋值位高
				else pca9505writedata[3] &= ~(0x01<<(num - 25));//赋值位低
			}
			else{
				if(value)pca9505writedata[4] |= 0x01<<(num - 33);//赋值位高
				else pca9505writedata[4] &= ~(0x01<<(num - 33));//赋值位低
			}
			PCA9505_writedata(PCA9505_ADDR1,pca9505writedata[0],pca9505writedata[1],pca9505writedata[2],pca9505writedata[3],pca9505writedata[4]);
	 }
	 else{//超出芯片控制
	 		//error
	 }
}
/*********************************************************
//设置所有输出
  value  控制的IO输出状态 0:全部输出低 1:全部输出高
*********************************************************/
void PCA9505_Set_All(unsigned char value)
{
		int i;
		for(i=0;i<5;i++){
			if(value==0)
				pca9505writedata[i]=0;
			else
				pca9505writedata[i]=0xff;
		}
		PCA9505_writedata(PCA9505_ADDR1,pca9505writedata[0],pca9505writedata[1],pca9505writedata[2],pca9505writedata[3],pca9505writedata[4]);
}
/*********************************************************
//读取所有输入
  pca9505readdata1  芯片1数据,分2组
  pca9505readdata2  芯片2数据,分2组
*********************************************************/
void PCA9505_Read_All(void)
{
		PCA9505_readdata(PCA9505_ADDR1,&pca9505readdata[0],&pca9505readdata[1],&pca9505readdata[2],&pca9505readdata[3],&pca9505readdata[4]);
}

如果需要测试程序源代码和手册以及测试板图纸的可以在这里下载PCA9505驱动含PCA9555驱动,搬砖也是不容易的~你懂得^_^

测试结果:

	PCA9505_Init();
//	//测试PCA9505  20230915
	PCA9505_Set_One_Value(3,1);
	PCA9505_Set_One_Value(11,1);
	PCA9505_Set_One_Value(20,1);
	PCA9505_Set_One_Value(30,1);
	PCA9505_Set_One_Value(35,1);

通过以上代码,在初始化之后分别设置了3、11、20、30、35通道高电平,使用万用表测试所有通道得出结果与预设值相同,这些通道全部均为高电平,且电平与芯片供电电源电平一致(手册说电源要在2.3~5.5V之间,我测试使用3.3V和5V均正常)

测试输入时默认全为0xff,即全部有内部上拉,给某个IO为低电平时对应数值会根据逻辑改变。

可以看见上面实物图种PCA9505的40个IO,我给IO25低电平,测试结果如下:

IO25属于第四组第一个IO,从第四组读取IO32~IO25 即 1111 1110 ,数据为0xFE

这里对于IO默认高电平的情况进行说明,目前配置输入模式时IO在浮空情况下默认有上拉,在实际测试输入时会根据实际高低电平进行状态读取,这里我尝试使用PI寄存器对输入极性反转设置,但是经过尝试发现极性反转只是输入数据的变化,电平还是上拉该点评,而且极性反转高电平显示数据0,低电平显示数据1,也不太适应,暂不需求,所以PI寄存器按需配置

测试到此基本就算是结束了,如有问题欢迎评论和留言,大家共同探讨,共同解决。

四、结语

成长就是不断的积累知识

  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我可以为你分析一下I/O扩展实验的实验结果及分析。 在I/O扩展实验中,我们通过添加I/O芯片来增加计算机的外设接口。具体来说,我们通过编写程序来控制I/O口扩展芯片,实现输入输出的功能。在实验过程中,我们可以使用开发板或者仿真软件进行实验。 实验结果需要根据具体的实验情况来进行分析。一般来说,我们需要检查以下几个方面: 1. 硬件连接是否正确:在实验中,我们需要将I/O口扩展芯片与计算机系统的I/O总线连接起来。因此,我们需要检查硬件连接是否正确,包括I/O口扩展芯片的引脚连接和电源连接等。 2. 程序是否正确:在实验中,我们需要编写程序来控制I/O口扩展芯片,实现输入输出的功能。因此,我们需要检查程序是否正确,包括程序的逻辑是否正确和代码是否有误等。 3. 输入输出是否正常:在实验中,我们可以通过输入输出端口来控制外部设备,例如LED灯、按键等。因此,我们需要检查输入输出是否正常,包括LED灯是否亮起、按键是否可以触发等。 通过对以上几个方面进行检查,我们可以评估实验的结果,并分析实验中出现的问题。在分析实验结果时,我们需要结合实验的目的和要求进行综合评估,从而得出实验的结论和展望。 总之,通过I/O扩展实验,我们可以增加计算机的外设接口,实现更多的输入输出功能。在实验过程中,我们需要注意硬件连接、程序正确性和输入输出是否正常等方面。通过分析实验结果,我们可以评估实验的效果,并对未来的实验和应用进行展望。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大桶矿泉水

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值