stm32的EEPROM(24C02)的一页只有8个字节 组织架构是256 * 8bits = 2k(bits)


步骤:
1、起始信号
2、检查总线是否忙碌
3、发送EEPROM设备地址和发送方向
4、发送要写入的单元格地址
5、开始发送数据
6、发送完响应noack 停止发送
7、结束信号
注意:以上的每一步都需要响应EV事件
- //-----------------------对EEPROM进行页写入----------------------------------
- // buffer : 要写入的缓冲区数据
- // addr :要写入的单元格地址
- // num :要写入的数据数量 不能超过页大小 8位
- uint16_t EEPROM_Page_write(u8 *buffer, u8 addr, uint8_t num)
- {
- //查询总线是否忙碌
- TimeOut_count = I2C_time_out;
- while (I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY))
- {
- if ((TimeOut_count--) == 0)
- return I2C_timeout_callback(4);
- }
-
- //发送起始信号
- I2C_GenerateSTART(EEPROM_I2C, ENABLE);
-
- //等待EV5事件响应
- TimeOut_count = I2C_time_out;
- while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT))
- {
- if ((TimeOut_count--) == 0)
- return I2C_timeout_callback(5);
- }
-
- //发送要写入的EEPROM的地址和读写方向
- I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDRESS, I2C_Direction_Transmitter);
-
- //等待EV事件响应
- TimeOut_count = I2C_time_out;
- while (I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS)
- {
- if ((TimeOut_count--) == 0)
- return I2C_timeout_callback(6);
- }
-
- //发送要写入EEPROM的单元地方
- I2C_SendData(EEPROM_I2C, addr);
-
- //等待EV事件响应
- TimeOut_count = I2C_time_out;
- while (I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
- {
- if ((TimeOut_count--) == 0)
- return I2C_timeout_callback(7);
- }
-
- while (num--)
- {
- //发送要写入的数据
- I2C_SendData(EEPROM_I2C, *buffer);
-
- //要写入的数据指针递增
- buffer++;
-
- //等待EV事件响应
- TimeOut_count = I2C_time_out;
- while (I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
- {
- if ((TimeOut_count--) == 0) return I2C_timeout_callback(8);
- }
- }
-
- //发送停止信号
- I2C_GenerateSTOP(I2C1, ENABLE);
-
- //写完马上读会出错 在写入时是不能读的
- Wait_for_StandBy();
-
- return 0;
- }

这里介绍了 AT24C02的内存内部架构是 32页的8byte组成的 32*8byte = 256 byte
所以stm32这I2C对EEPROM最多写入256个byte
关于连续写入会遇到的几个问题:
1、写入的单元格地址不一定是每一页的起始位,导致后面连续页写入位置对不齐,导致数据写入失败
2、 将连续的写入最后凑不满一页的几个字节单独写入,有助于提高效率

关于解决的方法就是:算出对不齐的位数,从要写入的数据中选出可以凑满一页的数据先行讲那一页进行凑满,后续再按正常对齐的方式进行写入。
- //buffer : 要写入的数据
- //addr : 要写入的单元格地址
- //num : 要写入的数据数量
- uint16_t I2c_Buffer_write(u8 *buffer, u8 addr, u16 num)
- {
- u16 Num_Page, Num_Single, count, aaddr;
-
- //算出是否对齐位置
- count = addr % EEPROM_PAGE_SIZE;
- //没对齐的话 aaddr代表需要单独写入的位数 为了凑齐一页的数量
- aaddr = EEPROM_PAGE_SIZE - count;
-
- //如果对齐了
- if (count == 0)
- {
- //算出需要插入的页数 和凑不满一页的单独数
- Num_Page = num / EEPROM_PAGE_SIZE;
- Num_Single = num % EEPROM_PAGE_SIZE;
-
- //若凑不满一页 则直接写入
- if (Num_Page == 0)
- {
- EEPROM_Page_write(buffer, addr, Num_Single);
- Wait_for_StandBy();
- }
- else
- {
- //先写入需要的页数
- while (Num_Page--)
- {
- EEPROM_Page_write(buffer, addr, EEPROM_PAGE_SIZE);
- Wait_for_StandBy();
-
- //每写一页都需要将 数据指针和单元格地址指针进行位移
- buffer += EEPROM_PAGE_SIZE;
- addr += EEPROM_PAGE_SIZE;
- }
- //如果有凑不满一页的位数
- if (Num_Single)
- {
- EEPROM_Page_write(buffer, addr, Num_Single);
- Wait_for_StandBy();
- }
- }
- }
- //若没有对齐
- else
- {
- //算出凑满第一页后还需要写入的位数
- num = num - aaddr;
- //算出凑满后还需要写入的页数
- Num_Page = num / EEPROM_PAGE_SIZE;
- //算出多余的凑不满一页的位数
- Num_Single = num % EEPROM_PAGE_SIZE;
-
- //若凑满一页后 不满一页的的话 直接写入
- if (Num_Page == 0)
- {
- EEPROM_Page_write(buffer, addr, aaddr);
- Wait_for_StandBy();
- }
- else
- {
- //若有凑不满一页的
- if(count)
- {
- //先写入凑满一页的位数
- EEPROM_Page_write(buffer, addr, aaddr);
- Wait_for_StandBy();
-
- //对数据指针和地址指针进行位移
- buffer += aaddr;
- addr += aaddr;
- }
-
- //接下来的操作跟对齐的操作一样
- while (Num_Page--)
- {
- EEPROM_Page_write(buffer, addr, EEPROM_PAGE_SIZE);
- Wait_for_StandBy();
-
- buffer += EEPROM_PAGE_SIZE;
- addr += EEPROM_PAGE_SIZE;
- }
-
- if (Num_Single)
- {
- EEPROM_Page_write(buffer, addr, Num_Single);
- Wait_for_StandBy();
- }
- }
- }
- return 1;
- }


从上面第一张步骤:
1、发送起始信号
2、发送要接收的EEPROM地址和发送方向
3、发送要接收的单元格地址
4、发送要写入的EEPROM地址和接收方向
5、开始接收数据
6、接收完毕发送noack应答结束传输
7、发送结束信号
注意:以上的每一步都需要响应EV事件
- // EPPROM_Random_Read : 连续读取
- // addr : 要读取的单元格地址
- // DATA :读取的内容存放区
- // num :要读取的数据数量
- uint32_t EPPROM_Random_Read(u8 addr, u8 *Data, u16 num)
- {
- //*((u8 *)0x4001080c) |=0x80;
- while (I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY))
- {
- if ((TimeOut_count--) == 0)
- return I2C_timeout_callback(99);
- }
- //发送起始信号
- I2C_GenerateSTART(EEPROM_I2C, ENABLE);
-
- //等待EV5事件响应
- TimeOut_count = I2C_time_out;
- while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT))
- {
- if ((TimeOut_count--) == 0)
- return I2C_timeout_callback(21);
- }
-
- //发送要写入的EEPROM的地址和读写方向 先选择写方向写入单元格地址
- I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDRESS, I2C_Direction_Transmitter);
-
- //等待EV6事件响应
- TimeOut_count = I2C_time_out;
- while (I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS)
- {
- if ((TimeOut_count--) == 0)
- return I2C_timeout_callback(22);
- }
-
- //发送要读取EEPROM的单元地方
- I2C_SendData(EEPROM_I2C, addr);
-
- //等待EV8_2事件响应
- TimeOut_count = I2C_time_out;
- while (I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
- {
- if ((TimeOut_count--) == 0)
- return I2C_timeout_callback(23);
- }
-
- //---------------------------------------------------------------------------------------------------------
- //-----------------------产生第二次起始信号---------------------------------------------------------
-
- //发送起始信号
- I2C_GenerateSTART(EEPROM_I2C, ENABLE);
-
- //等待EV事件响应
- TimeOut_count = I2C_time_out;
- while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT))
- {
- if ((TimeOut_count--) == 0)
- return I2C_timeout_callback(24);
- }
-
- //*********************************读方向************************************************
- //发送要写入的EEPROM的地址和读方向
- I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDRESS, I2C_Direction_Receiver);
-
- //等待EV事件响应
- TimeOut_count = I2C_time_out;
- while (I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS)
- {
- if ((TimeOut_count--) == 0)
- return I2C_timeout_callback(25);
- }
-
- while (num--)
- {
- if (num == 0)
- {
- I2C_AcknowledgeConfig(EEPROM_I2C, DISABLE);
- }
- else
- {
- I2C_AcknowledgeConfig(EEPROM_I2C, ENABLE);
- }
-
- //等待EV事件响应
- TimeOut_count = I2C_time_out;
- while (I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS)
- {
- if ((TimeOut_count--) == 0)
- return I2C_timeout_callback(26);
- }
-
- *Data = I2C_ReceiveData(EEPROM_I2C);
-
- // printf(" data = %d \r\n",*Data);
- Data++;
- }
-
- return 1;
- }
-
- #define Test_num 256
-
- /**
- * @brief 主函数
- * @param 无
- * @retval 无
- */
- int main(void)
- {
- u16 i;
- u8 buff[Test_num];
- u8 data[Test_num];
-
- //初始化要写入的数据
- for(i = 0 ; i < Test_num ; i++)
- {
- buff[i] = i;
- }
-
- /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
- Debug_USART_Config();
-
- //初始化I2C
- I2C_EE_init();
-
- /*调用printf函数,因为重定向了fputc,printf的内容会输出到串口*/
- printf("\r\n IIC实验 \r\n");
-
- I2c_Buffer_write(buff , 0x45 , Test_num);
-
- EPPROM_Random_Read(0x45 , data, Test_num);
-
- printf(" \r\n EEPROM读写实验结束 data = \n");
-
- for ( i = 0; i < Test_num; i++)
- {
- printf("%d ",data[i]);
- }
-
-
- while(1)
- {
-
- }
-
- }
