AT24C16 读写注意点

article/2025/10/9 12:29:52

开篇一张时序图镇楼:

这篇文章介绍了AT24C16的页写、连续读、写保护功能:AT24C16 读写_D.luffy的博客-CSDN博客_at24c16

页写算法我是参考这篇文章的:https://acuity.blog.csdn.net/article/details/78550427?utm_

char ee_24clxx_writebytes(u16 write_addr, char* pwrite_buff, u16 writebytes)  {  u8   write_len,page_offset;  char error = 0;  while(writebytes > 0)  {  page_offset = EE24CLXX_PAGESIZE - (write_addr % EE24CLXX_PAGESIZE); /*EE24CLXX_PAGESIZE为页大小,如24c16为16*/  write_len   = writebytes > page_offset ? page_offset : writebytes;  i2c_24clxx_write(write_addr,pwrite_buff, write_len);           /*写一页函数*/  writebytes   = writebytes - write_len;  if(writebytes > 0)  {  pwrite_buff = pwrite_buff + write_len;  write_addr  = write_addr + write_len;  i2c_24clxx_waitstandby(0);                  /*页写判忙,FRAM则不用*/  }  }  return error;  }  

AT24C16 內部有 2048*8 位的存储容量,即可以存储 2K 字节的数据。这 2K 字节被放在 128 个页内,每页存放 16 个字节。所以对 AT24C16 內部的访问需要 11 位地址(0~0x7ff)

总的来说虽然最后也实现了,但eeprom里有的坑似乎也全被我踩遍了。从只能写一页大小,到可以页写,再到可以实现随机写,还是蛮曲折并且浪费了我不少时间的。废话不多讲,下面介绍下我最终的成果:

eeprom页写接口:

每次写入,都要偏移 eeprom 內部的字地址和发送字串的地址。

/*********************************************************************************************************
** 函数名称: at24cxxWrite
** 功能描述: 驱动 write 函数
** 输 入  : pdevHdr    设备
**           pvBuf      写缓冲
**           stLen      写数据长度
** 输 出  : 成功读取数据字节数量
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static ssize_t  at24cxxWrite (PLW_DEV_HDR  pdevHdr, PVOID  pvBuf, size_t  stLen)
{INT             iError;AT24CXX_DEV    *pat24cxx   = (AT24CXX_DEV  *)pdevHdr;UINT8           ucOffset[1];UINT8           ucPageOffset;UINT8           ucWriteLen;INT             iTemp      = 0;ucOffset[0] = pat24cxx->AT24CXX_iOffset;                            /*  获得偏移量                  */if (stLen > __AT24XX_BYTES_SIZE) {I2C_DBG("stLen(%d) too long!\n",stLen);return (PX_ERROR);}while(stLen > 0) {ucPageOffset = __PAGE_OFFSET;                                   /*  计算页偏移                  */ucWriteLen   = stLen > ucPageOffset ? ucPageOffset : stLen;     /*  写的偏移                    */LW_I2C_MESSAGE  i2cMsgs[2] = {{.I2CMSG_usAddr    = __AT24XX_IIC_ADDR,.I2CMSG_usFlag    = 0,.I2CMSG_usLen     = 1,.I2CMSG_pucBuffer = ucOffset,                           /*  eeprom 内(字地址)寻址               */},{.I2CMSG_usAddr    = __AT24XX_IIC_ADDR,.I2CMSG_usFlag    = LW_I2C_M_NOSTART,.I2CMSG_usLen     = ucWriteLen,.I2CMSG_pucBuffer = pvBuf,                              /*  发送的字串寻址              */}};iError = API_I2cDeviceTransfer(pat24cxx->AT24CXX_pI2cDev, i2cMsgs, 2);if (iError < 0) {I2C_DBG("%s: __i2cByteDataWrite[0x%x 0x%x] error!\n\r", __func__, ucOffset, stLen);return  (PX_ERROR);}stLen -= ucWriteLen;                                            /*  更新剩余长度                */iTemp += 1;if (stLen > 0) {pvBuf                     += ucWriteLen;                    /*  写的字串地址要偏移          */pat24cxx->AT24CXX_iOffset += ucWriteLen;                    /*  写的eeprom 地址也要偏移     */ucOffset[0]                = pat24cxx->AT24CXX_iOffset;}if (iTemp > 124) {I2C_DBG("current stLen             == %ld\n", stLen);I2C_DBG("current position          == %08xx\n", pat24cxx->AT24CXX_iOffset);I2C_DBG("current msgAddrusleep     == %08xx\n", pvBuf);I2C_DBG("current __AT24XX_IIC_ADDR == %08xx--------------\n", __AT24XX_IIC_ADDR);}usleep(10 * 1000);                                              /*  eeprom内部写循环最大持续时间*/}return  (iTemp * __AT24XX_BYTES_PER_PAGE + stLen);
}

eeprom页读接口(之所以做成页读是因为本人在测试发大于1024个字节时,IIC驱动中的pend接口会报错传输超时,导致读取失败。不知道大家有没有遇到过这个问题。):

/*********************************************************************************************************
** 函数名称: at24cxxRead
** 功能描述: 驱动 read 函数
** 输 入  : pdevHdr   设备
**           pvBuf     读缓冲
**           stLen     读数据长度
** 输 出  : 成功数码管值的个数
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static ssize_t  at24cxxRead (PLW_DEV_HDR  pdevHdr, PVOID  pvBuf, size_t  stLen)
{INT             iError;AT24CXX_DEV    *pat24cxx   = (AT24CXX_DEV  *)pdevHdr;UINT8           ucOffset[1];UINT8           ucPageOffset;UINT8           ucWriteLen;INT             iTemp      = 0;ucOffset[0] = pat24cxx->AT24CXX_iOffset;                            /*  获得偏移量                  */if (stLen > __AT24XX_BYTES_SIZE) {I2C_DBG("stLen(%d) too long!\n",stLen);return (PX_ERROR);}while (stLen > 0) {ucPageOffset = __PAGE_OFFSET;                                   /*  计算页偏移                  */ucWriteLen   = stLen > ucPageOffset ? ucPageOffset : stLen;     /*  写的偏移                    */LW_I2C_MESSAGE  i2cMsgs[2] = {{.I2CMSG_usAddr    = __AT24XX_IIC_ADDR,.I2CMSG_usFlag    = 0,.I2CMSG_usLen     = 1,.I2CMSG_pucBuffer = ucOffset,                           /*  eeprom 内寻址               */},{.I2CMSG_usAddr    = __AT24XX_IIC_ADDR,.I2CMSG_usFlag    = LW_I2C_M_RD,                        /*  为读操作                    */.I2CMSG_usLen     = ucWriteLen,.I2CMSG_pucBuffer = pvBuf,                              /*  发送的字串寻址              */}};iError = API_I2cDeviceTransfer(pat24cxx->AT24CXX_pI2cDev, i2cMsgs, 2);if (iError < 0) {I2C_DBG("%s: __i2cByteDataRead[0x%x] error!\n\r", __func__, ucOffset);return  (PX_ERROR);}stLen -= ucWriteLen;                                            /*  更新剩余长度                */iTemp += 1;if (stLen > 0) {pvBuf                     += ucWriteLen;                    /*  读的字串地址要偏移          */pat24cxx->AT24CXX_iOffset += ucWriteLen;                    /*  读的eeprom 地址也要偏移     */ucOffset[0] = pat24cxx->AT24CXX_iOffset;}usleep(10 * 1000);                                              /*  eeprom内部写循环最大持续时间*/}return  (iTemp * __AT24XX_BYTES_PER_PAGE + stLen);
}

关于usleep 这个延时:

eeprom芯片中有一块缓存,数据是先写到这块缓存中,最终写到eeprom的存储空间还需要一点时间。从datasheet可以看到AT24C16的内部写循环最大持续时间为10ms.


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

相关文章

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;软技能等 其他文章 操作系统——概…

进程间的通信方式(六种)

进程之间的通信 参考文章&#xff1a;https://blog.csdn.net/qq_34827674/article/details/107678226 前提知识&#xff1a;每个进程都有自己的用户空间&#xff0c;而内核空间是每个进程共享的。因此进程之间想要进行通信&#xff0c;就需要通过内核来实现。 管道&#xff1…

【操作系统】进程间通信的五种方式

引言1.进程对白&#xff1a;管道、记名管道、套接字1.管道2.虫洞&#xff1a;套接字3.信号 4.信号旗语&#xff1a;信号量5.进程拥抱&#xff1a;共享内存 引言 进程作为人类的发明&#xff0c;自然免不了脱离人类的习性&#xff0c;也有通信需求。如果进程之间不进行任何通信…

进程之间的通信方式

进程之间的通信方式包括管道&#xff0c;消息队列&#xff0c;共享内存&#xff0c;信号&#xff0c;信号量&#xff0c;socket六种方式&#xff0c;下面来对这6种方式分别进行介绍。 一、管道 管道的结构示意图如上所示&#xff0c;管道包含一个输入端和一个输出端&#xff0…

进程间通信的六种常见方式

目录 进程间通信&#xff08;IPC&#xff09;&#xff1a; 一、管道 二、FIFO 三、消息队列 四、共享内存 五、信号 六、信号量 七、进程间通信方式总结&#xff1a; 进程间通信&#xff08;IPC&#xff09;&#xff1a; 进程间通信的方式有很多&#xff0c;这里主要…

idea数据库管理工具配置连接数据库

idea数据库管理工具配置连接数据库 —————————————————————————————————————————————————————— 在cmd中操作数据库太麻烦了&#xff0c;还好idea为我们提供了很方便的数据库管理工具&#xff0c;下面看看如何用idea连接…

idea连接数据库失败解决办法

一.IDEA连接Mysql报错&#xff1a; 未找到驱动程序类 ‘com.mysql.cj.jdbc.Driver‘.  Change driver class 报错详细内容&#xff1a;未找到驱动程序类 ‘com.mysql.cj.jdbc.Driver’. Change driver class 报错原因&#xff1a;Mysql版本为5.0&#xff0c;找不到com.mysql.…

IDEA中如何连接数据库并显示数据库信息。

我的相关博客&#xff1a; java代码程序中连接mysql数据库的方法及代码 mysql数据库并发上锁问题&#xff0c;java代码 关于IDEA中怎么连接mysql数据库 相信部分朋友在使用IDEA操作数据库的时候会出现有关数据库信息的报错。 显示没有此表&#xff0c;或者无数据库等错误信息…