设计简介
本设计是选用的是ESP32S3的芯片,学习IIC的使用,对EEPROM进行读写。
本实验中,开发板选用的是图灵哥TRGESP32S3拓展板,EEPROM芯片用的是板子上搭载的24C08。
24C02芯片简介
24C08是一种常见的EEPROM(可擦可编程只读存储器)芯片,属于24C系列,由多个半导体公司生产,如Atmel(现为Microchip Technology的一部分)、STMicroelectronics等。广泛应用于数据存储领域,特别是在需要非易失性存储的嵌入式系统中。以下是24C08芯片的一些基本特性和应用。
特性
- 存储容量:24C08提供8Kbit(即1KB)的存储空间。这通常被组织为128个字节页,每页8字节;
- 接口:它通过I²C(Inter-Integrated Circuit)总线进行通信,这是一种简单的两线式串行接口,仅需时钟线(SCL)和数据线(SDA)即可实现数据的传输;
- 电源电压:24C08支持多种电压等级,如2.5V、3.0V、3.5V和5V,这使得它能够适应不同的系统要求;
- 封装:常见的封装形式有8引脚的DIP(双列直插式)封装、8引脚的SOIC(小外形集成电路)封装以及其他表面贴装技术封装;
- 写保护功能:24C08通常包含一个写保护引脚(WP),当该引脚被拉高时,可以防止对存储器的意外写入,从而保护数据;
- 数据保持:即使在电源被移除的情况下,24C08也能保持数据长达100年;
- 擦写周期:24C08支持至少100,000次的擦写周期,适用于那些需要频繁更新数据的场合;
- 操作速度:24C08支持标准的I²C总线速度,以及高达400kHz的快速模式。
24C08的应用非常广泛,包括但不限于:
- 存储配置数据
- 保存用户设置
- 数据日志记录
- 在系统编程(ISP)中的应用
在使用24C08时,通常需要编写相应的软件来通过I²C接口与芯片通信,进行数据的读写操作。由于I²C协议的通用性,许多MCU和处理器都提供了直接支持该协议的硬件模块,使得24C08等EEPROM芯片的集成和使用变得相对简单。
24C08的写入时序
24C08芯片的写入过程涉及通过I²C总线发送特定的序列来启动写入操作,并将数据传输到芯片中。以下是24C08写入过程的一般步骤:
- 开始条件:
- 主设备(通常是MCU)通过将SDA线从高电平拉至低电平,同时SCL线保持高电平来生成一个开始条件;
- 发送设备地址:
- 主设备接着发送一个7位的设备地址,紧随其后的是一个读写位(R/W),其中0表示写操作;
- 24C08支持多个设备地址,通过A0、A1和A2引脚的不同组合来选择不同的地址;
- 主设备释放SDA线,允许从设备(24C08芯片)通过拉低SDA线来发送应答(ACK);
- 发送内存地址:
- 在接收到从设备的应答后,主设备发送一个16位的内存地址(对于24C08,通常只有低8位有效,因为它的存储空间小于256字节);
- 每发送一个字节后,主设备都会检查从设备的应答;
- 写入数据:
- 在发送完内存地址并获得应答后,主设备开始发送要写入的数据字节;
- 每发送一个字节,主设备都需要检查从设备的应答;
- 可以连续写入多个字节,直到达到页边界(对于24C08,每页8字节);
- 停止条件:
- 写入完成后,主设备生成一个停止条件来结束数据传输,这是通过将SDA线从低电平拉至高电平,同时SCL线保持高电平来实现的。
以下是写入过程的详细步骤:
- 主设备产生开始条件;
- 主设备发送设备地址和写操作位(0),并接收从设备的ACK;
- 主设备发送内存地址的低8位,并接收从设备的ACK;
- 主设备发送第一个数据字节,并接收从设备的ACK;
- 如果需要,主设备继续发送更多的数据字节,直到达到页边界或完成所有数据的写入;
- 在每个数据字节写入后,主设备都会收到从设备的ACK;
- 完成数据写入后,主设备产生停止条件。
需要注意的是,24C08的写入周期通常需要一些时间(例如,5毫秒)来完成,因此在写入操作后应等待足够的时间(比如加入一段延时),以确保数据正确地写入存储器。此外,如果在写入过程中需要跨页写入数据,必须先停止当前页的写入,然后重新发送新的内存地址以开始下一页的写入。
部分程序源码
24c02.cpp
/**
****************************************************************************************************
* @file 24c02.cpp
* @author Turinger Software
* @version V1.0
* @date 2024-09-20
* @brief EEPROM实验
* 实验平台 图灵哥 TRGESP32S3探索板
*
****************************************************************************************************
*/
#include "24c02.h"
#include <Wire.h>
/**
* @brief 初始化EEPROM器件
* @param 无
* @retval 无
*/
void at24c02_init(void)
{
Wire.begin(IIC_SDA, IIC_SCL, 400000); /* 初始化IIC连接 */
}
/**
* @brief 在AT24C02指定地址读出一个数据
* @param addr: 开始读取数据的地址
* @retval 读到的数据 / 0xFF:未接收到数据
*/
uint8_t at24c02_read_one_byte(uint8_t addr)
{
Wire.beginTransmission(EEPROM_ADDR); /* 发送从机的7位器件地址到发送队列 */
Wire.write(addr); /* 发送要读取从机数据的地址到发送队列 */
Wire.endTransmission(0); /* IIC 发送 发送队列的数据(传参为0,表示重新发送一个start信号,保持IIC总线有效连接) */
Wire.requestFrom(EEPROM_ADDR, 1); /* 主机向从机发送数据请求,并获取到数据 */
if (Wire.available() != 0) /* 得到已经接收到的数据字节数 */
{
return Wire.read(); /* 到数据缓冲区读取数据 */
}
return 0xFF;
}
/**
* @brief 在AT24C02指定地址写入一个数据
* @param addr: 写入数据的目的地址
* @param data: 要写入的数据
* @retval 无
*/
void at24c02_write_one_byte(uint8_t addr, uint8_t data)
{
Wire.beginTransmission(EEPROM_ADDR); /* 发送从机的7位器件地址到发送队列 */
Wire.write(addr); /* 发送要写入从机数据的地址到发送队列 */
Wire.write(data); /* 发送要写入从机数据到发送队列 */
Wire.endTransmission(1); /* IIC 发送 发送队列的数据(传参为1,表示发送stop信号,结束传输) */
delay(10); /* 注意: EEPROM 写入比较慢,必须等到10ms后再写下一个字节 */
}
/**
* @brief 检查AT24C02是否正常
* @note 检测原理: 在器件的末地址写如0X55, 然后再读取, 如果读取值为0X55
* 则表示检测正常. 否则,则表示检测失败.
*
* @param 无
* @retval 检测结果
* 0: 检测成功
* 1: 检测失败
*/
uint8_t at24c02_check(void)
{
uint8_t temp;
temp = at24c02_read_one_byte(255); /* 避免每次开机都写AT24CXX */
if (temp == 0X55) /* 读取数据正常 */
{
return 0;
}
else /* 排除第一次初始化的情况 */
{
at24c02_write_one_byte(255, 0X55); /* 先写入数据 */
temp = at24c02_read_one_byte(255); /* 再读取数据 */
if (temp == 0X55)
{
return 0;
}
}
return 1;
}
/**
* @brief 在AT24C02里面的指定地址开始读出指定个数的数据
* @param addr : 开始读出的地址 对24c02为0~255
* @param pbuf : 数据数组首地址
* @param datalen : 要读出数据的个数
* @retval 无
*/
void at24c02_read(uint8_t addr, uint8_t *pbuf, uint8_t datalen)
{
while (datalen--)
{
*pbuf++ = at24c02_read_one_byte(addr++);
}
}
/**
* @brief 在AT24C02里面的指定地址开始写入指定个数的数据
* @param addr : 开始写入的地址 对24c02为0~255
* @param pbuf : 数据数组首地址
* @param datalen : 要写入数据的个数
* @retval 无
*/
void at24c02_write(uint8_t addr, uint8_t *pbuf, uint8_t datalen)
{
while (datalen--)
{
at24c02_write_one_byte(addr, *pbuf);
addr++;
pbuf++;
}
}
24c02.h
/**
****************************************************************************************************
* @file 24c02.h
* @author Turinger Software
* @version V1.0
* @date 2024-09-20
* @brief EEPROM实验
* 实验平台 图灵哥 TRGESP32S3探索板
*
****************************************************************************************************
*/
#ifndef __24C02_H
#define __24C02_H
#include "Arduino.h"
/* 引脚定义 */
#define IIC_SCL 42
#define IIC_SDA 41
#define EEPROM_ADDR 0x50 /* 7位器件地址 */
/* 函数声明 */
void at24c02_init(void); /* 初始化IIC */
uint8_t at24c02_check(void); /* 检查器件 */
uint8_t at24c02_read_one_byte(uint8_t addr); /* 指定地址读取一个字节 */
void at24c02_write_one_byte(uint8_t addr,uint8_t data); /* 指定地址写入一个字节 */
void at24c02_write(uint8_t addr, uint8_t *pbuf, uint8_t datalen); /* 从指定地址开始写入指定长度的数据 */
void at24c02_read(uint8_t addr, uint8_t *pbuf, uint8_t datalen); /* 从指定地址开始读出指定长度的数据 */
#endif
iic_eeprom.ino
/**
******************************************************************************
* @file iic_eeprom.ino
* @author Turinger Software
* @version V1.0
* @date 2024-09-20
* @brief EEPROM 实验
******************************************************************************
* 实验平台 图灵哥 TRGESP32S3探索板
* 实验目的 学习IIC外设的使用,对EEPROM器件进行读写操作
*
* 硬件资源及引脚分配:
* 1, KEY --> ESP32S3 IO
* KEY --> IO0
* 2, UART0 --> ESP32S3 IO
* TXD0 --> IO43
* RXD0 --> IO44
* 3, EEPROM --> ESP32S3 IO
* SCL --> IO42
* SDA --> IO41
*
* 实验现象:
* 1, 检测IIC总线上是否有24C08器件,按下KEY会写入数据到EEPROM,每隔1秒钟会打印出EEPROM的0地址开始存放的有效内容
*
* 注意事项:
* 无
*
******************************************************************************
*/
#include "24c02.h"
#include "key.h"
#include "uart.h"
const uint8_t g_text_buf[] = {"ESP32S3 IIC TEST"}; /* 要写入到24c02的字符串数组 */
#define TEXT_SIZE sizeof(g_text_buf) /* TEXT字符串长度 */
uint8_t datatemp[TEXT_SIZE]; /* 从EEPROM读取到的数据 */
/**
* @brief 当程序开始执行时,将调用setup()函数,通常用来初始化变量、函数等
* @param 无
* @retval 无
*/
void setup()
{
key_init(); /* KEY初始化 */
uart_init(0, 115200); /* 串口0初始化 */
at24c02_init(); /* 初始化24CXX */
while (at24c02_check()) /* 检测不到24c02 */
{
Serial.println("24C02 Check Failed!");
delay(500);
}
Serial.println("24C02 Ready!");
}
/**
* @brief 循环函数,通常放程序的主体或者需要不断刷新的语句
* @param 无
* @retval 无
*/
void loop()
{
at24c02_read(0, datatemp, TEXT_SIZE); /* 从24C02的0地址处中读取TEXT_SIZE长度数据 */
Serial.printf("The Data Readed Is:%s \r\n", datatemp);
if (KEY == 0)
{
at24c02_write(0, (uint8_t *)g_text_buf, TEXT_SIZE); /* 向24C02的0地址处写入TEXT_SIZE长度数据 */
Serial.printf("24C02 Write %s Finished! \r\n", g_text_buf);
}
delay(1000);
}
实验结果
检测IIC总线上是否有24C08器件,按下KEY会写入数据到EEPROM,每隔1秒钟会打印出EEPROM的0地址开始存放的有效内容
实验到此结束,感谢观看。