第十五章 IIC_EXIO实验
本章,我们将继续使用ESP32-S3的硬件IIC接口去驱动IO扩展芯片XL9555。在本章中,实现和XL9555之间的双向通信,将使用其IO的输入输出功能。 本章分为如下几个小节: 15.1 XL9555介绍 15.2 硬件设计 15.3 软件设计 15.4 下载验证
15.1 XL9555介绍 XL9555是一款24引脚的CMOS器件,支持IIC总线或SMBus接口进行驱动。XL9555器件是一个16位通用并行输入/输出(GPIO)扩展器,可用其GPIO连接按键、LED、传感器等,解决需要额外的I/O的需求。 XL9555有如下特性: l IIC总线至16位GPIO扩展器 l 工作电源电压范围为2.3 V至5.5 V l 低待机电流消耗 l 5 V容错I/O端口 l 400 kHz快速模式IIC总线时钟频率 l SCL/SDA输入上的噪声滤波器 l 内部通电复位 l 器件地址由3个硬件地址引脚决定,最多可在总线上挂载8个器件 l 中断脚为开漏输出模式(低电平有效) l 16个I/O引脚,默认为16个输入 简单概括一下,XL9555可使用400kHz速率的IIC通信接口与微控制器进行连接,也就是用2根通信线可扩展使用16个IO。XL9555器件地址会由三个硬件地址引脚决定,理论上在这个IIC总线上可挂载8个XL9555器件,足以满足IO引脚需求。XL9555上电进行复位,16个I/O口默认为输入模式,当输入模式的IO口状态发生变化时,即发生从高电平变低电平或者从低电平变高电平,中断脚会拉低。当中断有效后,必须对XL9555进行一次读取/写入操作,复位中断,才可以输出下一次中断,否则中断将一直保持。 XL9555引脚图如下图所示。 图15.1.1 XL9555器件引脚图 XL9555器件总共有24个管脚,分别为电源线VCC、地线GND、GPIO口、通信线、地址线,上图用不同底色标注出来了。16个GPIO分为了2组,一组是8个,分为是P0x和P1x,这些GPIO都可通过器件寄存器进行配置作为输出或者输出使用。通信线就是SDA和SCL,中断线INT也划分过来通信线。而地址线就是A0、A1和A2,用来决定器件地址。 15.1.1 XL9555寻址 要进行IIC通信,首先得知道器件地址,XL9555器件地址是7位的,具体格式如下图。 图15.1.1.1 XL9555地址格式 从上图可以知道,XL9555器件地址由两部分组成,一部分就是“Fixed bits”即固定的4位“0100”;另一部分就是“Programmable bits”即可编程的3位“A2 A1 A0”,在硬件上,都把这三个引脚接地处理,所以这三位为“000”。最终可得到,XL9555器件地址为“0100000”即0x20。读操作地址就为0x41,即0100 0001;写操作地址就为0x40,即0100 0000。 15.1.2 XL9555寄存器介绍 接下来,介绍一下XL9555器件的八个寄存器,如下图所示。 图15.1.2.1 XL9555寄存器 由于在IIC通信中,数据都是以字节作为单位,表示寄存器地址的数据也是1个字节。由于XL9555器件只有八个寄存器,所以这里1个字节用3个位表示,即Table 5中的B2、B1和B0。这8个寄存器都是XL9555器件的16个GPIO进行配置,其实分为4种:输入查询、输出设置、极性翻转和端口配置,每种都有两个寄存器对应的就是P0端口和P1端口。 地址0x00和0x01的寄存器是“Input Port0”和“Input Port1”寄存器,主要用于获取P0和P1的IO输入状态。寄存器如下图所示。 图15.1.2.2 XL9555的Input Port Register详情 该寄存器只反应引脚输入逻辑电平情况,不管IO是设置成输入还是输出模式。打个比方,从0x00地址处(Input Port 0 Register)读出的数据是0x55,以二进制展开为01010101,从高位到低位对应的就是P07~P00的IO状态,P00的输入电平状态就为高电平。 地址0x02和0x03的寄存器是“Output Port0”和“Output Port1”寄存器,主要用于设置P0和P1的IO输出电平。寄存器如下图所示。 图15.1.2.3 XL9555的Output Port Register详情 该寄存器设置的是已经配置成输出模式的IO口的IO输出状态,1代表的是高电平,0代表的都是低电平,配置IO为输出模式的寄存器为Configuration Port寄存器。寄存器的一些位值对已经设置成输入模式的IO口是没有影响的。该寄存器还支持读取,读取到的值只是设置值,并不是实际引脚电平值,实际电平值通过Input Port寄存器查询即可。 地址0x04和0x05的寄存器是“Polarity Inversion Port0”和“Polarity Inversion Port1”寄存器,用于对端口0和端口1进行极性翻转。该寄存器值默认为0,所以对IO电平翻转功能并没有启用,且在本实验也没有用到,所以不做讲解,详细说明可看《XL9555数据手册》P13。 地址0x06和0x07的寄存器是“Configuration Port1”和“Configuration Port0”寄存器,用于配置P0和P1的IO输入/输出模式。寄存器如下图所示。 图15.1.2.4 XL9555的Configuration Port Register详情 该寄存器某一个位设置成1即作为输入模式,设置成0即作为输入模式。打个比方,要向0x06地址处(Configuration Port 0 Register)写入的数据是0x55,以二进制展开为01010101,从高位到低位对应的就是P07~P00的IO配置模式,P00、P02、P04、P06这四个IO口即配置为输入模式,而P01、P03、P05、P07这四个IO口配置为输出模式。XL9555上电复位后,所有IO口默认都是输入状态,即上图这两个寄存器读出来的值都是0xFF。 15.1.3 XL9555时序介绍 ESP32-S3是通过IIC总线跟XL9555进行通信的,对XL9555相关寄存器进行写入配置,对其16个IO进行使用。这里的时序主要就是写寄存器时序和读寄存器时序,我们一一介绍。 写寄存器时序 图15.1.3.1 单字节写入到寄存器时序图 上图中展示的是主机将单字节写入到寄存器的时序,主机在IIC总线发送第1个字节的数据为XL9555的写操作地址0x40(设备地址0x20 << 1 | 0),用于寻找总线上找到XL9555,在获得XL9555的应答信号之后,继续发送第2个字节数据,该字节数据是XL9555的寄存器地址,再等到XL9555的应答信号,主机继续发送第3字节数据,这里的数据即是写入在第2字节寄存器地址的数据。主机完成写操作后,可以发出停止信号,终止数据传输。 在《XL9555数据手册》P16中,还提供有对Output Port寄存器组(0x02和0x03)的写时序图,简单来说,就是在一个时序中,把两个寄存器都进行设置,大家自行去查看。当然用单字节写入寄存器时序也可完成配置,只不过是需要一个一个寄存器进行配置,这样子的配置过程更为清晰明了。 读寄存器时序 图15.1.3.2 单字节读取寄存器时序图 上图中展示的是主机从寄存器中读取一个字节数据的时序图。XL9555读取数据的过程是一个复合的时序,其中包含写时序和读时序。先看第一个通信过程,这里是写时序,起始信号产生后,主机发送XL9555的写操作地址0x40(设备地址0x20<< 1 | 0),获取从机应答信号后,接着发送需要读取的寄存器地址;在读时序中,起始信号产生后,主机发送XL9555的读操作地址0x41(设备地址0x20 << 1 | 1),获取从机应答信号后,接着从机返回刚刚在写时序中寄存器地址的数据,以字节为单位传输在总线上,主机接收到寄存器的数据后,发出非应答信号并以停止信号结束通信过程。 假如主机获取数据后返回的是应答信号,那么从机会一直传输数据,即把往后寄存器的数据也发送到总线上,这就是《XL9555数据手册》P17中从寄存器中读取多个字节的时序,大家可自行去查看。 15.2 硬件设计 1. 例程功能 通过按下KEY0~4按键来控制蜂鸣器和LED灯开关状态,KEY0和KEY1控制蜂鸣器开与关;KEY2和KEY3控制LED灯开与关。 2. 硬件资源 1)LED灯 LED-IO1 2)USART0 U0TXD-IO43 U0RXD-IO44 3)XL9555 IIC_INT-IO0(需用跳线帽在P5连接IO0) IIC_SDA-IO41 IIC_SCL-IO42 IO_03-BEEP IO_17-KEY0 IO_16-KEY1 IO_15-KEY2 IO_14-KEY3 3. 原理图 XL9555器件相关原理图,如下图所示。 图15.2.1 XL9555硬件原理图 从上图可以看到,ESP32-S3开发板对XL9555器件16个IO口的设计情况。IO0_0、IO0_1和IO1_4~IO1_7被用作输入IO,IO0_2~IO0_7和IO1_0~IO1_3被用作输出IO。 本实验主要就是用到XL9555器件的5个IO,分为IO1_7(KEY0)、IO1_6(KEY1)、IO1_5(KEY2)、IO1_4(KEY3)和IO0_3(BEEP)。 这里设计有4个按键,为了提高对按键的实时检测,使用到了中断引脚。但是这里的中断引脚并没有直接与ESP32-S3引脚相连,而是需要通过跳线帽对IIC_INT和BOOT进行连接,这时候IIC_INT就连接到IO0。 特别注意:24C02、XL9555共用IIC0,所以这两个器件在使用时,必须分时复用才可以。 15.3 软件设计 15.3.1 程序流程图 下面看看本实验的程序流程图: 图15.3.1 程序流程图 15.3.2 程序解析 1. XL9555驱动代码这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。XL9555驱动源码包括两个文件:xl9555.cpp和xl9555.h。 下面我们先解析XL9555.h的程序。对IIC引脚和XL9555器件地址做了相关定义。 #define IIC_SCL 42 #define IIC_SDA 41 #define IIC_INT_PIN 0 /* 需要用跳线帽进行连接 */ #define EXIO_ADDR 0x20 /* 7位器件地址 */ 我们选择使用IO42作为IIC的时钟线,IO41作为IIC的数据线,IO0作为IIC的中断线(需要用跳线帽选择连接),XL9555的器件地址为0x20。 由于我们这里会使用到IIC中断线,所以有一个IIC_INT宏用来读取中断线状态。 #define IIC_INT digitalRead(IIC_INT_PIN) 通过前面的介绍可知,XL9555器件有8个寄存器,所以这里我们也定义了对应的宏,如下所示。 /* 器件寄存器 */ #define XL9555_INPUT_PORT0_REG 0 /* 输入P0寄存器用于读取P0端口的输入值 */ #define XL9555_INPUT_PORT1_REG 1 /* 输入P1寄存器用于读取P1端口的输入值 */ #define XL9555_OUTPUT_PORT0_REG 2 /* 输出P0寄存器用于设置P0端口的输出值 */ #define XL9555_OUTPUT_PORT1_REG 3 /* 输出P1寄存器用于设置P1端口的输出值 */ #define XL9555_INVERSION_PORT0_REG 4 /* 极性反转P0寄存器用于当P0端口做为输入时,对输入的电平进行反转处理,即管脚为高电平时,设置这个寄存器中相应的位为1时,读取到的输入寄存器0,1的值就是低电平0 */ #define XL9555_INVERSION_PORT1_REG 5 /* 极性反转P1寄存器用于当P1端口做为输入时,对输入的电平进行反转处理,即管脚为高电平时,设置这个寄存器中相应的位为1时,读取到的输入寄存器0,1的值就是低电平0 */ #define XL9555_CONFIG_PORT0_REG 6 /* 配置P0寄存器用于配置P0端口的做为输入(1)或是输出(0) */ #define XL9555_CONFIG_PORT1_REG 7 /* 配置P1寄存器用于配置P1端口的做为输入(1)或是输出(0) */ 通过前面对XL9555寄存器介绍,我们知道这16个IO口在寄存器的位置都是固定的,基于单个IO操作单位的考虑,所以定义了每个引脚的宏以及一组端口的宏,如下所示: #define XL_PIN_P00 0x0001 #define XL_PIN_P01 0x0002 #define XL_PIN_P02 0x0004 #define XL_PIN_P03 0x0008 #define XL_PIN_P04 0x0010 #define XL_PIN_P05 0x0020 #define XL_PIN_P06 0x0040 #define XL_PIN_P07 0x0080 #define XL_PIN_P10 0x0100 #define XL_PIN_P11 0x0200 #define XL_PIN_P12 0x0400 #define XL_PIN_P13 0x0800 #define XL_PIN_P14 0x1000 #define XL_PIN_P15 0x2000 #define XL_PIN_P16 0x4000 #define XL_PIN_P17 0x8000 #define XL_PORT0_ALL_PIN 0x00FF #define XL_PORT1_ALL_PIN 0xFF00 以上的宏不利于查看与硬件的设计关系,所以重新再定义了一些宏,方便去理解以及使用。 /* IO扩展芯片XL9555的各个IO功能 */ #define KEY0 XL_PIN_P17 /* 按键0引脚 P17 */ #define KEY1 XL_PIN_P16 /* 按键1引脚 P16 */ #define KEY2 XL_PIN_P15 /* 按键2引脚 P15 */ #define KEY3 XL_PIN_P14 /* 按键3引脚 P14 */ #define SLCD_PWR XL_PIN_P13 /* SPI_LCD控制背光引脚 P13 */ #define SLCD_RST XL_PIN_P12 /* SPI_LCD复位引脚 P12 */ #define CT_RST XL_PIN_P11 /* 触摸屏中断引脚 P11 */ #define LCD_BL XL_PIN_P10 /* RGB屏背光控制引脚 P10 */ #define GBC_KEY XL_PIN_P07 /* ATK_MODULE接口KEY引脚 P07 */ #define GBC_LED XL_PIN_P06 /* ATK_MODULE接口LED引脚 P06 */ #define OV_RESET XL_PIN_P05 /* 摄像头复位引脚 P05 */ #define OV_PWDN XL_PIN_P04 /* 摄像头待机引脚 P04 */ #define BEEP XL_PIN_P03 /* 蜂鸣器控制引脚 P03 */ #define SPK_EN XL_PIN_P02 /* 功放使能引脚 P02 */ #define QMA_INT XL_PIN_P01 /* QMA6100P中断引脚 P01 */ #define AP_INT XL_PIN_P00 /* AP3216C中断引脚 P00 */ 在程序中,就是通过调用以上宏进行设置使用。 接下来,我们来解析一下xl9555.cpp的程序,首先先来看一下XL9555器件的初始化函数xl9555_init,代码如下: /** * @param 无 * @retval 无 */ void xl9555_init(void) { pinMode(IIC_INT_PIN, INPUT_PULLUP); /* 配置中断引脚 */ Wire.begin(IIC_SDA, IIC_SCL, 400000); /* 初始化IIC连接 */ /* 上电先读取一次清除中断标志 */ xl9555_read_port(0); xl9555_read_port(1); } 在XL9555初始化函数中,首先通过pinMode函数对中断引脚进行初始化,由于中断是低电平有效的,所以在这里的模式设置为上拉输入。然后调用Wire.begin函数接口就决定使用了IIC0,然后把IIC_SDA引脚和IIC_SCL引脚作为IIC0的数据线和时钟线使用。由于XL9555手册中描述到400kHz通信频率,所以这里直接把IIC0的通信速率设为400kHz。此外,在函数中,还调用到xl9555_read_port函数对寄存器进行读取,清除中断标志,以防出错。 接下来,看一下如何向XL9555寄存器写入一个字节数据的函数xl9555_write_reg,代码如下。 /** * @brief 向XL9555相关寄存器写数据 * @param reg : 寄存器地址 * @param data : 写入到寄存器的数据 * @retval 无 */ void xl9555_write_reg(uint8_t reg, uint8_t data) { Wire.beginTransmission(EXIO_ADDR); /* 发送从机的7位器件地址到发送队列 */ Wire.write(reg); /* 发送要写入从机寄存器的地址到发送队列 */ Wire.write(data); /* 发送要写入从机寄存器的数据到发送队列 */ Wire.endTransmission(); /* IIC发送发送队列的数据(无参数,表示发送stop信号) */ } 这里的写操作流程跟前面15.1小节中XL9555写寄存器时序图描述的过程是一致的。首先调用Wire.beginTransmission函数将从机地址0x20加入到发送数据队列,然后调用Wire.write函数将要写入数据的寄存器地址加入到发送数据队列,继续调用Wire.write函数将要写入寄存器地址的数据加入到发送数据队列,最后调用Wire.endTransmission函数将数据队列的数据发送到XL9555,最终实现对寄存器数据的写入。 继续看一下如何向XL9555相关寄存器读取一字节数据的函数xl9555_read_reg,代码如下。 /** * @brief 向XL9555相关寄存器读取数据 * @param reg : 寄存器地址 * @retval 寄存器的值 / 0xFF:未接收到数据 */ uint8_t xl9555_read_reg(uint8_t reg) { Wire.beginTransmission(EXIO_ADDR); /* 发送从机的7位器件地址到发送队列 */ Wire.write(reg); /* 发送要读取从机的寄存器地址到发送队列 */ Wire.endTransmission(0); /* IIC发送发送队列的数据(传参为0,表示重新发送一个start信号,保持IIC总线有效连接) */ Wire.requestFrom(EXIO_ADDR, 1); /* 主机向从机发送数据请求,并获取到数据 */ if (Wire.available() != 0) /* 得到已经接收到的数据字节数 */ { return Wire.read(); /* 到数据缓冲区读取数据 */ } return 0xFF; } 这里的读操作流程跟前面15.1小节中XL9555读寄存器时序图描述的过程是一致的。首先调用Wire.beginTransmission函数将从机地址0x50加入到发送数据队列,然后调用Wire.write函数将要要读取数据的寄存器地址加入到发送数据队列,继续调用Wire.endTransmission函数将数据队列的数据发送到XL9555。注意:Wire.endTransmission函数带参数0表明会重新发送一个起始信号,保持IIC总线的连接。后面就通过调用Wire.requestFrom函数向XL9555指定寄存器读取1字节数据并保存到接收缓冲区,Wire.available函数用于查询缓冲区是否有可读数据,而Wire.read函数就是用来读取缓冲区一字节数据。 基于写寄存器和读寄存器的函数接口,我们就可以为输出功能、输入功能以及端口配置功能封装成对应函数接口,方便调用,函数代码如下。 /** * @brief 设置XL9555某个IO的模式(输出或输入) * @param port_pin : 要设置的IO编号,P0~7或P1~7 * @param mode : IO_SET_OUTPUT / IO_SET_INPUT * @retval 无 */ void xl9555_io_config(uint16_t port_pin, io_mode_t mode) { uint8_t config_reg = 0; uint8_t config_value = 0; config_reg = xl9555_read_reg(port_pin > XL_PORT0_ALL_PIN ? \ XL9555_CONFIG_PORT1_REG : XL9555_CONFIG_PORT0_REG); /* 先读取设置Pin所在的寄存器情况 */ if (mode == IO_SET_OUTPUT) /* 根据 mode参数 设置输入输出情况,不能影响其他IO */ { config_value = config_reg&(~(port_pin>>(port_pin>XL_PORT0_ALL_PIN?8:0))); /* 得到某个IO设置为输出功能后的PORT值但不影响未设置的其他IO的状态 */ } else { config_value = config_reg|(port_pin>>(port_pin>XL_PORT0_ALL_PIN?8:0)); /* 得到某个IO设置为输入功能的PORT值但不影响未设置的其他IO的状态 */ } xl9555_write_reg(port_pin > XL_PORT0_ALL_PIN ? XL9555_CONFIG_PORT1_REG : XL9555_CONFIG_PORT0_REG, config_value); /* 向配置寄存器设置IO输入输出状态 */ } /** * @brief 设置XL9555配置为输出功能的IO的输出状态(高电平或低电平) * @param port_pin : 已经设置好输出功能的IO编号 * @param state : IO_SET_LOW / IO_SET_HIGH * @retval 无 */ void xl9555_pin_set(uint16_t port_pin, io_state_t state) { uint8_t pin_reg = 0; uint8_t pin_value = 0; pin_reg = xl9555_read_reg(port_pin > XL_PORT0_ALL_PIN ? XL9555_OUTPUT_PORT1_REG : XL9555_OUTPUT_PORT0_REG); /* 先读取设置Pin所在的寄存器情况 */ if (state == IO_SET_HIGH) /* 根据 state参数 设置IO的高低电平 */ { pin_value = pin_reg |(port_pin >> (port_pin > XL_PORT0_ALL_PIN ? 8 : 0)); /* 得到某个IO设置为高电平后的PORT值但不影响未设置的其他IO的状态 */ } else { pin_value = pin_reg & (~(port_pin >> (port_pin>XL_PORT0_ALL_PIN ?8:0))); /* 得到某个IO设置为低电平后的PORT值但不影响未设置的其他IO的状态 */ } xl9555_write_reg(port_pin > XL_PORT0_ALL_PIN ? XL9555_OUTPUT_PORT1_REG : XL9555_OUTPUT_PORT0_REG, pin_value); /* 向输出寄存器设置IO高低电平状态 */ } /** * @brief 获取XL9555配置为输入功能的IO的状态(高电平或低电平) * @param port_pin : 已经设置好输入功能的IO编号 * @retval 0低电平 / 1高电平 */ uint8_t xl9555_get_pin(uint16_t port_pin) { uint8_t pin_state = 0; uint8_t port_value = 0; port_value = xl9555_read_reg(port_pin > XL_PORT0_ALL_PIN ? \ XL9555_INPUT_PORT1_REG : XL9555_INPUT_PORT0_REG); /* 读取pin所在port的状态:1没有按下,0按下 */ pin_state = port_pin >> (port_pin > XL_PORT0_ALL_PIN ? 8 : 0); /* 假如是PORT1的PIN需要先右移8位 */ pin_state = pin_state & port_value; /* 得到需要查询位的状态 */ return pin_state ? 1 : 0; } xl9555_io_config函数主要就是设置XL9555某个IO的模式,可设置成输出,也可设置为输入。内部实现逻辑比较简单,先调用xl9555_read_reg函数读取对应端口的配置寄存器值,然后对要设置的IO位进行操作,仅仅是该IO位,不能影响到其他IO的配置,要配置成输出模式还是输入模式,具体要看参数mode。若参数mode为IO_SET_OUTPUT就要设置为输出模式,即对该IO位清零,否则就设置为输入模式,即对该IO位置1。最后,把整理后的端口值重新通过xl9555_write_reg函数写入到对应端口配置寄存器,即可完成对某个IO口的模式配置。 xl9555_pin_set函数内部实现逻辑跟xl9555_io_config函数是一样的,只不过访问操作寄存器不同而已,这里就不再赘述了。 xl9555_get_pin函数主要就是获取XL9555某个IO的电平状态,通过调用xl9555_read_reg函数去查询输入端口寄存器的值,然后与该位进行比较,最终知道该位的电平状态。 有时候,可能需要查询P0或P1端口的输入状态,这里也提供了xl9555_read_port函数;设置P0或P1端口的输出状态,也提供了xl9555_write_port函数。 2. 09_iic_exio.ino代码在09_iic_exio.ino里面编写如下代码: #include "xl9555.h" #include "led.h" #include "uart.h" /** * @brief 当程序开始执行时,将调用setup()函数,通常用来初始化变量、函数等 * @param 无 * @retval 无 */ void setup() { led_init(); /* LED初始化 */ uart_init(0, 115200); /* 串口0初始化 */ xl9555_init(); /* IO扩展芯片初始化 */ xl9555_io_config(KEY0 | KEY1 | KEY2 | KEY3, IO_SET_INPUT); /* 初始化IO扩展芯片用作按键的引脚为输入状态 */ xl9555_io_config(BEEP, IO_SET_OUTPUT); /* 初始化IO扩展芯片用作蜂鸣器控制的引脚为输出状态 */ } /** * @brief 循环函数,通常放程序的主体或者需要不断刷新的语句 * @param 无 * @retval 无 */ void loop() { if (!IIC_INT) /* 端口有发生变化变为低电平 */ { if (xl9555_get_pin(KEY0) == 0) { Serial.printf("KEY0 is pressed, BEEP is on \r\n"); xl9555_pin_set(BEEP, IO_SET_LOW); } if (xl9555_get_pin(KEY1) == 0) { Serial.printf("KEY1 is pressed, BEEP is off \r\n"); xl9555_pin_set(BEEP, IO_SET_HIGH); } if (xl9555_get_pin(KEY2) == 0) { Serial.printf("KEY2 is pressed, LED is on \r\n"); LED(0); } if (xl9555_get_pin(KEY3) == 0) { Serial.printf("KEY3 is pressed, LED is off \r\n"); LED(1); } } delay(200); } 在setup函数中,调用led_init函数完成LED初始化,调用uart_init函数完成串口初始化,调用xl9555_init函数完成XL9555初始化,然后调用xl9555_io_config函数对KEY0~KEY3设置为输入模式,对BEEP设置成输出模式。 在loop函数中,会以200毫秒间隔查询IIC_INT引脚是否拉低,假如说拉低,就说明IO口电平状态有发生变化。这时候就可以调用xl9555_get_pin函数去对KEY0、KEY1、KEY2和KEY3去判断,是否检测到低电平,若该按键检测到低电平,即该按键被拉低。 15.4 下载验证 下载代码完成后,按键被按下时,程序会执行特定的操作。例如,如果按下KEY0,程序会启动蜂鸣器;如果按下KEY1,程序会关闭蜂鸣器;如果按下KEY2,程序会关闭LED灯;如果按下KEY3,程序会打开LED灯。
|