您现在的位置是:首页 >学无止境 >STM32 AT24CXX器件地址的理解(IIC通讯协议)网站首页学无止境
STM32 AT24CXX器件地址的理解(IIC通讯协议)
if (EE_TYPE > AT24C16) /* 24C16以上的型号, 分2个字节发送地址 */
{
iic_send_byte(0XA0); /* 发送写命令, IIC规定最低位是0, 表示写入 */
iic_wait_ack(); /* 每次发送完一个字节,都要等待ACK */
iic_send_byte(addr >> 8);/* 发送高字节地址 */
}
else
{
iic_send_byte(0XA0 + ((addr >> 8) << 1)); /* 发送器件 0XA0 + 高位a8/a9/a10地址,写数据 */
}
iic_wait_ack(); /* 每次发送完一个字节,都要等待ACK */
iic_send_byte(addr % 256); /* 发送低位地址 */
iic_wait_ack(); /* 等待ACK, 此时地址发送完成了 */
EETYPE为宏定义,具体如下
#define AT24C01 127
#define AT24C02 255
#define AT24C04 511
#define AT24C08 1023
#define AT24C16 2047
#define AT24C32 4095
#define AT24C64 8191
#define AT24C128 16383
#define AT24C256 32767/* 开发板使用的是24c02,所以定义EE_TYPE为AT24C02 */
#define EE_TYPE AT24C02
根据尼使用得AT24C型号得不同,给EE_TYPE初始化不同的值。先讨论C16以下的
* 对于24C01/02, 其器件地址格式(8bit)为: 1 0 1 0 A2 A1 A0 R/W
* 对于24C04, 其器件地址格式(8bit)为: 1 0 1 0 A2 A1 a8 R/W
* 对于24C08, 其器件地址格式(8bit)为: 1 0 1 0 A2 a9 a8 R/W
* 对于24C16, 其器件地址格式(8bit)为: 1 0 1 0 a10 a9 a8 R/W
R/W : 读/写控制位 0,表示写; 1,表示读;
A0/A1/A2 : 对应器件的1,2,3引脚(只有24C01/02/04/8有这些脚,16以上的芯片没设计这些脚)
a8/a9/a10: 对应存储地址的高位。
比如24C04 有512byte(32page16byte),地址本质都是0 1这种二进制(经常我们看到的地址表示形式是0x00000008这种,是32位机下,四个二进制转换成一个十六进制形成的),一位二进制(2的一次方)能代表两个地址块,2位二进制(2的平方)能代表四个地址块,512个地址块就需要2的九次方,所以每个地址需要9位来表示来能把这521byte覆盖完。在发送时,只能一个字节一个字节的发送,你要一口气发九个字节,从机会领悟不到的,所以可以先把高位的1位弄成00000001发送,再发最后的八位,加上1 0 1 0 A2 A1 A0 R/W,一共要发三次才能确定要读或者写的地址,麻烦!!
所以我们把多出来的1位(第九位,这个最高位)放到1 0 1 0 A2 A1 A0 R/W的A0位去传输,这样只用传输两次即可。如果多了两位就把多的放在A1,和A0位去传输。
以上方法最多11bit地址,最多可以表示2048个位置,可以寻址24C16及以内的型号
针对C32以后的,不够用了,所以干脆就大大方方的先发1 0 1 0 A2 A1 A0 R/W,再分两次发送地址
iic_send_byte(0XA0 + ((addr >> 8) << 1));
这句代码的理解:addr >> 8左移八位,把八位之后的东西留下来再左移一位后与0XA0相加,左移这一位相当于是给R/W腾了个位置,通过这句代码,把地址的高x位取出来了,然后随着1 0 1 0 A2 A1 A0 R/W发送出去。