引言:AS5600为绝对值编码器,其接口有I2C和ADC两种,为配合FOC的10KHZ运行速率,博主使用I2C的DMA模式+高速波特率1MHZ或ADC模拟的方式读取电机电角度,并讲明绝对值编码器在PMSM电机里如何让电角度对齐正确角度,最后用STM32Cubemx和keil5实习代码。

1.I2C的HAL库函数及ADC的HAL库函数

序号 HAL库函数         作用
1  HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);         I2C的DMA模式发送
2  HAL_I2C_Master_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);         I2C的DMA模式接收
3  HAL_I2C_Master_Stop(I2C_HandleTypeDef *hi2c);         停止I2C
解释:
  • DevAddress:I2C 从设备的地址。
  • pData:指向接收数据缓冲区的指针。
  • Size:接收数据的字节数。
  • hi2c:开启的I2C通道号。

2.I2C工作原理

        I2C(Inter-Integrated Circuit)是一种广泛使用的串行通信协议,主要用于在短距离内连接集成电路(IC)之间的通信。I2C协议由飞利浦(Philips)公司在1982年提出,它是一种半双工通信协议,允许多个设备共享同一对信号线进行数据交换。I2C的工作原理基于主从式通信模型。

2.1 硬件线说明

I2C协议的通信由两条主要的信号线构成:

  1. SCL(Serial Clock Line,串行时钟线):用于传输时钟信号,由主设备产生。
  2. SDA(Serial Data Line,串行数据线):用于传输数据,双向通信。

2.2 工作过程

  1. 设备地址:每个连接到I2C总线上的设备都有一个唯一的地址。主设备在发送数据之前会向总线发送目标设备的地址,确保数据发送给正确的设备。

  2. 通信模式:I2C支持两种通信模式:

    • 主设备模式:主设备生成时钟信号并控制数据流。
    • 从设备模式:从设备响应主设备的请求,根据其地址和指令进行通信。
  3. 开始条件(Start Condition):通信开始时,主设备将SDA线从高电平拉低到低电平,同时SCL保持为高电平。这个信号告诉总线上的所有设备,接下来是一个新的通信会话。

  4. 地址传输:主设备发送一个包含目标从设备地址的数据包。地址通常是7位或10位,表示目标设备的唯一身份。传输过程中,第8位表示读写标志(0表示写操作,1表示读操作)。

  5. 数据传输:主设备和从设备通过SDA线传输数据。数据按字节传输,数据的高位在前,低位在后。数据传输时,SCL线会产生时钟脉冲,确保数据同步。

  6. 确认信号(ACK/NACK):每个字节传输后,接收方(主设备或从设备)会发送一个确认信号。如果接收方成功接收数据,它会将SDA拉低表示ACK(Acknowledgment);如果数据有误或没有接收,接收方会发送NACK(No Acknowledgment),表示数据接收失败。

  7. 停止条件(Stop Condition):通信完成后,主设备会发送停止条件,表示此次数据传输结束。停止条件是在SCL线为高电平时,SDA从低电平拉高到高电平。

3.STM32CubeMx配置

按如下图开启I2C即可

4.代码讲解

        I2C的DMA模式读取AS5600编码值

#define PI 3.1415926f
#define Slave_Addr                0x36<<1//设备从地址 
#define Angle_Hight_Register_Addr 0x0C //寄存器高位地址
uint8_t readBuffer[2];
float I2C_AS5600(){
   /*
      angle_d为机械角度,单位:弧度,范围(0 -- 6.28)
      当前I2C模式为DMA模式,波特率1MHZ
    */
    float angle_d;
    int16_t in_angle;   
HAL_I2C_Mem_Read_DMA(&hi2c1,Slave_Addr,Angle_Hight_Register_Addr,I2C_MEMADD_SIZE_8BIT,readBuffer,2);
    in_angle = ((int16_t)readBuffer[0] <<8) | (readBuffer[1]);
    angle_d = (float)in_angle * 2 *PI / 4096;
    return angle_d; 
}

        Justfloat格式串口发送 

load_data[0] = IaU24;
load_data[1] = IaU24;
load_data[2] = IaU24;
load_data[3] = m_theta;
load_data[4] = 0;
memcpy(tempData, (uint8_t *)&load_data, sizeof(load_data));
HAL_UART_Transmit_DMA(&huart3,(uint8_t *)tempData,6*4);

结果:vofa上正常读取机械角度,先正转然后反转,范围是0~6.28

5.Stm32的I2C的死锁BUG

        如果在读着I2C时,AS5600突然不工作了(AS5600和Stm32的BUG,或者突然一个电平波动导致),SDA口和SCL口同时拉高I2C进入空闲状态,Stm32会在读取I2C的标志位时,因I2C已经没信号了,造成进入I2C的死循环

__HAL_I2C_GET_FLAG(hi2c, Flag)总是等于Status导致无限循环。如下代码循环里,或者其他读取I2C标志位的循环里

static HAL_StatusTypeDef I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, FlagStatus Status,
                                                    uint32_t Timeout, uint32_t Tickstart)
{
  while (__HAL_I2C_GET_FLAG(hi2c, Flag) == Status)
  {
    /* Check for the Timeout */
    if (Timeout != HAL_MAX_DELAY)
    {
      if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U))
      {
        hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
        hi2c->State = HAL_I2C_STATE_READY;
        hi2c->Mode = HAL_I2C_MODE_NONE;

        /* Process Unlocked */
        __HAL_UNLOCK(hi2c);
        return HAL_ERROR;
      }
    }
  }
  return HAL_OK;
}
__weak uint32_t HAL_GetTick(void)
{
  return uwTick;
}

解决方式:1.用GPIO的开启关闭模拟I2C通信协议原理,缺点是此方式是阻塞方法,占用计算空间大,没I2C的DMA模式快,不能满足10KHZ的FOC运行条件        2.换个编码器吧,STM32的HAL库I2C通信太烂了

                       


创作不易,感性您的指正与关注

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐