0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

STM32基础知识:IIC总线操作EEPROM存储模块AT24C02

CHANBAEK 来源:上下求索电子er 作者:上下求索电子er 2023-10-26 14:25 次阅读

STM32基础:IIC总线操作EEPROM存储模块AT24C02

参考文档:AT24C02数据手册

STM32基础:IIC概述与软件模拟IIC一文中,详细介绍了使用STM32的GPIO口模拟IIC总线的方法,如果读者对IIC总线还不了解,请先阅读此文。

本文是IIC总线的实际应用,将带领读者一步一步阅读AT24C02数据手册,看时序图了解如何使用IIC接口EEPROM存储模块AT24C02,并编写代码使用STM32驱动这个模块。

1 AT24C02概述

1.1 基本描述

图片
《AT24C02数据手册》P1

从上文可以知道,AT24C02提供2048位串行电可擦除和可编程只读存储器(EEPROM),组织256字节。该器件针对许多汽车应用进行了优化,在这些应用中,低功耗和低电压操作是必不可少的。

AT24C02具有节省空间的8引脚JEDEC SOIC和8引脚TSSOP封装,可通过 双线串行接口(即IIC) 访问。此外,整个系列还提供2.7V (2.7V至5.5V)版本。

1.2 重要特点

AT24C02有如下特点,重点用红色标出:

图片
《AT24C02数据手册》P1

  • 存储器内部按组织256字节 × 8位 (2K)组织
  • 双线串行接口(IIC)
  • 兼容400kHz通信速率
  • 具有硬件数据保护的写保护引脚
  • 8字节/页写模式
  • 允许部分页写入
  • 高可靠性:100万次写周期,数据保留:100年

1.3 引脚定义

图片
《AT24C02数据手册》P1

图片
《AT24C02数据手册》P2

图片
《AT24C02数据手册》P3

DA、SCL为IIC总线使用引脚不再赘述。从上文可以知道,A2,A1和A0引脚用于AT24C02的设备地址输入。WP为写保护引脚,提供硬件数据保护。写保护引脚在连接到地(GND)时允许正常的读写操作。当写保护引脚接在VCC上时,写保护功能开启,操作如下表所示。

图片
《AT24C02数据手册》P3

在开发板的原理图上可以看到,设备地址输入A2、A1、A0都为0,WP已近接在GND上关闭了写保护,我们可以正常读写。

图片

1.4 存储空间

图片
《AT24C02数据手册》P4

AT24C02,2K,串行EEPROM内部组织为32页,每页8字节,2K需要一个8位的字地址进行随机字寻址。

1.5 设备地址

图片
《AT24C02数据手册》P8

2K EEPROM设备都需要一个 8位设备地址字包含一个启动条件 ,以使芯片能够进行读或写操作。

设备地址字前4位最高有效位为1010。这对所有串行EEPROM设备都是通用的。接下来的3位是1K/2K EEPROM的A2、A1和A0设备地址位。设备地址的第8位是读写操作选择位。如果该位高,则进行读操作;如果该位低,则进行写操作。

综上,如果对AT24C02进行读操作,则设备地址为10100001B=A1H;如果对AT24C02进行写操作,则设备地址为10100000B=A0H.

图片
《AT24C02数据手册》P9

2 AT24C01编程

2.1 写操作:字编程和页编程

图片
《AT24C02数据手册》P8

写数据有字编程和页编程两种方式:

  • 字编程:一次写入一个字节。
  • 页编程:1K/2K EEPROM能够一次写入一个8字节的页。

如果打算写入数据,则需要知道数据的存储地址。因为AT24C02的存储空间为2K(2^11),故寻址空间为02^11-1,即000H7FFH。每页8字节,故第1页地址000H,第2页地址008H,第3页地址010H,……,第256页地址7F8H。

下图描述了字编程写数据的过程,根据图中的分析和前文的讲述,可以写出字编程函数:

图片
《AT24C02数据手册》P10

/**
 * @brief AT24C02初始化
 * 
 */
void AT24C02_Init(void)
{
  IIC_Init();  // 初始化IIC总线
}

/**
 * @brief AT24C02字节写入
 * 
 * @param Address: 字节地址
 * @param Data: 待写入的数据
 */
void AT24C02_ByteWrite(uint8_t Address, uint8_t Data)
{
  IIC_StartSignal();        // 发送开始信号

  // 发送设备地址,写操作
  IIC_SendBytes(0xA0);     
  if (IIC_WaitACK() == 1)   // AT24C02没应答
  {
    printf("[AT24C02] Answered the device address: Errorn");
    IIC_StopSignal();       // 发送停止信号
  }
  else
  {
    printf("[AT24C02] Answered the device address: OKn");
  }

  // 发送字地址
  IIC_SendBytes(Address);   
  if (IIC_WaitACK() == 1)   // AT24C02没应答
  {
    printf("[AT24C02] Answered the word address: Errorn");
    IIC_StopSignal();       // 发送停止信号
  }
  else
  {
    printf("[AT24C02] Answered the word address: OKn");
  }

  // 发送待写入的数据
  IIC_SendBytes(Data);     
  if (IIC_WaitACK() == 1)   // AT24C02没应答
  {
    printf("[AT24C02] Answered the data: Errorn");
    IIC_StopSignal();       // 发送停止信号
  }
  else
  {
    printf("[AT24C02] Answered the data: OKn");
  }

  IIC_StopSignal();         // 发送停止信号
}

下图描述了页编程写数据的过程,根据图中的分析和前文的讲述,可以写出页编程函数:

图片
《AT24C02数据手册》P10

/**
 * @brief AT24C02页编程(8字节/页)
 * 
 * @param Address: 页地址
 * @param buf: 待写入的数据
 * @param DataLen: 待写入的数据长度 
 */
void AT24C02_PageWrite(uint32_t Address, uint8_t *buf, uint8_t DataLen)
{
  IIC_StartSignal();        // 发送开始信号

  // 发送设备地址,写操作
  IIC_SendBytes(0xA0);
  if (IIC_WaitACK() == 1)   // AT24C02没应答
  {
    printf("[AT24C02] Answered the device address: Errorn");
    IIC_StopSignal();       // 发送停止信号
  }
  else
  {
    printf("[AT24C02] Answered the device address: OKn");
  }

  // 发送页地址
  IIC_SendBytes(Address);
  if (IIC_WaitACK() == 1)   // AT24C02没应答
  {
    printf("[AT24C02] Answered the page address: Errorn");
    IIC_StopSignal();       // 发送停止信号
  }
  else
  {
    printf("[AT24C02] Answered the page address: OKn");
  }

  // 循环发送数据
  while (DataLen--)
  {
    IIC_SendBytes(*buf++);  // 发送数据
    if (IIC_WaitACK() == 1) // AT24C02没应答
    {
      printf("[AT24C02] Answered the data: Errorn");
      IIC_StopSignal();     // 发送停止信号
    }
    else
    {
      printf("[AT24C02] Answered the data: OKn");
    }
  }

  IIC_StopSignal();         // 发送停止信号
}

2.2 读操作:当前地址读

图片
《AT24C02数据手册》P19

  1. 当前地址读:内部地址计数器保存着上次访问时最后一个地址加1的值 。(使用”当前地址读“读出的数据,其地址为上次访问的最后一个地址加1。)
  2. 只要芯片有电,该地址就一直保存,当读到最后页的最后字节,地址会回转到0:
  3. 当写到某页尾的最后一个字节,地址会回转到该页的首字节。
  4. 接收器件地址(读/写选择位为"1")、EEPROM应答ACK后,当前地址的数据就随时钟送出。主器件无需应答"0",但需发送停止条件。

图片
《AT24C02数据手册》P10

根据此图和前文的讲述,编写当前地址读函数:

/**
 * @brief AT24C02当前地址读
 * 
 * @return uint8_t 当前地址的数据
 */
uint8_t AT24C02_CurrentAddressRead(void)
{
  uint8_t Data;

  IIC_StartSignal(); // 发送开始信号

  // 发送设备地址,读操作
  IIC_SendBytes(0xA1);     
  if (IIC_WaitACK() == 1)   // AT24C02没应答
  {
    printf("[AT24C02] Answered the device address: Errorn");
    IIC_StopSignal();       // 发送停止信号
  }
  else
  {
    printf("[AT24C02] Answered the device address: OKn");
  }
  
  // 读取1字节数据
  Data = IIC_ReadBytes();

  // 发送应答信号
  IIC_MasterACK(1); // 不应答

  IIC_StopSignal(); // 发送停止信号
  return Data;      // 返回接收到的数据
}

下面我们测试前面写的四个函数(AT24C02_InitAT24C02_ByteWriteAT24C02_PageWriteAT24C02_CurrentAddressRead),测试过程为:

  • 使用AT24C02_Init初始化AT24C02
  • 使用AT24C02_PageWrite向0x00写入“0123456”
  • 使用AT24C02_ByteWrite向0x07写入“7”
  • 使用AT24C02_CurrentAddressRead进行“当前地址读”
    (0x00-0x07已经被写入“01234567”,即第一页写满了,此时地址会回到该页首字节,使用“当前地址读”读出的应该是该页第一个字节“0”)

如果输出的提示信息全部正常且返回值为“0”则说明这四个函数编写正确。测试效果如下图,测试成功。

uint8_t data;

AT24C02_Init()

AT24C02_PageWrite(0x00, "0123456", 6);
HAL_Delay(100);

AT24C02_ByteWrite(0x07, '7');  
HAL_Delay(100);

data = AT24C02_CurrentAddressRead();
printf("AT24C02_CurrentAddressRead: %c", data);

图片

2.3 读操作:随机读

图片
《AT24C02数据手册》P9

随机读需先写一个目标字地址 ,一旦EEPROM接收器设备地址(读/写选择位为"0")和字地址并应答了ACK,主机就产生一个重复的起始条件。然后,主器件发送设备地址(读/写选择位为"1"),EEPROM应答ACK,并随时钟送出数据。主器件无需应答"0",但需发送停止条件。

图片
《AT24C02数据手册》P11

根据此图和前文的讲述,编写随机读函数:

/**
 * @brief AT24C02随机读1字节数据
 * 
 * @param Address: 字地址 
 * @return uint8_t 读取到的数据
 */
uint8_t AT24C02_RandomRead(uint8_t Address)
{
  uint8_t Data;

  IIC_StartSignal(); // 发送开始信号

  // 发送设备地址,写操作
  IIC_SendBytes(0xA0);     
  if (IIC_WaitACK() == 1)   // AT24C02没应答
  {
    printf("[AT24C02] Answered the device address: Errorn");
    IIC_StopSignal();       // 发送停止信号
  }
  else
  {
    printf("[AT24C02] Answered the device address: OKn");
  }

  // 发送字数据的地址
  IIC_SendBytes(Address);   
  if (IIC_WaitACK() == 1)   // AT24C02没应答
  {
    printf("[AT24C02] Answered the word address: Errorn");
    IIC_StopSignal();       // 发送停止信号
  }
  else
  {
    printf("[AT24C02] Answered the word address: OKn");
  }

  IIC_StartSignal();        // 发送开始信号

  // 发送设备地址,读操作
  IIC_SendBytes(0xA1);     
  if (IIC_WaitACK() == 1)   // AT24C02没应答
  {
    printf("[AT24C02] Answered the device address: Errorn");
    IIC_StopSignal();       // 发送停止信号
  }
  else
  {
    printf("[AT24C02] Answered the device address: OKn");
  }
  
  // 读取1字节数据
  Data = IIC_ReadBytes();

  // 发送应答信号
  IIC_MasterACK(1); // 不应答

  IIC_StopSignal(); // 发送停止信号

  return Data;      // 返回接收到的数据
}

下面我们测试AT24C02_RandomRead函数,测试过程为:

  • 使用AT24C02_Init初始化AT24C02
  • 使用AT24C02_PageWrite向0x00写入“01234567”
  • 使用AT24C02_RandomRead读出0x07处的数据
uint8_t data;

AT24C02_Init();
AT24C02_PageWrite(0x00, "01234567", 7);
HAL_Delay(100);

data = AT24C02_RandomRead(0x07);
printf("AT24C02_RandomRead: %c", data);

如果输出的提示信息全部正常且返回值为“7”则说明函数编写正确。测试效果如下图,测试成功。

图片

如果想要“随机读”函数可以一次读取多个字节,可以修改函数为如下形式:

/**
 * @brief AT24C02随机读n个字节
 * 
 * @param Address: 字地址 
 * @param RecvBuf: 接收缓冲区 
 * @param DataLen: 接收数据长度 
 */
void AT24C02_RandomRead(uint8_t Address, uint8_t *RecvBuf, uint8_t DataLen)
{
  uint8_t Data;

  IIC_StartSignal(); // 发送开始信号

  // 发送设备地址,写操作
  IIC_SendBytes(0xA0);     
  if (IIC_WaitACK() == 1)   // AT24C02没应答
  {
    printf("[AT24C02] Answered the device address: Errorn");
    IIC_StopSignal();       // 发送停止信号
  }
  else
  {
    printf("[AT24C02] Answered the device address: OKn");
  }

  // 发送字数据的地址
  IIC_SendBytes(Address);   
  if (IIC_WaitACK() == 1)   // AT24C02没应答
  {
    printf("[AT24C02] Answered the word address: Errorn");
    IIC_StopSignal();       // 发送停止信号
  }
  else
  {
    printf("[AT24C02] Answered the word address: OKn");
  }

  IIC_StartSignal();        // 发送开始信号

  // 发送设备地址,读操作
  IIC_SendBytes(0xA1);     
  if (IIC_WaitACK() == 1)   // AT24C02没应答
  {
    printf("[AT24C02] Answered the device address: Errorn");
    IIC_StopSignal();       // 发送停止信号
  }
  else
  {
    printf("[AT24C02] Answered the device address: OKn");
  }
  
  // 读取n字节数据
  DataLen -= 1;
  while (DataLen--) // 读取n-1字节数据,最后1字节数据单独读取
  {
    *RecvBuf++ = IIC_ReadBytes();

    // 发送应答信号
    IIC_MasterACK(0); // 应答
  }
  *RecvBuf++ = IIC_ReadBytes(); // 读取最后1字节数据
  
  // 发送应答信号
  IIC_MasterACK(1); // 不应答

  IIC_StopSignal(); // 发送停止信号

  return Data;      // 返回接收到的数据
}

下面我们测试AT24C02_RandomRead函数,测试过程为:

  • 使用AT24C02_Init初始化AT24C02
  • 使用AT24C02_PageWrite向0x00写入“01234567”
  • 使用AT24C02_RandomRead读出0x00-0x07处的数据
uint8_t RecvBuf[10] = {0};

AT24C02_Init();
AT24C02_PageWrite(0x00, "01234567", 8);
HAL_Delay(100);

AT24C02_RandomRead(0x00, RecvBuf, 8);
printf("AT24C02_RandomRead: %s", RecvBuf);

如果输出的提示信息全部正常且返回值为“01234567”则说明函数编写正确。测试效果如下图,测试成功。

图片

2.4 读操作:顺序读

图片
《AT24C02数据手册》P9

AT24C02还有一种读操作,就是顺序读取。顺序读取由当前地址读取或随机地址读取启动。主机接收到一个数据字后,它以确认响应。只要 EEPROM 接收到应答,将自动增加字地址并继续随时钟发送后面的数据。当达到内存地址限制时,地址自动回转到0,认可继续顺序读取数据。主机不应答“0”,而发送停止条件,即可结束顺序读操作。

图片
《AT24C02数据手册》P11

正所谓“纸上得来终觉浅,绝知此事要躬行”。在对顺序读写略加分析后,顺序读取的代码这里不再给出,读者可以结合本文对前面几种读写操作的讲解和顺序读操作的流程自行完成。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • STM32
    +关注

    关注

    2239

    文章

    10671

    浏览量

    348738
  • EEPROM
    +关注

    关注

    9

    文章

    927

    浏览量

    80314
  • IIC总线
    +关注

    关注

    1

    文章

    65

    浏览量

    20152
  • 存储模块
    +关注

    关注

    0

    文章

    14

    浏览量

    8828
收藏 人收藏

    评论

    相关推荐

    AUTOSAR存储模块基础知识

    AUTOSAR存储模块的解释文章很多,本文整理存储模块基础知识
    发表于 10-08 09:30 5058次阅读

    STM32 IIC读写AT24C02(二)

    上次已经完成了IIC读写AT24C02的协议层,现在开始编写读写AT24C02的驱动函数。先从单字节的读写开始。
    发表于 07-22 10:31 758次阅读
    <b class='flag-5'>STM32</b> <b class='flag-5'>IIC</b>读写<b class='flag-5'>AT24C02</b>(二)

    【OneNET麒麟座试用体验】6.EEPROM存储AT24C02的使用

    AT24C02是一款EEPROM存储芯片,存储大小只有256字节,没有听错,就是字节,相比我们512K的Flash,那么这么小的空间能干什么呢? 因为Flash只能整页擦出再重新写,而
    发表于 04-01 10:36

    IICAT24C02的读写

    IICAT24C02的读写(单片机实验)有问题欢迎私信哦课程设计(综合实验)内容及要求通过IIC总线扩展1片AT24C02芯片 ,实现单片
    发表于 07-16 06:27

    AT24C02芯片工作原理是什么

    AT24C02芯片工作原理在IIC通信时,一般有写和读两种操作,我们用AT24C02来具体讲解。AT24C02芯片工作原理
    发表于 07-29 09:04

    如何使用IIC总线AT24C02存储芯片去读写代码呢

    AT24C02存储芯片有哪些功能特性?IIC总线有哪些特征呢?如何使用IIC总线
    发表于 11-25 06:45

    配置STM32IIC硬件时序读写AT24C02和AT24C08

    时序的,本文采用的是模拟时序,下篇文章就介绍配置STM32IIC硬件时序读写AT24C02和AT24C08。模拟时序更加方便移植到其他单片机,通用性更高,不分MCU;硬件时序效率更高
    发表于 12-08 06:27

    EEPROM原理相关电路AT24C02器件

    AT24C02AT24C02器件地址AT24C02是2KROM的 eeprom。地址对应第一个。EEPROM自写代码unsigned c
    发表于 01-11 07:14

    AT24C02通过IIC总线接口进行操作

    ,CATALYST公司的先进CMOS技术实质上减少了器件的功耗。AT24C02有一个8字节页写缓冲器。该器件通过IIC总线接口进行操作,有一个专门的写保护功能。
    发表于 01-25 08:04

    微雪电子EEPROM存储模块AT24C简介

    AT24C EEPROM存储模块 I2C接口 提供测试程序(AVR、STM32、STM8、C8051F) 型号 AT24CXX
    的头像 发表于 12-30 09:49 2055次阅读
    微雪电子<b class='flag-5'>EEPROM</b><b class='flag-5'>存储模块</b>AT<b class='flag-5'>24</b>C简介

    EEPROM存储芯片AT24C02芯片手册

    EEPROM存储芯片AT24C02芯片手册(嵌入式开发培训需要学多久)-EEPROM存储芯片AT24C0
    发表于 07-30 13:20 178次下载
    <b class='flag-5'>EEPROM</b><b class='flag-5'>存储</b>芯片<b class='flag-5'>AT24C02</b>芯片手册

    STM32入门开发: 介绍IIC总线、读写AT24C02(EEPROM)(采用模拟时序)

    时序的,本文采用的是模拟时序,下篇文章就介绍配置STM32IIC硬件时序读写AT24C02和AT24C08。模拟时序更加方便移植到其他单片机,通用性更高,不分MCU;硬件时序效率更高
    发表于 11-25 20:06 39次下载
    <b class='flag-5'>STM32</b>入门开发: 介绍<b class='flag-5'>IIC</b><b class='flag-5'>总线</b>、读写<b class='flag-5'>AT24C02</b>(<b class='flag-5'>EEPROM</b>)(采用模拟时序)

    Linux驱动开发-编写(EEPROM)AT24C02驱动

    AT24C02IIC接口的EEPROM存储芯片,这颗芯片非常经典,百度搜索可以找到非常多的资料,大多都是51、STM32单片机的示例代码,
    的头像 发表于 09-17 15:29 3020次阅读
    Linux驱动开发-编写(<b class='flag-5'>EEPROM</b>)<b class='flag-5'>AT24C02</b>驱动

    STM32 IIC读写AT24C02(一)

    要用IIC读写AT24C02,首先要了解IIC是什么。
    发表于 07-22 10:28 583次阅读
    <b class='flag-5'>STM32</b> <b class='flag-5'>IIC</b>读写<b class='flag-5'>AT24C02</b>(一)

    单片机IIC总线AT24C02的应用

    电子发烧友网站提供《单片机IIC总线AT24C02的应用.doc》资料免费下载
    发表于 11-16 09:24 2次下载
    单片机<b class='flag-5'>IIC</b><b class='flag-5'>总线</b>及<b class='flag-5'>AT24C02</b>的应用