AT24C02介绍与应用

AT24C02介绍与应用

image-20260508115138000

一、容量与地址数量

  • 总容量:2Kbit = 256字节(Byte)
  • 地址总数256个,地址范围:0x00~0xFF(十进制0~255),8位地址寻址
  • 页结构:32页 × 8字节/页(页写一次最多连续写8字节)

二、每个地址存多少数据

  • 最小寻址单元1字节(8bit),即每个地址只能存1字节(0~255)

三、如何选择地址写入(I2C写流程)

1. 硬件地址(选芯片)

  • 从机地址:1010 A2 A1 A0 0(写操作,最低位R/W=0)
  • A2/A1/A0引脚:接地=0,接VCC=1;多片时用来区分芯片(最多8片)

2. 片内地址(选存储位置)

  • 发送完从机地址并收到应答后,发送1字节片内地址(0x00~0xFF),即要写入的目标地址

3. 写字节(单字节写)

  1. 起始信号 → 从机地址(写)→ 应答
  2. 发送片内地址 → 应答
  3. 发送1字节数据 → 应答
  4. 停止信号 → 等待5~10ms(内部编程)

4. 页写(连续写最多8字节)

  • 流程同单字节写,但发完首地址后连续发1~8字节,地址自动递增;不能跨页(如0x07→0x08会回到页首0x00)

image-20260127192158452

四、代码应用

#ifndef __IIC_24C02_H
#define __IIC_24C02_H
#include "stdint.h"
#include "main.h"
#include "nv128h_oneline.h"     // 使用这里的延时函数 HAL_Delay_us(1);


// 可根据自己硬件修改引脚
#define IIC_SDA_PIN    GPIO_PIN_14
#define IIC_SCL_PIN    GPIO_PIN_13
#define IIC_GPIO_PORT  GPIOB

// AT24C02 容量:256字节 地址0~255
#define AT24C02_ADDR   0xA0

// 底层IIC
void IIC_Init(void);
void IIC_Start(void);
void IIC_Stop(void);
void IIC_Write_Byte(uint8_t dat);
uint8_t IIC_Read_Byte(uint8_t ack);
uint8_t IIC_Wait_Ack(void);

// AT24C02 功能函数
void AT24C02_Write_Byte(uint8_t addr, uint8_t data);
uint8_t AT24C02_Read_Byte(uint8_t addr);
void AT24C02_Write_Page(uint8_t addr, uint8_t *buf, uint8_t len);
void AT24C02_Read_Buf(uint8_t addr, uint8_t *buf, uint8_t len);

#endif

#include "main.h"
#include "gpio.h"
#include "IIC_24C02.h"


// 引脚位操作
#define SDA_OUT()  HAL_GPIO_WritePin(IIC_GPIO_PORT,IIC_SDA_PIN,GPIO_PIN_RESET)
#define SDA_IN()   HAL_GPIO_ReadPin(IIC_GPIO_PORT,IIC_SDA_PIN)
#define SCL_LOW()  HAL_GPIO_WritePin(IIC_GPIO_PORT,IIC_SCL_PIN,GPIO_PIN_RESET)
#define SCL_HIGH() HAL_GPIO_WritePin(IIC_GPIO_PORT,IIC_SCL_PIN,GPIO_PIN_SET)

// IIC初始化
void IIC_Init(void)
{
    GPIO_InitTypeDef gpio_conf = {0};
    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    gpio_conf.Pin = IIC_SDA_PIN | IIC_SCL_PIN;
    gpio_conf.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_conf.Pull = GPIO_PULLUP;
    gpio_conf.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(IIC_GPIO_PORT, &gpio_conf);
    
    SDA_OUT();
    SCL_HIGH();
}

// IIC起始信号
void IIC_Start(void)
{
    SDA_OUT();
    SCL_HIGH();
    HAL_Delay_us(1);
    SDA_OUT();
    HAL_Delay_us(1);
    SCL_LOW();
}

// IIC停止信号
void IIC_Stop(void)
{
    SDA_OUT();
    SCL_LOW();
    HAL_Delay_us(1);
    SDA_OUT();
    HAL_Delay_us(1);
    SCL_HIGH();
    HAL_Delay_us(1);
    SDA_OUT();
}

// IIC等待应答
uint8_t IIC_Wait_Ack(void)
{
    uint8_t time = 0;
    SDA_OUT();
    HAL_Delay_us(1);
    SCL_HIGH();
    HAL_Delay_us(1);
    
    while(SDA_IN())
    {
        time++;
        if(time > 250)
        {
            IIC_Stop();
            return 1;
        }
    }
    SCL_LOW();
    return 0;
}

// IIC写一个字节
void IIC_Write_Byte(uint8_t dat)
{
    uint8_t i;
    for(i=0;i<8;i++)
    {
        SCL_LOW();
        HAL_Delay_us(1);
        if(dat & 0x80)
            SDA_OUT();
        else
            SDA_OUT();
        dat <<= 1;
        HAL_Delay_us(1);
        SCL_HIGH();
        HAL_Delay_us(1);
    }
    SCL_LOW();
}

// IIC读一个字节
uint8_t IIC_Read_Byte(uint8_t ack)
{
    uint8_t i,dat=0;
    for(i=0;i<8;i++)
    {
        SCL_LOW();
        HAL_Delay_us(1);
        dat <<= 1;
        SCL_HIGH();
        HAL_Delay_us(1);
        if(SDA_IN()) dat |= 0x01;
    }
    if(ack)
        SDA_OUT();
    else
        SDA_OUT();
    HAL_Delay_us(1);
    SCL_LOW();
    return dat;
}

// AT24C02 单字节写入
void AT24C02_Write_Byte(uint8_t addr, uint8_t data)
{
    IIC_Start();
    IIC_Write_Byte(AT24C02_ADDR);
    IIC_Wait_Ack();
    IIC_Write_Byte(addr);
    IIC_Wait_Ack();
    IIC_Write_Byte(data);
    IIC_Wait_Ack();
    IIC_Stop();
    HAL_Delay(5);   // 必须等待烧录
}

// AT24C02 单字节读取
uint8_t AT24C02_Read_Byte(uint8_t addr)
{
    uint8_t res;
    IIC_Start();
    IIC_Write_Byte(AT24C02_ADDR);
    IIC_Wait_Ack();
    IIC_Write_Byte(addr);
    IIC_Wait_Ack();
    IIC_Start();
    IIC_Write_Byte(AT24C02_ADDR | 0x01);
    IIC_Wait_Ack();
    res = IIC_Read_Byte(0);
    IIC_Stop();
    return res;
}

// 页写:一页最多8字节,不要跨页
void AT24C02_Write_Page(uint8_t addr, uint8_t *buf, uint8_t len)
{
    uint8_t i;
    IIC_Start();
    IIC_Write_Byte(AT24C02_ADDR);
    IIC_Wait_Ack();
    IIC_Write_Byte(addr);
    IIC_Wait_Ack();
    
    for(i=0;i<len;i++)
    {
        IIC_Write_Byte(buf[i]);
        IIC_Wait_Ack();
    }
    IIC_Stop();
    HAL_Delay(5);
}

// 批量读取任意长度
void AT24C02_Read_Buf(uint8_t addr, uint8_t *buf, uint8_t len)
{
    uint8_t i;
    IIC_Start();
    IIC_Write_Byte(AT24C02_ADDR);
    IIC_Wait_Ack();
    IIC_Write_Byte(addr);
    IIC_Wait_Ack();
    IIC_Start();
    IIC_Write_Byte(AT24C02_ADDR | 0x01);
    IIC_Wait_Ack();
    
    for(i=0;i<len;i++)
    {
        if(i == len-1)
            buf[i] = IIC_Read_Byte(0);
        else
            buf[i] = IIC_Read_Byte(1);
    }
    IIC_Stop();
}
/**
  * @brief  基于SysTick滴答定时器的精准微秒延时 (STM32G070 64MHz)
  * @param  us: 延时微秒数
  * @retval 无
  */
void HAL_Delay_us(uint32_t us)
{
    uint32_t ticks = 64U * us;    // 64MHz = 64个tick = 1us
    uint32_t start = SysTick->VAL;
    uint32_t elapsed = 0;

    while (1)
    {
        uint32_t now = SysTick->VAL;

        // 正常递减
        if (now <= start)
        {
            elapsed += start - now;
        }
        // 处理溢出(HAL默认LOAD=63999,1ms溢出一次)
        else
        {
            elapsed += (SysTick->LOAD + 1) - now + start;
        }
        start = now;

        if (elapsed >= ticks)
        {
            break;
        }
    }
}

应用示例:

// 初始化
IIC_Init();

// 1. 单字节读写
AT24C02_Write_Byte(0x00, 0x55);   // 地址0写入0x55
uint8_t val = AT24C02_Read_Byte(0x00);

// 2. 数组批量写入读取
uint8_t wbuf[4] = {11,22,33,44};
uint8_t rbuf[4];
AT24C02_Write_Page(0x10, wbuf, 4);
AT24C02_Read_Buf(0x10, rbuf, 4);

image-20260508115057689

image-20260508115115503

参看资料:

AT24C02(I2C总线) - Q&25 - 博客园

AT24C02 -PDF数据手册-参考资料-立创商城

posted @ 2026-05-08 11:52  Q&25  阅读(133)  评论(0)    收藏  举报