stm32cubemx I2C读取AT24C16

article/2025/10/9 10:48:19

本文对如何使用stm32cube生成I2C工程不作说明,仅对在对AT24Cxx系列的使用时作出易忽略的说明;

1、at24cxx页面结构:

从该图可以看出16K(bit)共有128个页,每页由16byte构成。16k = 128 * 16 * 8;

特别注意:除at24c01和at24c02的页由8个byte构成,其它的都是由16byte构成。(这关系到对芯片的连续读写)

2.at24cxx的设备地址:

A:作为设备地址的一部分;P:作为页地址的一部分;

对于大多数人来说都知道I2c设备具有一个设备地址,并且在一条总线上是唯一。若要在一个I2C总线上挂多个AT24CXX系列芯片,则需要A2,A1,A0作为设备地址的一部分,设备地址的最低位作为是读(1)写(0)。

对于在一条总线挂载的设备数:看有几个位用作设备地址。


例:AT24C04: 有两位用作设备地址(A2,A1),一位用作页地址(P0).则可挂载的设备数为2^2 = 4个。

       AT24C16:没有用作设备地址的位,三位用作页地址(P0,P1,P2)。则仅可挂载设备数为2^0= 1个。


可能有人会考虑若A0,A1,A2用作地址了,那实际硬件接线该怎么接呢?

直接按照AT24C02的接就OK了.都接地。

3、页面连续读写:

注意:连续写并不是可以一直连续的写N个数据,而是写一页的数据(AT24C02只能连续写8byte的数据,其它的可以连续写16byte的数据。);

当从某个地址连续写多个数据时,要确定这个地址在某一页的偏移量,从而确定该页中最多还可以连续写多少byte数据。

以AT24C16为例;

比如在0x0025读写,则该位置的偏移量为:0x0025 & 0x000FF = 0x0005, 即该页还可以写  = 每页的字节数 - 偏移量 = 0x0F - 0x05  = 0x0A 即在该页还可以连续写10byte数据;

4、地址问题:

由于在传输过程中,地址数据是一个8位的地址,只能按该8位地址寻址的数据有2^8=256byte数据,

对于容量大于256byte容量的设备,我们还有设备ID中的页地址位可以使用。

例:以AT24C16为例 :

比如我们要访问(写)第0x0456的这一byte数据0x55:

(1)、开始信号:

(2)、设备号(高4位为:1101 p p p r/w), 此时设备号应设置为:0xA4;

(3)、地址:0x56;

(4)、数据:0x55;

(5)、结束;

5、时间控制:


每完成一次写操作后要进行一定的延时,让芯片去处理数据;从该图看,保险的时间为5ms.


例子:

#include "at24c16.h"
#include "i2c.h"#define E2PROM_SIZE 0x0800    //2k byte 16bit
#define E2PROM_BASE_ID    0xA0#define E2PROM_WRITE 0x00
#define E2PROM_READ     0x01#define E2PROM_BASE_WID E2PROM_BASE_ID + E2PROM_WRITE
#define E2PROM_BASE_RID E2PROM_BASE_ID + E2PROM_READ#define E2PROM_PAGE_MASK    0x000F
uint8_t writeAT24C16(uint16_t addr, uint8_t *data, uint16_t len)
{uint8_t wNum = 0;uint16_t lenLeft = len;uint8_t deviceId ;uint8_t *p = data;/*is the address overfolw*/if(addr + len >= E2PROM_SIZE)return 1;/*calculate the current write position to know how many word can write continully*/wNum = 16 - addr & E2PROM_PAGE_MASK;if(wNum == 0)wNum = 16;wNum = lenLeft>=wNum ? wNum : lenLeft;/*transmit the date to e2prom*/while(lenLeft){/*calculate the device id*/deviceId = (addr >> 8)<=0 ?  E2PROM_BASE_WID : (E2PROM_BASE_WID | (uint8_t)((addr>>7)&0x0E));if( HAL_I2C_Mem_Write(&hi2c1, deviceId, addr&0x00FF, I2C_MEMADD_SIZE_8BIT, p, wNum, 0x20) != HAL_OK){printf("I2S Write error!\r\n");HAL_Delay(5);continue;}            addr += wNum;lenLeft -= wNum;p += wNum;wNum = lenLeft > 16 ? 16 : lenLeft;    HAL_Delay(5);}return HAL_OK;
}uint8_t readAT24C16(uint16_t addr, uint8_t *data, uint16_t len)
{uint8_t rNum = 0;uint16_t lenLeft = len;uint8_t deviceId ;uint8_t *p = data;/*is the address overfolw*/if(addr + len >= E2PROM_SIZE)return 1;/*calculate the current write position to know how many word can write continully*/rNum = 16 - addr & E2PROM_PAGE_MASK;if(rNum == 0)rNum = 16;rNum = lenLeft>=rNum ? rNum : lenLeft;/*transmit the date to e2prom*/    while(lenLeft){/*calculate the device id*/deviceId = (addr >> 8)<=0 ?  E2PROM_BASE_RID : (E2PROM_BASE_RID | (uint8_t)((addr>>7)&0x0E));if( HAL_I2C_Mem_Read(&hi2c1, deviceId, addr&0x00FF, I2C_MEMADD_SIZE_8BIT, p, rNum, 20) != HAL_OK){printf("I2S Read error!\r\n");continue;}            addr += rNum;lenLeft -= rNum;p += rNum;rNum = lenLeft > 16 ? 16 : lenLeft;    }return HAL_OK;    
}void vE2romTest()
{uint8_t WriteBuffer[BufferSize],ReadBuffer[BufferSize];uint16_t i;printf("\r\n***************I2C Example*******************************\r\n");for(i=0; i<256; i++)WriteBuffer[i]=i;    /* WriteBuffer init *//* wrinte date to EEPROM */if(!writeAT24C16(0x05,WriteBuffer,BufferSize))printf("\r\n EEPROM 24C16 Write Test OK \r\n");elseprintf("\r\n EEPROM 24C16 Write Test False \r\n");/* read date from EEPROM */readAT24C16(0x05,ReadBuffer, BufferSize);for(i=0; i<256; i++)printf("0x%02X  ",ReadBuffer[i]);if(memcmp(WriteBuffer,ReadBuffer,BufferSize) == 0 ) /* check date */printf("\r\n EEPROM 24C16 Read Test OK\r\n");elseprintf("\r\n EEPROM 24C16 Read Test False\r\n");
}


测试结果:




http://chatgpt.dhexx.cn/article/HYwJ3GMg.shtml

相关文章

STM32之 AT24C16(EEPROM)驱动代码(程序稳定,清晰明了)

AT24C16电路图 第一部分&#xff1a;IIC协议代码头文件(iic.h) #ifndef IIC_H #define IIC_H #include "stm32f10x.h" #include "sys.h" #include "delay.h"#define write 0 #define read 1//IIC总线地址接口定义 #define IIC_SCL PBout(7) #d…

GD32F4xx MCU控制I2C EEPROM(AT24C16)记录

1、AT24C16简介 1.1 主要参数 工作电压:1.8v ~ 5.5v存储空间:2048 Bytes ,分128页,16Bytes/页, 地址范围 0~2047。接口: I2C 总线I2C时钟频率: 1MHz( 5v ) , 400KHz( 1.8v, 2.5v, 2.7v)。1.2 电路连接 1.3 其他说明 AT24C16未使用器件地址引脚,总线上最多只可以连接一…

AT24C04、AT24C08、AT24C16系列EEPROM芯片单片机读写驱动程序

一、概述 在之前的一篇博文中&#xff0c;记录了AT24C01、AT24C02芯片的读写驱动&#xff0c;先将之前的相关文章include一下&#xff1a; 1.IIC驱动&#xff1a;4位数码管显示模块TM1637芯片C语言驱动程序 2.AT24C01/AT24C02读写&#xff1a;AT24C01/AT24C02系列EEPROM芯片单…

IIC方式读驱动AT24C16芯片

闲来无事&#xff0c;找了块msp430的板子编写了个IIC驱动AT24C16的程序。 IIC作是一种简单&#xff0c;双向&#xff0c;同步的二进制总线&#xff0c;由SDA数据线和SCL时钟线组成&#xff0c;所有接到IIC总线上的各设备的SDA数据线都连接到总线的SDA数据线上&#xff0c;用来…

AT24C16页写和多页写

AT24C16 2K字节(存储内存) 128&#xff08;页面数&#xff09;* 16 &#xff08;每页的字节数&#xff09; 2^11 (寻址地址位数 11位)。 AT24C16有128(2^7128)页只需要7位地址&#xff0c;分为高3位和低4位&#xff0c;高3位在设备地址中&#xff0c;低4位在字地址中。 设备…

EEPROM(AT24C16)页写算法

1. 写在前面 学习单片机或者从事嵌入式开发的&#xff0c;对于EEPROM绝不会陌生&#xff0c;尤其的24系列的EEPROM很是经典&#xff0c;或者与此兼容的FRAM系列&#xff0c;如AT24C02、AT24C16、FM24C16等。 驱动起这个系列的EEPROM&#xff0c;可以说是没有任何难点&#xff0…

AT24C16 读写注意点

开篇一张时序图镇楼&#xff1a; 这篇文章介绍了AT24C16的页写、连续读、写保护功能&#xff1a;AT24C16 读写_D.luffy的博客-CSDN博客_at24c16 页写算法我是参考这篇文章的&#xff1a;https://acuity.blog.csdn.net/article/details/78550427?utm_ char ee_24clxx_writeby…

AT24C16 读写

at24c16 有8块 256字节组成&#xff0c;共2K字节16K bit I2C开始信号后&#xff0c;第一个字节为器件地址&#xff0c;由10103位块地址1位读写标志组成&#xff0c; 3位块地址刚好可以表示 8个块&#xff0c; 所以一次写完256字节&#xff0c;换到下一下块的时候&#xff0c;要…

进程间通信的方式(附代码分析)

进程间通信的方式 1. 进程间通信的几种方式 管道 比如 ls | grep 1;也就是将 进程 ls 拿到的结果作为 grep 1 这个进程的输入。实现了进程间的通信。 消息队列 消息队列就是我们的内核给我们创建的一种消息队列。我们可以往其中发送消息&#xff0c;也可以从其中接收消息。 …

linux进程--进程间通信方式(一)

一、多进程 首先&#xff0c;先来讲一下fork之后&#xff0c;发生了什么事情。 由fork创建的新进程被称为子进程&#xff08;child process&#xff09;。该函数被调用一次&#xff0c;但返回两次。两次返回的区别是子进程的返回值是0&#xff0c;而父进程的返回值则是新进程…

进程间通信的方式——信号、管道、消息队列、共享内存

进程间通信的方式——信号、管道、消息队列、共享内存 多进程&#xff1a; 首先&#xff0c;先来讲一下fork之后&#xff0c;发生了什么事情。 由fork创建的新进程被称为子进程&#xff08;child process&#xff09;。该函数被调用一次&#xff0c;但返回两次。两次返回的区别…

Android 进程间通信的几种实现方式

一、概述 由于应用程序之间不能共享内存。在不同应用程序之间交互数据&#xff08;跨进程通讯&#xff09;&#xff0c;在android SDK中提供了4种用于跨进程通讯的方式。这4种方式正好对应于android系统中4种应用程序组件&#xff1a;Activity、Content Provider、Broadcast和S…

进程间通信的方式及原理

# 进程间通信的方式 文章目录 # 进程间通信的方式消息队列使用步骤 管道 消息队列 信号 信号量 socket 消息队列 首先消息队列就是内核维护的一块链表区域&#xff0c;只要是有足够权限的进程都可以向队列中添加消息&#xff0c;只要是有读权限的进程都可以在里面拿出消息 克…

C | 进程间通信的方式

C | 进程间通信的方式 1.无名管道 无名管道是实现亲缘间进程通信的一种方式&#xff0c;属于半双工通信。 无名管道的实现是队列&#xff0c;不能使用lseek对读写指针偏移。 无名管道有两个端&#xff1a;数据流入端和数据流出端&#xff0c;也叫写端和读端。它们是两个固定…

面试题:进程间通信的方式

liunx六大进程间通信方式 管道&#xff0c;消息队列&#xff0c;共享内存&#xff0c;信号量&#xff0c;socket&#xff0c;信号&#xff0c;文件锁 1&#xff0c;管道 1&#xff0c;匿名管道&#xff1a; 概念&#xff1a;在内核中申请一块固定大小的缓冲区&…

进程间通信的几种方式浅谈(上)

程序员必须让拥有依赖关系的进程集协调&#xff0c;这样才能达到进程的共同目标。可以使用两种技术来达到协调。第一种技术在具有通信依赖关系的两个进程间传递信息。这种技术称做进程间通信&#xff08;interprocess communication&#xff09;。第二种技术是同步&#xff0c;…

进程间通信的几种方式

一、管道 在Linux 中&#xff0c;管道是一种使用非常频繁的通信机制。从本质上说&#xff0c;管道也是一种文件&#xff0c;但它又和一般的文件有所不同&#xff0c;管道可以克服使用文件进行通信的两个问题&#xff0c;具体表现如下所述。 • 限制管道的大小。实际上&#x…

【进程间通信】进程间通信方式汇总

个人主页&#xff1a;董哥聊技术 我是董哥&#xff0c;嵌入式领域新星创作者 创作理念&#xff1a;专注分享高质量嵌入式文章&#xff0c;让大家读有所得&#xff01; 文章目录 1、管道模型1.1 匿名管道1.2 命名管道 2、消息队列2.1 创建消息队列2.2 发送消息2.3 接收消息 3、共…

android中进程间通信的几种方式

进程间通信&#xff08;IPC&#xff09;方式 使用Bundle使用文件共享使用Messenger使用AIDL使用COntentProvider使用Socket 一、使用Bundle 我们都知道Android中三大组件Activity&#xff0c;Service&#xff0c;Receiver都支持在Intent中传递Bundle数据&#xff0c;而Bundle…

操作系统——进程间通信

文章目录 其他文章管道消息队列共享内存信号量信号Socket总结 个人博客网站&#xff1a; https://xingkongdiyiren.github.io/myblog/,完整的Java知识体系&#xff0c;包括408&#xff0c;架构&#xff0c;业务&#xff0c;产品&#xff0c;软技能等 其他文章 操作系统——概…