搜索
bottom↓
回复: 0

《ESP32-S3使用指南—MicroPython版 V1.0》第十四章 IO扩展实验

[复制链接]

出0入234汤圆

发表于 5 天前 | 显示全部楼层 |阅读模式
2.jpg
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
1.png
3.png

第十四章 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总线挂载多个器件的示意图,如下图所示。

第十四章 IO扩展实验737.png
图14.1.1.1 IIC总线挂载多个器件

       下面来学习IIC总线协议,IIC总线时序图如下所示:

第十四章 IO扩展实验814.png
图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的基本的读写通讯过程,包括主机写数据到从机即写操作,主机到从机读取数据即读操作。下面先看一下写操作通讯过程图,如下图所示.

第十四章 IO扩展实验1748.png
图14.1.1.3 写操作通讯过程图

       主机首先在IIC总线上发送起始信号,那么这时总线上的从机都会等待接收由主机发出的数据。主机接着发送从机地址+0(写操作)组成的8bit数据,所有从机接收到该8bit数据后,自行检验是否是自己的设备的地址,假如是自己的设备地址,那么从机就会发出应答信号。主机在总线上接收到有应答信号后,才能继续向从机发送数据。注意:IIC总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号。
       接着讲解一下IIC总线的读操作过程,先看一下读操作通讯过程图,如下图所示。

第十四章 IO扩展实验2002.png
图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的引脚说明如下表所示。

1.png
表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的从机地址格式如下图所示。

第十四章 IO扩展实验3420.png
图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寄存器中的字节。这个数据的低三位表示操作不同的寄存器,例如,操作读和写和内部寄存器(输入、输出、极性反转和配置)。如下图所示。

第十四章 IO扩展实验3727.png
图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”寄存器配置需结合实际的原理图来设置,如下图所示。

第十四章 IO扩展实验4132.png
图14.1.2.3 XL9555硬件原理图

       从上图可以看到,IO0_0~IO0_1和IO1_4~IO1_7被用作输入IO,其他管脚被用作输出IO。根据这些信息,我们使用寄存器6和寄存器7来配置端口0和端口1的IO输入/输出状态。

       3,配置IO输入输出模式
       XL9555的配置输入输出模式的写数据时序如下图所示。

第十四章 IO扩展实验4290.png
图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的配置输出写数据时序如下图所示。

第十四章 IO扩展实验4561.png
图14.1.2.5 寄存器2和寄存器3写数据流程

       由图可知,首先发送XL9555的从机地址+写信号(R/W=0),然后等待XL9555的应答信号,在应答成功后,发送数据(DATA0:用来配置寄存器2的IO输出状态)给XL9555就可以了,发送完数据,会收到XL9555的应答信号,接着,再一次发送数据(DATA1:用来配置寄存器3的IO输出状态)并且接收到XL9555的应答信号,最后就是IIC结束信号。

       5,读数据(输入状态)
       XL9555的读数据时序如下图所示:


第十四章 IO扩展实验4797.png


       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构造函数

  1. /* xl9555结构体 */
  2. typedef struct _xl9555_obj_t
  3. {
  4.     mp_obj_base_t   base;       /* 基地址 */
  5.     mp_obj_base_t   *iic_obj;   /* 指向IIC控制块 */
  6. } xl9555_obj_t;

  7. mp_obj_t xl9555_make_new(const mp_obj_type_t *type,size_t n_args,
  8. size_t n_kw,const mp_obj_t *all_args )
  9. {
  10.     /* 创建对象的参数 */
  11.     enum
  12.     {
  13.         ARG_iic,
  14.     };

  15.     static const mp_arg_t allowed_args[] = {
  16.         { MP_QSTR_iic, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
  17.     };
  18.     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
  19. mp_arg_parse_all_kw_array(n_args, n_kw, all_args,
  20. MP_ARRAY_SIZE(allowed_args), allowed_args, args);

  21.     /* 创建对象 */
  22.     xl9555_self = m_new_obj(xl9555_obj_t);
  23.     xl9555_self->base.type = &xl9555_type;
  24.     /* 设置对象参数 */
  25. mp_obj_base_t *xl9555_obj=
  26. (mp_obj_base_t*)MP_OBJ_TO_PTR(args[ARG_iic].u_obj);

  27.     if (xl9555_obj == MP_OBJ_NULL)
  28.     {
  29.         mp_raise_ValueError(MP_ERROR_TEXT("I2C init ???"));
  30.     }

  31.     xl9555_self->iic_obj        = xl9555_obj;

  32.     if (xl9555_obj == MP_OBJ_NULL)
  33.     {
  34.         mp_raise_ValueError(MP_ERROR_TEXT("I2C init ???"));
  35.     }
  36.         /* 初始化XL9555 */
  37.     xl9555_init();
  38.    
  39.     return MP_OBJ_FROM_PTR(xl9555_self);
  40. }
复制代码
       从上述源代码中可以得知,该构造函数只有一个参数,即传入IIC驱动的控制块。我们可以通过这个控制块调用IIC驱动下的收发函数。然后,我们还创建了一个XL9555对象,用于实例化对象并引用类的方法。最后,调用了xl9555_init函数来初始化XL9555 IO扩展芯片。以下是该初始化代码的示例:
  1. /**
  2. * @brief       XL9555初始化
  3. * @param       无
  4. * @retval      无
  5. */
  6. void xl9555_init(void)
  7. {
  8.     /* 上电先读取一次清除中断标志 */
  9.     uint8_t r_data[2];
  10.     xl9555_read_byte(r_data, 2);
  11.    
  12.     /* 配置XL9555端口,即写配置寄存器,数据格式为:地址 + CMD + 6 input + 12 output */
  13.     xl9555_ioconfig(0xF003);
  14.     xl9555_pin_write(BEEP_IO,1);
  15.     xl9555_pin_write(SPK_EN_IO,1);
  16. }

  17. /**
  18. * @brief       XL9555的IO配置
  19. * @param       config_value:配置数值
  20. * @retval      返回配置数值
  21. */
  22. static uint16_t xl9555_ioconfig(uint16_t config_value)
  23. {
  24.     /* 从机地址 + CMD + data1(P0) + data2(P1) */
  25. /* P00、P01、P14、P15、P16、P17为输入,其他引脚为输出
  26. -->1111 0000 0000 0011 .注意:0为输出,1为输入*/
  27.     uint8_t data[2];
  28.     esp_err_t err;
  29.     int retry = 3;

  30.     data[0] = (uint8_t)(0xFF & config_value);
  31.     data[1] = (uint8_t)(0xFF & (config_value >> 8));

  32.     do
  33.     {
  34.         err = xl9555_write_byte(XL9555_CONFIG_PORT0_REG, data, 2);
  35.         
  36.         if (err != ESP_OK)
  37.         {
  38.             retry--;
  39.             mp_hal_delay_ms(100);
  40.             ESP_LOGE("IIC", "%s configure %X failed, ret: %d",
  41. __func__, config_value, err);
  42.             xl9555_failed = 1;
  43.             
  44.             if ((retry <= 0) && xl9555_failed)
  45.             {
  46.                 mp_hal_delay_ms(5000);
  47.                 esp_restart();
  48.             }
  49.         }
  50.         else
  51.         {
  52.             xl9555_failed = 0;
  53.             break;
  54.         }
  55.         
  56.     } while (retry);
  57.    
  58.     return config_value;
  59. }
复制代码
       我们可以看到,首先,作者上电先读取一次数据清除中断标志,然后调用xl9555_ioconfig函数配置P0端和P1端的管脚输入输出模式,最后,调用xl9555_pin_write函数关闭蜂鸣器和喇叭功能。

       2,XL9555写时序
  1. /**
  2. * @brief       向XL9555写入16位IO值
  3. * @param       data:存储区
  4. * @param       len :读取数据大小
  5. * @retval      ESP_OK:读取成功;其他:读取失败
  6. */
  7. esp_err_t xl9555_write_byte(uint8_t reg,  uint8_t* data, size_t len)
  8. {
  9.     int data_len = 0;
  10.     mp_obj_base_t *self = (mp_obj_base_t *)MP_OBJ_TO_PTR(xl9555_self->iic_obj);
  11. mp_machine_i2c_p_t *i2c_p =
  12. (mp_machine_i2c_p_t *)MP_OBJ_TYPE_GET_SLOT(self->type, protocol);

  13.     mp_machine_i2c_buf_t bufs[2] = {
  14.         {.len = 1, .buf = ®},
  15.         {.len = len, .buf = data},
  16.     };

  17. data_len = i2c_p->transfer(self, XL9555_ADDR,2,
  18. bufs, MP_MACHINE_I2C_FLAG_STOP);
  19.    
  20.     if (data_len != 0)
  21.     {
  22.         return ESP_OK;
  23.     }
  24.     else
  25.     {
  26.         return ESP_FAIL;
  27.     }
  28. }
复制代码
       在上述源代码中,作者根据传入的IIC控制块,调用了IIC收发函数来发送XL9555的命令和数据。发送完成后,函数返回了ESP_OK状态。

       3,XL9555读时序
  1. /**
  2. * @brief       读取XL9555的16位IO值
  3. * @param       data:存储区
  4. * @param       len :读取数据大小
  5. * @retval      ESP_OK:读取成功;其他:读取失败
  6. */
  7. esp_err_t xl9555_read_byte(uint8_t* data, size_t len)
  8. {
  9.     int data_len = 0;
  10.     uint8_t memaddr_buf[1];
  11.     memaddr_buf[0]  = XL9555_INPUT_PORT0_REG;
  12.     mp_obj_base_t *self = (mp_obj_base_t *)MP_OBJ_TO_PTR(xl9555_self->iic_obj);
  13. mp_machine_i2c_p_t *i2c_p =
  14. (mp_machine_i2c_p_t *)MP_OBJ_TYPE_GET_SLOT(self->type, protocol);

  15.     mp_machine_i2c_buf_t bufs[2] = {
  16.         {.len = 1, .buf = memaddr_buf},
  17.         {.len = len, .buf = data},
  18.     };

  19. data_len = i2c_p->transfer(self, XL9555_ADDR, 2, bufs,
  20. MP_MACHINE_I2C_FLAG_WRITE1
  21. | MP_MACHINE_I2C_FLAG_READ
  22. | MP_MACHINE_I2C_FLAG_STOP);
  23.    
  24.     if (data_len != 0)
  25.     {
  26.         return ESP_OK;
  27.     }
  28.     else
  29.     {
  30.         return ESP_FAIL;
  31.     }
  32. }
复制代码
       同样地,XL9555的读时序也是利用IIC收发函数来实现的。写时序和读时序的唯一区别在于最后的flag标志位不同,从而导致发送流程有所不同。如果读者想了解i2c_p->transfer函数的收发流程,可以在MicroPython源代码中找到machine_i2c.c文件(位于micropython\ports\esp32路径下)。

       4,控制某个IO的状态
  1. /**
  2. * @brief       控制所有IO的电平
  3. * @param       reg_value:寄存器的数值
  4. * @retval      返回16位IO状态
  5. */
  6. uint16_t xl9555_multi_write_ex(uint16_t reg_value)
  7. {
  8.     uint8_t w_data[2];
  9.     esp_err_t err;
  10.     int retry = 3;

  11.     w_data[0] = (uint8_t)(0xFF & reg_value);
  12.     w_data[1] = (uint8_t)(0xFF & (reg_value >> 8));

  13.     do
  14.     {
  15.         /* 控制某个IO的电平 */
  16.         err = xl9555_write_byte(XL9555_OUTPUT_PORT0_REG, w_data, 2);
  17.         
  18.         if (err != ESP_OK)
  19.         {
  20.             retry--;
  21.             mp_hal_delay_ms(100);
  22.             ESP_LOGE("IIC", "%s failed, prev:%X, target: %X",
  23. __func__, xl9555_value, reg_value);
  24.             xl9555_failed = 1;
  25.         }
  26.         else
  27.         {
  28.             xl9555_failed = 0;
  29.             break;
  30.         }
  31.         
  32.     } while (retry);

  33.     if (xl9555_failed == 0)
  34.     {
  35.         xl9555_value = reg_value;
  36.     }
  37.    
  38.     return xl9555_value;
  39. }

  40. /**
  41. * @brief       控制某个IO的电平
  42. * @param       pin:控制的IO
  43. * @param       val:电平
  44. * @retval      返回16位IO状态
  45. */
  46. uint16_t xl9555_pin_write(uint16_t pin, int val)
  47. {
  48.     uint16_t i;
  49.     uint16_t wrt_data = xl9555_value;
  50.     uint16_t bitval = (val > 0) ? 1 : 0;
  51.     uint16_t temp;

  52.     for (i = 0; i < 16; i++)
  53.     {
  54.         temp = 0x1 << i;

  55.         if (pin & temp)
  56.         {
  57.             if (val) wrt_data |= temp;
  58.             else wrt_data &= ~temp;
  59.         }
  60.     }

  61.     return xl9555_multi_write_ex(wrt_data);
  62. }
复制代码
       上述源码中,作者先判断控制哪个IO,然后调用xl9555_multi_write_ex函数控制这个IO的电平输出。

       5,读取IO状态
  1. /**
  2. * @brief       读取XL9555的所有IO状态
  3. * @param       无
  4. * @retval      返回16位IO状态
  5. */
  6. uint16_t xl9555_multi_read_ex(void)
  7. {
  8.     uint16_t ret;
  9.     esp_err_t err;
  10.     uint8_t r_data[2];
  11.     int retry = 3;

  12.     do
  13.     {
  14.         err = xl9555_read_byte(r_data, 2);
  15.         
  16.         if (err != ESP_OK)
  17.         {
  18.             retry--;
  19.             mp_hal_delay_ms(100);
  20.             ESP_LOGE("IIC", "%s failed, prev:%X, target: %X",
  21. __func__, xl9555_value, xl9555_readonly_value);
  22.             xl9555_value = 1;
  23.         }
  24.         else
  25.         {
  26.             xl9555_value = 0;
  27.             break;
  28.         }
  29.         
  30.     } while (retry);

  31.     ret = r_data[1] << 8 | r_data[0];

  32.     xl9555_readonly_value = ret;
  33.     return ret;
  34. }

  35. /**
  36. * @brief       获取某个IO状态
  37. * @param       pin:要获取状态的IO
  38. * @retval      返回IO口的状态(0/1)
  39. */
  40. int xl9555_pin_read(uint16_t pin)
  41. {
  42.     return (xl9555_multi_read_ex() & pin) ? 1 : 0;
  43. }
复制代码
       从上述源代码中可以得知,作者首先调用了xl9555_multi_read_ex函数来读取所有IO的状态。然后,将这十六位的数值与读取的IO数值进行比较。如果数值为0,则输出为低电平;反之,则为高电平。

       14.2.2 C模块构造与类的方法

       1,atk_xl9555类与IIC构造函数
       xl9555和IIC的构造对象方法如下:
  1. class machine.I2C(id, scl, sda, freq=400000)
  2. class atk_xl9555.init(iic)
  3. 使用示例:
  4. i2c0 = I2C(0, scl = Pin(42), sda = Pin(41), freq = 400000)
  5. xl9555 = atk_xl9555.init(i2c0)
复制代码
       该构造方法的参数描述,如下表所示。

2.png
表14.2.2.1 IIC和XL9555构造函数参数描述

       返回值:IIC和XL9555对象。

       2,xl9555类的方法

       ①:控制某个扩展IO输出电平
       其方法原型如下:
  1. xl9555.write_bit(pin, value)
复制代码
       该函数的参数描述,如下表所示。

3.png
表14.2.2.2 xl9555.write_bit方法参数描述

       返回值:无。

       ②:读取某个扩展IO电平。
       其方法原型如下:
  1. xl9555.read_bit(pin)
复制代码
       该方法的参数描述,如下表所示。

4.png
表14.2.3.3 xl9555.write_bit方法参数描述

       返回值:读取IO的电平值

       ③:按键扫描。
       其方法原型如下:
  1. 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、独立按键和蜂鸣器硬件部分的原理图,如下图所示。

第十四章 IO扩展实验13527.png 第十四章 IO扩展实验13528.png

第十四章 IO扩展实验13530.png
图14.3.1 XL9555、独立按键和蜂鸣器原理图

       这里需要注意的是:独立按键设计为采样到按键另一端的低电平为有效电平。

       14.4 软件设计

       14.4.1 程序流程图
       程序流程图能帮助我们更好的理解一个工程的功能和实现的过程,对学习和设计工程有很好的主导作用。下面看看本实验的程序流程图:

第十四章 IO扩展实验13704.png
图14.4.1.1 程序流程图

       14.4.2 程序解析
       本书籍的代码都在main.py脚本下编写的,读者可在光盘资料下找到对应的源码。IO扩展实验main.py源码如下:
  1. from machine import Pin,I2C
  2. import atk_xl9555 as io_ex
  3. import time


  4. """
  5. * @brief       程序入口
  6. * @param       无
  7. * @retval      无
  8. """
  9. if __name__ == '__main__':
  10.    
  11.     # 初始化LED并输出高电平
  12.     led = Pin(1,Pin.OUT,value = 1)
  13.     # IIC初始化
  14.     i2c0 = I2C(0, scl = Pin(42), sda = Pin(41), freq = 400000)
  15.     # XL9555初始化
  16.     xl9555 = io_ex.init(i2c0)
  17.    
  18.     while True:
  19.         
  20.         # 获取按键值
  21.         key = int(xl9555.key_scan())
  22.         
  23.         if key == io_ex.KEY0:
  24.             xl9555.write_bit(io_ex.BEEP,0)      # 打开蜂鸣器
  25.         elif key == io_ex.KEY1:
  26.             xl9555.write_bit(io_ex.BEEP,1)      # 关闭蜂鸣器
  27.         elif key == io_ex.KEY2:
  28.             led.value(0)                        # 打开LED
  29.         elif key == io_ex.KEY3:
  30.             led.value(1)

  31.         time.sleep_ms(10)                       # 延时10ms
复制代码
       这示例代码的功能是:使用I2C通信协议,通过操作XL9555芯片来控制LED灯和蜂鸣器的状态。主程序进入无限循环,不断地扫描XL9555芯片的按键输入。如果KEY0被按下,则打开蜂鸣器;如果KEY1被按下,则关闭蜂鸣器;如果KEY2被按下,则关闭LED灯;如果KEY3被按下,则打开LED灯。每次按键操作后,程序会暂停10毫秒,以等待下一次按键输入。

       14.5 下载验证
       下载代码完成后,按键被按下时,程序会执行特定的操作。例如,如果按下KEY0,程序会启动蜂鸣器;如果按下KEY1,程序会关闭蜂鸣器;如果按下KEY2,程序会关闭LED灯;如果按下KEY3,程序会打开LED灯。

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-25 06:26

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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