找回密码
 立即注册
查看: 43|回复: 1

I2C协议基础及应用-AT24Cxx篇(支持任意型号读写)

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:410
  • 最近打卡:2025-10-21 09:12:26
已绑定手机

34

主题

133

回帖

2083

积分

荣誉版主

Rbowlystar

积分
2083
发表于 3 天前 | 显示全部楼层 |阅读模式


【虹星宝典】记录单片机学习之旅——目录


    I2C协议,也称iic协议。常用于短距离、低速设备间的数据传输,是有飞利浦(NXP)开发的同步串行通信协议,仅需两根线(SDA:数据线;SCL:时钟线)即可进行多设备的半双工互联通信。
    基本的通讯时序分为:起始信号(IIC_Start)、结束信号(IIC_Stop)、发送ACK应答信号(IIC_SendACK)、发送NACK应答信号(IIC_SendNoACK)、接收ACK/NACK应答信号(IIC_WaitACK)和读/写1字节数据,并可以衍生出读/写N字节数据等。
    本篇作为IIC协议入门实验的器件是AT24C128(实验箱上为AT24C02)。



一、IIC部分
【时刻周期】
以SCL的脉冲信号为标准(这个可以决定IIC的通讯速率)。
当SCL=0时,SDA的电平无效,此时可以随意改变SDA的电平,即从蓝色到黄色这段时间。
当SCL=1时,SDA的电平需要保持稳定,持续到再一次SCL=0的瞬间(及SCL维持信号稳定的一小段时间),此时数据有效,将被接收方读取,
即从黄色到红色这段时间。一个SCL周期,传输1bit数据。
  1. void IIC_Wait(void)
  2. {
  3.     Delay2us();
  4. }
复制代码


截图202510192210345364.jpg


【起始信号】和【结束信号】
起始信号:先拉低SDA总线,再拉低SCL总线
  1. void IIC_Start(void)
  2. {
  3.     IIC_SCL = 1;
  4.     IIC_SDA = 1;
  5.     IIC_Wait();
  6.     IIC_SDA = 0;
  7.     IIC_Wait();
  8.     IIC_SCL = 0;
  9.     IIC_Wait();
  10. }
复制代码


结束信号:先拉高SCL总线,再拉高SDA总线
  1. void IIC_Stop(void)
  2. {
  3.     IIC_SCL = 0;
  4.     IIC_SDA = 0;
  5.     IIC_Wait();
  6.     IIC_SCL = 1;
  7.     IIC_Wait();
  8.     IIC_SDA = 1;
  9.     IIC_Wait();
  10. }
复制代码


截图202510192214243582.jpg


【发送ACK应答信号】和【发送NACK应答信号】
发送ACK信号:1位数据,SDA=0
  1. void IIC_SendACK(void)
  2. {
  3.     IIC_SDA = 0;
  4.     IIC_Wait();
  5.     IIC_SCL = 1;
  6.     IIC_Wait();
  7.     IIC_SCL = 0;
  8.     IIC_Wait();
  9. }
复制代码


发送NACK信号:1位数据,SDA=1
  1. void IIC_SendNoACK(void)
  2. {
  3.     IIC_SDA = 1;
  4.     IIC_Wait();
  5.     IIC_SCL = 1;
  6.     IIC_Wait();
  7.     IIC_SCL = 0;
  8.     IIC_Wait();
  9. }
复制代码


截图202510192215348400.jpg


【接收ACK/NACK应答信号】
接收和发送原理一致。区别是作为接收方。
  1. u8 IIC_WaitACK(void)
  2. {
  3.     u8 ack = 0;
  4.     IIC_SDA = 1;
  5.     IIC_Wait();
  6.     IIC_SCL = 1;
  7.     IIC_Wait();
  8.     ack = IIC_SDA;  // 0:ACK 1:NACK
  9.     IIC_Wait();
  10.     IIC_SCL = 0;
  11.     IIC_Wait();
  12.     return !ack;    // 取反后 1:有应答 0:无应答
  13. }
复制代码


【读/写1字节数据】
一般8bit数据+1bitACK信号作为一包数据。
  1. u8 IIC_R_Byte(void)
  2. {
  3.     u8 i = 8, dat = 0;
  4.     IIC_SDA = 1;
  5.     IIC_Wait();
  6.     do
  7.     {
  8.         IIC_SCL = 1;
  9.         IIC_Wait();
  10.         dat <<= 1;
  11.         if (IIC_SDA)
  12.             dat |= 1;
  13.         IIC_SCL = 0;
  14.         IIC_Wait();
  15.     } while (--i);
  16.     return dat;
  17. }
复制代码


截图202510192216495452.jpg


  1. void IIC_W_Byte(u8 dat)
  2. {
  3.     u8 i = 8;
  4.     do
  5.     {
  6.         if (dat & 0x80)
  7.             IIC_SDA = 1;
  8.         else
  9.             IIC_SDA = 0;
  10.         IIC_Wait();
  11.         dat <<= 1;
  12.         IIC_SCL = 1;
  13.         IIC_Wait();
  14.         IIC_SCL = 0;
  15.         IIC_Wait();
  16.     } while (--i);
  17. }
复制代码


截图202510192217139835.jpg


二、AT24Cxx部分
主要用途
AT24CXX是一种EEPROM存储器,主要用于失去电源时,仍可以储存处理器的重要数据。使用I2C协议进行数据通信,具有宽电压(约1.7V to 5.5V)


从机地址

AT24CXX最多有3个从机地址配置引脚(A0/A1/A2),即最多挂载8个从机。
        01 = A0/A1/A2        *08-byte Page Write mode*
        02 = A0/A1/A2        *08-byte Page Write mode*
        04 = NC/A1/A2        *16-byte Page Write Mode*
        08 = NC/NC/A2        *16-byte Page Write Mode*
        16 = NC/NC/NC        *16-byte Page Write Mode*
        32 = A0/A1/A2        *32-byte Page Write Mode*
        64 = A0/A1/A2        *32-byte Page Write Mode*
        128 = A0/A1/A2        *64-byte Page Write Mode*
        256 = A0/A1/A2        *64-byte Page Write Mode*
        512 = A0/A1/A2        *128-byte Page Write Mode*
        1024 = NC/A1/NC       



命名含义

其中XX可代表存储的容量大小,一般为XX*128byte:
        01 = 128 Byte = 1K bit
        02 = 256 Byte = 2K bit
        04 = 512 Byte = 4K bit
        08 = 1024 Byte = 8K bit
        16 = 2048 Byte = 16K bit
        32 = 4096 Byte = 32K bit
        64 = 8192 Byte = 64K bit
        128 = 16384 Byte = 128K bit
        256 = 32768 Byte = 256K bit
        512 = 65536 Byte = 512K bit
        1024 = 131072 Byte = 1M bit



数据读写

每个数据地址可以保存1Byte数据(即char/u8类型)。
一般读写的协议格式为:(具体请看对应的手册)
​        对于01/02/04/08/16为【从机地址】【数据地址】【数据】....
​        对于32/64/128/256.等为【从机地址】【数据地址高位】【数据地址低位】【数据】....
由于1字节(8bit)最多描述2^8=256个,所以01(128)/02(256)有3个地址配置引脚可用。
04(512),需要9bit,所有只有2个地址配置引脚,而将【从机地址】中对应的NC位作为第9bit
08(1024),需要10bit,同理2个NC位作为第9/10bit
16(2048),需要11bit,3个地址配置引脚均为NC。
而从32(4096)开始,【数据地址】使用2Byte(16bit)表示,最多可以描述2^16=65536个,因此不需要向地址配置引脚借位。1024(131072)需要借1位,当手册中有2个NC位,这个用的少不深入讨论了。
注:AT24Cxx每次连续写入,最多写1页数据,便要等AT24Cxx完成1次擦写周期,一般为5-10ms。



  1. u8 AT24Cxx_R_Byte(u32 AT24Cxx_Type, u8 AT24Cxx_id, u16 AT24Cxx_addr)
  2. {
  3.         u8 R_Byte;
  4.         if (AT24Cxx_addr > AT24Cxx_Type)
  5.                 return 0xFF;
  6.         // 1字节地址长度
  7.     if (AT24Cxx_Type <= AT24C16)
  8.         {
  9.                 IIC_R_NByte(AT24Cxx_id | (u8)((AT24Cxx_addr >> 8) << 1), AT24Cxx_addr, IIC_REG_TYPE_1Byte, &R_Byte, 1);
  10.         }
  11.         // 2字节地址长度
  12.         else
  13.         {
  14.                 IIC_R_NByte(AT24Cxx_id, AT24Cxx_addr, IIC_REG_TYPE_2Byte, &R_Byte, 1);
  15.         }
  16.         return R_Byte;
  17. }
  18. void AT24Cxx_R_NByte(u32 AT24Cxx_Type, u8 AT24Cxx_id, u16 AT24Cxx_addr, u8 *R_buff, u32 num)
  19. {
  20.         if ((AT24Cxx_addr + num - 1) > AT24Cxx_Type)
  21.                 return;
  22.         // 1字节地址长度
  23.     if (AT24Cxx_Type <= AT24C16)
  24.         {
  25.                 IIC_R_NByte(AT24Cxx_id | (u8)((AT24Cxx_addr >> 8) << 1), AT24Cxx_addr, IIC_REG_TYPE_1Byte, R_buff, num);
  26.         }
  27.         // 2字节地址长度
  28.         else
  29.         {
  30.                 IIC_R_NByte(AT24Cxx_id, AT24Cxx_addr, IIC_REG_TYPE_2Byte, R_buff, num);
  31.         }
  32. }
复制代码

  1. #define Write_Cycle_Time 400        // 400us
  2. void AT24Cxx_W_Byte(u32 AT24Cxx_Type, u8 AT24Cxx_id, u16 AT24Cxx_addr, u8 W_Byte)
  3. {
  4.         if (AT24Cxx_addr > AT24Cxx_Type)
  5.                 return ;
  6.         // 1字节地址长度
  7.     if (AT24Cxx_Type <= AT24C16)
  8.         {
  9.                 IIC_W_NByte(AT24Cxx_id | (u8)((AT24Cxx_addr >> 8) << 1), AT24Cxx_addr, IIC_REG_TYPE_1Byte, &W_Byte, 1);
  10.         }
  11.         // 2字节地址长度
  12.         else
  13.         {
  14.                 IIC_W_NByte(AT24Cxx_id, AT24Cxx_addr, IIC_REG_TYPE_2Byte, &W_Byte, 1);
  15.         }
  16.         delay_us(Write_Cycle_Time);        // 等待一段写周期 一般为5-10ms 测试最短为400-500us
  17. }
  18. void AT24Cxx_W_NByte(u32 AT24Cxx_Type, u8 AT24Cxx_id, u16 AT24Cxx_addr, u8 *W_buff, u32 num)
  19. {
  20.         u16 addr_offset = 0;        // 地址偏移量
  21.         u16 page = 0;                        // 计算要写多少页
  22.         u8 Remainder = 0;                // 不满1页
  23.        
  24.         if ((AT24Cxx_addr + num - 1) > AT24Cxx_Type)
  25.                 return;
  26.         switch (AT24Cxx_Type)
  27.         {
  28.         // 08-byte Page Write mode
  29.         case AT24C01:
  30.         case AT24C02:
  31.                 for (page = 0; page < (num / 8); page++)
  32.                 {
  33.                         addr_offset = AT24Cxx_addr + page * 8;
  34.                         IIC_W_NByte(AT24Cxx_id | (u8)((addr_offset >> 8) << 1), addr_offset, IIC_REG_TYPE_1Byte, &W_buff[page * 8], 8);
  35.                         delay_us(Write_Cycle_Time);
  36.                 }
  37.                 addr_offset = AT24Cxx_addr + page * 8;
  38.                 Remainder = num % 8;
  39.                 // 如果有空余数据
  40.                 if (Remainder)
  41.                         IIC_W_NByte(AT24Cxx_id | (u8)((addr_offset >> 8) << 1), addr_offset, IIC_REG_TYPE_1Byte, &W_buff[page * 8], Remainder);
  42.                 break;
  43.         // 16-byte Page Write mode
  44.         case AT24C04:
  45.         case AT24C08:
  46.         case AT24C16:
  47.                 for (page = 0; page < (num / 16); page++)
  48.                 {
  49.                         addr_offset = AT24Cxx_addr + page * 16;
  50.                         IIC_W_NByte(AT24Cxx_id | (u8)((addr_offset >> 8) << 1), addr_offset, IIC_REG_TYPE_1Byte, &W_buff[page * 16], 16);
  51.                         delay_us(Write_Cycle_Time);
  52.                 }
  53.                 addr_offset = AT24Cxx_addr + page * 16;
  54.                 Remainder = num % 16;
  55.                 // 如果有空余数据
  56.                 if (Remainder)
  57.                         IIC_W_NByte(AT24Cxx_id | (u8)((addr_offset >> 8) << 1), addr_offset, IIC_REG_TYPE_1Byte, &W_buff[page * 16], Remainder);
  58.                 break;
  59.         // 32-byte Page Write mode
  60.         case AT24C32:
  61.         case AT24C64:
  62.                 for (page = 0; page < (num / 32); page++)
  63.                 {
  64.                         addr_offset = AT24Cxx_addr + page * 32;
  65.                         IIC_W_NByte(AT24Cxx_id | (u8)((addr_offset >> 8) << 1), addr_offset, IIC_REG_TYPE_2Byte, &W_buff[page * 32], 32);
  66.                         delay_us(Write_Cycle_Time);
  67.                 }
  68.                 addr_offset = AT24Cxx_addr + page * 32;
  69.                 Remainder = num % 32;
  70.                 // 如果有空余数据
  71.                 if (Remainder)
  72.                         IIC_W_NByte(AT24Cxx_id | (u8)((addr_offset >> 8) << 1), addr_offset, IIC_REG_TYPE_2Byte, &W_buff[page * 32], Remainder);
  73.                 break;
  74.         // 64-byte Page Write mode
  75.         case AT24C128:
  76.         case AT24C256:
  77.                 for (page = 0; page < (num / 64); page++)
  78.                 {
  79.                         addr_offset = AT24Cxx_addr + page * 64;
  80.                         IIC_W_NByte(AT24Cxx_id | (u8)((addr_offset >> 8) << 1), addr_offset, IIC_REG_TYPE_2Byte, &W_buff[page * 64], 64);
  81.                         delay_us(Write_Cycle_Time);
  82.                 }
  83.                 addr_offset = AT24Cxx_addr + page * 64;
  84.                 Remainder = num % 64;
  85.                 // 如果有空余数据
  86.                 if (Remainder)
  87.                         IIC_W_NByte(AT24Cxx_id | (u8)((addr_offset >> 8) << 1), addr_offset, IIC_REG_TYPE_2Byte, &W_buff[page * 64], Remainder);
  88.                 break;
  89.         // 128-byte Page Write mode
  90.         case AT24C512:
  91.                 for (page = 0; page < (num / 128); page++)
  92.                 {
  93.                         addr_offset = AT24Cxx_addr + page * 128;
  94.                         IIC_W_NByte(AT24Cxx_id | (u8)((addr_offset >> 8) << 1), addr_offset, IIC_REG_TYPE_2Byte, &W_buff[page * 128], 128);
  95.                         delay_us(Write_Cycle_Time);
  96.                 }
  97.                 addr_offset = AT24Cxx_addr + page * 128;
  98.                 Remainder = num % 128;
  99.                 // 如果有空余数据
  100.                 if (Remainder)
  101.                         IIC_W_NByte(AT24Cxx_id | (u8)((addr_offset >> 8) << 1), addr_offset, IIC_REG_TYPE_2Byte, &W_buff[page * 128], Remainder);
  102.                 break;
  103.         default:
  104.                 break;
  105.         }
  106.         delay_us(Write_Cycle_Time);
  107. }
复制代码


三、实验结果

简单搞了一个串口读写和擦除的指令。
W(写指令):往地址0-254写入0-254,对于AT24C02(ai8051u实验箱)的地址255是校验码。
R(读指令):把地址0-255的数据读出来
E(擦除指令):往地址0-254的数据写0

  1. // 写 W(0x57)
  2.         if (RX1_Buffer[0] == 'W')
  3.         {
  4.             // at24c02 实验箱
  5.             // Uart1_printf("开始写入\r\n");
  6.             // for ( i = 0; i < 128; i++)
  7.             // {
  8.             //     TX1_Buffer[i] = i;
  9.             // }
  10.             // AT24Cxx_W_NByte(AT24C02, AT24C02_ID1, 0, TX1_Buffer, 128);
  11.             // for ( i = 128; i < 255; i++)
  12.             // {
  13.             //     TX1_Buffer[i-128] = i;
  14.             // }
  15.             // AT24Cxx_W_NByte(AT24C02, AT24C02_ID1, 128, TX1_Buffer, 127);
  16.             // Uart1_printf("写入完成\r\n");
  17.             
  18.             // at24128
  19.             Uart1_printf("开始写入\r\n");
  20.             for ( i = 0; i < 128; i++)
  21.             {
  22.                 TX1_Buffer[i] = i;
  23.             }
  24.             AT24Cxx_W_NByte(AT24C128, AT24C128_ID1, 0, TX1_Buffer, 128);
  25.             for ( i = 128; i < 255; i++)
  26.             {
  27.                 TX1_Buffer[i-128] = i;
  28.             }
  29.             AT24Cxx_W_NByte(AT24C128, AT24C128_ID1, 128, TX1_Buffer, 127);
  30.             Uart1_printf("写入完成\r\n");
  31.         }
  32.         // 读 R(0x52)
  33.         else if (RX1_Buffer[0] == 'R')
  34.         {
  35.             // at24c02 实验箱
  36.             // for ( i = 0; i < 96; i++)
  37.             // {
  38.             //     TX1_Buffer[i] = AT24Cxx_R_Byte(AT24C02, AT24C02_ID1, i);
  39.             // }
  40.             // Uart1_Send_NByte(TX1_Buffer, 96);
  41.             // for ( i = 0; i < 96; i++)
  42.             // {
  43.             //     TX1_Buffer[i] = AT24Cxx_R_Byte(AT24C02, AT24C02_ID1, 96 + i);
  44.             // }
  45.             // Uart1_Send_NByte(TX1_Buffer, 96);
  46.             // for ( i = 0; i < 64; i++)
  47.             // {
  48.             //     TX1_Buffer[i] = AT24Cxx_R_Byte(AT24C02, AT24C02_ID1, 192 + i);
  49.             // }
  50.             // Uart1_Send_NByte(TX1_Buffer, 64);
  51.             // at24c128
  52.             for ( i = 0; i < 96; i++)
  53.             {
  54.                 TX1_Buffer[i] = AT24Cxx_R_Byte(AT24C128, AT24C128_ID1, i);
  55.             }
  56.             Uart1_Send_NByte(TX1_Buffer, 96);
  57.             for ( i = 0; i < 96; i++)
  58.             {
  59.                 TX1_Buffer[i] = AT24Cxx_R_Byte(AT24C128, AT24C128_ID1, 96 + i);
  60.             }
  61.             Uart1_Send_NByte(TX1_Buffer, 96);
  62.             for ( i = 0; i < 64; i++)
  63.             {
  64.                 TX1_Buffer[i] = AT24Cxx_R_Byte(AT24C128, AT24C128_ID1, 192 + i);
  65.             }
  66.             Uart1_Send_NByte(TX1_Buffer, 64);
  67.         }
  68.         // 擦除 E(0x45)
  69.         else if (RX1_Buffer[0] == 'E')
  70.         {
  71.             // at24c02 实验箱
  72.             // Uart1_printf("开始擦除\xfd\r\n");
  73.             // for ( i = 0; i < 0xff; i++)
  74.             // {
  75.             //     AT24Cxx_W_Byte(AT24C02, AT24C02_ID1, i, 0);
  76.             //     delay_us(500);
  77.             // }
  78.             // Uart1_printf("擦除\xfd完成\r\n");
  79.             // at24c128
  80.             Uart1_printf("开始擦除\xfd\r\n");
  81.             for ( i = 0; i < 0xff; i++)
  82.             {
  83.                 AT24Cxx_W_Byte(AT24C128, AT24C128_ID1, i, 0);
  84.                 delay_us(500);
  85.             }
  86.             Uart1_printf("擦除\xfd完成\r\n");
  87.         }
复制代码



结果如下:
先读一下,数据全为0。

截图202510192221355667.jpg
再执行写命令
截图202510192221565708.jpg
再读一下,数据正常
截图202510192222175251.jpg
擦除指令
截图202510192222396209.jpg
再读一下,数据已全部擦除
截图202510192222581684.jpg


番外-有趣的实验

实验箱中测试2.5M速率和50K速率。从发送读取指令,到第1次接收串口反馈的时间差。约读96字节数据

2.5M:约20ms
50K:约90ms

截图202510192224549939.jpg



好奇又测了几组:
1M,约20ms

截图202510192225198712.jpg


500K,约20ms
截图202510192225375737.jpg


400K,约20ms
截图202510192225591455.jpg


250K,约30ms
截图202510192226159932.jpg


125K,约40ms
截图202510192226406767.jpg


100K,约50-60ms
截图202510192227014683.jpg


50K,约90-100ms
截图202510192227264119.jpg


结果表明,400K大约就是最大速率了,再高也会因为从机跟不上而限速了。


如何使用?
截图202510192231029221.jpg
config.h里选择软硬件模式


截图202510192231386515.jpg
iic.h里修改引脚定义,注意修改GPIO初始化


截图202510192232148942.jpg
主函数初始化GPIO和IIC即可。
具体任务在task_uart1_polling.c中



13_IIC-AT24C128.zip (442.34 KB, 下载次数: 3)
IIC总线协议手册.pdf (1.29 MB, 下载次数: 1)
AT24C01_02C.pdf (954.67 KB, 下载次数: 0)
AT24C04_08C.pdf (879.92 KB, 下载次数: 0)
AT24C16C.pdf (992.86 KB, 下载次数: 0)
AT24C32_64C.pdf (812.67 KB, 下载次数: 0)
AT24C128_256C.pdf (1.18 MB, 下载次数: 0)
AT24C256C.pdf (900.91 KB, 下载次数: 1)
AT24C512C.pdf (954.76 KB, 下载次数: 1)
AT24C1024.pdf (212.73 KB, 下载次数: 2)



回复

使用道具 举报 送花

3

主题

1861

回帖

570

积分

等待验证会员

积分
570
发表于 3 天前 | 显示全部楼层
在嵌入式系统与微控制器应用中,I²C(Inter-Integrated Circuit)协议因其结构简单、通信稳定、支持多主多从架构等优点,被广泛应用于各类低速外设的通信场景。AT24Cxx系列EEPROM芯片作为典型的I²C接口器件,常用于数据存储、配置信息保存等应用场景。本文将围绕I²C协议的基本原理、通信时序及在AT24Cxx系列芯片上的具体应用进行详细解析,并提供通用读写函数的设计思路,以支持任意型号的AT24Cxx芯片。

一、I²C协议基础

1.1 协议概述

I²C协议是由飞利浦公司(现NXP)提出的一种同步串行通信协议,主要用于短距离、低速设备之间的数据传输。其核心特点包括:
双线制通信:仅需SDA(数据线)和SCL(时钟线)两根信号线;
半双工通信:同一时刻只能单向传输;
多主多从架构:支持多个主设备和多个从设备连接在同一总线上;
硬件开漏结构:需外接上拉电阻,确保信号稳定;
地址识别机制:每个从设备具有唯一地址,主设备通过地址选择通信对象;
应答机制:通信过程中通过ACK/NACK进行数据确认,提高通信可靠性。

1.2 通信时序

I²C通信由起始信号、数据传输、应答机制和结束信号组成,具体时序如下:

1.2.1 起始信号(Start)
SCL为高电平时,SDA由高变低,表示通信开始。

1.2.2 结束信号(Stop)
SCL为高电平时,SDA由低变高,表示通信结束。

1.2.3 数据传输
每次传输1字节(8位),高位(MSB)先传;
每字节后必须跟随一个应答位(ACK/NACK)。

1.2.4 应答机制(ACK/NACK)
ACK:接收方在第9个SCL周期将SDA拉低,表示接收成功;
NACK:SDA保持高电平,表示接收失败或数据结束。

1.2.5 重复起始信号(Repeated Start)
在不发送Stop信号的情况下,再次发送Start信号,用于切换读写方向或访问不同设备。

二、AT24Cxx系列EEPROM简介

AT24Cxx是Atmel(现Microchip)推出的一系列I²C接口的EEPROM存储芯片,常见的型号包括AT24C01(1Kbit)、AT24C02(2Kbit)、AT24C128(128Kbit)等。其主要特性如下:
支持I²C总线接口,频率支持100kHz/400kHz;
宽电压范围(1.7V~5.5V);
内部页写缓冲(Page Write)功能;
高达1百万次擦写寿命;
数据保持时间可达100年;
支持硬件地址选择,最多可挂载多个芯片。

2.1 地址格式

AT24Cxx的从机地址为7位,其中高4位固定为1010,接下来的3位为硬件地址引脚A2、A1、A0的电平组合。例如:
  1. 地址格式 = 1 0 1 0 A2 A1 A0
复制代码
当A2=0, A1=0, A0=0时,地址为0xA0(写)和0xA1(读);
实际通信中,地址的最低位表示读写方向(0为写,1为读)。

2.2 读写操作流程

2.2.1 写操作

1. 发送Start信号;
2. 发送从机地址(写地址);
3. 等待ACK;
4. 发送存储地址(高字节可选);
5. 继续发送数据;
6. 每发送一个字节等待ACK;
7. 发送Stop信号;
8. 延迟10ms(确保写入完成)。
注意:AT24Cxx支持页写操作,一页大小为16/32/64字节(依型号而定),若写入数据超过页边界,将覆盖当前页开头数据。

2.2.2 读操作

1. 发送Start信号;
2. 发送从机地址(写地址);
3. 等待ACK;
4. 发送存储地址(高字节可选);
5. 再次发送Start信号(Re-Start);
6. 发送从机地址(读地址);
7. 接收数据;
8. 每接收一个字节发送ACK/NACK;
9. 发送Stop信号。

三、通用读写函数设计(适用于任意AT24Cxx型号)

为实现对任意AT24Cxx芯片的兼容读写,函数设计需具备以下特性:
可配置从机地址;
支持高位地址(如AT24C128/256);
自动处理页写边界;
提供字节读写与多字节读写接口。

3.1 写函数(单字节写)
  1. c
  2. void AT24CXXWriteByte(uint8t devAddr, uint16t memAddr, uint8t data)
  3. {
  4.     IICStart();
  5.     IICSendByte(devAddr > 8)); // 发送高地址
  6.         IICWaitACK();
  7.     }
  8.     IICSendByte((uint8t)memAddr);    // 发送低地址
  9.     IICWaitACK();
  10.     IICSendByte(data);                // 发送数据
  11.     IICWaitACK();
  12.     IICStop();
  13.     DelayMs(10);                       // 等待写入完成
  14. }
复制代码

3.2 读函数(单字节读)

```c
uint8t AT24CXXReadByte(uint8t devAddr, uint16t memAddr)
{
    uint8t data;

    IICStart();
    IICSendByte(devAddr > 8));
        IICWaitACK();
    }

    IICSendByte((uint8t)memAddr);
    IICWaitACK();

    IICStart();
    IICSendByte((devAddr

[本文内容由国芯人工智能辅助生成,仅供参考]
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-10-22 05:40 , Processed in 0.170774 second(s), 57 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表