[单片机芯片] CH32V103的硬件IIC连续读写AT24系列EEPROM

[复制链接]
3416|8
 楼主| 药无尘 发表于 2024-3-7 16:53 | 显示全部楼层 |阅读模式
看到网上没有CH32V系列的关于硬件IIC连续读写AT24系列EEPROM的文章。我在借鉴了网上一些资料后在官方例程基础上做了修改,由于AT24系列EEPROM的写Page是有长度限制的,低容量的是8bytes,高容量的是16/32bytes。所以在写之前先要做地址对齐,先将不对齐的部分写入,然后连续按照页大小写入,最后收尾即可。

        要注意的是每次写入之间要加延时,经测试要大于2ms为妙,测试过1ms延时会卡死。

代码如下:

  1. /*
  2. *@Note
  3. I2C接口操作EEPROM外设例程: 此代码在官方例程基础上修改,其中部分代码借鉴了stm32等其他类型单片机的IIC流程
  4. I2C1_SCL(PB10)、I2C1_SDA(PB11)。
  5. 本例程使用 EEPROM 为 AT24Cxx系列。
  6. 操作步骤:
  7. READ EEPROM:Start + 0xA0 + 8bit Data Address + Start + 0xA1 + Read Data + Stop.
  8. WRITE EERPOM:Start + 0xA0 + 8bit Data Address + Write Data + Stop.
  9. */

  10. #include "debug.h"

  11. /**********************************************************************
  12. *@Note:
  13. AT24Cxx:
  14. READ EEPROM:Start + 0xA0 + 8bit Data Address + Start + 0xA1 + Read Data + Stop.
  15. WRITE EERPOM:Start + 0xA0 + 8bit Data Address + Write Data + Stop.
  16. *******************************************************************************/
  17. /* EERPOM DATA ADDRESS Length Definition */
  18. #define Address_8bit     0
  19. #define Address_16bit    1

  20. /* EERPOM DATA ADDRESS Length Selection */
  21. #define Address_Lenth    Address_8bit
  22. //#define Address_Lenth   Address_16bit

  23. /* Global define */
  24. #define SIZE             sizeof(TEXT_Buffer)
  25. //写入和读取的初始地址
  26. #define WR_Address       2
  27. //器件的页大小
  28. #define PAGE_SIZE        16
  29. /* Global Variable */
  30. const u8 TEXT_Buffer[] = {"CH32V103 IIC TEST GOOD LUCK!\r Let's Go!\r AT24C02 Page=8,AT24C4/8/16 Page=16,AT24C32/64 Page=32."};

  31. /*********************************************************************
  32. * @fn      IIC_Init
  33. *
  34. * [url=home.php?mod=space&uid=247401]@brief[/url]   Initializes the IIC peripheral.
  35. *
  36. * [url=home.php?mod=space&uid=266161]@return[/url]  none
  37. */
  38. void IIC_Init(u32 bound, u16 address)
  39. {
  40.     GPIO_InitTypeDef GPIO_InitStructure = {0};
  41.     I2C_InitTypeDef  I2C_InitTSturcture = {0};

  42.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  43.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);

  44.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  45.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
  46.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  47.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  48.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  49.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
  50.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  51.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  52.     I2C_InitTSturcture.I2C_ClockSpeed = bound;
  53.     I2C_InitTSturcture.I2C_Mode = I2C_Mode_I2C;
  54.     I2C_InitTSturcture.I2C_DutyCycle = I2C_DutyCycle_2;
  55.     I2C_InitTSturcture.I2C_OwnAddress1 = address;
  56.     I2C_InitTSturcture.I2C_Ack = I2C_Ack_Enable;
  57.     I2C_InitTSturcture.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  58.     I2C_Init(I2C2, &I2C_InitTSturcture);

  59.     I2C_Cmd(I2C2, ENABLE);

  60.     I2C_AcknowledgeConfig(I2C2, ENABLE);
  61. }

  62. /*********************************************************************
  63. * @fn      AT24CXX_Init
  64. *
  65. * @brief   Initializes AT24xx EEPROM.
  66. *
  67. * @return  none
  68. */
  69. void AT24CXX_Init(void)
  70. {
  71.     IIC_Init(100000, 0xA0);
  72. }

  73. /*********************************************************************
  74. * @fn      AT24CXX_ReadOneByte
  75. *
  76. * @brief   Read one data from EEPROM.
  77. *
  78. * @param   ReadAddr - Read frist address.
  79. *
  80. * @return  temp - Read data.
  81. */
  82. u8 AT24CXX_ReadOneByte(u16 ReadAddr)
  83. {
  84.     u8 temp = 0;

  85.     while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY) != RESET);
  86.     I2C_GenerateSTART(I2C2, ENABLE);

  87.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
  88.     I2C_Send7bitAddress(I2C2, 0XA0, I2C_Direction_Transmitter);

  89.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  90. #if(Address_Lenth == Address_8bit)
  91.     I2C_SendData(I2C2, (u8)(ReadAddr & 0x00FF));
  92.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  93. #elif(Address_Lenth == Address_16bit)
  94.     I2C_SendData(I2C2, (u8)(ReadAddr >> 8));
  95.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  96.     I2C_SendData(I2C2, (u8)(ReadAddr & 0x00FF));
  97.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  98. #endif

  99.     I2C_GenerateSTART(I2C2, ENABLE);

  100.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
  101.     I2C_Send7bitAddress(I2C2, 0XA0, I2C_Direction_Receiver);

  102.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
  103.     while(I2C_GetFlagStatus(I2C2, I2C_FLAG_RXNE) == RESET)
  104.         I2C_AcknowledgeConfig(I2C2, DISABLE);

  105.     temp = I2C_ReceiveData(I2C2);
  106.     I2C_GenerateSTOP(I2C2, ENABLE);

  107.     return temp;
  108. }



  109. /*********************************************************************
  110. * @fn      AT24CXX_MulitReadByte
  111. *
  112. * @brief   Read one data from EEPROM.
  113. *
  114. * @param   ReadAddr - Read frist address.
  115. *          Readbuffer - Read data buffer.
  116. *          Num - Size will be read.
  117. *
  118. * @return  read_count
  119. */
  120. u8 AT24CXX_MulitReadBytes(u16 ReadAddr,u8 *Readbuffer, u8 Num )
  121. {
  122.     u8 read_count=0;
  123.     while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY) != RESET);
  124.     I2C_GenerateSTART(I2C2, ENABLE);

  125.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
  126.     I2C_Send7bitAddress(I2C2, 0XA0, I2C_Direction_Transmitter);

  127.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  128. #if(Address_Lenth == Address_8bit)
  129.     I2C_SendData(I2C2, (u8)(ReadAddr & 0x00FF));
  130.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  131. #elif(Address_Lenth == Address_16bit)
  132.     I2C_SendData(I2C2, (u8)(ReadAddr >> 8));
  133.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  134.     I2C_SendData(I2C2, (u8)(ReadAddr & 0x00FF));
  135.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  136. #endif

  137.     I2C_GenerateSTART(I2C2, ENABLE);

  138.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
  139.     I2C_Send7bitAddress(I2C2, 0XA0, I2C_Direction_Receiver);

  140.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

  141.     while(Num--)
  142.        {

  143.         if(Num==0) //最后一个数据产生停止应答信号
  144.         {
  145.          //应答必须关闭,否则下次IIC将不能用
  146.          I2C_AcknowledgeConfig(I2C2, DISABLE);  //需要在接受到最后一位数据前关闭应答
  147.          }
  148.         while(I2C_GetFlagStatus(I2C2, I2C_FLAG_RXNE) == RESET);       //等待收到数据
  149.          *Readbuffer++=I2C_ReceiveData(I2C2);  //收到数据放入缓存
  150.          read_count++;
  151.       }
  152.        I2C_GenerateSTOP(I2C2, ENABLE);          //发送停止信号
  153.        I2C_AcknowledgeConfig(I2C1,ENABLE) ;     //开启应答方便下一次使用

  154.        return read_count;
  155. }



  156. /*********************************************************************
  157. * @fn      AT24CXX_WriteOneByte
  158. *
  159. * @brief   Write one data to EEPROM.
  160. *
  161. * @param   WriteAddr - Write frist address.
  162. *
  163. * @return  DataToWrite - Write data.
  164. */
  165. void AT24CXX_WriteOneByte(u16 WriteAddr, u8 DataToWrite)
  166. {
  167.     while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY) != RESET);
  168.     I2C_GenerateSTART(I2C2, ENABLE);

  169.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
  170.     I2C_Send7bitAddress(I2C2, 0XA0, I2C_Direction_Transmitter);

  171.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  172. #if(Address_Lenth == Address_8bit)
  173.     I2C_SendData(I2C2, (u8)(WriteAddr & 0x00FF));
  174.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  175. #elif(Address_Lenth == Address_16bit)
  176.     I2C_SendData(I2C2, (u8)(WriteAddr >> 8));
  177.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  178.     I2C_SendData(I2C2, (u8)(WriteAddr & 0x00FF));
  179.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  180. #endif

  181.     if(I2C_GetFlagStatus(I2C2, I2C_FLAG_TXE) != RESET)
  182.     {
  183.         I2C_SendData(I2C2, DataToWrite);
  184.     }

  185.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) ;
  186.     I2C_GenerateSTOP(I2C2, ENABLE);
  187. }

  188. /*********************************************************************
  189. * @fn      AT24CXX_WritePage
  190. *
  191. * @brief   Write one data to EEPROM.
  192. *
  193. * @param   WriteAddr - Write frist address.
  194. *          WriteBuffer - data will be write
  195. *          Num - data num 1~8,page is 8 byte
  196. *
  197. * @return  DataToWrite - Write data.
  198. */
  199. void AT24CXX_WritePage(u16 WriteAddr, u8 *WriteBuffer, u8 Num)
  200. {
  201.     while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY) != RESET);
  202.     I2C_GenerateSTART(I2C2, ENABLE);

  203.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
  204.     I2C_Send7bitAddress(I2C2, 0XA0, I2C_Direction_Transmitter);

  205.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  206. #if(Address_Lenth == Address_8bit)
  207.     I2C_SendData(I2C2, (u8)(WriteAddr & 0x00FF));
  208.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  209. #elif(Address_Lenth == Address_16bit)
  210.     I2C_SendData(I2C2, (u8)(WriteAddr >> 8));
  211.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  212.     I2C_SendData(I2C2, (u8)(WriteAddr & 0x00FF));
  213.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  214. #endif

  215.     while(!(I2C_GetFlagStatus(I2C2,I2C_FLAG_TXE)));
  216.     I2C_SendData(I2C2, *WriteBuffer++);
  217.     while(!(I2C_GetFlagStatus(I2C2,I2C_FLAG_TXE)));
  218.     while(Num)
  219.     {
  220.         Num--;
  221.         if(Num==0)  break;  //全部发送完毕,直接退出
  222.         //还有数据则继续发送
  223.         I2C_SendData(I2C2, *WriteBuffer++);
  224.         while(!(I2C_GetFlagStatus(I2C2,I2C_FLAG_TXE))); //等待数据发送完毕
  225.     }

  226.     while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) ;
  227.     I2C_GenerateSTOP(I2C2, ENABLE);
  228. }


  229. /*********************************************************************
  230. * @fn      AT24CXX_Read
  231. *
  232. * @brief   Read multiple data from EEPROM.
  233. *
  234. * @param   ReadAddr - Read frist address. (AT24c02: 0~255)
  235. *          pBuffer - Read data.
  236. *          NumToRead - Data number.
  237. *
  238. * @return  none
  239. */
  240. void AT24CXX_Read(u16 ReadAddr, u8 *pBuffer, u16 NumToRead)
  241. {
  242.     while(NumToRead)
  243.     {
  244.         *pBuffer++ = AT24CXX_ReadOneByte(ReadAddr++);
  245.         NumToRead--;
  246.     }
  247. }

  248. /*********************************************************************
  249. * @fn      AT24CXX_Write
  250. *
  251. * @brief   Write multiple data to EEPROM.
  252. *
  253. * @param   WriteAddr - Write frist address. (AT24c02: 0~255)
  254. *          pBuffer - Write data.
  255. *          NumToWrite - Data number.
  256. *
  257. * @return  none
  258. */
  259. void AT24CXX_Write(u16 WriteAddr, u8 *pBuffer, u16 NumToWrite)
  260. {
  261.     while(NumToWrite--)
  262.     {
  263.         AT24CXX_WriteOneByte(WriteAddr, *pBuffer);
  264.         WriteAddr++;
  265.         pBuffer++;
  266.         Delay_Ms(2);
  267.     }
  268. }


  269. void AT24CXX_MulitWriteBytes(u16 WriteAddr, u8 *pBuffer, u16 NumToWrite)
  270. {
  271.     BOOL last_time = 0;
  272.     u8 duiqi_count = 0;
  273.     //首先要对齐到页
  274.     if(WriteAddr%PAGE_SIZE !=0 ){
  275.         duiqi_count = ((u8)(WriteAddr/PAGE_SIZE )+1)*PAGE_SIZE -WriteAddr;
  276.         printf("duiqi_count:%d\r\n", duiqi_count);
  277.         AT24CXX_WritePage(WriteAddr, pBuffer,duiqi_count);
  278.         NumToWrite = NumToWrite - duiqi_count;
  279.         WriteAddr = WriteAddr + duiqi_count;
  280.         pBuffer = pBuffer + duiqi_count;
  281.         Delay_Ms(3);
  282.     }
  283.     //将剩余数据写入
  284.     while(!last_time)
  285.         {
  286.             if(NumToWrite <= PAGE_SIZE ) //如果小于页大小,为最后 一次写入
  287.             {
  288.                 AT24CXX_WritePage(WriteAddr, pBuffer,NumToWrite);
  289.                 last_time = 1;
  290.             }
  291.             else { //连续页写入
  292.                 AT24CXX_WritePage(WriteAddr, pBuffer,PAGE_SIZE);
  293.                 WriteAddr = WriteAddr + PAGE_SIZE;
  294.                 pBuffer = pBuffer + PAGE_SIZE;
  295.                 NumToWrite = NumToWrite -PAGE_SIZE;
  296.             }
  297.             Delay_Ms(3);
  298.         }
  299. }

  300. /*********************************************************************
  301. * @fn      main
  302. *
  303. * @brief   Main program.
  304. *
  305. * @return  none
  306. */
  307. int main(void)
  308. {
  309.     u8 data[SIZE];

  310.     Delay_Init();
  311.     USART_Printf_Init(115200);
  312.     printf("SystemClk:%d\r\n", SystemCoreClock);

  313.     AT24CXX_Init();

  314.     printf("Start Write 24Cxx....\r\n");
  315.     //AT24CXX_Write(50, (u8 *)TEXT_Buffer, SIZE); //官方是单个写入,多次重复
  316.     AT24CXX_MulitWriteBytes(WR_Address, (u8 *)TEXT_Buffer, SIZE); //修改后是多次页写入
  317.     printf("24Cxx Write Sucess!\r\n");

  318.     Delay_Ms(50);

  319.     printf("Start Read 24Cxx....\r\n");
  320.     AT24CXX_MulitReadBytes(WR_Address,data,SIZE); //修改后是直接连续读取
  321.     //AT24CXX_Read(100, data, SIZE); //官方程序是单个读取,多次重复
  322.     printf("The Data Readed Is: \r\n");
  323.     printf("%s\r\n", data);

  324.     while(1);
  325. }


评论

理想的应该是判断EEPROM是否空闲,然后再开始写下一页  发表于 2024-4-17 20:15
tpgf 发表于 2024-4-2 12:13 | 显示全部楼层
延时的时间是否应该根据通讯数据的多少来定呢
八层楼 发表于 2024-4-2 12:46 | 显示全部楼层
如果延时时间过短  就会卡死的原因是什么呢
guanjiaer 发表于 2024-4-2 13:50 | 显示全部楼层
这个等待时间和iic的通讯速度有关系吗
keaibukelian 发表于 2024-4-2 14:27 | 显示全部楼层
这种使用模块的 难道底层不自动进行延时?
heimaojingzhang 发表于 2024-4-2 23:50 | 显示全部楼层
eeprom的读写的速度最快能达到多少呢
呐咯密密 发表于 2024-4-17 20:14 | 显示全部楼层
EEPROM写数据需要时间,每次切页要等待,这个时间需要根据手册来定
您需要登录后才可以回帖 登录 | 注册

本版积分规则

79

主题

623

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部