搜索
bottom↓
回复: 0

《ESP32-S3使用指南—MicroPython版 V1.0》第十七章 EEPROM实验

[复制链接]

出0入234汤圆

发表于 4 天前 | 显示全部楼层 |阅读模式
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

第十七章 EEPROM实验


       本章,我们将介绍如何使用ESP32-S3的硬件IIC协议端口,并实现和24C02之间的双向通信,并把结果显示在SPILCD模块上。本章分为如下几个小节:
       17.1 24C02介绍
       17.2 AT24C02 C模块解析
       17.3 硬件设计
       17.4 程序设计
       17.5 下载验证

       17.1 24C02介绍
       24C02是一个2K bit的串行EEPROM存储器,内部含有256个字节。在24C02里面还有一个8字节的页写缓冲器。该设备的通信方式IIC,通过其SCL和SDA与其他设备通信,芯片的引脚图如下图所示。

第十七章 EEPROM实验272.png
图17.1.1 24C02引脚图

       上图的WP引脚是写保护引脚,接高电平只读,接地允许读和写,我们的板子设计是把该引脚接地。每一个设备都有自己的设备地址,24C02也不例外,但是24C02的设备地址是包括不可编程部分和可编程部分,可编程部分是根据上图的硬件引脚A0、A1和A2所决定。设备地址最后一位用于设置数据的传输方向,即读操作/写操作,0是写操作,1是读操作,具体格式如下图所示。

第十七章 EEPROM实验468.png
图17.1.2 24C02设备地址格式图

       根据我们的板子设计,A0、A1和A2均接地处理,所以24C02设备的读操作地址为:0xA1;写操作地址为:0xA0。
       在前面已经说过IIC总线的基本读写操作,那么我们就可以基于IIC总线的时序的上,理解24C02的数据传输时序。
       下面把实验中到的数据传输时序讲解一下,分别是对24C02的写时序和读时序。24C02写时序图如下图所示。

第十七章 EEPROM实验660.png
图17.1.3 24C02写时序图

       上图展示的主机向24C02写操作时序图,主机在IIC总线发送第1个字节的数据为24C02的设备地址0xA0,用于寻找总线上找到24C02,在获得24C02的应答信号之后,继续发送第2个字节数据,该字节数据是24C02的内存地址,再等到24C02的应答信号,主机继续发送第3字节数据,这里的数据即是写入在第2字节内存地址的数据。主机完成写操作后,可以发出停止信号,终止数据传输。
       上面的写操作只能单字节写入到24C02,效率比较低,所以24C02有页写入时序,大大提高了写入效率,下面看一下24C02页写时序图,如下图所示。

第十七章 EEPROM实验942.png
图17.1.4 24C02页写时序

       在单字节写时序时,每次写入数据时都需要先写入设备的内存地址才能实现,在页写时序中,只需要告诉24C02第一个内存地址1,后面数据会按照顺序写入到内存地址2,内存地址3等,大大节省了通信时间,提高了时效性。因为24C02每次只能8bit数据,所以它的页大小也就是1字节。页写时序的操作方式跟上面的单字节写时序差不多,所以不作过多解释了。参考以上说明去理解页写时序。
       说完两种写入方式之后,下图是关于24C02的读时序。

第十七章 EEPROM实验1172.png
图17.1.5 24C02读时序图

       24C02读取数据的过程是一个复合的时序,其中包含写时序和读时序。先看第一个通信过程,这里是写时序,起始信号产生后,主机发送24C02设备地址0xA0,获取从机应答信号后,接着发送需要读取的内存地址;在读时序中,起始信号产生后,主机发送24C02设备地址0xA1,获取从机应答信号后,接着从机返回刚刚在写时序中内存地址的数据,以字节为单位传输在总线上,假如主机获取数据后返回的是应答信号,那么从机会一直传输数据,当主机发出的是非应答信号并以停止信号发出为结束,从机就会结束传输。

       17.2 AT24C02 C模块解析

       17.2.1 C模块解析
       作者将简要介绍正点原子AT24C02 C模块驱动。这个讲解内容会分为几个部分:AT24C02构造函数、读写数据。AT24C02 C模块驱动可在A盘6,软件资料1,软件2,MicroPython开发工具01-Windows2,正点原子MicroPython驱动CModules_LibIIC路径下找到。

       1,AT24C02构造函数
  1. mp_obj_t at24cx_make_new(const mp_obj_type_t *type,size_t n_args,
  2. size_t n_kw,const mp_obj_t *all_args )
  3. {
  4.     /* 创建对象的参数 */
  5.     enum
  6.     {
  7.         ARG_iic,
  8.     };

  9.     static const mp_arg_t allowed_args[] = {
  10.         { MP_QSTR_iic, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
  11.     };
  12.     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
  13. mp_arg_parse_all_kw_array(n_args, n_kw, all_args,
  14.                           MP_ARRAY_SIZE(allowed_args), allowed_args, args);

  15.         /* 创建对象 */
  16.     at24cx_self = m_new_obj(at24cx_obj_t);
  17.     at24cx_self->base.type = &at24cx_type;
  18.     /* 设置对象参数 */
  19. mp_obj_base_t *at24cx_obj   = (mp_obj_base_t*)
  20. MP_OBJ_TO_PTR(args[ARG_iic].u_obj);
  21.     at24cx_self->iic_obj        = at24cx_obj;

  22.     if (at24cx_obj == MP_OBJ_NULL)
  23.     {
  24.         mp_raise_ValueError(MP_ERROR_TEXT("I2C init ???"));
  25.     }

  26.     return MP_OBJ_FROM_PTR(at24cx_self);
  27. }
复制代码
       在上述源代码中,作者创建了一个at24cx对象控制块,并设置了该对象的相关参数。接着,他判断IIC控制块是否为空。如果IIC控制块不为空,则返回at24cx对象控制块。

       2,在AT24CXX指定地址读出一个数据
  1. /**
  2. * @brief       在AT24CXX指定地址读出一个数据
  3. * @param       addr: 开始读数的地址
  4. * @retval      读到的数据
  5. */
  6. static uint8_t at24cxx_read_one_byte(uint16_t addr)
  7. {
  8.     esp_err_t ret = 0;
  9.     uint8_t data = 0;
  10.     hw_i2c_obj_t *self = MP_OBJ_TO_PTR(at24cx_self->iic_obj);
  11.     i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  12.     i2c_master_start(cmd);
  13.     /* 根据不同的24CXX型号, 发送高位地址
  14.     * 1, 24C16以上的型号, 分2个字节发送地址
  15. * 2, 24C16及以下的型号, 分1个低字节地址 + 占用器件地址的bit1~bit3位
  16. 用于表示高位地址, 最多11位地址
  17.     *    对于24C01/02, 其器件地址格式(8bit)为: 1  0  1  0  A2  A1  A0  R/W
  18.     *    对于24C04,    其器件地址格式(8bit)为: 1  0  1  0  A2  A1  a8  R/W
  19.     *    对于24C08,    其器件地址格式(8bit)为: 1  0  1  0  A2  a9  a8  R/W
  20.     *    对于24C16,    其器件地址格式(8bit)为: 1  0  1  0  a10 a9  a8  R/W
  21.     *    R/W      : 读/写控制位 0,表示写; 1,表示读;
  22.     *    A0/A1/A2 : 对应器件的1,2,3引脚(只有24C01/02/04/8有这些脚)
  23. *    a8/a9/a10: 对应存储整列的高位地址, 11bit地址最多可以表示2048个位置,
  24. 可以寻址24C16及以内的型号
  25.     */  
  26.     if (EE_TYPE > AT24C16)
  27. {
  28. /* 发送写命令 */
  29.         i2c_master_write_byte(cmd, (AT_ADDR<<1)|I2C_MASTER_WRITE, ACK_CHECK_EN);   
  30.         /* 发送高地址 */
  31. i2c_master_write_byte(cmd, addr >> 8, ACK_CHECK_EN);                           
  32.     }
  33.     else
  34.     {
  35.         /* 送器件地址0XA0,写数据 */
  36. i2c_master_write_byte(cmd, 0XA0 + ((addr / 256) << 1), ACK_CHECK_EN);           
  37.     }
  38.     /* 发送低地址 */
  39.     i2c_master_write_byte(cmd, addr % 256, ACK_CHECK_EN);                              
  40.     i2c_master_start(cmd);
  41.     i2c_master_write_byte(cmd, (AT_ADDR << 1) | I2C_MASTER_READ, ACK_CHECK_EN);
  42.     i2c_master_read_byte(cmd, &data, NACK_VAL);
  43.     i2c_master_stop(cmd);
  44.     ret = i2c_master_cmd_begin(self->port, cmd, 1000);
  45.     i2c_cmd_link_delete(cmd);
  46.     mp_hal_delay_ms(10);
  47.    
  48.     return data;
  49. }
复制代码
       这里的函数的实现跟前面第17.1小节24C02数据传输中的读时序一致,主机首先调用i2c_master_start函数产生起始信号,然后调用i2c_master_write_byte函数发送第1个字节数据设备写地址,之后等待24Cxx设备返回应答信号;收到应答信号后,继续发送第2个1字节数据内存地址addr;等待接收应答后,重新调用i2c_master_start函数产生起始信号,这一次的设备方向改变了,调用i2c_master_write_byte函数发送设备读地址,然后等待设备返回应答信号,同时使用i2c_master_read_byte去读取从从机发出来的数据。由于i2c_master_read_byte函数的最后形参是NACK_VAL,所以在获取完1个字节的数据后,主机发送非应答信号,停止数据传输,最终调用i2c_master_stop函数产生停止信号,返回从从机addr中读取到的数据。

       3,在AT24CXX指定地址写入一个数据
  1. /**
  2. * @brief       在AT24CXX指定地址写入一个数据
  3. * @param       addr: 写入数据的目的地址
  4. * @param       data: 要写入的数据
  5. * @retval      无
  6. */
  7. static void at24cxx_write_one_byte(uint16_t addr, uint8_t data)
  8. {
  9.     esp_err_t ret = 0;
  10.     hw_i2c_obj_t *self = MP_OBJ_TO_PTR(at24cx_self->iic_obj);
  11.     i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  12.     i2c_master_start(cmd);
  13.    
  14.     if (EE_TYPE > AT24C16)
  15.     {
  16.         /* 发送写命令 */
  17.         i2c_master_write_byte(cmd, (AT_ADDR<<1)|I2C_MASTER_WRITE, ACK_CHECK_EN);
  18.         /* 发送高地址 */
  19.         i2c_master_write_byte(cmd, addr >> 8, ACK_CHECK_EN);
  20.     }
  21.     else
  22.     {
  23.         /* 发送器件地址0XA0,写数据 */
  24.         i2c_master_write_byte(cmd, 0XA0 + ((addr / 256) << 1), ACK_CHECK_EN);
  25.     }
  26.     /* 发送低地址 */
  27.     i2c_master_write_byte(cmd, addr % 256, ACK_CHECK_EN);
  28.     i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
  29.     i2c_master_stop(cmd);
  30.     ret = i2c_master_cmd_begin(self->port, cmd, 1000);
  31.     i2c_cmd_link_delete(cmd);
  32.    
  33.     mp_hal_delay_ms(10);
  34. }
复制代码
       该函数的操作流程跟前面已经分析过的24C02单字节写时序一样,首先调用i2c_master_start函数产生起始信号,然后调用i2c_master_write_byte函数发送第1个字节数据设备地址,等待24Cxx设备返回应答信号;收到应答信号后,继续发送第2个1字节数据内存地址addr;等待接收应答后,最后发送第3个字节数据写入内存地址的数据data,24Cxx设备接收完数据,返回应答信号,主机调用i2c_master_stop函数产生停止信号终止数据传输,最终需要延时10ms,等待EEPROM写入完毕。
       我们的函数兼容24Cxx系列多种容量,就在发送设备地址处做了处理,这里说一下为什么需要这样子设计。大家请看一下24Cxx芯片内存组织表,见下表所示。

1.png
表17.2.1.1 24Cxx芯片内存组织表

       主机发送的设备地址和内存地址共同确定了要写入的地方,这里分析一下24C16的使用的是i2c_master_write_byte(0XA0+((addr>>8)<<1))和i2c_master_write_byte(addr % 256)确定写入位置,由于它内存大小一共2048字节,所以只需要定义11个寻址地址线,2048 = 2^11。主机下发读写命令的时候带了3位,后面再跟1个字节(8位)的地址,正好11位,就不需要再发后续的地址字节了。
       而容量大于24C16的芯片,需要单独发送2个字节(甚至更多)的地址,如24C32,它的大小为4096,需要12个寻址地址线支持,4096 = 2^12。24C16是2个字节刚刚好,而它需要三个字节才能确定写入的位置。24C32芯片规定设备写地址0xA0/读地址0xA1,后面接着发送8位高地址,最后才发送8位低地址。与函数里面的操作是一致。
       值得注意的是,上述的AT24CXX写数据和读数据都没有使用IIC控制块的收发函数,因为该收发函数无法兼容多种型号判定。因此,作者使用了IDF的API来实现对多种型号的兼容。

       4,检查AT24CXX是否正常
  1. /**
  2. * @brief       检查AT24CXX是否正常
  3. * @note        检测原理: 在器件的末地址写如0X55, 然后再读取, 如果读取值为0X55
  4. *              则表示检测正常. 否则,则表示检测失败.
  5. * @param       无
  6. * @retval      检测结果
  7. *              0: 检测成功
  8. *              1: 检测失败
  9. */
  10. uint8_t at24cxx_check(void)
  11. {
  12.     uint8_t temp;
  13.     uint16_t addr = EE_TYPE;
  14.     temp = at24cxx_read_one_byte(addr);     /* 避免每次开机都写AT24CXX */

  15.     if (temp == 0X55)                       /* 读取数据正常 */
  16.     {
  17.         return 0;
  18.     }
  19.     else                                    /* 排除第一次初始化的情况 */
  20.     {
  21.         at24cxx_write_one_byte(addr, 0X55); /* 先写入数据 */
  22.         temp = at24cxx_read_one_byte(255);  /* 再读取数据 */

  23.         if (temp == 0X55)return 0;
  24.     }

  25.     return 1;
  26. }
复制代码
       每次开机时,都要检测器件是否正常,若读取的数值不为0x55,则系统无法对AT24Cxx器件进行读取操作。

       5,在AT24CXX里面的指定地址开始读出指定个数的数据
  1. /**
  2. * @brief                   在AT24CXX里面的指定地址开始读出指定个数的数据
  3. * @param                    addr    : 开始读出的地址 对24c02为0~255
  4. * @param               pbuf    : 数据数组首地址
  5. * @param               datalen : 要读出数据的个数
  6. * @retval              无
  7. */
  8. void at24cxx_read(uint16_t addr, uint8_t *pbuf, uint16_t datalen)
  9. {
  10.     while (datalen--)
  11.     {
  12.         *pbuf++ = at24cxx_read_one_byte(addr++);
  13.     }
  14. }
复制代码
       该函数实现了在指定地址读取指定个数的数据。

       6,在AT24CXX里面的指定地址开始写入指定个数的数据
  1. /**
  2. * @brief                     在AT24CXX里面的指定地址开始写入指定个数的数据
  3. * @param               addr    : 开始写入的地址 对24c02为0~255
  4. * @param               pbuf    : 数据数组首地址
  5. * @param               datalen : 要写入数据的个数
  6. * @retval              无
  7. */
  8. void at24cxx_write(uint16_t addr, uint8_t *pbuf, uint16_t datalen)
  9. {
  10.     while (datalen--)
  11.     {
  12.         at24cxx_write_one_byte(addr, *pbuf);
  13.         addr++;
  14.         pbuf++;
  15. }
  16. }
复制代码
       该函数实现了在指定地址写入指定个数的数据。

       17.2.2 C模块构造与类的方法

       1,atk_at24cx类的构造函数
       在 MicroPython 中at24cx对象的构造函数如下:
  1. class atk_at24cx.init(iic)
  2. 使用示例:at24cx = atk_at24cx.init(iic)
复制代码
       该构造函数的参数描述,如下表所示。

2.png
表17.2.2.1 atk_at24cx.init构造函数参数描述

       返回值:返回指定引脚的at24cx对象。

       2,at24cx类的方法


       ①:检测设备是否存在。
       其函数原型如下:
  1. at24cx.at24cxx_check()
复制代码

       ②:向at24cx设备写数据。
       其函数原型如下:
  1. at24cx.at24cxx_write(addr,str,datalen)
复制代码
       该函数的参数描述,如下表所示。

3.png
表17.2.2.2 at24cx.at24cxx_write函数参数描述

       ③:向at24cx设备读数据,返回读取的数据。
       其函数原型如下:
  1. at24cx.at24cxx_read(addr,datalen)
复制代码
       该函数的参数描述,如下表所示。

4.png
表17.2.2.3 at24cx.at24cxx_read函数参数描述

       17.3 硬件设计

       1. 例程功能
       本章实验功能简介:每按下KEY0,MCU通过IIC总线向24C02写入数据,通过按下KEY1来控制24C02读取数据。同时在SPILCD上面显示相关信息。

       2. 硬件资源
       1)XL9555
              IIC_INT-IO0(需在P5连接IO0)
              IIC_SDA-IO41
              IIC_SCL-IO42

       2)SPILCD
              CS-IO21
              SCK-IO12
              SDA-IO11
              DC-IO40(在P5端口,使用跳线帽将IO_SET和LCD_DC相连)
              PWR- IO1_3(XL9555)
              RST- IO1_2(XL9555)

       3)AT24C02
              IIC_SDA-IO41
              IIC_SCL-IO42

       3. 原理图
       24C02硬件部分的原理图,如下图所示。

第十七章 EEPROM实验9219.png
图17.3.1 IIC连接原理

       17.4 程序设计

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

第十七章 EEPROM实验9347.png
图17.4.1.1 程序流程图

       17.4.2 程序解析
       本书籍的代码都在main.py脚本下编写的,读者可在光盘资料下找到对应的源码。EEPROM实验main.py源码如下:
  1. from machine import Pin,SPI,I2C
  2. import atk_xl9555 as io_ex
  3. import atk_lcd as lcd
  4. import atk_at24cx as at24c02
  5. import time


  6. """
  7. * @brief       程序入口
  8. * @param       无
  9. * @retval      无
  10. """
  11. if __name__ == '__main__':
  12.    
  13.     var1 = 'Hello ALIENTEK ESP32-S3'
  14.     # IIC初始化
  15.     i2c0 = I2C(0, scl = Pin(42), sda = Pin(41), freq = 400000)
  16.     # 初始化XL9555
  17.     xl9555 = io_ex.init(i2c0)
  18.    
  19.     # 复位LCD
  20.     xl9555.write_bit(io_ex.SLCD_RST,0)
  21.     time.sleep_ms(100)
  22.     xl9555.write_bit(io_ex.SLCD_RST,1)
  23.     time.sleep_ms(100)
  24.     # 初始化SPI
  25.     spi = SPI(2,baudrate=80000000, sck=Pin(12), mosi = Pin(11), miso = Pin(13))
  26.     # 初始化LCD,lcd = 0为正点原子2.4寸屏幕;lcd = 1为正点原子1.3寸SPILCD屏幕;
  27.     display = lcd.init(spi,dc=Pin(40,Pin.OUT),cs=Pin(21, Pin.OUT),dir=1,lcd = 0)
  28.     # 开启背光
  29.     xl9555.write_bit(io_ex.SLCD_PWR,1)
  30.     time.sleep_ms(100)
  31.     # 显示实验信息
  32.     display.string(0, 5, 240, 32, 32, "ESP32-S3",lcd.RED)
  33.     display.string(30, 70, 200, 16, 16, "EEPORM TEST", lcd.RED)
  34.     display.string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", lcd.RED)
  35.     display.string(30, 110, 200, 16, 16, "Data:", lcd.RED)
  36.     # 初始化atc02
  37.     at24cx = at24c02.init(i2c0)
  38.     time.sleep_ms(500)              # 延时500ms
  39.    
  40.     # 检测设备是否存在
  41.     while at24cx.at24cxx_check():
  42.         print("设备查询未成功!!!")
  43.         time.sleep_ms(500)          # 延时500ms
  44.    
  45.     while True:
  46.         
  47.         # 获取按键值
  48.         key = int(xl9555.key_scan())
  49.         
  50.         if key == io_ex.KEY0:
  51.             # 向设备写数据
  52.             at24cx.at24cxx_write(0,var1,len(var1))
  53.         elif key == io_ex.KEY1:
  54.             # 读取数据
  55.             data = str(at24cx.at24cxx_read(0,len(var1)))
  56.             display.string(110, 110, 200, 16, 16, str(data), lcd.BLUE)

  57.         time.sleep_ms(10)          # 延时10ms
复制代码
       这示例代码通过按键来控制与AT24C02 EEPROM芯片之间的数据交互。它初始化了I2C和SPI接口,以及XL9555芯片和LCD显示屏。然后,它显示一些预设的实验信息,并检测AT24C02设备是否存在以及在无限循环中获取按键值。当KEY0按键被按下时,系统把“Hello ALIENTEK ESP32-S3”数据写入到AT24C02设备的地址当中,当KEY1按键被按下时,系统从AT24C02设备的地址中读取数据,并显示在SPILCD屏幕上。

       17.5 下载验证
       将程序下载到开发板后,按下KEY0写入数据,然后再按KEY1读取数据,最终SPILCD显示的内容如下图所示。

第十七章 EEPROM实验11478.png
图17.5.1 IIC实验程序运行效果图

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

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

本版积分规则

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

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

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

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