《ESP32-S3使用指南—MicroPython版 V1.0》第十四章 IO扩展实验
1)实验平台:正点原子ESP32S3开发板
2)购买链接:https://detail.tmall.com/item.htm?id=768499342659
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-347618-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子手把手教你学ESP32S3快速入门视频教程:https://www.bilibili.com/video/BV1sH4y1W7Tc
6)正点原子FPGA交流群:132780729
第十四章 IO扩展实验
在正点原子ESP32-S3开发板中,搭载了一颗16位的IO扩展芯片,该芯片主要用于控制输出和获取用户的输入,然后通过IIC协议传输至MCU内核。在本章中,我们将介绍如何通过自编写MicroPython模块来驱动该芯片,并实现按键控制蜂鸣器和LED开关状态的功能。
14.1 IIC简介&XL9555简介
14.2 XL9555 C模块解析
14.3 硬件设计
14.4 软件设计
14.5 下载验证
14.1 IIC简介 &XL9555简介
14.1.1 IIC简介
IIC(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器以及其外围设备。它是由数据线SDA和时钟线SCL构成的串行总线,可发送和接收数据,在CPU与被控IC之间、IC与IC之间进行双向传送。
IIC总线有如下特点:
①总线由数据线SDA和时钟线SCL构成的串行总线,数据线用来传输数据,时钟线用来同步数据收发。
②总线上每一个器件都有一个唯一的地址识别,所以我们只需要知道器件的地址,根据时序就可以实现微控制器与器件之间的通信。
③数据线SDA和时钟线SCL都是双向线路,都通过一个电流源或上拉电阻连接到正的电压,所以当总线空闲的时候,这两条线路都是高电平。
④总线上数据的传输速率在标准模式下可达100kbit/s在快速模式下可达400kbit/s在高速模式下可达3.4Mbit/s。
⑤总线支持设备连接。在使用IIC通信总线时,可以有多个具备IIC通信能力的设备挂载在上面,同时支持多个主机和多个从机,连接到总线的接口数量只由总线电容400pF的限制决定。IIC总线挂载多个器件的示意图,如下图所示。
图14.1.1.1 IIC总线挂载多个器件
下面来学习IIC总线协议,IIC总线时序图如下所示:
图14.1.1.2 IIC总线时序图
为了便于大家更好的了解IIC协议,我们从起始信号、停止信号、应答信号、数据有效性、数据传输以及空闲状态等6个方面讲解,大家需要对应图17.1.1.2的标号来理解。
① 起始信号
当SCL为高电平期间,SDA由高到低的跳变。起始信号是一种电平跳变时序信号,而不是一个电平信号。该信号由主机发出,在起始信号产生后,总线就处于被占用状态,准备数据传输。
② 停止信号
当SCL为高电平期间,SDA由低到高的跳变。停止信号也是一种电平跳变时序信号,而不是一个电平信号。该信号由主机发出,在停止信号发出后,总线就处于空闲状态。
③ 应答信号
发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
观察上图标号③就可以发现,有效应答的要求是从机在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。如果接收器是主机,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主机接收器发送一个停止信号。
④ 数据有效性
IIC总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。数据在SCL的上升沿到来之前就需准备好。并在下降沿到来之前必须稳定。
⑤ 数据传输
在I2C总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。数据位的传输是边沿触发。
⑥ 空闲状态
IIC总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。
了解前面的知识后,下面介绍一下IIC的基本的读写通讯过程,包括主机写数据到从机即写操作,主机到从机读取数据即读操作。下面先看一下写操作通讯过程图,如下图所示.
图14.1.1.3 写操作通讯过程图
主机首先在IIC总线上发送起始信号,那么这时总线上的从机都会等待接收由主机发出的数据。主机接着发送从机地址+0(写操作)组成的8bit数据,所有从机接收到该8bit数据后,自行检验是否是自己的设备的地址,假如是自己的设备地址,那么从机就会发出应答信号。主机在总线上接收到有应答信号后,才能继续向从机发送数据。注意:IIC总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号。
接着讲解一下IIC总线的读操作过程,先看一下读操作通讯过程图,如下图所示。
图14.1.1.4 读操作通讯过程图
主机向从机读取数据的操作,一开始的操作与写操作有点相似,观察两个图也可以发现,都是由主机发出起始信号,接着发送从机地址+1(读操作)组成的8bit数据,从机接收到数据验证是否是自身的地址。 那么在验证是自己的设备地址后,从机就会发出应答信号,并向主机返回8bit数据,发送完之后从机就会等待主机的应答信号。假如主机一直返回应答信号,那么从机可以一直发送数据,也就是图中的(n byte + 应答信号)情况,直到主机发出非应答信号,从机才会停止发送数据。
24C02的数据传输时序是基于IIC总线传输时序,下面讲解一下24C02的数据传输时序。
14.1.2 XL9555简介
XL9555是信路达推出的一款24引脚CMOS器件,通过I²C总线/SMBus接口(串行时钟线(SCL)、串行数据线(SDA))为大多数微控制器系列提供16位通用并行输入/输出(GPIO)扩展。这些设备设计用于2.3-V至5.5-V VCC操作。这些改进包括更高的驱动能力、5V I/O容差、更低的电源电流、单独的I/O配置和更小的封装。当ACPI电源开关、传感器、按钮、LED、风扇等需要额外的I/O时,I/O扩展器提供了一个简单的解决方案。当任何输入状态与其对应的输入端口寄存器状态不同时,这些设备开漏中断(/INT)输出被激活,并用于向系统主机指示输入状态已改变。在超时或其他不当操作的情况下,系统主设备可以利用上电重置功能重置这些设备。通电重置将寄存器设置为默认值,并初始化I²C/SMBus状态机。三个硬件引脚(A0、A1和A2)改变固定的I²C总线地址,并允许多达八个设备共享同一I²C总线/SMBus。
XL9555有如下特性:
I²C总线至16位GPIO扩展器
工作电源电压范围为2.3 V至5.5 V
低待机电流消耗
5 V容错I/O端口
400 kHz快速模式I²C总线时钟频率
SCL/SDA输入上的噪声滤波器
内部通电复位
通电时无故障
极性反转寄存器
开漏有源低中断输出
16个I/O引脚,默认为16个输入
1,引脚说明
XL9555的引脚说明如下表所示。
表14.1.2.1 XL9555引脚说明
我们使用的XL9555采用QFN24封装,总共24个脚,其中包括:16个准双向IO口(P00~P07,P10~P17)、3个地址线(A0~A2)、SCL、SDA、INT、GND和Vcc。每个XL9555只需要最少2个IO口,就可以扩展16路IO,在MCU的IO不够用的时候,XL9555是一个非常不错的IO扩展方案。
2,寻址
一个IIC总线上,可以挂多个XL9555(通过A0~A2寻址),XL9555的从机地址格式如下图所示。
图14.1.2.1 XL9555从机地址格式
图中的A0~A2为XL9555的寻址信息,我们开发板上A0~A2都是接GND的,所以,XL9555的地址为:0X20(左移了一位);R/W为读/写控制位,R/W=0的时候,表示写数据到XL9555,用来使IO输出电平;R/W=1的时候,表示读取XL9555的数据,获取IO口的状态。相关内容,请参考《XL9555.pdf》规格书。
3,芯片寄存器地址
在成功确认地址字节之后,总线主机发送一个命令,该命令指向存储在设备的控制XL9555寄存器中的字节。这个数据的低三位表示操作不同的寄存器,例如,操作读和写和内部寄存器(输入、输出、极性反转和配置)。如下图所示。
图14.1.2.2 芯片寄存器地址
从上图可以看出,“Input Port0”和“Input Port1”寄存器用于获取端口0和端口1的IO输入状态;“Output Port0”和“Output Port1”寄存器用于配置端口0和端口1的IO输出电平;“Polarity Inversion Port0”和“Polarity Inversion Port1”用于对端口0和端口1进行极性翻转,例如,如果P00输入的电平为低电平,那么XL9555将对它进行极性翻转,因此MCU获得的是高电平状态,同理,输出一样的原理;“Configuration Port1”和“Configuration Port0”寄存器则用于配置端口0和端口1的IO输入/输出模式。
值得注意的是,“Configuration Port1”和“Configuration Port0”寄存器配置需结合实际的原理图来设置,如下图所示。
图14.1.2.3 XL9555硬件原理图
从上图可以看到,IO0_0~IO0_1和IO1_4~IO1_7被用作输入IO,其他管脚被用作输出IO。根据这些信息,我们使用寄存器6和寄存器7来配置端口0和端口1的IO输入/输出状态。
3,配置IO输入输出模式
XL9555的配置输入输出模式的写数据时序如下图所示。
图14.1.2.4 寄存器6和寄存器7写数据流程
由图可知,XL9555操作寄存器6和寄存器7的数据写入非常简单,首先发送XL9555的从机地址+写信号(R/W=0),然后等待XL9555的应答信号,在应答成功后,发送数据(DATA0:用来配置寄存器6的IO输入输出模式)给XL9555就可以了,发送完数据,会收到XL9555的应答信号,接着,再一次发送数据(DATA1:用来配置寄存器7的IO输入输出模式)并且接收到XL9555的应答信号,最后就是IIC结束信号。
4,写数据(输出状态)
XL9555的配置输出写数据时序如下图所示。
图14.1.2.5 寄存器2和寄存器3写数据流程
由图可知,首先发送XL9555的从机地址+写信号(R/W=0),然后等待XL9555的应答信号,在应答成功后,发送数据(DATA0:用来配置寄存器2的IO输出状态)给XL9555就可以了,发送完数据,会收到XL9555的应答信号,接着,再一次发送数据(DATA1:用来配置寄存器3的IO输出状态)并且接收到XL9555的应答信号,最后就是IIC结束信号。
5,读数据(输入状态)
XL9555的读数据时序如下图所示:
XL9555的读数据流程:首先发送XL9555的从机地址+读信号(R/W=1),然后等待XL9555应答(注意:XL9555在发送应答的同时,会锁存P00~P07和P10~P17的数据),然后读取P00~P07的数据,再读取P10~P17的数据。数据读取支持连续读取,在最后的时候发送STOP信号,即可完成读数据操作。
6,中断
XL9555带有中断输出脚,它可以连接到MCU的中断输入引脚上。在输入模式中(IO口输出高电平,即可做输入使用),输入的上升沿或下降沿都可以产生中断,在tiv时间之后INT有效。特别注意:初始化XL9555以及一旦中断有效后,必须对XL9555进行一次读取/写入操作,复位中断,才可以输出下一次中断,否则中断将一直保持(无法输出下一次输入信号变化所产生的中断)。
14.2 XL9555 C模块解析
14.2.1 C模块解析
在先前的章节里,作者已经详述了C模块的添加流程以及整体架构,接下来作者将简要介绍正点原子XL9555 C模块驱动。这个讲解内容会分为几个部分:XL9555构造函数、写入数据、读取数据。XL9555 C模块驱动可在A盘6,软件资料1,软件2,MicroPython开发工具01-Windows2,正点原子MicroPython驱动CModules_LibIIC路径下找到。
1,XL9555构造函数
/* xl9555结构体 */
typedef struct _xl9555_obj_t
{
mp_obj_base_t base; /* 基地址 */
mp_obj_base_t *iic_obj; /* 指向IIC控制块 */
} xl9555_obj_t;
mp_obj_t xl9555_make_new(const mp_obj_type_t *type,size_t n_args,
size_t n_kw,const mp_obj_t *all_args )
{
/* 创建对象的参数 */
enum
{
ARG_iic,
};
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_iic, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
};
mp_arg_val_t args;
mp_arg_parse_all_kw_array(n_args, n_kw, all_args,
MP_ARRAY_SIZE(allowed_args), allowed_args, args);
/* 创建对象 */
xl9555_self = m_new_obj(xl9555_obj_t);
xl9555_self->base.type = &xl9555_type;
/* 设置对象参数 */
mp_obj_base_t *xl9555_obj=
(mp_obj_base_t*)MP_OBJ_TO_PTR(args.u_obj);
if (xl9555_obj == MP_OBJ_NULL)
{
mp_raise_ValueError(MP_ERROR_TEXT("I2C init ???"));
}
xl9555_self->iic_obj = xl9555_obj;
if (xl9555_obj == MP_OBJ_NULL)
{
mp_raise_ValueError(MP_ERROR_TEXT("I2C init ???"));
}
/* 初始化XL9555 */
xl9555_init();
return MP_OBJ_FROM_PTR(xl9555_self);
} 从上述源代码中可以得知,该构造函数只有一个参数,即传入IIC驱动的控制块。我们可以通过这个控制块调用IIC驱动下的收发函数。然后,我们还创建了一个XL9555对象,用于实例化对象并引用类的方法。最后,调用了xl9555_init函数来初始化XL9555 IO扩展芯片。以下是该初始化代码的示例:
/**
* @brief XL9555初始化
* @param 无
* @retval 无
*/
void xl9555_init(void)
{
/* 上电先读取一次清除中断标志 */
uint8_t r_data;
xl9555_read_byte(r_data, 2);
/* 配置XL9555端口,即写配置寄存器,数据格式为:地址 + CMD + 6 input + 12 output */
xl9555_ioconfig(0xF003);
xl9555_pin_write(BEEP_IO,1);
xl9555_pin_write(SPK_EN_IO,1);
}
/**
* @brief XL9555的IO配置
* @param config_value:配置数值
* @retval 返回配置数值
*/
static uint16_t xl9555_ioconfig(uint16_t config_value)
{
/* 从机地址 + CMD + data1(P0) + data2(P1) */
/* P00、P01、P14、P15、P16、P17为输入,其他引脚为输出
-->1111 0000 0000 0011 .注意:0为输出,1为输入*/
uint8_t data;
esp_err_t err;
int retry = 3;
data = (uint8_t)(0xFF & config_value);
data = (uint8_t)(0xFF & (config_value >> 8));
do
{
err = xl9555_write_byte(XL9555_CONFIG_PORT0_REG, data, 2);
if (err != ESP_OK)
{
retry--;
mp_hal_delay_ms(100);
ESP_LOGE("IIC", "%s configure %X failed, ret: %d",
__func__, config_value, err);
xl9555_failed = 1;
if ((retry <= 0) && xl9555_failed)
{
mp_hal_delay_ms(5000);
esp_restart();
}
}
else
{
xl9555_failed = 0;
break;
}
} while (retry);
return config_value;
} 我们可以看到,首先,作者上电先读取一次数据清除中断标志,然后调用xl9555_ioconfig函数配置P0端和P1端的管脚输入输出模式,最后,调用xl9555_pin_write函数关闭蜂鸣器和喇叭功能。
2,XL9555写时序
/**
* @brief 向XL9555写入16位IO值
* @param data:存储区
* @param len :读取数据大小
* @retval ESP_OK:读取成功;其他:读取失败
*/
esp_err_t xl9555_write_byte(uint8_t reg,uint8_t* data, size_t len)
{
int data_len = 0;
mp_obj_base_t *self = (mp_obj_base_t *)MP_OBJ_TO_PTR(xl9555_self->iic_obj);
mp_machine_i2c_p_t *i2c_p =
(mp_machine_i2c_p_t *)MP_OBJ_TYPE_GET_SLOT(self->type, protocol);
mp_machine_i2c_buf_t bufs = {
{.len = 1, .buf = ®},
{.len = len, .buf = data},
};
data_len = i2c_p->transfer(self, XL9555_ADDR,2,
bufs, MP_MACHINE_I2C_FLAG_STOP);
if (data_len != 0)
{
return ESP_OK;
}
else
{
return ESP_FAIL;
}
} 在上述源代码中,作者根据传入的IIC控制块,调用了IIC收发函数来发送XL9555的命令和数据。发送完成后,函数返回了ESP_OK状态。
3,XL9555读时序
/**
* @brief 读取XL9555的16位IO值
* @param data:存储区
* @param len :读取数据大小
* @retval ESP_OK:读取成功;其他:读取失败
*/
esp_err_t xl9555_read_byte(uint8_t* data, size_t len)
{
int data_len = 0;
uint8_t memaddr_buf;
memaddr_buf= XL9555_INPUT_PORT0_REG;
mp_obj_base_t *self = (mp_obj_base_t *)MP_OBJ_TO_PTR(xl9555_self->iic_obj);
mp_machine_i2c_p_t *i2c_p =
(mp_machine_i2c_p_t *)MP_OBJ_TYPE_GET_SLOT(self->type, protocol);
mp_machine_i2c_buf_t bufs = {
{.len = 1, .buf = memaddr_buf},
{.len = len, .buf = data},
};
data_len = i2c_p->transfer(self, XL9555_ADDR, 2, bufs,
MP_MACHINE_I2C_FLAG_WRITE1
| MP_MACHINE_I2C_FLAG_READ
| MP_MACHINE_I2C_FLAG_STOP);
if (data_len != 0)
{
return ESP_OK;
}
else
{
return ESP_FAIL;
}
} 同样地,XL9555的读时序也是利用IIC收发函数来实现的。写时序和读时序的唯一区别在于最后的flag标志位不同,从而导致发送流程有所不同。如果读者想了解i2c_p->transfer函数的收发流程,可以在MicroPython源代码中找到machine_i2c.c文件(位于micropython\ports\esp32路径下)。
4,控制某个IO的状态
/**
* @brief 控制所有IO的电平
* @param reg_value:寄存器的数值
* @retval 返回16位IO状态
*/
uint16_t xl9555_multi_write_ex(uint16_t reg_value)
{
uint8_t w_data;
esp_err_t err;
int retry = 3;
w_data = (uint8_t)(0xFF & reg_value);
w_data = (uint8_t)(0xFF & (reg_value >> 8));
do
{
/* 控制某个IO的电平 */
err = xl9555_write_byte(XL9555_OUTPUT_PORT0_REG, w_data, 2);
if (err != ESP_OK)
{
retry--;
mp_hal_delay_ms(100);
ESP_LOGE("IIC", "%s failed, prev:%X, target: %X",
__func__, xl9555_value, reg_value);
xl9555_failed = 1;
}
else
{
xl9555_failed = 0;
break;
}
} while (retry);
if (xl9555_failed == 0)
{
xl9555_value = reg_value;
}
return xl9555_value;
}
/**
* @brief 控制某个IO的电平
* @param pin:控制的IO
* @param val:电平
* @retval 返回16位IO状态
*/
uint16_t xl9555_pin_write(uint16_t pin, int val)
{
uint16_t i;
uint16_t wrt_data = xl9555_value;
uint16_t bitval = (val > 0) ? 1 : 0;
uint16_t temp;
for (i = 0; i < 16; i++)
{
temp = 0x1 << i;
if (pin & temp)
{
if (val) wrt_data |= temp;
else wrt_data &= ~temp;
}
}
return xl9555_multi_write_ex(wrt_data);
} 上述源码中,作者先判断控制哪个IO,然后调用xl9555_multi_write_ex函数控制这个IO的电平输出。
5,读取IO状态
/**
* @brief 读取XL9555的所有IO状态
* @param 无
* @retval 返回16位IO状态
*/
uint16_t xl9555_multi_read_ex(void)
{
uint16_t ret;
esp_err_t err;
uint8_t r_data;
int retry = 3;
do
{
err = xl9555_read_byte(r_data, 2);
if (err != ESP_OK)
{
retry--;
mp_hal_delay_ms(100);
ESP_LOGE("IIC", "%s failed, prev:%X, target: %X",
__func__, xl9555_value, xl9555_readonly_value);
xl9555_value = 1;
}
else
{
xl9555_value = 0;
break;
}
} while (retry);
ret = r_data << 8 | r_data;
xl9555_readonly_value = ret;
return ret;
}
/**
* @brief 获取某个IO状态
* @param pin:要获取状态的IO
* @retval 返回IO口的状态(0/1)
*/
int xl9555_pin_read(uint16_t pin)
{
return (xl9555_multi_read_ex() & pin) ? 1 : 0;
} 从上述源代码中可以得知,作者首先调用了xl9555_multi_read_ex函数来读取所有IO的状态。然后,将这十六位的数值与读取的IO数值进行比较。如果数值为0,则输出为低电平;反之,则为高电平。
14.2.2 C模块构造与类的方法
1,atk_xl9555类与IIC构造函数
xl9555和IIC的构造对象方法如下:
class machine.I2C(id, scl, sda, freq=400000)
class atk_xl9555.init(iic)
使用示例:
i2c0 = I2C(0, scl = Pin(42), sda = Pin(41), freq = 400000)
xl9555 = atk_xl9555.init(i2c0)
该构造方法的参数描述,如下表所示。
表14.2.2.1 IIC和XL9555构造函数参数描述
返回值:IIC和XL9555对象。
2,xl9555类的方法
①:控制某个扩展IO输出电平
其方法原型如下:
xl9555.write_bit(pin, value) 该函数的参数描述,如下表所示。
表14.2.2.2 xl9555.write_bit方法参数描述
返回值:无。
②:读取某个扩展IO电平。
其方法原型如下:
xl9555.read_bit(pin) 该方法的参数描述,如下表所示。
表14.2.3.3 xl9555.write_bit方法参数描述
返回值:读取IO的电平值
③:按键扫描。
其方法原型如下:
xl9555.key_scan() 返回值:按下的按键值。
14.3 硬件设计
1. 例程功能
本章实验功能简介:通过按下KEY0~4按键来控制蜂鸣器和LED灯开关状态,KEY0和KEY1控制蜂鸣器开与关;KEY2和KEY3控制LED灯开与关。
2. 硬件资源
1)LED灯
LED-IO1
2)XL9555
IIC_INT-IO0(需在P5连接IO0)
IIC_SDA-IO41
IIC_SCL-IO42
IO_17-KEY0
IO_16-KEY1
IO_15-KEY2
IO_14-KEY3
3. 原理图
XL9555、独立按键和蜂鸣器硬件部分的原理图,如下图所示。
图14.3.1 XL9555、独立按键和蜂鸣器原理图
这里需要注意的是:独立按键设计为采样到按键另一端的低电平为有效电平。
14.4 软件设计
14.4.1 程序流程图
程序流程图能帮助我们更好的理解一个工程的功能和实现的过程,对学习和设计工程有很好的主导作用。下面看看本实验的程序流程图:
图14.4.1.1 程序流程图
14.4.2 程序解析
本书籍的代码都在main.py脚本下编写的,读者可在光盘资料下找到对应的源码。IO扩展实验main.py源码如下:
from machine import Pin,I2C
import atk_xl9555 as io_ex
import time
"""
* @brief 程序入口
* @param 无
* @retval 无
"""
if __name__ == '__main__':
# 初始化LED并输出高电平
led = Pin(1,Pin.OUT,value = 1)
# IIC初始化
i2c0 = I2C(0, scl = Pin(42), sda = Pin(41), freq = 400000)
# XL9555初始化
xl9555 = io_ex.init(i2c0)
while True:
# 获取按键值
key = int(xl9555.key_scan())
if key == io_ex.KEY0:
xl9555.write_bit(io_ex.BEEP,0) # 打开蜂鸣器
elif key == io_ex.KEY1:
xl9555.write_bit(io_ex.BEEP,1) # 关闭蜂鸣器
elif key == io_ex.KEY2:
led.value(0) # 打开LED
elif key == io_ex.KEY3:
led.value(1)
time.sleep_ms(10) # 延时10ms 这示例代码的功能是:使用I2C通信协议,通过操作XL9555芯片来控制LED灯和蜂鸣器的状态。主程序进入无限循环,不断地扫描XL9555芯片的按键输入。如果KEY0被按下,则打开蜂鸣器;如果KEY1被按下,则关闭蜂鸣器;如果KEY2被按下,则关闭LED灯;如果KEY3被按下,则打开LED灯。每次按键操作后,程序会暂停10毫秒,以等待下一次按键输入。
14.5 下载验证
下载代码完成后,按键被按下时,程序会执行特定的操作。例如,如果按下KEY0,程序会启动蜂鸣器;如果按下KEY1,程序会关闭蜂鸣器;如果按下KEY2,程序会关闭LED灯;如果按下KEY3,程序会打开LED灯。
页:
[1]