目录
有关储存器的介绍
存储器的简介

RAM:随机储存,断电丢失数据,存储比较快。
SRAM:是最快的,内部是锁存器,D触发器,用电路来储存数据,一般用于电脑的CPU高速缓存。
DRAM:利用电容的充放电以达到储存数据的目的,充电就是高电平,放完电之后就是低电平,因为电容存在漏电现象,要配一个扫描电路,每隔一段时间就补电,电脑中的内存条和手机里的运行内存是动态RAM。
ROM:只读储存,断电不丢失数据,存储比较慢
Mask ROM:不能写入,只能读取
PROM:升级版Mask ROM,只能写入一次
EPROM:三十分钟紫外线照射可擦除
E2PROM:5V低压电即可擦除
以上四个ROM可以说是一个家族的。
Flash:目前应用最广
硬盘:C盘......(应用磁相关的原理存储)
软盘:以前的A盘和B盘(现在我们电脑上基本没有应用软盘了,所以从C盘开始)
光盘:应用光信号存储数据
存储器简化模型

我们的存储器在内部实际上都是像一种网格的结构。
横向的线称为地址总线,用来选中哪一根线就是我们的哪一个地址;
纵向的线称为数据总线,数据是从下面出来的。
那数据是怎么存的呢?
比如说我们选中了第一行的地址总线,我们给它加上一个高电平1,其他的暂时都不接。然后,先说一下这些网格的交错处是不连接的,我们现在把交错的第一个节点、第二和第三个节点给连上,其他的都不连。那我们现在读取一下下面这八位数据,是怎样的呢?
我们连上了那三个节点后,数据就可以顺着前三根数据总线下来了,它们下来是1,第一行的其他交错节点都没连,所以数据不能下来,因此把它当做0。
这样我们第一行存的数据下来就是11100000,其他种情况同理,这样就可以存储不同的数据。

这就是存储器存储数据的最基本的原理。
我们就知道了如何在这里储存,就是控制我们的节点短路和断路这一个过程。
Mask ROM的内部交错处结构是这样的

如果我们想要存储断开,就是什么都不接,它存的就是0
如果我们想要把它短路,为了它们不相互干扰,就可以接一个二极管(二极管是单向的)。当高电平过来的时候,就可以通过,但是想要从其他地方串过来就不行了。
厂家做Mask ROM的时候,如果你告诉它需要存储某个数据,他们就会连上哪一个节点,这个电路一旦完成,就相当于焊死了,所以不能再改了,所以早期的ROM只能读,不能写。
之后出现了一种PROM,它是升级版的Mask ROM,只能写入一次。
它的内部交错处结构是这样的(把每一个节点都做成这种形状)

两根二极管头对头,即使它过来也通不过去,即使通过了第一个,它也通不过第二个,相当于一种断路。

但是这个蓝色的二极管有个特点就是容易被击穿。二极管有个特性就是它反向是截止的,但是当反向电压超过一定数值之后,它就会被击穿,击穿之后它变成短路了,这就是由断路变成短路的变成状态。
所以如果在这种结构的左边接一个高电压的时候,比如说12V,或者24V等等,然后右边下面我们接一个0V(接GND),这时那个标为蓝色的二极管两端就承受了24V的高电压,所以它就被击穿了。

揭穿之后就相当于变成这种结构(相当于短路)

因此我们可以一次选中,相应击穿就得到我们想要的数据。二极管一旦被击穿之后(烧毁),不能恢复,所以是一次性的,所以只能写入一次。
所以我们平时说下载程序,也可以说是"烧录程序",因为早期的确是烧录,就是把里面的二极管烧毁。
早期的单片机有一个控制引脚,它在编程的时候需要加一个高电压(编程电压),就是用来击毁里面的这个二极管。
这种情况(击穿相当于短路,不击穿相当于断路)和保险丝比较像,如果我们在这里都接上保险丝的话,它就有一个特点,就是它没有被烧断的时候是短路,但是如果加上大电流,这个保险丝就被烧断了,烧断的时候就是断路,这样也能控制我们的编程。
因此PROM有一种是二极管击穿型,一种是保险丝型。
可以说之后发展出来的可重复多次写入的ROM就是利用一种可以让断路变成短路(起死回生)的材料或者原理方法实现了可逆性击毁,比如可擦除的ROM。
因为在地址总线一次只能选中一行,所以我们一般都会加一个译码器(138译码器),它可以把多位数据(地址)变成输入端只有一位被选中的输出端(串行输入,并行输出)。

总而言之,在译码器之前就是输出我们实际的地址,下面就输出数据。
接下来是本节的主角!
AT24C02介绍
AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息
存储介质:E2PROM(电可擦除可编程ROM )
通讯接口:I2C总线
容量:256字节

AT24C02引脚及应用电路

只要接这个范围内的电压就可以工作1.8V-5.5V。
接WP的这个7号引脚直接接了GND,所以这个芯片没有用到写保护功能,如果需要这个功能的话,可以将这个引脚接在IO口或者开关上。
A0,A1,A2是可以选择的接都到VCC或者接到GND,这里全部接到GND,代表这三个都是0。
SCL和SDA引出去分别接了一个4.7K的上拉电阻。
我们开发板的EEPROM模块的原理图:

VSS=GND,VDD=VCC,E0=A0,E1=A1,E2=A2,WE=写使能(低电平使能,高电平保护),这里SCL和SDA没有接上拉电阻因为我们单片机的每个IO口都已经接了一个上拉电阻。

这一部分是I2C协议规范所需要的

我们看一下EEPROM模块的内部框图

这一块都是和I2C接口协议有关的东西

我们现在讲的是下面标蓝色的这一块

然后这部分是用来数据擦除的部分:

这个是地址寄存器

具体里面的电路是怎么工作的就不具体介绍了,我们主要大概了解到这里是把I2C数据拿进来,通过一些逻辑执行操作就可以了。

本节的重难点来了
I2C总线介绍
I2C总线(Inter IC BUS)是由Philips公司开发的一种通用数据总线
两根通信线:SCL(Serial Clock)、SDA(Serial Data)
同步(因为有同步的时钟线SCL)、半双工(双向分时,因为SDA只有一根线,而且哟啊负责来回通信,所以只能分时地复用一根线),带数据应答 (在发送一个字节数据之后,要求对方接收到数据之后给它一个应答,判断是否发送成功,所以 I2C总线的检测应答的功能还是比较完备的,而我们之前学习的串口就没有,串口发出数据后没有检测应答,弊端就是不知道对方在不在线)
通用的I2C总线,可以使各种设备的通信标准统一,对于厂家来说,使用成熟的方案可以缩短芯片设计周期、提高稳定性,对于应用者来说,使用通用的通信协议可以避免学习各种各样的自定义协议,降低了学习和应用的难度

上图是常用的I2C设备
所有I2C设备的SCL连在一起,SDA连在一起
设备的SCL和SDA均要配置成开漏输出模式
SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右
开漏输出和上拉电阻的共同作用实现了"线与"的功能,此设计主要是为了解决多机通信互相干扰的问题
I2C电路规范
所有I2C设备的SCL连在一起,SDA连在一起(不像我们前几节学的串口UART通信的TXD和RXT要交叉连接)
开漏输出模式和弱上拉模式
设备的SCL和SDA均要配置成开漏输出模式 (单片机的IO口是弱上拉模式)


开漏输出模式是因为高电平驱动能力弱,相当于断开。
SCL和SDA各添加一个上拉电阻****(当有空闲设备不通信时,可能会影响到正在通信的设备,所以需要加上拉电阻,使其空闲设备处于一个高阻态(不是高电平也不是低电平)的情况下,这样空闲设备就会断路)****,阻值一般为4.7KΩ左右
开漏输出和上拉电阻的共同作用实现了****"线与"**** (有一个低电平就是低电平0) 的功能,此设计主要是为了解决多机通信互相干扰的问题

我们知道如果CPU想要和其中一个设备通信的话,那么最好的状态就是其他的设备不要影响它,则其他设备相当于断开。CPU跟其中一个设备通信的时候,其他引脚全部输出1,相当于断开,这样就不会干扰到CPU和它的通信了。因此用开漏模式就可以解决多机通信互相干扰的问题。

如果所有设备用弱上拉模式的话,即使开关断开输出1,还是有一个上拉电阻碍事,虽然也不会有太大影响,但是总归不太好。如果接多了上拉电阻,电阻并联,上拉能力肯定越来越强,会干扰通信。所以所有设备都开漏,那数字1就发送不出去。

所以我们在外面接两个电阻,当所有设备都断开的时候,这两个电阻充当上拉能力。CPU想发0的时候,就把输出口拉到低电平。想发1的时候,就松手不拉了,输出口就会被外部的电阻自动拉到高电平。当其他设备没有进行通信的时候,直接输出1,对我们的电路没有干扰(没有干扰是因为内部没有向外部输出,输出的1是外部上拉提供的,这里上拉电阻是将总线的拉成高电平,当连接在总线上的任意一个设备输出低电平时,总线被拉低就是输出了低电平。)
其中一个设备的内部结构
这幅图是其中一个设备的内部结构

下面这个东西是一个输入的缓存,可以把它想象成一个电压表

它可以检测这个点的电压进行操作,

它的输入阻抗是很大的,所以这个一点就相当于是断开

这个东西就相当于一个电子开关:给低电平相当于它导通,如果给高电平相当于它断开

如果给高电平这个电子开关断开,而旁边这条线路也是断开的,所以这这根引脚就是断开的,就可以不干扰外界。

I2C通信是怎么实现的
下面举一个小例子能够更明白I2C通信是怎么实现的:
比如现在有个弹簧控制着一根杆子的升降,杆子上面左右两边都有一根标尺。在A和B两个人眼前,他们两个人可以通过标尺的升降来判断对方发给自己的数据是1还是0,如果两人是松手的状态,标尺就不动,说明发给对方的数据是1,如果其中一人伸手拉下了杆子,那么标尺就会下降,对方就知道发送过来的数据是0,如果松手,标尺上升则代表发送过来的数据是1。
I2C的标准可以想象成如果再A和B之间再多站几个人的话,这几个人都会被标成一个地址,如果主机想要和他们其中一个通信,那么只需要通过时序去发送地址就找到从机。比如说一开始主机摇摇杆子,所有人看到杆子被摇了,说明有人想要开始了,然后主机开始发1/0的数据(通过松手拉下来松手拉下来)就把地址发送出去,其他人看这个地址跟自己一样,就知道主机在找他,就会默认跟主机构建联系,其他人发现地址和自己的不一样,就什么不管,不会去干扰通信。主机就和地址一样的那个人开始通信(双方拉杆子交流)。

接下来就开始正式介绍I2C时序结构:
I2C时序结构
起始条件和终止条件
起始条件:SCL高电平期间,SDA从高电平切换到低电平(主机开始摇杆子)
终止条件:SCL高电平期间,SDA从低电平切换到高电平

发送一个字节
SCL低电平期间,主机将数据位依次放到SDA线上(高位在前),然后拉高SCL,从机 将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节

注意:SCL高电平期间读取数据位时:

PS:我们的单片机是主机,24C02是从机。主机和从机的程序是不一样的,我们只写主机,从机是主动检测的,从机读取数据的时候是程序自动完成的,我们只需要把主机的时序模拟出来就好了。

接收一个字节
SCL低电平期间,从机将数据位依次放到SDA线上(高位在前),然后拉高SCL,主机 将在SCL高电平期间读取 数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA ****,****将SDA置1就相当于释放,释放的时候主机是完全不干扰这个通信线的。换言之就是主机释放掉数据线之后,把对线的控制权交给从机,从机就把它拉下来/松手。如果主机是在拉下来的状态把控制权交给从机的话,那从机不论发啥都是0)

上图SDA紫色部分就是从机控制总线的时候
发送应答和接收应答
发送应答:在接收完一个字节之后,主机在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答
接收应答:在发送完一个字节之后,主机在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)

主机接收完一个字节后再发送给从机一位数据(1/0),告知从机是否应答


主机发送完一个字节后再接收从机发过来的一位数据(1/0),这位数据表示从机是否应答


I2C数据帧
(基本上所有的传感器的数据帧结构都遵循这三种格式)
发送一帧数据

解析图:

完成任务:向谁发什么(由从机地址的前7位决定发给谁,发还是写由地址的读写位决定,发什么由发送字节数据那一部分决定)
接收一帧数据

解析图:

完成任务:向谁收什么
先发送再接收数据帧(复合格式)

完成任务:向谁收指定的什么
用一个大白话来翻译一下这种复合格式就是:
老师(主机):现在开始听题环节。
老师(主机):小明你来听题。
小明(从机):收到。
老师(主机):第一题......
小明(从机):收到。
老师(主机):第二题......
小明(从机):收到。
......
老师(主机):第N题......
小明(从机):收到。
老师(主机):现在开始答题环节。
老师(主机):小明你来答题。
小明(从机):收到,第一题答案是.....
此时老师(主机)接收小明的答案。
老师(主机):收到。
小明(从机):第二题答案是.....
此时老师(主机)接收小明的答案。
老师(主机):收到。
......
小明(从机):第N题答案是.....
此时老师(主机)接收小明的答案。
老师(主机):收到/(不应答)。
老师(主机):本次的问答环节结束。
几乎所有的I2C都遵循以上这三种数据帧格式
我们看一下I2C如何去适配这些结构的呢?
字节写:在WORD ADDRESS(字地址)处写入数据DATA

随机读:读出在WORD ADDRESS处的数据DATA(这其实是一种复合格式)

AT24C02的固定地址为1010 ,可配置地址本开发板上为000
所以SLAVE ADDRESS+W为0xA0,SLAVE ADDRESS+R为0xA1
补充一下手册上的数据帧的解析图:
字节写:在"字地址"处写入"数据"

根据我们前面说的时序,可以划分成这样:其实和我们前面看到的是一样的。

随机读:读出在"字地址"处的"数据"


下节开始演示代码!