- 准备知识
本章我们要学习一次读取任意地址的数据和任意长度连续地址的数据。与第二章同样的我们首先从AT24C02中找到读取的时序图,如下图1和图2所示。
图1 任意读取一个地址的数据
图2 顺序读取任意长度的数据
在AT24C02的数据手册中我们找到了以上2种读取数据的时序的方法,图1介绍了读取任意1个地址的数据的时序。图2介绍了一次顺序读取多个字节的数据。显然的图1方法效率很低,所以我们这章节学习图2的时序方法。
很多人一时看不明白图2开头R/W前面虚线部分是什么意思.其实很简单,首先我们看图1中读的过程中有两个起始位START,第一个START是要写入从机的地址和写入数据开始的地址,所以第一部分START是STM32的主机写时序,这部分需要参考上一节我们学习写一个字节的时序,从第二个START开始才是读时序,所以第二个START开始在把图2相连接就组成了顺序读取的时序。
然后我们在看下STM32主机时读的时序,如图3
图3 STM32作为主机读的时序图
显然的读取和写入时序很像,只是事件不同。所以这里就不多说了。
为了程序设计方便,我们画出组成好顺序读取完整时序图,如下图4.
图片4 顺序多字节读取时序图
看了上图我们就清楚了,顺序读取的逻辑顺序了,读取过程如下:发送起始位—检测EV5(成功)—发送写地址—检测EV6(成功)—发送写入首地址—检测EV8(成功)—再次发送起始位–检测EV5(成功)—发送读地址—检测EV6(成功)—发送数据—检测EV7(成功)—–发送停止位。逻辑和流程清楚了以后我们上代码。
代码如下:
oid eeprom_ByteRead(unsigned char *pBuffer, unsigned char ReadAddr, unsigned short NumByteToRead) { I2C_AcknowledgeConfig(I2C1, ENABLE); // 这里使能 因为每次读取在结束有个非应答信号 回吧应答关闭 ,这里开启保证读取正常 不然反复读取会出错。 /**********产生起始位*****************/ I2C_GenerateSTART(I2C1,ENABLE) ; delay_for_eeprom(0x100); /**********检测EV5事件 是否响应*********/ if( I2C_CheckEvent (I2C1,I2C_EVENT_MASTER_MODE_SELECT )) { I2C_Send7bitAddress (I2C1,eeprom_addr_wr,I2C_Direction_Transmitter); delay_for_eeprom(0x100); /**********检测EV6事件 是否响应*********/ if(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ))//有EV6事件代表地址发送成功 和 应答成功 { I2C_SendData (I2C1,ReadAddr); delay_for_eeprom(0x100); /**********检测EV8事件 是否响应*********/ if(I2C_CheckEvent (I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED))//有EV8事件代表地址发送成功 和 应答成功 { I2C_GenerateSTART(I2C1,ENABLE) ; delay_for_eeprom(0x100); /**********检测EV5事件 是否响应*********/ if(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT))//EV5检测起始位 发送是否成功 { I2C_Send7bitAddress (I2C1,eeprom_addr_rd,I2C_Direction_Receiver); delay_for_eeprom(0x100); /**********检测EV6事件 是否响应*********/ if(I2C_CheckEvent (I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))//EV6检测起始位 发送是否成功 { for(;NumByteToRead>0;NumByteToRead--) { delay_for_eeprom(0x100); /**********检测EV7事件 是否响应*********/ if( I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED )) { *pBuffer = I2C_ReceiveData(I2C1); pBuffer++; } } I2C_AcknowledgeConfig(I2C1, DISABLE); I2C_GenerateSTOP(I2C1, ENABLE); delay_for_eeprom(0x1000);//这个延迟为了 保证数据数据读取寄存器已经读取完成,不影响下次写入或读取。 参考AT24C02手册P8页 ACKNOWLEDGE POLLING printf("读取成功") ; } else printf("读数据的第2次EV6事件失败") ;//没有检测到EV6事件 } else printf("读数据的第2次EV5事件失败") ; //没有检测到EV5事件 } else printf("读数据的第1次EV8事件失败") ;//没有检测到EV8事件 } else printf("读数据的第1次EV6事件失败");//没有检测到EV6事件 } else printf("读数据的第1次EV5事件失败") ;//没有检测到EV5事件 }
函数的第一行I2C_AcknowledgeConfig(I2C1, ENABLE);这个代码是因为每一次读取的最后1个数据需要相应非应答信号,所以程序最后会关闭应答使能。每一次执行这个函数,先打开应答使能,不至于导致多次写入失败。延迟函数就不多少了,上一章节说的很明白了。 其他部分代码注释应该写的很明白了。到这里读取部分已经完成,此时我们就可以结合前面一章内容,写一个字节后,再来读取。看看是否可以读取成功。测试截图我们到最后统一演示。那么今天就学习到这里,下一章节我们学习多数据的写入。
原创文章,作者:小峰,如若转载,请注明出处:http://www.wfblog.com/archives/344.html