UC头条:STM32F103 实例应用(9)——I2C读写24C02
-------------|-----------|----------------|--------------------------------- 2021/01/14 | r0.1 | 青梅煮久 | 创建 -------------|-----------|----------------|--------------------------------- | | | -------------|-----------|----------------|--------------------------------- | | | -------------|-----------|----------------|--------------------------------- | | | ============================================================================*//********************************************************************* * INCLUDES */#include'main.h'#include'board_eeprom.h'#include'board_i2c.h'/********************************************************************* * PUBLIC FUNCTIONS *//** @brief 判断串行EERPOM是否正常 @param 无 @return 1 表示正常, 0 表示不正常 */ uint8_t ee_CheckOk(void){if(i2c_CheckDevice(EEPROM_DEV_ADDR)==0){return1;}else{/* 失败后,切记发送I2C总线停止信号 */i2c_Stop;return0;}}/** @brief 从串行EEPROM指定地址处开始读取若干数据 @param _pReadBuf -[in] 存放读到的数据的缓冲区指针 @param _usAddress -[in] 起始地址 @param _usSize -[in] 数据长度,单位为字节 @return 0 表示失败,1表示成功 */ uint8_t ee_ReadBytes(uint8_t *_pReadBuf, uint16_t _usAddress, uint16_t _usSize){ uint16_t i;/* 采用串行EEPROM随即读取指令序列,连续读取若干字节 *//* 第1步:发起I2C总线启动信号 */i2c_Start;/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */i2c_SendByte(EEPROM_DEV_ADDR | EEPROM_I2C_WR);/* 此处是写指令 *//* 第3步:等待ACK */if(i2c_WaitAck!=0){goto cmd_fail;/* EEPROM器件无应答 */}/* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */i2c_SendByte((uint8_t)_usAddress);/* 第5步:等待ACK */if(i2c_WaitAck!=0){goto cmd_fail;/* EEPROM器件无应答 */}/* 第6步:重新启动I2C总线。前面的代码的目的向EEPROM传送地址,下面开始读取数据 */i2c_Start;/* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */i2c_SendByte(EEPROM_DEV_ADDR | EEPROM_I2C_RD);/* 此处是读指令 *//* 第8步:发送ACK */if(i2c_WaitAck!=0){goto cmd_fail;/* EEPROM器件无应答 */}/* 第9步:循环读取数据 */for(i =0; i < _usSize; i++){ _pReadBuf[i]=i2c_ReadByte;/* 读1个字节 *//* 每读完1个字节后,需要发送Ack, 最后一个字节不需要Ack,发Nack */if(i != _usSize -1){i2c_Ack;/* 中间字节读完后,CPU产生ACK信号(驱动SDA = 0) */}else{i2c_NAck;/* 最后1个字节读完后,CPU产生NACK信号(驱动SDA = 1) */}}/* 发送I2C总线停止信号 */i2c_Stop;return1;/* 执行成功 */ cmd_fail:/* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 *//* 发送I2C总线停止信号 */i2c_Stop;return0;}/** @brief 向串行EEPROM指定地址写入若干数据,采用页写操作提高写入效率 @param _pWriteBuf -[in] 存放写数据的缓冲区指针 @param _usAddress -[in] 起始地址 @param _usSize -[in] 数据长度,单位为字节 @return 0 表示失败,1表示成功 */ uint8_t ee_WriteBytes(uint8_t *_pWriteBuf, uint16_t _usAddress, uint16_t _usSize){ uint16_t i,m; uint16_t usAddr;/* 写串行EEPROM不像读操作可以连续读取很多字节,每次写操作只能在同一个page。 对于24xx02,page size = 8 简单的处理方法为:按字节写操作模式,没写1个字节,都发送地址 为了提高连续写的效率: 本函数采用page wirte操作。 */ usAddr = _usAddress;for(i =0; i < _usSize; i++){/* 当发送第1个字节或是页面首地址时,需要重新发起启动信号和地址 */if((i ==0)||(usAddr &(EEPROM_PAGE_SIZE -1))==0){/* 第0步:发停止信号,启动内部写操作 */i2c_Stop;/* 通过检查器件应答的方式,判断内部写操作是否完成, 一般小于 10ms CLK频率为200KHz时,查询次数为30次左右 */for(m =0; m <1000; m++){/* 第1步:发起I2C总线启动信号 */i2c_Start;/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */i2c_SendByte(EEPROM_DEV_ADDR | EEPROM_I2C_WR);/* 此处是写指令 *//* 第3步:发送一个时钟,判断器件是否正确应答 */if(i2c_WaitAck==0){break;}}if(m ==1000){goto cmd_fail;/* EEPROM器件写超时 */}/* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */i2c_SendByte((uint8_t)usAddr);/* 第5步:等待ACK */if(i2c_WaitAck!=0){goto cmd_fail;/* EEPROM器件无应答 */}}/* 第6步:开始写入数据 */i2c_SendByte(_pWriteBuf[i]);/* 第7步:发送ACK */if(i2c_WaitAck!=0){goto cmd_fail;/* EEPROM器件无应答 */} usAddr++;/* 地址增1 */}/* 命令执行成功,发送I2C总线停止信号 */i2c_Stop;return1; cmd_fail:/* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 *//* 发送I2C总线停止信号 */i2c_Stop;return0;}/** @brief 擦除EEPROM @param 无 @return 无 */voidee_Erase(void){ uint16_t i; uint8_t buf[EEPROM_SIZE];/* 填充缓冲区 */for(i =0; i < EEPROM_SIZE; i++){ buf[i]=0x00;}/* 写EEPROM, 起始地址 = 0,数据长度为 256 */if(ee_WriteBytes(buf,0, EEPROM_SIZE)==0){printf('擦除eeprom出错!\r\n');return;}else{printf('擦除eeprom成功!\r\n');}}/********************************************************************* * LOCAL FUNCTIONS *//** @brief 延时函数 @param 无 @return 无 */staticvoidee_Delay(__IO uint32_t nCount){for(; nCount !=0; nCount--);}/** @brief eeprom AT24C02 读写测试 @param 无 @return 正常返回1,异常返回0 */ uint8_t ee_Test(void){ uint16_t i; uint8_t write_buf[EEPROM_SIZE]; uint8_t read_buf[EEPROM_SIZE];/*-----------------------------------------------------------------------------------*/if(ee_CheckOk==0){/* 没有检测到EEPROM */printf('没有检测到串行EEPROM!\r\n');return0;}/*------------------------------------------------------------------------------------*//* 填充测试缓冲区 */for(i =0; i < EEPROM_SIZE; i++){ write_buf[i]= i;}/*------------------------------------------------------------------------------------*/if(ee_WriteBytes(write_buf,0, EEPROM_SIZE)==0){printf('写eeprom出错!\r\n');return0;}else{printf('写eeprom成功!\r\n');}/*写完之后需要适当的延时再去读,不然会出错*/ee_Delay(0x0FFFFF);/*-----------------------------------------------------------------------------------*/if(ee_ReadBytes(read_buf,0, EEPROM_SIZE)==0){printf('读eeprom出错!\r\n');return0;}else{printf('读eeprom成功,数据如下:\r\n');}/*-----------------------------------------------------------------------------------*/for(i =0; i < EEPROM_SIZE; i++){if(read_buf[i]!= write_buf[i]){printf('0x%02X ', read_buf[i]);printf('错误:EEPROM读出与写入的数据不一致');return0;}printf(' %02X', read_buf[i]);if((i &15)==15){printf('\r\n');}}printf('eeprom读写测试成功\r\n');return1;}/*********************************************END OF FILE**********************/