1、24C02简介

  24C02是一个2Kbit的串行EEPROM存储芯片,可存储256个字节数据。工作电压范围为1.8V到6.0V,具有低功耗CMOS技术,自定时擦写周期,1000000次编程/擦除周期,可保存数据100年。24C02有一个16字节的页写缓冲器和一个写保护功能。通过I2C总线通讯读写芯片数据,通讯时钟频率可达400KHz。

  可以通过存储IC的型号来计算芯片的存储容量是多大,比如24C02后面的02表示的是可存储2Kbit的数据,转换为字节的存储量为2*1024/8 = 256byte;有比如24C04后面的04表示的是可存储4Kbit的数据,转换为字节的储存量为2*1024/8 = 512byte;以此来类推其它型号的存储空间。

  24C02的管脚图如下:

  VCC和VSS是芯片的电源和地,电压的工作范围为:+1.8V~+6.0V。

  A0、A1、A2是IC的地址选择脚。

  WP是写保护使能脚。

  SCL是I2C通讯时钟引脚。

  SDA是I2C通讯数据引脚。

2、24C02的设备地址和写写保护功能

  I2C主机在与24C02通讯时,需要发送一个设备地址进行寻址,在I2C总线上,每一个从机设备的地址都是唯一的。

  24C02的设备地址包含两部分,第一部分是bit7~bit4是固定的“1010”,第二部分bit3~bit1位由A2、A1、A0组成。主机在与24C02进行通讯时,除了发送设备地址还需要发送数据的读写方向位R/W,24C02的是设备地址与R/W位组成了一个字节的数据。如下图:

  上图列出了几个存储IC的设备地址与R/W位组成的字节。由图中可以看到,存储IC地址的bit7~bit4位固定为“1010”;bit3~bit1位由A2、A1、A0引脚的电平状态决定,如果Ax接的是电源(高电平),那么Ax=1,如果Ax接的是地,那么Ax=0,即由A2、A1、A0可以组合成8种设备地址,也就是说在同一个I2C总线上可以同时挂载8个24C02芯片。一般如果I2C总线上只有一片24C02芯片的话,A2、A1、A0引脚都接到地。

  由于24C02只有256个字节的存储空间,所以只需要1个字节就可以寻址完24C02的存储空间,但是无法寻址完更大容量的存储IC,比如24C04的存储容量是512字节,需要9个bit的地址位才能寻址完。由上图可以看到,24C04的设备地址内是没有A0参数的,被a8代替了,这个a8就是24C04的第9个bit的地址位,也就是说24C04的A0引脚是不起作用的,这样也就造成了在I2C总线上只能同时挂载4个24C04芯片。其它存储器如24C08、24C16也可以这么类推。

  24C02的WP引脚是写保护引脚,当WP引脚接高电平的时,24C02只能进行读取操作,不能进行写操作。只有当WP引脚悬空或接低电平时,24C02才能进行写操作。

3、24C02数据读取操作

  在这里只是对24C02的读写进行一些说明和一些注意的实现,不会涉及具体的程序代码,只是进行代码概述,工程代码已经上传到个人GitHub中,感兴趣的可以去GitHub中下载查看,GitHub代码地址如下:

https://github.com/h1019384803/STM32F103ZET6_I2C.git。这是一个使用STM32F103ZET6的IO模拟I2C操作24C02的工程。

  MCU通过使用I2C读取24C02任意存储空间地址内的数据,代码如下:  

 uint8_t AT24CXX_READ_ONE_BYTE(uint16_t address)
{
uint8_t dat; I2C_START();
AT24CXX_ERR = I2C_WRITE_BYTE(AT24CXX_WIRTE_CMD);
if(AT24CXX_ERR != )//没有响应直接退出
{
AT24CXX_ERR = I2C_WRITE_BYTE(address & 0xFF);
if(AT24CXX_ERR != )
{
I2C_START(); AT24CXX_ERR = I2C_WRITE_BYTE(AT24CXX_READ_CMD);
if(AT24CXX_ERR != )
{
dat = I2C_READ_BYTE();
I2C_STOP();
}
}
} return dat;
}

  第5行主机产生一个I2C起始信号,第6行发送设备地址和写数据位给24C02,第9行是发送需要读取的地址给24C02,第12行主机产生一个重复起始信号,第14行设备地址和读数据位给24C02,第17行是读取24C02相应地址存储的数据。第18行是主机产生I2C结束信号。

  在上面的程序代码中,AT24CXX_ERR是用来获取24C02的应答信号,如果主机与24C02的通讯正常,主机每发送一个字节给24C02,24C02都会反馈一个应答信号给主机,如果24C02没有反馈应答信号,那么说明24C02正在进行其它操作或者通讯异常导致无法通讯,主机会产生一个结束信号来结束操作。在I2C_WRITE_BYTE()函数内部有一个等待应答信号的操作,如果没有收到应答信号,在I2C_WRITE_BYTE()函数内会产生一个停止信号来结束当前操作。AT24CXX_ERR用来判断接下来的操作是否执行,如果AT24CXX_ERR=0说明没有收到应答信号,直接退本次读取操作;如果AT24CXX_ERR!=0说明有收到应答信号,继续读取操作。

  24C02内部有一个地址计数器,主机发送要读写的存储空间地址给24C02,就相当于改变24C02的内部地址计数器的值,主机每读写一个字节24C02之后,它内部地址计数器的值就会自动加1。也就是说如果当前地址是N,那么主机读取完一个字节的数据之后,再次读的话就变为了读取N+1地址的数据。

  这里需要注意的一点是,24C02的内部地址计数器的地址只能从0~255之间递增,这是因为24C02的存储控制只有256个字节,地址计数器只能在0~255(共256个地址)内变化。如果连续读取使得地址计数器超过255,那么地址计数器就会从0地址开始循环。比如说当前内部计数器地址为255,主机在读取一个字节数据之后会导致内部计数器地址变为0,那么主机再次读取数据的时候读取得到的是24C02地址0的数据。

  MCU使用I2C连续读取24C02内多个存储空间地址数数的代码如下:

 void AT24CXX_READ_BUFF(uint16_t address,uint8_t *buffer,uint16_t Len)
{
uint16_t i; I2C_START();
AT24CXX_ERR = I2C_WRITE_BYTE(AT24CXX_WIRTE_CMD);
if(AT24CXX_ERR != )//没有响应直接退出
{
AT24CXX_ERR = I2C_WRITE_BYTE(address & 0xFF);
if(AT24CXX_ERR != )
{
I2C_START();
AT24CXX_ERR = I2C_WRITE_BYTE(AT24CXX_READ_CMD);
if(AT24CXX_ERR != )
{
for(i=;i<Len;i++)
{
buffer[i] = I2C_READ_BYTE();
}
} if(AT24CXX_ERR != )
{
I2C_STOP();
}
}
}
}

  上面的代码,大部分跟读取一个字节的程序代码是一样的,不一样的是第16~19行,这里用一个for循环来连续读取24C02内的数据,这里并没有对超范围读取数据进行限制,所以在使用的时候需要注意不要连续读取超过24C02的存储空间,就算超过也不会有问题,只是会重新开始从0地址读取。

4、24C02数据写入操作

  MCU使用I2C写入一个字节数据到24C02任意存储空间地址内的代码如下:

 void AT24CXX_WRITE_ONE_BYTE(uint16_t address,uint8_t dat)
{
I2C_START();
AT24CXX_ERR = I2C_WRITE_BYTE(AT24CXX_WIRTE_CMD);
if(AT24CXX_ERR != )//没有响应直接退出
{
AT24CXX_ERR = I2C_WRITE_BYTE(address & 0xFF);
if(AT24CXX_ERR != )
{
AT24CXX_ERR = I2C_WRITE_BYTE(dat);
if(AT24CXX_ERR != )
{
I2C_STOP();
}
}
}
}

  第3行主机产生一个I2C起始信号,第4行发送设备地址和写数据位给24C02,第7行是发送需要写入数据的地址给24C02,第10行是将要写入的数据发送给24C02。第18行是主机产生I2C结束信号。上面大部分操作跟读取是一样的,不一样的只是最后将读取操作改为了写入操作。

  如果需要连续写入数据,可以如下:

     for(i = ;i < ;i ++)
{
AT24C02_BUFF[i] = i;
AT24CXX_WRITE_ONE_BYTE(i,AT24C02_BUFF[i]);
}

  但是在实际使用的过程中,发现只有一部分AT24C02_BUFF[]数组里面的数据被写入到了24C02当中,有一些数据没有写进24C02。这是因为24C02擦写数据没有那么快,需要一定的时间,在24C02正在擦写数据的过程中,是不会应答主机的通讯的,所以如果主机在写入一个数据之后又立马写入另一个数据,就会导致24C02跟不上主机的通讯速度从而导致无法写入数据。

  需要注意的是24C02并不是在主机发送数据给24C02之后就立马擦写数据的,24C02是在主机产停止信号之后才开始擦写数据的,并且在擦写数据完成之前不会响应主机的其它操作。

  可以通过一定的延时函数来等待24C02擦写完成,代码如下:

    for(i = ;i < ;i ++)
{
AT24C02_BUFF[i] = i;
AT24CXX_WRITE_ONE_BYTE(i,AT24C02_BUFF[i]);
HAL_Delay();
}

  通过调用HAL_Delay()函数进行延时,具体的延时时间可以通过调试来决定,这里使用1ms的延时时间,具体24C02擦写数据需要多久并不清楚。

  除了通过延时函数进行等待24C02擦写完成,也可以通过发送设备地址给24C02,然后查询是否有应答信号返回来判断24C02是否擦写完成。24C02在擦写数据时是不会反馈应答信号给主机的,这样就可以通过不断的发送数据给24C02,然后查询应答信号来判断24C02是否擦写完成,一旦擦写完成就可以进行下一个数据的写入。代码如下:

 void Wait_AT24CXX_WRITE_OK(void)
{
uint8_t Wait_Cnt; Wait_Cnt = ;
do
{
I2C_START();
AT24CXX_ERR = I2C_WRITE_BYTE(AT24CXX_WIRTE_CMD);
if(AT24CXX_ERR != )
{
I2C_STOP();//接收到响应信号退出
break;
} }while(Wait_Cnt--); }

  Wait_Cnt是一个次数限制变量,不能无限的在里面等待,不然遇到异常就有可能造成程序卡死。

  程序通过发送起始信号、发送设备地址和写数据方向给24C02,如果24C02反馈了一个应答信号给主机,主机就产生一个停止信号,然后退出当前循环。应用代码如下:

     for(i = ;i < ;i ++)
{
AT24C02_BUFF[i] = i;
AT24CXX_WRITE_ONE_BYTE(i,AT24C02_BUFF[i]);
Wait_AT24CXX_WRITE_OK();//可以通过发送设备地址给从机,通过从机反馈的响应信号来判断从机是否可以正常通讯
}

5、24C02页写入

  24C02有一个页写入功能,可以连续写入16个字节的数据。

  24C02可以以页来划分存储空间,每16个字节组成一个页,24C02的存储空间大小为256个字节,所以24C02总共有16个页。如:

  页0:地址从0x00~0x0F

  页1:地址从0x10~0x1F

  ......

  页15:地址从0xF0~0xFF  

  24C02可以在一个页内连续的写入数据,但是需要注意的是如果写入的数据超过页大小,那么就会覆盖页初始地址的值,比如说连续写入3个数据,第1个数据写入到地址0x0F当中,第2个数据由于溢出页的限制,会被写入到地址0x00当中,第3个数据会被写入到地址0x01当中。

  以个人的理解,24C02内部有一个16byte的数据缓存器,在上面的介绍中知道,主机在发送数据给24C02的时候,24C02是不会擦写数据的,只有当主机发送停止信号之后24C02才会擦写数据。那么当主机发送数据给24C02时,只是将数据写入到了24C02内部的缓存器中,只有当主机发送结束信号之后,24C02才将缓存器内的数据写入到内部存储空间。

  由24C02的数据缓存器只有16个byte(每个型号的存储IC的页大小是不一样的也就是缓存器大小是不不一样的)。所以如果写入的数据超过缓存器的大小就会覆盖之前写入的数据。

  使用页写入连续将数据写入24C02的代码如下:  

 void AT24CXX_WRITE_BUFF(uint16_t address,uint8_t *Buffer,uint16_t Len)
{
uint8_t i;
uint16_t re_main; if(address >= )//对输入的地址进行限制,24C02只有256个字节的存储空间,其它型号的存储器IC可以通过查资料
{
return;
} re_main = - address;//计算出还有多少存储空间 if(Len > re_main)//如果要写入的数据量超过剩余存储空间,则只写入剩余存储空间数量的数据
{
Len = re_main;
} re_main = - address%;//计算当前页还可以写入多少个数据 if(Len <= re_main)//如果要写入的数据小于等于当前页剩余的存储空间,则只写入Len个字节数据就好,不需要跨页操作
{
re_main = Len;
} do
{
I2C_START();
AT24CXX_ERR = I2C_WRITE_BYTE(AT24CXX_WIRTE_CMD);
if(AT24CXX_ERR == )//没有响应直接退出
{
break;
} I2C_WRITE_BYTE(address & 0xFF);
for(i = ;i < re_main;i ++)//最多连续写入一个页数据的大小
{
AT24CXX_ERR = I2C_WRITE_BYTE(Buffer[i]);
} I2C_STOP();
Wait_AT24CXX_WRITE_OK();//等待24C02完成擦写数据动作 if(re_main != Len)
{
address += re_main;//已经写入re_main个数据,
Buffer += re_main;
Len -= re_main; re_main = ;//写一个页的的大小也是16个字节 if(Len <= re_main)
{
re_main = Len;
}
}
else
{
break;//数据写入完成退出
}
}
while();
}

  AT24CXX_WRITE_BUFF()函数的思路如下:

  首先判断输入的地址是否超过存储IC的存储空间,如果超过则退出,如第6~9行。

  计算出输入的地址到存储器存储的结束地址剩余多少空间,如果要写入的数据比剩余空间还多,那么剩余多少空间就写入多少空间,需要写入的多余部分就去掉,如第11~16行。

  计算当前页还可以写入多少数据,如果当前页剩余的空间比Len要写入的数据长度还大,那么只要写入当前页就足够了,不需要再跨页写入数据。如第18~23行。

  通过一个while(1)循环连续写入数据到24C02中。

  第27~41行是将re_main个数据写入到24C02当中,由于是在一个页内操作,所以可以连续写入,写完之后在产生一个结束信号然后等待24C02擦写完成。

  如果不需要跨页写入就已经将数据全部写完,那么就可以直接break退出while循环,如第58行。

  如果需要跨页写入数据,还需要将地址、buffer、Len减去已经写入的数据量,然后下一个页可以写入整个页的数据量,也就是16个字节,通过比较判断一个页的剩余空间是否能够写完剩余的Len数据,如果不行就重复循环操作,如果可以写完,在写完之后就退出while循环。

EEPROM存储芯片24C02的更多相关文章

  1. 4.9版本的linux内核中eeprom存储芯片at24c512的驱动源码在哪里

    答:drivers/misc/eeprom/at24.c,内核配置项为CONFIG_EEPROM_AT24 Location: -> Device Drivers -> Misc devi ...

  2. 玩转X-CTR100 l STM32F4 l AT24C02 EEPROM存储

    我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ]      本文介绍X-CTR100控制器 板载EEP ...

  3. EEPROM的存储大小

    学习单片机时,常见的EEPROM如24C02的大小为2Kbit(有的也称2KB).这里的2KB到底能存储多少数据呢? 2KB中,B表示单位bit,K表示1024. 单片机编程中常用的数据类型为unsi ...

  4. EEPROM原理详解

    EEPROM(Electrically Erasable Programmable read only memory)即电可擦可编程只读存储器,是一种掉电后数据不丢失(不挥发)存储芯片. EERPOM ...

  5. EEPROM工作原理透彻详解

    原文链接点击这里 EEPROM(Electrically Erasable Programmable read only memory)即电可擦可编程只读存储器,是一种掉电后数据不丢失(不挥发)存储芯 ...

  6. STC8H开发(十二): I2C驱动AT24C08,AT24C32系列EEPROM存储

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  7. U盘详解

    摘要:U盘,称呼最早来源于朗科公司生产的一种新型存储设备,名曰“优盘”,使用USB接口进行连接.USB接口就连到电脑的主机后,U盘的资料可与电脑交换.而之后生产的类似技术的设备由于朗科已进行专利注册, ...

  8. 设备树..ing

    .dts==>.dtb ==>device_node ==>  platform_device ==> led_dev.c  ==>匹配 led_drv.c    (设备 ...

  9. 玩转 RTC时钟库 DS3231

    1.前言     接着博主的上一篇 玩转 RTC时钟库 + DS1302,这一篇我们重点讲解DS3231时钟模块.没有看过上一篇的同学,麻烦先去阅读一下,因为很多理论基础已经在上一篇做了详细讲解,这里 ...

随机推荐

  1. vue 项目总结,以及对未来的理解,对性能方面的认知

    之前自己写了一个vue项目,因为没有经验,所以很多方面的提升做的不好,比如说路由.比如说ajax都没有封装,比如说业务逻辑和通用逻辑都混合在一起,导致大片大片重复的代码累积.忽悠忽悠没入门的前端感觉还 ...

  2. node代理遇到的坑记

    在进行前端mock地址代理时候,进行了webpack的node反向代理: 实际mock地址是:http://10.118.183.10/mock/hb/startwork/openredpacket ...

  3. sf-git机制

    为什么要专门写一篇关于sf科技公司的GIT管理机制呢?因为本周经历了两天的学习和考试,刚开始没在意,因为之前公司也用的GIT,所以没怎么看视频,就看了文档,练习考试时候才发现并非以前的那种git流程, ...

  4. SpringBoot2 整合ElasticJob框架,定制化管理流程

    本文源码:GitHub·点这里 || GitEE·点这里 一.ElasticJob简介 1.定时任务 在前面的文章中,说过QuartJob这个定时任务,被广泛应用的定时任务标准.但Quartz核心点在 ...

  5. abp(net core)+easyui+efcore实现仓储管理系统——入库管理之四(四十)

    abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...

  6. Python - 常用内置变量

    直接上代码 #!/usr/bin/env python # -*- coding: utf-8 -*- """ 这是注释__doc__会打印这部分内容 "&qu ...

  7. 创建和存储 cookie

    在这个例子中我们要创建一个存储访问者名字的 cookie.当访问者首次访问网站时,他们会被要求填写姓名.名字会存储于 cookie 中.当访问者再次访问网站时,他们就会收到欢迎词. 首先,我们会创建一 ...

  8. H5新特性之语义化标签

    一.为什么要增加新的语义化标签 在HTML 5出来之前,我们用div来表示章节,但是这些div都没有实际意义,这样的布局方式使我们的结构不够清晰,于是语义化标签应运而生. 二.何为语义化标签 顾名思义 ...

  9. oracle中plsql练习题-----编写一个PL/SQL块,输出所有员工的员工姓名、员工号、工资和部门号

    一.思路:首先输出需要变量接收,需要声明变量,于是考虑什么变量类型比较合适,在这我用的是table类型,最后,查询出来,循环输出即可. 二.具体实现 -- 编写一个PL/SQL块,输出所有员工的员工姓 ...

  10. jvm 性能调优工具之 jstat 命令详解

    Jstat名称:Java Virtual Machine statistics monitoring tool 官方文档:https://docs.oracle.com/javase/1.5.0/do ...