Files
2026-07-14 18:17:00 +08:00

226 lines
6.0 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 模块名称AT24C02 EEPROM 驱动
* 模块功能提供AT24C02的读写操作接口基于STM32 HAL I2C
* 适用平台STM32F103C8T6
* 作者:王建锋
* 创建日期2026-07-14
* 修改记录:
* 2026-07-14 王建锋 创建初始版本
*/
#include "at24c02.h"
#include <stdio.h>
/* 引用CubeMX生成的I2C句柄 */
extern I2C_HandleTypeDef hi2c1;
/*
* 函数功能AT24C02字节写入
* 入口参数addr - 目标地址0~255
* data - 要写入的数据
* 返回值: 0=成功,负值=错误码
* 函数说明:先发送写命令,再等待内部写周期完成
*/
int at24c02_write_byte(uint8_t addr, uint8_t data)
{
uint8_t buf[2];
HAL_StatusTypeDef hal_ret;
buf[0] = addr;
buf[1] = data;
hal_ret = HAL_I2C_Master_Transmit(&hi2c1, AT24C02_ADDR_WRITE,
buf, 2, AT24C02_I2C_TIMEOUT);
if (hal_ret != HAL_OK) {
return AT24C02_ERR_I2C;
}
/* 等待内部写周期完成 */
return at24c02_wait_ready();
}
/*
* 函数功能AT24C02随机读取
* 入口参数addr - 目标地址0~255
* 返回值:>=0=读取的数据,负值=错误码
* 函数说明:假写操作设定地址,再重新发送读命令读取
*/
int at24c02_read_byte(uint8_t addr)
{
uint8_t data;
HAL_StatusTypeDef hal_ret;
/* 假写:发送设备地址 + 字地址 */
hal_ret = HAL_I2C_Master_Transmit(&hi2c1, AT24C02_ADDR_WRITE,
&addr, 1, AT24C02_I2C_TIMEOUT);
if (hal_ret != HAL_OK) {
return AT24C02_ERR_I2C;
}
/* 重发起始条件 + 读 */
hal_ret = HAL_I2C_Master_Receive(&hi2c1, AT24C02_ADDR_READ,
&data, 1, AT24C02_I2C_TIMEOUT);
if (hal_ret != HAL_OK) {
return AT24C02_ERR_I2C;
}
return data;
}
/*
* 函数功能AT24C02页写入
* 入口参数addr - 起始地址0~255
* p_data - 数据缓冲区指针
* len - 写入长度≤8
* 返回值: 0=成功,负值=错误码
* 函数说明:页写入,自动等待写周期完成
*/
int at24c02_write_page(uint8_t addr, const uint8_t *p_data, uint8_t len)
{
uint8_t buf[AT24C02_PAGE_SIZE + 1];
HAL_StatusTypeDef hal_ret;
uint8_t i;
/* 参数校验 */
if ((p_data == NULL) || (len == 0) || (len > AT24C02_PAGE_SIZE)) {
return AT24C02_ERR_PARAM;
}
if (addr + len > AT24C02_SIZE) {
return AT24C02_ERR_PARAM;
}
buf[0] = addr;
for (i = 0; i < len; i++) {
buf[i + 1] = p_data[i];
}
hal_ret = HAL_I2C_Master_Transmit(&hi2c1, AT24C02_ADDR_WRITE,
buf, len + 1, AT24C02_I2C_TIMEOUT);
if (hal_ret != HAL_OK) {
return AT24C02_ERR_I2C;
}
/* 等待内部写周期完成 */
return at24c02_wait_ready();
}
/*
* 函数功能AT24C02连续写入跨页自动拆分
* 入口参数addr - 起始地址0~255
* p_data - 数据缓冲区指针
* len - 写入长度
* 返回值: 0=成功,负值=错误码
* 函数说明:自动处理跨页边界,逐页写入
*/
int at24c02_write_buf(uint8_t addr, const uint8_t *p_data, uint16_t len)
{
uint8_t page_remaining;
int ret;
if ((p_data == NULL) || (len == 0)) {
return AT24C02_ERR_PARAM;
}
if (addr + len > AT24C02_SIZE) {
return AT24C02_ERR_PARAM;
}
while (len > 0) {
/* 当前页剩余空间 */
page_remaining = AT24C02_PAGE_SIZE - (addr % AT24C02_PAGE_SIZE);
if (page_remaining > len) {
page_remaining = (uint8_t)len;
}
ret = at24c02_write_page(addr, p_data, page_remaining);
if (ret != AT24C02_OK) {
return ret;
}
addr += page_remaining;
p_data += page_remaining;
len -= page_remaining;
}
return AT24C02_OK;
}
/*
* 函数功能AT24C02连续读取
* 入口参数addr - 起始地址0~255
* p_buf - 接收缓冲区指针
* len - 读取长度
* 返回值: 0=成功,负值=错误码
* 函数说明:从指定地址开始顺序读取多个字节
*/
int at24c02_read_buf(uint8_t addr, uint8_t *p_buf, uint16_t len)
{
HAL_StatusTypeDef hal_ret;
if ((p_buf == NULL) || (len == 0)) {
return AT24C02_ERR_PARAM;
}
if (addr + len > AT24C02_SIZE) {
return AT24C02_ERR_PARAM;
}
/* 假写:设定读起始地址 */
hal_ret = HAL_I2C_Master_Transmit(&hi2c1, AT24C02_ADDR_WRITE,
&addr, 1, AT24C02_I2C_TIMEOUT);
if (hal_ret != HAL_OK) {
return AT24C02_ERR_I2C;
}
/* 顺序读 */
hal_ret = HAL_I2C_Master_Receive(&hi2c1, AT24C02_ADDR_READ,
p_buf, len, AT24C02_I2C_TIMEOUT);
if (hal_ret != HAL_OK) {
return AT24C02_ERR_I2C;
}
return AT24C02_OK;
}
/*
* 函数功能检测AT24C02设备是否存在
* 入口参数:无
* 返回值: 0=检测到设备,-1=未响应
* 函数说明通过I2C发送设备地址检查是否有ACK应答
*/
int at24c02_scan(void)
{
HAL_StatusTypeDef hal_ret;
hal_ret = HAL_I2C_IsDeviceReady(&hi2c1, AT24C02_ADDR_WRITE,
3, AT24C02_I2C_TIMEOUT);
if (hal_ret != HAL_OK) {
printf("AT24C02: no device found\r\n");
return AT24C02_ERR_DEVICE;
}
printf("AT24C02: device detected\r\n");
return AT24C02_OK;
}
/*
* 函数功能:等待内部写周期完成(应答查询)
* 入口参数:无
* 返回值: 0=完成,-3=超时
* 函数说明:发送设备地址(写模式),直到器件应答
*/
int at24c02_wait_ready(void)
{
HAL_StatusTypeDef hal_ret;
uint16_t trials = 50;
while (trials--) {
hal_ret = HAL_I2C_IsDeviceReady(&hi2c1, AT24C02_ADDR_WRITE,
1, 1);
if (hal_ret == HAL_OK) {
return AT24C02_OK;
}
HAL_Delay(1);
}
return AT24C02_ERR_TIMEOUT;
}