总括
SHT20可能代表主要需要读的设备,EEPROM可能代表需要读写的设备
EEPROM
一页的字节数
01为8个字节,02/04/08/16为16个字节,128/256为64字节
在操作AT24C256时发现EEPROM连续写入时不能跨页写(比如,第一页0~63,我先向63写入一个数据再向64写入一个数据,64没有得到想要的数据,该数据覆盖了第一页第一个地址的数据)
1 Myiic_Start(); 2 Myiic_SendByte(EEPROM_WRITEADDRESS); 3 Myiic_SlaveAck(); 4 5 Myiic_SendByte(63>>8); 6 Myiic_SlaveAck(); 7 8 Myiic_SendByte(63); 9 Myiic_SlaveAck(); 10 11 Myiic_SendByte (63); 12 Myiic_SlaveAck(); 13 Myiic_SendByte(64); 14 Myiic_SlaveAck(); 15 Myiic_Stop(); 16 Delay_ms(15); 17 OLED_Printf(0, 0, OLED_8X16, "%d",EEPROM_ReadByte(63)); 18 OLED_Printf(0, 16, OLED_8X16, "%d",EEPROM_ReadByte(64)); 19 OLED_Printf(0, 32, OLED_8X16, "%d",EEPROM_ReadByte(0));
清一下EEPROM做下个实验
当我将数据写入地址63后重新开启一次IIC时序将数据写入地址64,发现写成功了
1 EEPROM_WriteByte(63,63); 2 EEPROM_WriteByte(64,64); 3 OLED_Printf(0, 0, OLED_8X16, "%d",EEPROM_ReadByte(63)); 4 OLED_Printf(0, 32, OLED_8X16, "%d",EEPROM_ReadByte(64));
1 void EEPROM_WriteByte(uint16_t RegAddress, uint8_t Data) 2 { 3 Myiic_Start(); //iic起始 4 Myiic_SendByte(EEPROM_WRITEADDRESS); //发送从机地址,读写位为0,表示即将写入 5 Myiic_SlaveAck(); //接收应答 6 7 Myiic_SendByte(RegAddress>>8); //发送寄存器地址 8 Myiic_SlaveAck(); //接收应答 9 10 Myiic_SendByte(RegAddress); //发送寄存器地址 11 Myiic_SlaveAck(); //接收应答 12 13 Myiic_SendByte(Data); //发送要写入寄存器的数据 14 Myiic_SlaveAck(); //接收应答 15 16 Myiic_Stop(); //iic终止 17 Delay_ms(15); 18 }
总结一下EEPROM不能跨页写,多出本页的数据会从本页前面的地址开始覆盖,如果想要跨页必须重新开启IIC时序
不同型号的芯片可存储的字节数
(20)01--128个字节(20+7)
02--256个字节
04--512个字节
08--1024个字节
16--2048个字节
128--16384个字节
256--32768个字节(215)
寄存器地址
以256为例0~0x7FFF(正好是15位),这里和MPU6050比较一下
MPU6050也是写入寄存器(SHT20是写入指令),但是每个寄存器有它自己单独的地址
读写时序
01~16都是8位寄存器地址,而04~16地址(9~11位)显然超过了8位,超出的位写在从机地址里面(PX),也就是说仅可以通过AX来更改从机地址,因此01~02可以挂载8个从机,04可以挂载4个从机,08可以挂载2个从机,16可以挂载1个从机
1 FunctionalState I2C_WriteByte(uint8_t SendByte, uint16_t WriteAddress) 2 { 3 if(!I2C_Start())return DISABLE; /* 判断是否有起始信号*/ 4 5 I2C_SendByte((((WriteAddress&0x0700)>>7)|0xA0)&0xFFFE); /*从机地址加写入寄存器地址的高8位(16是0x0700,08是0x0300,04是0x0100)*/ 6 7 if(!I2C_WaitAck()){I2C_Stop(); return DISABLE;} /* 等待应答信号*/ 8 9 I2C_SendByte((uint8_t)(WriteAddress & 0x00FF)); /* 发送字地址(低8位数据) */ 10 11 I2C_WaitAck(); /* 等待应答 */ 12 13 I2C_SendByte(SendByte); /* 发送数据 */ 14 15 I2C_WaitAck(); /* 等待应答 */ 16 17 I2C_Stop(); /* 等待停止 */ 18 19 return ENABLE; 20 }
而128和256都是16位地址,因此IIC时序时先写入高位地址,应答,再写入低位地址,应答
1 uint8_t EEPROM_ReadByte(uint16_t RegAddress) 2 { 3 uint8_t Data; 4 5 Myiic_Start(); //iic起始 6 Myiic_SendByte(EEPROM_WRITEADDRESS); //发送从机地址,读写位为0,表示即将写入 7 Myiic_SlaveAck(); //接收应答 8 9 Myiic_SendByte(RegAddress>>8); //发送寄存器地址 10 Myiic_SlaveAck(); //接收应答 11 12 Myiic_SendByte(RegAddress); //发送寄存器地址 13 Myiic_SlaveAck(); //接收应答 14 15 Myiic_Start(); //iic重复起始 16 Myiic_SendByte(EEPROM_READADDRESS); //发送从机地址,读写位为1,表示即将读取 17 Myiic_SlaveAck(); //接收应答 18 19 Data = Myiic_ReceiveByte(); //接收指定寄存器的数据 20 Myiic_HostAck(1); //发送应答,给从机非应答,终止从机的数据输出 21 Myiic_Stop(); //iic终止 22 23 return Data; 24 }
写等待
当EEPROM接收到停止信号后有10ms的写等待将数据写入数据区,这期间不响应主机,不能对EEPROM做任何操作,如果想要写入数据后马上读数据需要注意这个问题
当然上次写完成后好久才操作EEPROM就不用加延时函数了
SHT20
(项目心得跳过来的看这里)这里仅说一个最重要的地方,当主机发送从机地址+读标志位时,由于从机测量时间的问题,主机要一直等待从机响应,其他地方正常响应就好了
1 float SHT20_Read(uint8_t cmd) 2 { 3 float Humidity,Temperature; 4 uint16_t data;//高位一个字节,低位一个字节 5 Myiic_Start(); 6 Myiic_SendByte(SHT20_WriteAddress); 7 if(Myiic_SlaveAck()==0)//正常响应 8 { 9 Myiic_SendByte(cmd); 10 if(Myiic_SlaveAck()==0)//正常响应 11 { 12 do 13 { 14 Delay_us(8); 15 Myiic_Start(); 16 Myiic_SendByte(SHT20_ReadAddress); 17 Myiic_W_SDA(1); 18 Myiic_W_SCL(1); 19 } 20 while(Myiic_R_SDA()); 21 Myiic_W_SCL(0); 22 data=Myiic_ReceiveByte(); 23 data<<=8;//iic通信是高位先行,因此数据是高位先进来 24 data|=Myiic_ReceiveByte(); 25 Myiic_HostAck(1); 26 Myiic_Stop(); 27 if(cmd==RH_Measurement_NoHold) 28 { 29 Humidity =(data*125)/65536-6; 30 return Humidity; 31 } 32 else if(cmd==T_Measurement_NoHold) 33 { 34 Temperature = (data*175.72)/65536-46.85; 35 return Temperature; 36 } 37 } 38 } 39 return Slave_Error; 40 }
1 uint8_t Myiic_SlaveAck(void) 2 { 3 uint8_t AckBit; 4 Myiic_W_SDA(1); 5 Myiic_W_SCL(1); 6 AckBit = Myiic_R_SDA(); 7 Myiic_W_SCL(0); 8 return AckBit; 9 }