STM32 IIC实验中关于AT24Cxx的读写

在正点原子的STM32IIC实验例程中,从AT24Cxx芯片中某一位读取一个数据的操作如下:
u8 AT24CXX_ReadOneByte(u16 ReadAddr)
{
u8 temp=0;
IIC_Start();
if(EE_TYPE>AT24C16)
{
IIC_Send_Byte(0XA0);
IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr>>8);
}else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));
IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr%256);
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(0XA1);
IIC_Wait_Ack();
temp=IIC_Read_Byte(0);
IIC_Stop();
return temp;
}

其中难以理解的部分是:
if(EE_TYPE>AT24C16)
{
IIC_Send_Byte(0XA0);
IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr>>8);
}else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));
IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr%256);
IIC_Wait_Ack();
要理解这段程序需要结合AT24Cxx芯片的硬件结构。下面是百度文库中这种芯片的中文版参考手册地址。
https://wenku.baidu.com/view/05030b2fd15abe23492f4d7e.html
要对AT24Cxx芯片的某一位进行读写,首先要发送这一位的地址。对于不同容量型号AT24Cxx芯片的地址数据组成,下面这篇博客讲解的比较详细。
https://www.cnblogs.com/leo0621/p/8251897.html
从这篇文章中可以看出,对于型号为AT24C01~AT24C16的芯片,确定芯片中存储地址需要两个字节的地址信息,分别是一个字节(8位)的设备地址信息,和一个字节(8位)的数据地址信息。在设备地址信息中,高四位是固定的,为1010,最低位是用来表示是读还是写,第2,3,4位即A0,A1,A2是设备选用地址。
对AT24C01/02,A0,A1,A2作为片选位,从硬件上保证是拉高还是拉低,表示选择某一个2K芯片,由于三位用于选择,因此,最多可以配置8个2K芯片。
对AT24C04,A1,A2作为片选位,从硬件上保证拉高还是拉低,表示选择某一个4K芯片,由于两位用于选择,因此,最多可以配置4个4K芯片。而硬件上的A0位悬空,在编程时设备地址位的第二位作为页寻址位P0位。(关于页寻址的问题参考上两个资料,里面都有提到相关知识)
对AT24C08,A2位作为片选位,从硬件上保证拉高还是拉低,表示选择某一个8K芯片,由于一位用于选择,因此,最多可以配置2个8K芯片。而硬件上的A0,A1位悬空,在编程时设备地址位的第二位和第三位分别作为页寻址位P0位和P1位。
对AT24C16,无片选位,意味着只能配置1个16K芯片,硬件上A0,A1,A2全部悬空,编程时设备地址位的第二,三,四位分别作为页寻址位P0,P1和P2位。

需要注意的是,上面说的芯片的存储容量单位是bit,换成字节(byte)的话AT2402是256字节,AT24C04是512字节,依次类推。寻址的时候,是按照字节来寻址的,每个字节有一个地址。在操作的时候也是对每个字节进行操作。

用两个字节-设备地址和数据地址进行寻址,至多只能寻址211个地址,因为一共16位,设备地址的高四位始终不变,而设备地址的最低位用于表示读还是写操作,因此可用的只有11位,故而最多寻址211,也就是2K个字节,16K的bit。因此这种寻址方法,不管对哪种容量的芯片,最多的容量也即是16k,对AT24C02,最多8片,2x8=16k,对AT24C04,最多4片,4x4=16k,依次类推。
STM32 IIC实验中关于AT24Cxx的读写_第1张图片而要配置更大的容量,则需要增加一位数据位。这个时候设备地址只起到了标志读还是写的作用,第2,3,4位置为0。在读或者写数据的时候,首先发送设备地址位0XA0(写)或者是0XA1(读)。接着发送数据地址高八位,然后发送数据地址低八位。这种方法做多寻址216,即219bits,也就是512k。
当大于512k时,将设备地址的一位作为页寻址,在前面提到的博客中有详细讲解,这里就不赘述了。

有了上面的知识之后,我们再来看这段代码,首先看这个if的判断条件:
if(EE_TYPE>AT24C16)
这是用来判断要进行读写的芯片的容量,因为容量决定了设备地址和数据地址的分配方法。如果容量大于16K,则设备地址只起到了一个标志读写操作的作用,有两位数据地址表示要读写的字节的地址。故而首先发送0XA0,然后发送要写入的地址的高八位。这里是通过将16位地址数据右移8位实现的这个操作。即如下代码:
IIC_Send_Byte(0XA0);
IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr>>8);
在后面再将低八位,也即是ReadAddr%256发送给芯片在,这就完成了对要读取的字节的位置的寻址。
而当芯片的容量小于16k的时候,设备地址中可能用于页寻址的位。来分析这一句:
IIC_Send_Byte(0XA0+((ReadAddr/256)<<1))
假如是AT24C02,则设备地址中无页寻址的位,则ReadAddr的高八位均为0,则((ReadAddr/256)<<1)也为0,因此最后就是发送0XA0。
假如是AT24C04,则设备地址中有一位页寻址的位,假如是1,则(ReadAddr/256)为0X01,再左移一位为0x02,则最终发送的位0XA2。正好对应P0位为1。依次类推。
其实ReadAddr/256,也就是ReadAddr的高八位(但是高8位的第4位到第8位一定为0)即为设备地址的第2,3,4位的值,因此,将ReadAddr/256然后再左移一位加到0XA0中,对应的就是目标字节的设备地址。ReadAddr的低八位就是数据目标字节的数据地址。这样就能理解这段代码的含义了。

还有一个问题是,为什么是从AT24Cxx中读取数据,却最先发送0XA0,这是写数据的信号。之后才再启动一次IIC通信,然后再发送读取信号。直接发送0XA1和地址进行读取不行吗?
这个问题就要涉及到读写操作的时序问题了。其实在读取的时候最先的一个0XA0是伪写操作,这个伪写操作是为了修改存储器内部的工作指针。具体的可以看这篇博文中的随机写的内容。
https://www.cnblogs.com/dengxiaojun/p/4279446.html

菜鸡初学STM32,难免有很多的错误,请各位批评指正!

你可能感兴趣的:(STM32,STM32)