[STM32F1] VSCODE STM32 裸机之I2C总线 AT24C02

[复制链接]
 楼主| zero949079783 发表于 2021-11-21 16:14 | 显示全部楼层 |阅读模式
本帖最后由 zero949079783 于 2021-11-21 16:32 编辑

开发环境:VSCODE(gcc编译链)+STM32CubeMX(也可以使用HUAWEI-LiteOS-Studio) 。
代码:链接:https://pan.baidu.com/s/1uXfIR0GFQOBZPl1NfQP08w  
提取码:6b0c


1.png
Master  features  主模式特性

I2C Speed Mode: IIC模式设置 快速模式和标准模式。实际上也就是速率的选择。

I2C Clock Speed:I2C传输速率,默认为100KHz

Slave  features  从模式特性

Clock No Stretch Mode: 时钟没有扩展模式

IIC时钟拉伸(Clock stretching)
clock stretching通过将SCL线拉低来暂停一个传输.直到释放SCL线为高电平,传输才继续进行.clock stretching是可选的,实际上大多数从设备不包括SCL驱动,所以它们不能stretch时钟.
Primary Address Length selection: 从设备地址长度 设置从设备的地址是7bit还是10bit 大部分为7bit
-Dual Address Acknowledged: 双地址确认

Primary slave address:  从设备初始地址

stm32f4xx_hal_i2c.c文件:
1、HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout)  //  Checks if target device is ready for communication.


eg:
    //检查设备是否准备好,地址检查,次数超时
    status=HAL_I2C_IsDeviceReady(&hi2c1, ADDRESS_W, 10, HAL_MAX_DELAY);

2、HAL_I2C_StateTypeDef HAL_I2C_GetState(I2C_HandleTypeDef *hi2c)  //Return the I2C handle state. 总线工作状态

eg:        
     //检查总线是否准备好
      flag=HAL_I2C_GetState(&hi2c1);

3、HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)   //Write an amount of data in blocking mode to a specific memory address

eg:
//发送写寄存器命令
HAL_I2C_Mem_Write(&hi2c1, ADDRESS_W, MPU_PWR_MGMT1_REG, 1, &pdata, 1, HAL_MAX_DELAY);

4、HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)  
// Read an amount of data in blocking mode from a specific memory address  MemAddSize 只能填1or2,代表8位或者16位,size代表uint16_t。

eg:
//读取寄存器命令
HAL_I2C_Mem_Read(&hi2c1, ADDRESS_R, MPU_DEVICE_ID_REG, 1, &pdata, 1, HAL_MAX_DELAY);

#define I2C_MEMADD_SIZE_8BIT            0x00000001U  ,上边的1代表的是8bit。
#define I2C_MEMADD_SIZE_16BIT           0x00000010U

HAL库硬件I2C写数据:
A_HAL库硬件IIC写数据.png
  1. /**
  2. * [url=home.php?mod=space&uid=247401]@brief[/url]        AT24C02任意地址写入一个字节
  3. * @param        addr —— 写数据的地址(0-255)
  4. * @param        dat  —— 存放写入数据的地址
  5. * @param             size :数据长度
  6. * @retval        成功 —— HAL_OK
  7. */
  8. uint32_t AT24C02_Write_Data(uint16_t addr,uint8_t dat)
  9. {
  10.     HAL_StatusTypeDef status = HAL_OK;
  11.     status = HAL_I2C_Mem_Write(&hi2c1,AT24C02_READ_ADD,addr,I2C_MEMADD_SIZE_8BIT,&dat,1,100);
  12.     // if(status != HAL_OK)
  13.         // {
  14.         // /* Execute user timeout callback */
  15.         // }

  16.     while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) //总线超时检测
  17.         {
  18.                
  19.         }

  20.     /*****************************************************************
  21.      检查设备是否准备好,地址检查,次数超时 ,必须加入,否则总线会写进去数据  
  22.     *****************************************************************/
  23.     while (HAL_I2C_IsDeviceReady(&hi2c1, AT24C02_READ_ADD, 300, 300) == HAL_TIMEOUT)   
  24.     {

  25.     }

  26.         // /* Wait for the end of the transfer */
  27.         while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)//总线超时检测
  28.         {
  29.                
  30.         }
  31.         return status;
  32. }

HAL库硬件I2C读数据:
A_HAL库硬件IIC读数据.png
  1. /**
  2. * [url=home.php?mod=space&uid=247401]@brief[/url]        AT24C02任意地址读多个字节数据
  3. * @param        addr —— 读数据的地址(0-255)
  4. * @param        read_buf —— 存放读取数据的地址
  5. * @param        size :数据长度
  6. * @retval        成功 —— HAL_OK
  7. */
  8. uint32_t  AT24C02_Read_Byte(uint8_t addr, uint8_t *read_buf,uint16_t size)
  9. {
  10.     HAL_StatusTypeDef status = HAL_OK;
  11.         
  12.         status = HAL_I2C_Mem_Read(&hi2c1,AT24C02_READ_ADD,addr,I2C_MEMADD_SIZE_8BIT,read_buf,size,0xFFFF);

  13.         return status;
  14. }


HAL库模拟IIC写数据:
B_HAL库模拟IIC写数据.png
  1. void AT24C02_Write_Data(uint8_t Addr,uint8_t Data){
  2.         
  3.         /* 第1步:发起I2C总线启动信号 */
  4.         I2C_Start();
  5.         /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
  6.         I2C_Write_Byte(AT24C02_WRITE_ADD);
  7.         /* 第3步:等待ACK */
  8.         I2C_Wirte_Ack();
  9.         /* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */
  10.         I2C_Write_Byte(Addr);
  11.          /* 第5步:等待ACK */
  12.         I2C_Wirte_Ack();
  13.         /* 第6步:开始写入数据 */
  14.         I2C_Write_Byte(Data);
  15.         /* 第7步:发送ACK */
  16.         I2C_Wirte_Ack();
  17.         /* 发送I2C总线停止信号 */
  18.         I2C_Stop();
  19.         delay_ms(5);
  20. }

HAL库模拟IIC读数据:
B_HAL库模拟IIC读数据.png
  1. uint8_t AT24C02_Read_Data(uint8_t Addr)
  2. {
  3.         uint8_t Data;
  4.         /* 第1步:发起I2C总线启动信号 */
  5.         I2C_Start();
  6.          /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
  7.         I2C_Write_Byte(AT24C02_WRITE_ADD);
  8.         /* 第3步:等待ACK */
  9.         I2C_Wirte_Ack();
  10.         /* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */
  11.         I2C_Write_Byte(Addr);
  12.          /* 第5步:等待ACK */
  13.         I2C_Wirte_Ack();
  14.   /* 第6步:重新启动I2C总线。前面的代码的目的向EEPROM传送地址,下面开始读取数据 */
  15.         I2C_Start();
  16.          /* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
  17.         I2C_Write_Byte(AT24C02_READ_ADD);
  18.         /* 第8步:发送ACK */
  19.         I2C_Wirte_Ack();
  20.         
  21.         /* 第9步:读取数据 */
  22.         Data=I2C_Read_Data();
  23.          /* 第10步:发送ACK */
  24.         I2C_Wirte_Ack();
  25.         /* 发送I2C总线停止信号 */
  26.         I2C_Stop();

  27.         return Data;
  28. }


标准库模拟IIC写数据:
C_标准库模拟IIC写数据.png
  1. void AT24C02_Write_Data(uint8_t Addr,uint8_t Data){
  2.         
  3.         /* 第1步:发起I2C总线启动信号 */
  4.         I2C_Start();
  5.         /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
  6.         I2C_Write_Byte(AT24C02_WRITE_ADD);/* 此处是写指令 */
  7.         /* 第3步:发送一个时钟,判断器件是否正确应答 */
  8.         I2C_Wirte_Ack();
  9.         /* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */
  10.         I2C_Write_Byte(Addr);
  11.                 /* 第5步:等待ACK */
  12.         I2C_Wirte_Ack();
  13.         /* 第6步:开始写入数据 */
  14.         I2C_Write_Byte(Data);
  15.         /* 第7步:发送ACK */
  16.         I2C_Wirte_Ack();
  17.         /* 命令执行成功,发送I2C总线停止信号 */
  18.         I2C_Stop();
  19.         //写完入后延时
  20.         delay_ms(5);
  21. }

标准库模拟IIC读数据:
C_标准库模拟IIC读数据.png
  1. uint8_t AT24C02_Read_Data(uint8_t Addr)
  2. {
  3.         uint8_t Data;
  4.         
  5.         /* 第1步:发起I2C总线启动信号 */
  6.         I2C_Start();
  7.         /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
  8.         I2C_Write_Byte(AT24C02_WRITE_ADD);
  9.         /* 第3步:等待ACK */
  10.         I2C_Wirte_Ack();
  11.         /* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */
  12.         I2C_Write_Byte(Addr);
  13.         /* 第5步:等待ACK */
  14.         I2C_Wirte_Ack();

  15.         /* 第6步:重新启动I2C总线。前面的代码的目的向EEPROM传送地址,下面开始读取数据 */
  16.         I2C_Start();
  17.         /* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
  18.         I2C_Write_Byte(AT24C02_READ_ADD);/* 此处是读指令 */
  19.         /* 第8步:发送ACK */
  20.         I2C_Wirte_Ack();
  21.         /* 第9步:读取数据 */
  22.         Data=I2C_Read_Data();
  23.         /* 第8步:发送ACK */
  24.         I2C_Wirte_Ack();
  25.         /* 命令执行成功,发送I2C总线停止信号 */
  26.         I2C_Stop();
  27.         
  28.         
  29.         return Data;
  30. }



标准库硬件IIC写数据:
D_标准库硬件IIC写数据.png
  1. <blockquote>/**


标准库硬件IIC读数据:
D_标准库硬件IIC读数据.png
  1. /**
  2.   * [url=home.php?mod=space&uid=247401]@brief[/url]   I2C读多个字节
  3.         *        @param                device_addr        :设备地址
  4.         * @param           addr :地址
  5.         *        @param    data :数据                     
  6.         *        @param          size :数据长度
  7.   *                [url=home.php?mod=space&uid=2817080]@ARG[/url]
  8.   * @retval
  9.   */
  10. uint32_t I2C_Read_Data(uint8_t device_addr,uint8_t addr,uint8_t *data,uint16_t size){
  11.         
  12.         //第一次起始信号
  13.         I2C_GenerateSTART(I2C1,ENABLE );        //起始信号
  14.         
  15.         TimeOut = I2CTIME; //超时检测时间
  16.         while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT ) == ERROR)         //EV5事件
  17.         {
  18.                 if(TimeOut-- == 0)        // 防卡死 超时检测时间
  19.                 {
  20.                         return 0;
  21.                 }
  22.         }
  23.         
  24.         //EV5事件被检测到,发送设备地址
  25.         I2C_Send7bitAddress(I2C1,device_addr,I2C_Direction_Transmitter);//设备地址,写入模式
  26.         
  27.         TimeOut = I2CTIME; //超时检测时间
  28.         while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR)         //写数据EV6事件
  29.         {
  30.                 if(TimeOut-- == 0)        // 防卡死 超时检测时间
  31.                 {
  32.                         return 0;
  33.                 }
  34.         }
  35.         
  36.         //EV6事件被检测到,发送要操作的存储单元地址
  37.         I2C_SendData(I2C1,addr);         //地址
  38.         
  39.         TimeOut = I2CTIME; //超时检测时间
  40.         while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING) == ERROR)         //写数据EV8事件        
  41.         {
  42.                 if(TimeOut-- == 0)        // 防卡死 超时检测时间
  43.                 {
  44.                         return 0;
  45.                 }
  46.         }
  47.         

  48.         //第二次起始信号
  49.         
  50.         I2C_GenerateSTART(I2C1,ENABLE );        //起始信号
  51.         
  52.         TimeOut = I2CTIME; //超时检测时间
  53.         while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT ) == ERROR)         //EV5事件
  54.         {
  55.                 if(TimeOut-- == 0)        // 防卡死 超时检测时间
  56.                 {
  57.                         return 0;
  58.                 }
  59.         }
  60.         
  61.         //EV5事件被检测到,发送设备地址
  62.         I2C_Send7bitAddress(I2C1,EEPROM_I2C_ADDR,I2C_Direction_Receiver);//读入模式
  63.         
  64.         while(size){
  65.                
  66.                 if(size==1){
  67.                                 
  68.                                 //接收最后一个字节
  69.                                 I2C_AcknowledgeConfig(I2C1,DISABLE);               
  70.                         }
  71.                                 TimeOut = I2CTIME; //超时检测时间
  72.                                 while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED  ) == ERROR)         //读数据EV7事件
  73.                                 {
  74.                                         if(TimeOut-- == 0)        // 防卡死 超时检测时间
  75.                                         {
  76.                                                 return 0;
  77.                                         }
  78.                                 }        
  79.                         
  80.                         //EV7事件被检测到时,数据寄存器有新的有效数据
  81.                         *data = I2C_ReceiveData(I2C1);
  82.                         data++; //下一个数据
  83.                         size--;
  84.                 }
  85.                
  86.                
  87.                         
  88.         //数据传输完成
  89.         I2C_GenerateSTOP(I2C1,ENABLE);
  90.         //I2C_AcknowledgeConfig(I2C1,ENABLE); //重新配置ACK使能,以便下次通讯
  91.         return 1;        
  92. }



1637480658(1).png



  
您需要登录后才可以回帖 登录 | 注册

本版积分规则

33

主题

91

帖子

1

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