通过I2C总线中写一个字节给从设备

2019-07-21 09:00发布

最近开始着手I2C总线,对于程序源码中的一些东西始终不能理解,个人理解,I2C总线作为I2C器件之间的通讯协议,在数据有效性的前提下,先有start()起始信号,然后发送一个从器件地址(AT24C02即为0XA0),然后ACK应答,再发送一个字节地址,再ACK应答,此时前奏已经准备完毕,再次发送的字节即为数据信息,每一个字节信息后都跟一次ACK应答,发送完毕后给一个STOP()停止信号,此为I2C通讯,但是对于字节地址,个人不是很理解,器件地址对于从器件是固定的,但是我以什么为依据来写字节地址 ?例如我现在要写一个字节的数据给AT24C02,那此字节地址应该是什么 ?还有源码中的一些代码也没看懂是什么意思

8888888.png
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
6条回答
DreamWaterPro
2019-07-21 10:56
首先说一下基础知识吧,当一个IIC总线中挂了多个器件时,需要用器件地址来指定要进行操作的器件;对于AT24CX系列芯片,由于你想存储或者读取若干个字节的数据,你就得需要告诉这个器件你想要操作的这个字节在什么位置,特殊地对于AT24C02,存储容量为256字节,其对应的字节地址就是0x00~0xff,每个地址对应着一个字节的存储空间。来看看我在数据手册上的截图:
TIM截图20180726083558.png
对于AT24C01,存储容量128字节,地址可以用0x00~0x7f来表示;对于AT24C02,存储容量为256字节,地址可以用0x00~0xff来表示;但是对于容量为512字节的AT2404来说,其地址用一个字节就表示不下了,范围为0x0000~0x01ff.但是根据IIC总线协议,一次性我们都是传8bit也就是一个字节,面对现在9bit的字节地址咋整呢?Atmel公司设计AT24CXX系列芯片的时候,为了使芯片的设备地址可以通过硬件设置,所以留了A0~A2三个引脚,他们对应在设备地址中占了低3bit(不考虑读写控制位):
TIM截图20180726083710.png
所以我们我们为什么不可以利用这3bit,表示字节地址中超过一字节的部分呢?也就是说,对于AT24C04这样的器件,将其认为是两个AT24C02的组合,通过器件地址中的最低位来指定是哪个虚拟的“AT24C02”在起作用。实际上ATMEL公司也是这样做的,它把这连续的512字节空间分为两个容量为256字节的页(Page,简写为P),通过设备地址中的最后一位(P0)来指定读写的页:
TIM截图20180726084032.png
同理,对于其他的1024字节、2048字节,所需要的地址分别是10位、11位,其中超过8位的地址部分就都用P0 P1 P2来表示了:
TIM截图20180726084157.png
目前为止我们解决了AT24C16及以下容量芯片的存储问题。那么对于AT24C32这种容量为4096字节,地址为12位的设备怎么办呢?我们的设备地址也没有空余的地方可以利用了,于是ATMEL公司就索性使用两个字节来表示字节地址:
TIM截图20180726084615.png
注意,现在我们如果想对一个字节进行操作,需要发送的内容为设备地址+字节地址高+字节地址低+数据,变成了四个 字节了!作为对比,我们看看AT24C16及更低容量芯片的写时序:
TIM截图20180726084831.png
实际上AT24C32和AT24C16的时序是一样的。对于容量更大的AT24C128和AT24C256,在设备地址上略有不同:
asdasda.png
图中红框圈出的部分一定要保持bit0。
好了,目前为止我们知道了从AT24C01~AT24C256这8款容量不同的ATMEL家的EEPROM,下面来解答楼主的问题。

问题一:为何要用AT24C02与AT24C16进行比较?
我们可以直观地发现,从AT24C16到AT24C32是一个转变——前者及容量更低的版本使用设备地址(含<=bit字节地址+读写控制位)+字节地址来读写器件上的某一个字节,后者及容量更大的版本则使用设备地址+字节地址高+字节地址低的方式来读写器件上的某一个字节,所以为了使得所写的读写函数能够在所有的ATMEL家EEPROM上都能够进行读写,使用了EE_TYPE来表示器件类型,并且对于不同器件使用不同的读写策略。

问题二:发送器件地址为什么要在0xa0后面加上((writeAddr/256)<<1)?
首先说一下这里的writeAddr,注意是u16型,可以表示最大为64KB的存储空间(当然实际上对于ATMEL家的芯片还用不到这么多),之所以用u16型而不是u8型其实就是为了能够表示超过256字节的地址,这对于目前ATMEL的EEPROM产品来讲是足够的。其次,我觉得这里的程序用到了一个假设,那么就是对于有A0 A1 A2引脚这样的可硬件设置的地址脚,全部接地,否则对于部分器件这个函数将不能够正确工作。第三,这里的writeAddr/256相当于取writeAddr的高8位,后面的writeAddr%256相当于取writeAddr的低8位。
0xa0其实是器件地址的固定部分。注意这个代码的出现的位置,如果执行了这段代码说明EE_TYPE<=AT24C16,也就是说所使用的器件为AT24C01~AT24C16。具体地,对于AT24C01 AT24C02来讲,它的writeAddr中的有效数据不会超过8bit,因此writeAddr/256为0,左移后+0+0xa0还是0xa0,读写位正好也为0(因为左移的时候右侧自动补0的缘故)。对于AT24C04~AT24C16来讲,writeAddr/256后取得的writeAddr高8位中有最多3bit的页地址(P0 P1 P2),这里再左移一位+0xa0就正好组成了他们的“设备地址”,同时左移的补0也正好使得读写控制位为0,表示进行写操作。

问题三:为什么又要对writeAddr%256?
这个操作是取writeAddr的低8位,其实这里就没有什么可以讲的了,高字节部分的地址要么是单独的一个字节发过去了(AT24C32及以上),要么是作为页地址合并在器件地址中发过去了(AT24C04~AT24C16),剩下就只有这个字节地址的低字节部分没有发了。

最后附上相关的数据手册。其实ATMEL公司设计的这个小玩意儿还是很有意思的。
01~16
AT24C16.pdf (444.98 KB, 下载次数: 71) 2018-7-26 09:11 上传 点击文件名下载附件
AT24C01~AT24C16

32,64
AT24C32.pdf (240.13 KB, 下载次数: 66) 2018-7-26 09:11 上传 点击文件名下载附件
AT24C32,AT24C64

128,256
AT24C256 datasheet.pdf (410.66 KB, 下载次数: 101) 2018-7-26 09:11 上传 点击文件名下载附件
AT24C128,AT24C256




一周热门 更多>