• STM32之I2C对EEPROM 页读写、连续读写操作


    页写入

    原理

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

     步骤:

    1、起始信号

    2、检查总线是否忙碌

    3、发送EEPROM设备地址和发送方向

    4、发送要写入的单元格地址

    5、开始发送数据

    6、发送完响应noack 停止发送   

    7、结束信号

    注意:以上的每一步都需要响应EV事件

    代码

    1. //-----------------------对EEPROM进行页写入----------------------------------
    2. // buffer : 要写入的缓冲区数据
    3. // addr :要写入的单元格地址
    4. // num :要写入的数据数量 不能超过页大小 8位
    5. uint16_t EEPROM_Page_write(u8 *buffer, u8 addr, uint8_t num)
    6. {
    7. //查询总线是否忙碌
    8. TimeOut_count = I2C_time_out;
    9. while (I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY))
    10. {
    11. if ((TimeOut_count--) == 0)
    12. return I2C_timeout_callback(4);
    13. }
    14. //发送起始信号
    15. I2C_GenerateSTART(EEPROM_I2C, ENABLE);
    16. //等待EV5事件响应
    17. TimeOut_count = I2C_time_out;
    18. while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT))
    19. {
    20. if ((TimeOut_count--) == 0)
    21. return I2C_timeout_callback(5);
    22. }
    23. //发送要写入的EEPROM的地址和读写方向
    24. I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDRESS, I2C_Direction_Transmitter);
    25. //等待EV事件响应
    26. TimeOut_count = I2C_time_out;
    27. while (I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS)
    28. {
    29. if ((TimeOut_count--) == 0)
    30. return I2C_timeout_callback(6);
    31. }
    32. //发送要写入EEPROM的单元地方
    33. I2C_SendData(EEPROM_I2C, addr);
    34. //等待EV事件响应
    35. TimeOut_count = I2C_time_out;
    36. while (I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
    37. {
    38. if ((TimeOut_count--) == 0)
    39. return I2C_timeout_callback(7);
    40. }
    41. while (num--)
    42. {
    43. //发送要写入的数据
    44. I2C_SendData(EEPROM_I2C, *buffer);
    45. //要写入的数据指针递增
    46. buffer++;
    47. //等待EV事件响应
    48. TimeOut_count = I2C_time_out;
    49. while (I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
    50. {
    51. if ((TimeOut_count--) == 0) return I2C_timeout_callback(8);
    52. }
    53. }
    54. //发送停止信号
    55. I2C_GenerateSTOP(I2C1, ENABLE);
    56. //写完马上读会出错 在写入时是不能读的
    57. Wait_for_StandBy();
    58. return 0;
    59. }

    连续写

    原理

     这里介绍了 AT24C02的内存内部架构是 32页的8byte组成的  32*8byte = 256 byte

    所以stm32这I2C对EEPROM最多写入256个byte

    关于连续写入会遇到的几个问题:

    1、写入的单元格地址不一定是每一页的起始位,导致后面连续页写入位置对不齐,导致数据写入失败

    2、 将连续的写入最后凑不满一页的几个字节单独写入,有助于提高效率

     关于解决的方法就是:算出对不齐的位数,从要写入的数据中选出可以凑满一页的数据先行讲那一页进行凑满,后续再按正常对齐的方式进行写入。

    代码

    1. //buffer : 要写入的数据
    2. //addr : 要写入的单元格地址
    3. //num : 要写入的数据数量
    4. uint16_t I2c_Buffer_write(u8 *buffer, u8 addr, u16 num)
    5. {
    6. u16 Num_Page, Num_Single, count, aaddr;
    7. //算出是否对齐位置
    8. count = addr % EEPROM_PAGE_SIZE;
    9. //没对齐的话 aaddr代表需要单独写入的位数 为了凑齐一页的数量
    10. aaddr = EEPROM_PAGE_SIZE - count;
    11. //如果对齐了
    12. if (count == 0)
    13. {
    14. //算出需要插入的页数 和凑不满一页的单独数
    15. Num_Page = num / EEPROM_PAGE_SIZE;
    16. Num_Single = num % EEPROM_PAGE_SIZE;
    17. //若凑不满一页 则直接写入
    18. if (Num_Page == 0)
    19. {
    20. EEPROM_Page_write(buffer, addr, Num_Single);
    21. Wait_for_StandBy();
    22. }
    23. else
    24. {
    25. //先写入需要的页数
    26. while (Num_Page--)
    27. {
    28. EEPROM_Page_write(buffer, addr, EEPROM_PAGE_SIZE);
    29. Wait_for_StandBy();
    30. //每写一页都需要将 数据指针和单元格地址指针进行位移
    31. buffer += EEPROM_PAGE_SIZE;
    32. addr += EEPROM_PAGE_SIZE;
    33. }
    34. //如果有凑不满一页的位数
    35. if (Num_Single)
    36. {
    37. EEPROM_Page_write(buffer, addr, Num_Single);
    38. Wait_for_StandBy();
    39. }
    40. }
    41. }
    42. //若没有对齐
    43. else
    44. {
    45. //算出凑满第一页后还需要写入的位数
    46. num = num - aaddr;
    47. //算出凑满后还需要写入的页数
    48. Num_Page = num / EEPROM_PAGE_SIZE;
    49. //算出多余的凑不满一页的位数
    50. Num_Single = num % EEPROM_PAGE_SIZE;
    51. //若凑满一页后 不满一页的的话 直接写入
    52. if (Num_Page == 0)
    53. {
    54. EEPROM_Page_write(buffer, addr, aaddr);
    55. Wait_for_StandBy();
    56. }
    57. else
    58. {
    59. //若有凑不满一页的
    60. if(count)
    61. {
    62. //先写入凑满一页的位数
    63. EEPROM_Page_write(buffer, addr, aaddr);
    64. Wait_for_StandBy();
    65. //对数据指针和地址指针进行位移
    66. buffer += aaddr;
    67. addr += aaddr;
    68. }
    69. //接下来的操作跟对齐的操作一样
    70. while (Num_Page--)
    71. {
    72. EEPROM_Page_write(buffer, addr, EEPROM_PAGE_SIZE);
    73. Wait_for_StandBy();
    74. buffer += EEPROM_PAGE_SIZE;
    75. addr += EEPROM_PAGE_SIZE;
    76. }
    77. if (Num_Single)
    78. {
    79. EEPROM_Page_write(buffer, addr, Num_Single);
    80. Wait_for_StandBy();
    81. }
    82. }
    83. }
    84. return 1;
    85. }

    连续读

    原理

     从上面第一张步骤:

    1、发送起始信号

    2、发送要接收的EEPROM地址和发送方向

    3、发送要接收的单元格地址

    4、发送要写入的EEPROM地址和接收方向

    5、开始接收数据

    6、接收完毕发送noack应答结束传输

    7、发送结束信号

    注意:以上的每一步都需要响应EV事件

    代码

    1. // EPPROM_Random_Read : 连续读取
    2. // addr : 要读取的单元格地址
    3. // DATA :读取的内容存放区
    4. // num :要读取的数据数量
    5. uint32_t EPPROM_Random_Read(u8 addr, u8 *Data, u16 num)
    6. {
    7. //*((u8 *)0x4001080c) |=0x80;
    8. while (I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY))
    9. {
    10. if ((TimeOut_count--) == 0)
    11. return I2C_timeout_callback(99);
    12. }
    13. //发送起始信号
    14. I2C_GenerateSTART(EEPROM_I2C, ENABLE);
    15. //等待EV5事件响应
    16. TimeOut_count = I2C_time_out;
    17. while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT))
    18. {
    19. if ((TimeOut_count--) == 0)
    20. return I2C_timeout_callback(21);
    21. }
    22. //发送要写入的EEPROM的地址和读写方向 先选择写方向写入单元格地址
    23. I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDRESS, I2C_Direction_Transmitter);
    24. //等待EV6事件响应
    25. TimeOut_count = I2C_time_out;
    26. while (I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS)
    27. {
    28. if ((TimeOut_count--) == 0)
    29. return I2C_timeout_callback(22);
    30. }
    31. //发送要读取EEPROM的单元地方
    32. I2C_SendData(EEPROM_I2C, addr);
    33. //等待EV8_2事件响应
    34. TimeOut_count = I2C_time_out;
    35. while (I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
    36. {
    37. if ((TimeOut_count--) == 0)
    38. return I2C_timeout_callback(23);
    39. }
    40. //---------------------------------------------------------------------------------------------------------
    41. //-----------------------产生第二次起始信号---------------------------------------------------------
    42. //发送起始信号
    43. I2C_GenerateSTART(EEPROM_I2C, ENABLE);
    44. //等待EV事件响应
    45. TimeOut_count = I2C_time_out;
    46. while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT))
    47. {
    48. if ((TimeOut_count--) == 0)
    49. return I2C_timeout_callback(24);
    50. }
    51. //*********************************读方向************************************************
    52. //发送要写入的EEPROM的地址和读方向
    53. I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDRESS, I2C_Direction_Receiver);
    54. //等待EV事件响应
    55. TimeOut_count = I2C_time_out;
    56. while (I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS)
    57. {
    58. if ((TimeOut_count--) == 0)
    59. return I2C_timeout_callback(25);
    60. }
    61. while (num--)
    62. {
    63. if (num == 0)
    64. {
    65. I2C_AcknowledgeConfig(EEPROM_I2C, DISABLE);
    66. }
    67. else
    68. {
    69. I2C_AcknowledgeConfig(EEPROM_I2C, ENABLE);
    70. }
    71. //等待EV事件响应
    72. TimeOut_count = I2C_time_out;
    73. while (I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS)
    74. {
    75. if ((TimeOut_count--) == 0)
    76. return I2C_timeout_callback(26);
    77. }
    78. *Data = I2C_ReceiveData(EEPROM_I2C);
    79. // printf(" data = %d \r\n",*Data);
    80. Data++;
    81. }
    82. return 1;
    83. }

    主函数

    1. #define Test_num 256
    2. /**
    3. * @brief 主函数
    4. * @param 无
    5. * @retval 无
    6. */
    7. int main(void)
    8. {
    9. u16 i;
    10. u8 buff[Test_num];
    11. u8 data[Test_num];
    12. //初始化要写入的数据
    13. for(i = 0 ; i < Test_num ; i++)
    14. {
    15. buff[i] = i;
    16. }
    17. /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
    18. Debug_USART_Config();
    19. //初始化I2C
    20. I2C_EE_init();
    21. /*调用printf函数,因为重定向了fputc,printf的内容会输出到串口*/
    22. printf("\r\n IIC实验 \r\n");
    23. I2c_Buffer_write(buff , 0x45 , Test_num);
    24. EPPROM_Random_Read(0x45 , data, Test_num);
    25. printf(" \r\n EEPROM读写实验结束 data = \n");
    26. for ( i = 0; i < Test_num; i++)
    27. {
    28. printf("%d ",data[i]);
    29. }
    30. while(1)
    31. {
    32. }
    33. }

    结果截图

     

  • 相关阅读:
    LeetCode-791. 自定义字符串排序【哈希表,字符串,排序】
    Android上传私有插件到私有MAVEN-PUBLISH
    Tomcat颁布自定义SSL(Https)证书
    Docker:Elasticsearch安装配置IK分词器
    [附源码]计算机毕业设计校园商铺Springboot程序
    基于python命令流及代码的Plaxis自动化建模
    吴恩达深度学习笔记:深度学习引言1.1-1.5
    【uvm】参数化Class中的静态属性
    【PHP】sign加签方法示例
    VUE3 TypeError: defineConfig is not a function
  • 原文地址:https://blog.csdn.net/weixin_47321452/article/details/127436174