24C256 (i2c)指令及时序(代码含单个字节和整页字节的写入)
1. I2C 地址
- I2C 地址:设备的 I2C 地址为
0x50
(7 位地址),在写和读操作中使用时会左移一位并添加读/写标志。- 写操作:
0xA0
- 读操作:
0xA1
- 写操作:
2. 基本指令
a. 写入指令
- 写命令(Write Command):
- 格式:
(设备地址 << 1) | 0
(例如0xA0
) - 步骤:
- 发送 START。
- 发送控制字节(写命令)。
- 发送 16 位内存地址(高字节和低字节)。
- 发送要写入的数据字节。
- 发送 STOP。
- 格式:
b. 读取指令
- 读取命令(Read Command):
- 格式:
(设备地址 << 1) | 1
(例如0xA1
) - 步骤:
- 发送 START。
- 发送控制字节(写命令)。
- 发送 16 位内存地址(高字节和低字节)。
- 发送 START。
- 发送控制字节(读命令)。
- 读取数据字节。
- 发送 NACK(如果不再读取数据)。
- 发送 STOP。
- 格式:
3. 页面写入
- 页面写入(Page Write):
- 每个页面的大小为 64 字节,写入时不能跨越页面边界。
- 格式和步骤与写入命令相同,写入的数据可以是 1 至 64 字节。
- 24C256 具有 512 个页面,每个页面大小为 64 字节
- 在使用 24C256 EEPROM 进行读写时,地址通常需要手动管理。每次写入或读取数据时,您需要指定开始地址。24C256 是一个 256Kb 的 EEPROM,其中每个地址存储 1 字节数据,地址范围从 0 到 32767(0x0000 到 0x7FFF)。
- esp32 写页函数为:i2c_master_write_to_device()。
4. 状态和控制指令
- 写保护(WP):
- WP 引脚:用于启用或禁用写保护功能。
- 连接到 Vcc:写保护开启。
- 连接到 GND:写保护关闭。
- WP 引脚:用于启用或禁用写保护功能。
#include "driver/i2c.h"
#include <stdio.h>
#include <string.h>
#define I2C_MASTER_SCL_IO 15 // SCL 引脚
#define I2C_MASTER_SDA_IO 21 // SDA 引脚
#define I2C_MASTER_FREQ_HZ 100000 // I2C 时钟频率
#define I2C_MASTER_PORT I2C_NUM_0 // I2C 端口
#define EEPROM_I2C_ADDRESS 0x50 // 24C256 I2C 地址// I2C 初始化函数
void i2c_master_init() {i2c_config_t conf = {.mode = I2C_MODE_MASTER,.sda_io_num = I2C_MASTER_SDA_IO,.scl_io_num = I2C_MASTER_SCL_IO,.sda_pullup_en = GPIO_PULLUP_ENABLE,.scl_pullup_en = GPIO_PULLUP_ENABLE,.master.clk_speed = I2C_MASTER_FREQ_HZ};i2c_param_config(I2C_MASTER_PORT, &conf);i2c_driver_install(I2C_MASTER_PORT, conf.mode, 0, 0, 0);
}// 向 24C256 写入一个字节
esp_err_t eeprom_write_byte(uint16_t mem_address, uint8_t data) {i2c_cmd_handle_t cmd = i2c_cmd_link_create();i2c_master_start(cmd);i2c_master_write_byte(cmd, (EEPROM_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);// 发送内存地址的高字节和低字节i2c_master_write_byte(cmd, (mem_address >> 8) & 0xFF, true);i2c_master_write_byte(cmd, mem_address & 0xFF, true);// 发送要写入的数据i2c_master_write_byte(cmd, data, true);i2c_master_stop(cmd);esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_PORT, cmd, 1000 / portTICK_PERIOD_MS);i2c_cmd_link_delete(cmd);// EEPROM 写入完成后通常需要 5ms 延迟vTaskDelay(5 / portTICK_PERIOD_MS);return ret;
}// 从 24C256 读取一个字节
esp_err_t eeprom_read_byte(uint16_t mem_address, uint8_t *data) {i2c_cmd_handle_t cmd = i2c_cmd_link_create();// 发送写命令,设置内存地址指针i2c_master_start(cmd);i2c_master_write_byte(cmd, (EEPROM_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);i2c_master_write_byte(cmd, (mem_address >> 8) & 0xFF, true);i2c_master_write_byte(cmd, mem_address & 0xFF, true);i2c_master_stop(cmd);esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_PORT, cmd, 1000 / portTICK_PERIOD_MS);i2c_cmd_link_delete(cmd);if (ret != ESP_OK) {return ret;}// 读取数据cmd = i2c_cmd_link_create();i2c_master_start(cmd);i2c_master_write_byte(cmd, (EEPROM_I2C_ADDRESS << 1) | I2C_MASTER_READ, true);i2c_master_read_byte(cmd, data, I2C_MASTER_NACK);i2c_master_stop(cmd);ret = i2c_master_cmd_begin(I2C_MASTER_PORT, cmd, 1000 / portTICK_PERIOD_MS);i2c_cmd_link_delete(cmd);return ret;
}
#define PAGE_SIZE 64 // 每页大小// 写入一页数据到 EEPROM
void eeprom_write_page(uint16_t addr, uint8_t* data, size_t len) {// 确保写入长度不超过页面大小if (len > PAGE_SIZE) {len = PAGE_SIZE; // 截断长度}uint8_t buffer[PAGE_SIZE + 2]; // 额外的两个字节用于存储地址buffer[0] = (addr >> 8) & 0xFF; // 地址高字节buffer[1] = addr & 0xFF; // 地址低字节memcpy(&buffer[2], data, len); // 将数据拷贝到缓冲区// 发送写入命令到 EEPROMesp_err_t ret = i2c_master_write_to_device(I2C_MASTER_PORT,EEPROM_I2C_ADDRESS, buffer, len + 2, 1000 / portTICK_PERIOD_MS);if (ret == ESP_OK) {// 写入成功,等待写入完成(大约 5 毫秒)vTaskDelay(5 / portTICK_PERIOD_MS);} else {// 处理写入错误}
}void app_main() {uint8_t data1[PAGE_SIZE] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};// 初始化 I2Ci2c_master_init();uint8_t write_data = 0x5A; // 要写入的数据uint16_t address = 0x65; // 24C256 的地址 0x88// 向 EEPROM 写入数据esp_err_t ret = eeprom_write_byte(address, write_data);if (ret == ESP_OK) {printf("Data 0x%X written to EEPROM at address 0x%X\n", write_data, address);} else {printf("Error writing data to EEPROM\n");}vTaskDelay(10 / portTICK_PERIOD_MS);// 读取 EEPROM 中的数据uint8_t read_data = 0;ret = eeprom_read_byte(address, &read_data);if (ret == ESP_OK) {printf("Data 0x%X read from EEPROM at address 0x%X\n", read_data, address);} else {printf("Error reading data from EEPROM\n");}//写页eeprom_write_page(0, data1, PAGE_SIZE); //从地址0x0开始vTaskDelay(10 / portTICK_PERIOD_MS);ret = eeprom_read_byte(7, &read_data); //读地址0x7if (ret == ESP_OK) {printf("Data 0x%X read from EEPROM at address 0x%X\n", read_data,7);} else {printf("Error reading data from EEPROM\n");}}