基于MC9S12G128的I2C驱动M24M02 EEPROM的实现方案
一、硬件连接配置
MC9S12G128 M24M02
------------ --------
SCL → SCL (PB2)
SDA → SDA (PB3)
GND → GND
VCC → 3.3V
WP → VCC (写保护关闭)
二、关键寄存器配置
#include "derivative.h" // 包含MC9S12G128寄存器定义
#define I2C_BASE_ADDR 0x00 // I2C模块基地址
#define FCLKDIV (*(volatile unsigned char *)0x0000) // 时钟分频寄存器
#define FSTAT (*(volatile unsigned char *)0x0001) // 状态寄存器
#define FCCOBIX (*(volatile unsigned char *)0x0002) // 命令/地址指针
#define FCCOB (*(volatile unsigned short *)0x0003) // 数据缓冲区
// 设备地址配置(7位地址格式)
#define M24M02_ADDR 0xA0 // A17=0, A16=0, E2=0
#define MEM_ADDR_SIZE 2 // 16位内存地址
三、I2C初始化函数
void I2C_Init() {
// 设置I2C时钟分频(总线频率=总线时钟/(2*(FCLKDIV+1)))
FCLKDIV = 0x17; // 24MHz总线时钟 → 100kHz I2C
// 清除状态标志
FSTAT = 0x00;
// 配置I2C为主模式,启用ACK
// (具体配置需参考MC9S12G128数据手册的I2C章节)
}
四、EEPROM写操作
void EEPROM_Write(uint16_t memAddr, uint8_t *data, uint16_t size) {
uint16_t pageAddr = memAddr & 0xFF00; // 页地址高位
uint16_t offset = memAddr & 0x00FF; // 页内偏移
while(size > 0) {
uint16_t writeSize = (size > 256) ? 256 : size; // 单页最大256字节
// 发送起始条件+设备地址+写命令
I2C_Start();
I2C_Write(M24M02_ADDR << 1 | 0); // 写模式
// 发送内存地址(高字节在前)
I2C_Write((pageAddr >> 8) & 0xFF);
I2C_Write(pageAddr & 0xFF);
// 写入数据
for(uint16_t i=0; i<writeSize; i++) {
I2C_Write(data[offset + i]);
}
I2C_Stop();
// 等待写入完成(需根据时序添加延时)
Delay_ms(5); // M24M02写入时间≤5ms
// 更新地址和剩余数据
size -= writeSize;
memAddr += writeSize;
pageAddr += (offset + writeSize) / 256;
offset = (offset + writeSize) % 256;
}
}
五、EEPROM读操作
void EEPROM_Read(uint16_t memAddr, uint8_t *buffer, uint16_t size) {
uint16_t pageAddr = memAddr & 0xFF00;
uint16_t offset = memAddr & 0x00FF;
// 发送起始条件+设备地址+写命令(发送内存地址)
I2C_Start();
I2C_Write(M24M02_ADDR << 1 | 0);
// 发送内存地址
I2C_Write((pageAddr >> 8) & 0xFF);
I2C_Write(pageAddr & 0xFF);
// 重新发送起始条件+设备地址+读命令
I2C_Start();
I2C_Write((M24M02_ADDR << 1) | 1);
// 读取数据
for(uint16_t i=0; i<size; i++) {
buffer[i] = I2C_Read(i == size-1); // 最后一字节发送NACK
}
I2C_Stop();
}
六、辅助函数实现
// I2C起始条件
void I2C_Start() {
while(!IBSR_IBIF); // 等待总线空闲
IBSR_IBIF = 1; // 清除中断标志
IBDR = 0xFF; // 拉低SDA启动信号
while(IBSR_IBAL); // 等待SDA拉低
}
// I2C停止条件
void I2C_Stop() {
while(!IBSR_IBIF);
IBSR_IBIF = 1;
IBDR = 0xFF; // 拉高SDA
while(IBSR_IBAL);
}
// I2C写字节
uint8_t I2C_Write(uint8_t data) {
while(!IBSR_IBIF);
IBSR_IBIF = 1;
IBDR = data;
while(IBSR_IBAL);
return IBSR_IBT; // 返回ACK状态
}
// I2C读字节
uint8_t I2C_Read(uint8_t ack) {
while(!IBSR_IBIF);
IBSR_IBIF = 1;
IBSR_IBR = ack; // 设置ACK/NACK
while(IBSR_IBAL);
return IBDR;
}
参考代码 基于9S12G128的I2C驱动并含有EEPROM的M24M02的存储器读写程序 www.youwenfan.com/contentcsr/57243.html
七、完整工程结构
M24M02_Driver/
├── Src/
│ ├── main.c
│ ├── i2c.c
│ └── eeprom.c
├── Inc/
│ ├── i2c.h
│ └── eeprom.h
├── Libs/
│ └── MC9S12G128_Driver/
└── Project/
├── .project
└── .ccsproject
八、扩展功能实现
-
页写入保护
void EEPROM_LockPage(uint16_t pageAddr) { uint8_t data[3] = {0x00, (pageAddr>>8)&0xFF, pageAddr&0xFF}; EEPROM_Write(0x0000, data, 3); // 写入页锁定位 } -
CRC校验功能
uint16_t EEPROM_CalculateCRC(uint16_t addr, uint16_t size) { uint16_t crc = 0xFFFF; while(size--) { crc ^= (uint16_t)(*buffer++) << 8; for(uint8_t i=0; i<8; i++) { crc = (crc & 0x8000) ? (crc << 1) ^ 0x1021 : crc << 1; } } return crc; }