IO扩展是个好东西, 占用资源少. 适合用在响应要求不高的场合.

PCF8575最大的好处是有个中断反馈引脚, 方便读取状态.

下面直接上代码.

Vivado中的配置.

ZYNQ7020使用IIC协议读写IO扩展芯片PCF8575_#define


XDC文件的配置

set_property -dict {PACKAGE_PIN L14 IOSTANDARD LVCMOS33} [get_ports IIC_0_scl_io]
set_property -dict {PACKAGE_PIN L16 IOSTANDARD LVCMOS33} [get_ports IIC_0_sda_io]
set_property PULLUP true [get_ports IIC_0_scl_io]
set_property PULLUP true [get_ports IIC_0_sda_io]

SDK中的代码.

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
//#include "sleep.h"
#include "xparameters.h" // 包含设备参数信息
#include "xuartps.h"     // 包含UART PS的函数声明
#include "xiicps.h"

#include "xil_io.h"

///SLCR寄存器,绝对地址,
#define SLCR_UNLOCK_ADDR        0xF8000008
#define SLCR_LOCK_ADDR            0xF8000004

//FPGA_RST_CTRL寄存器,绝对地址,

#define FPGA_RST_CTRL          0xF8000240
#define UNLOCK_KEY          0xDF0D  //解锁码
#define LOCK_KEY            0x767B  //加锁码

#define PL_RST_MASK            0x01//低四位对应FCLK_RESETN[3:0]
#define PL_CLR_MASK            0x00




void PlSoftwareReset(void)
{
    Xil_Out32(SLCR_UNLOCK_ADDR, UNLOCK_KEY);  //解锁

    Xil_Out32(FPGA_RST_CTRL, PL_RST_MASK);  //复位
    Xil_Out32(FPGA_RST_CTRL, PL_CLR_MASK);  //拉起复位

    Xil_Out32(SLCR_LOCK_ADDR, LOCK_KEY);  //加锁
} 
// PlSoftwareReset 原文链接:

XUartPs debug_uart; // UART实例


int debug_init(void) {
    int Status;
    XUartPs_Config *Config;

    //默认使用uart0 如果要用uart1 请改成 XPAR_XUARTPS_1_DEVICE_ID
    Config = XUartPs_LookupConfig(XPAR_XUARTPS_0_DEVICE_ID);
    if (NULL == Config) {
        return XST_FAILURE;
    }

    Status = XUartPs_CfgInitialize(&debug_uart, Config, Config->BaseAddress);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    XUartPs_SetBaudRate(&debug_uart, 115200);

    return XST_SUCCESS;
}


#define IIC_DEVICE_ID		XPAR_XIICPS_0_DEVICE_ID
#define TEST_BUFFER_SIZE	512


#define IIC_SCLK_RATE		200000


u8 SendBuffer[2];    /**< Buffer for Transmitting Data */
u8 RecvBuffer[2];    /**< Buffer for Receiving Data */

XIicPs Iic;

u8 IIC_SLAVE_ADDR=	0x20; //PCF8575 的IC芯片地址, A0,A1,A2地址均连接到了低电平时的地址.

int Status;
void iic_init(void ){

		XIicPs_Config *Config;
		int Index;

		/*
		 * Initialize the IIC driver so that it's ready to use
		 * Look up the configuration in the config table,
		 * then initialize it.
		 */
		Config = XIicPs_LookupConfig(IIC_DEVICE_ID);
		if (NULL == Config) {
			return XST_FAILURE;
		}

		Status = XIicPs_CfgInitialize(&Iic, Config, Config->BaseAddress);
		if (Status != XST_SUCCESS) {
			return XST_FAILURE;
		}

		/*
		 * Perform a self-test to ensure that the hardware was built correctly.
		 */
		Status = XIicPs_SelfTest(&Iic);
		if (Status != XST_SUCCESS) {
			return XST_FAILURE;
		}
		/*
		 * Set the IIC serial clock rate.
		 */
		XIicPs_SetSClk(&Iic, IIC_SCLK_RATE);

		/*
		 * Send the buffer using the IIC and ignore the number of bytes sent
		 * as the return value since we are using it in interrupt mode.
		 */


}

int main()
{
  PlSoftwareReset();//重启FPGA的PL部分,debug的时候不需要每次 烧录FPGA了.
  init_platform();

  debug_init();
  iic_init();
	while(1){
		xil_printf("Hello\n");
		SendBuffer[0] = 0x0;//P0.0 到P0.7引脚置低
		SendBuffer[1] = 0x0;//P1.0 到P1.7引脚置低
		//写入IO口数据
		Status = XIicPs_MasterSendPolled(&Iic, SendBuffer, 2, IIC_SLAVE_ADDR);
		usleep(100);

		SendBuffer[0] = 0x02;//P0.0 和P0.1引脚置高
		SendBuffer[1] = 0x02;//P1.0 和P1.1引脚置高
		//读取IO口数据
		Status = XIicPs_MasterSendPolled(&Iic, SendBuffer, 2, IIC_SLAVE_ADDR);
		usleep(100);

		//读取引脚状态.
		Status = XIicPs_MasterRecvPolled(&Iic, RecvBuffer, 2, IIC_SLAVE_ADDR);
	//		if (Status != XST_SUCCESS) {
	//			return XST_FAILURE;
	//		}
		xil_printf("P0=>%d",RecvBuffer[0]);
		xil_printf("P1=>%d",RecvBuffer[1]);
		sleep(1);
	}

    cleanup_platform();
    return 0;
}

亲测正常, 注意IIC的地址, 有的从0x20开始的, 有的是0x40开始的.