数码之家

 找回密码
 立即注册
搜索
查看: 69|回复: 0

[Arduino] 《ESP32S3 Arduino开发指南》第十五章 IIC_EXIO实验

[复制链接]
发表于 昨天 09:22 | 显示全部楼层 |阅读模式
第十五章 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总线至16GPIO扩展器
l 工作电源电压范围为2.3 V5.5 V
l 低待机电流消耗
l 5 V容错I/O端口
l 400 kHz快速模式IIC总线时钟频率
l SCL/SDA输入上的噪声滤波器
l 内部通电复位
l 器件地址由3个硬件地址引脚决定,最多可在总线上挂载8个器件
l 中断脚为开漏输出模式(低电平有效)
l 16I/O引脚,默认为16个输入
简单概括一下,XL9555可使用400kHz速率的IIC通信接口与微控制器进行连接,也就是用2根通信线可扩展使用16IOXL9555器件地址会由三个硬件地址引脚决定,理论上在这个IIC总线上可挂载8XL9555器件,足以满足IO引脚需求。XL9555上电进行复位,16I/O口默认为输入模式,当输入模式的IO口状态发生变化时,即发生从高电平变低电平或者从低电平变高电平,中断脚会拉低。当中断有效后,必须对XL9555进行一次读取/写入操作,复位中断,才可以输出下一次中断,否则中断将一直保持。
XL9555引脚图如下图所示。
15.1.1 XL9555器件引脚图
XL9555器件总共有24个管脚,分别为电源线VCC、地线GNDGPIO口、通信线、地址线,上图用不同底色标注出来了。16个GPIO分为了2组,一组是8个,分为是P0xP1x,这些GPIO都可通过器件寄存器进行配置作为输出或者输出使用。通信线就是SDASCL,中断线INT也划分过来通信线。而地址线就是A0A1A2,用来决定器件地址。
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中的B2B1B0。这8个寄存器都是XL9555器件的16GPIO进行配置,其实分为4种:输入查询、输出设置、极性翻转和端口配置,每种都有两个寄存器对应的就是P0端口和P1端口。
地址0x000x01的寄存器是Input Port0”和“Input Port1”寄存器,主要用于获取P0P1IO输入状态。寄存器如下图所示。
15.1.2.2 XL9555Input Port Register详情
该寄存器只反应引脚输入逻辑电平情况,不管IO是设置成输入还是输出模式。打个比方,从0x00地址处(Input Port 0 Register)读出的数据是0x55,以二进制展开为01010101,从高位到低位对应的就是P07~P00IO状态,P00的输入电平状态就为高电平。
地址0x020x03的寄存器是Output Port0”和“Output Port1”寄存器,主要用于设置P0P1IO输出电平。寄存器如下图所示。
15.1.2.3 XL9555Output Port Register详情
该寄存器设置的是已经配置成输出模式的IO口的IO输出状态,1代表的是高电平,0代表的都是低电平,配置IO为输出模式的寄存器为Configuration Port寄存器。寄存器的一些位值对已经设置成输入模式的IO口是没有影响的。该寄存器还支持读取,读取到的值只是设置值,并不是实际引脚电平值,实际电平值通过Input Port寄存器查询即可。
地址0x040x05的寄存器是Polarity Inversion Port0”和“Polarity Inversion Port1”寄存器,用于对端口0和端口1进行极性翻转。该寄存器值默认为0,所以对IO电平翻转功能并没有启用,且在本实验也没有用到,所以不做讲解,详细说明可看《XL9555数据手册》P13。
地址0x060x07的寄存器是Configuration Port1”和“Configuration Port0”寄存器,用于配置P0P1IO输入/输出模式。寄存器如下图所示。
15.1.2.4 XL9555Configuration Port Register详情
该寄存器某一个位设置成1即作为输入模式,设置成0即作为输入模式。打个比方,要向0x06地址处(Configuration Port 0 Register)写入的数据是0x55,以二进制展开为01010101,从高位到低位对应的就是P07~P00IO配置模式,P00P02P04P06这四个IO口即配置为输入模式,而P01P03P05P07这四个IO口配置为输出模式。XL9555上电复位后,所有IO口默认都是输入状态,即上图这两个寄存器读出来的值都是0xFF。
15.1.3 XL9555时序介绍
ESP32-S3是通过IIC总线跟XL9555进行通信的,对XL9555相关寄存器进行写入配置,对其16IO进行使用。这里的时序主要就是写寄存器时序和读寄存器时序,我们一一介绍。
写寄存器时序
15.1.3.1 单字节写入到寄存器时序图
上图中展示的是主机将单字节写入到寄存器的时序,主机在IIC总线发送第1个字节的数据为XL9555的写操作地址0x40(设备地址0x20 << 1 | 0),用于寻找总线上找到XL9555,在获得XL9555的应答信号之后,继续发送第2个字节数据,该字节数据是XL9555的寄存器地址,再等到XL9555的应答信号,主机继续发送第3字节数据,这里的数据即是写入在第2字节寄存器地址的数据。主机完成写操作后,可以发出停止信号,终止数据传输。
在《XL9555数据手册》P16中,还提供有对Output Port寄存器组(0x020x03)的写时序图,简单来说,就是在一个时序中,把两个寄存器都进行设置,大家自行去查看。当然用单字节写入寄存器时序也可完成配置,只不过是需要一个一个寄存器进行配置,这样子的配置过程更为清晰明了。
读寄存器时序
15.1.3.2 单字节读取寄存器时序图
上图中展示的是主机从寄存器中读取一个字节数据的时序图。XL9555读取数据的过程是一个复合的时序,其中包含写时序和读时序。先看第一个通信过程,这里是写时序,起始信号产生后,主机发送XL9555的写操作地址0x40(设备地址0x20<< 1 | 0),获取从机应答信号后,接着发送需要读取的寄存器地址;在读时序中,起始信号产生后,主机发送XL9555的读操作地址0x41(设备地址0x20 << 1 | 1),获取从机应答信号后,接着从机返回刚刚在写时序中寄存器地址的数据,以字节为单位传输在总线上,主机接收到寄存器的数据后,发出非应答信号并以停止信号结束通信过程。
假如主机获取数据后返回的是应答信号,那么从机会一直传输数据,即把往后寄存器的数据也发送到总线上,这就是《XL9555数据手册》P17中从寄存器中读取多个字节的时序,大家可自行去查看。
15.2 硬件设计
1. 例程功能
通过按下KEY0~4按键来控制蜂鸣器和LED灯开关状态,KEY0KEY1控制蜂鸣器开与关;KEY2KEY3控制LED灯开与关。
2. 硬件资源
1LED
LED-IO1
2USART0
U0TXD-IO43
U0RXD-IO44
3XL9555
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器件16IO口的设计情况。IO0_0IO0_1IO1_4IO1_7被用作输入IOIO0_2~IO0_7IO1_0~IO1_3被用作输出IO
本实验主要就是用到XL9555器件的5IO,分为IO1_7KEY0)、IO1_6KEY1)、IO1_5KEY2)、IO1_4KEY3)和IO0_3BEEP)。
这里设计有4个按键,为了提高对按键的实时检测,使用到了中断引脚。但是这里的中断引脚并没有直接与ESP32-S3引脚相连,而是需要通过跳线帽对IIC_INTBOOT进行连接,这时候IIC_INT就连接到IO0。
特别注意:24C02XL9555共用IIC0,所以这两个器件在使用时,必须分时复用才可以。
15.3 软件设计
15.3.1 程序流程图
下面看看本实验的程序流程图:
图15.3.1 程序流程图
15.3.2 程序解析
1. XL9555驱动代码
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。XL9555驱动源码包括两个文件:xl9555.cppxl9555.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时,读取到的输入寄存器01的值就是低电平0 */
#define XL9555_INVERSION_PORT1_REG 5  
/* 极性反转P1寄存器用于当P1端口做为输入时,对输入的电平进行反转处理,即管脚为高电平时,设置这个寄存器中相应的位为1时,读取到的输入寄存器01的值就是低电平0 */
#define XL9555_CONFIG_PORT0_REG  6  
/* 配置P0寄存器用于配置P0端口的做为输入(1)或是输出(0) */
#define XL9555_CONFIG_PORT1_REG  7  
/* 配置P1寄存器用于配置P1端口的做为输入(1)或是输出(0) */
通过前面对XL9555寄存器介绍,我们知道这16IO口在寄存器的位置都是固定的,基于单个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,代码如下:
/**
* @brief     初始化IO扩展芯片
* @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~7P1~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);   
/* 假如是PORT1PIN需要先右移8*/
    pin_state = pin_state & port_value;    /* 得到需要查询位的状态 */
    return pin_state ? 1 : 0;
}
xl9555_io_config函数主要就是设置XL9555某个IO的模式,可设置成输出,也可设置为输入。内部实现逻辑比较简单,先调用xl9555_read_reg函数读取对应端口的配置寄存器值,然后对要设置的IO位进行操作,仅仅是该IO位,不能影响到其他IO的配置,要配置成输出模式还是输入模式,具体要看参数mode。若参数modeIO_SET_OUTPUT就要设置为输出模式,即对该IO位清零,否则就设置为输入模式,即对该IO位置1。最后,把整理后的端口值重新通过xl9555_write_reg函数写入到对应端口配置寄存器,即可完成对某个IO口的模式配置。
xl9555_pin_set函数内部实现逻辑跟xl9555_io_config函数是一样的,只不过访问操作寄存器不同而已,这里就不再赘述了。
xl9555_get_pin函数主要就是获取XL9555某个IO的电平状态,通过调用xl9555_read_reg函数去查询输入端口寄存器的值,然后与该位进行比较,最终知道该位的电平状态。
有时候,可能需要查询P0P1端口的输入状态,这里也提供了xl9555_read_port函数;设置P0P1端口的输出状态,也提供了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函数去对KEY0KEY1KEY2KEY3去判断,是否检测到低电平,若该按键检测到低电平,即该按键被拉低。
15.4 下载验证
下载代码完成后,按键被按下时,程序会执行特定的操作。例如,如果按下KEY0,程序会启动蜂鸣器;如果按下KEY1,程序会关闭蜂鸣器;如果按下KEY2,程序会关闭LED灯;如果按下KEY3,程序会打开LED灯。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-5-15 02:46 , Processed in 0.109200 second(s), 9 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

快速回复 返回顶部 返回列表