唐_cWBGTI · 4 天前

【灵动Mini-F5375-OB开发板测评】使用IIC通信读取AS5600磁编码器

首先感谢灵动微电子和极术社区提供免费的开发板。
刚好这段时间我们的电机驱动产品准备更换成国产方案,基于各种原因综合考虑,选择了灵动微电子的MM32F5370系列单片机,项目刚启动,就遇到了此次活动。那必须得冲一波!
运气挺好,通过了活动的审核,拿到了心心念念的开发板。

qq_pic_merged_1748631578559.jpg

既然是为了开发电机驱动,那磁编码器自然不可少。基于我手上的物料储备,选择了AS5600作为电机驱动的位置传感器。

AS5600是一个12位的非接触式磁角度位置传感器,提供I2C数字通信接口,设备地址为0x36。
AS5600.png

首先需要准备以下物料:

  • 灵动Mini-F5375-OB开发板
  • AS5600磁编码器
  • 5*2 磁铁

使用到的单片机外设如下:

  • IIC2(PA4,PA5 复用功能AF20);
  • USART3(PC10,PC11 复用功能AF7);

开始编程

首先需要初始化i2c,代码如下:

void I2C_Configure(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    I2C_InitTypeDef  I2C_InitStruct;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);

    I2C_DeInit(I2C2);

    I2C_StructInit(&I2C_InitStruct);
    I2C_InitStruct.I2C_Mode       = I2C_MODE_MASTER;
    I2C_InitStruct.I2C_OwnAddress = I2C_OWN_ADDRESS;
    I2C_InitStruct.I2C_ClockSpeed = 100000;
    I2C_Init(I2C2, &I2C_InitStruct);

    I2C_TargetAddressConfig(I2C2, 0x36 << 1); // AS5600的地址,注意要移位

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_20);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_20);

    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_4 | GPIO_Pin_5;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
    GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_OD;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    I2C_Cmd(I2C2, ENABLE);
}

然后根据AS5600的读写时序编写AS5600驱动

  • AS5600头文件,申明寄存器地址和接口函数

    #ifndef __AS5600_H
    #define __AS5600_H
    
    #include "i2c/i2c.h"
    typedef union
    {
      uint8_t data8[2];
      uint16_t data16;
    }byte8_to_byte16;
    
    typedef enum
    {
    _zmco = 0x00,
    _zpos_h = 0x01,
    _zpos_l = 0x02,
    _mpos_h = 0x03,
    _mpos_l = 0x04,
    _mang_h = 0x05,
    _mang_l = 0x06,
    _conf_h = 0x07,    
    _conf_l = 0x08,
    _raw_ang_h = 0x0c,
    _raw_ang_l = 0x0d,
    _ang_h = 0x0e,
    _ang_l = 0x0f,
    _stat = 0x0b,
    _agc = 0x1a,
    _mag_h = 0x1b,
    _mag_l = 0x1c,
    _burn = 0xff
    }as5600_registers_t;
    
    uint16_t read_raw_angle(void);
    uint8_t detect_magnet(void);
  • AS5600源文件,实现读写逻辑

    #include "as5600.h"
    
    uint8_t read_one_byte(uint8_t reg_addr)
    {
      uint8_t data = 0;
      I2C_SendData(I2C2, reg_addr);
      while(RESET == I2C_GetFlagStatus(I2C2, I2C_STATUS_FLAG_TFE))
      {
      }
      I2C_ReadCmd(I2C2);
      while (RESET == I2C_GetFlagStatus(I2C2, I2C_STATUS_FLAG_RFNE))
      {
      }
      data = I2C_ReceiveData(I2C2);
      return data;
    }
    
    byte8_to_byte16 buff;
    uint16_t read_raw_angle(void)
    {    
      buff.data8[1] = read_one_byte(0x0C);
      buff.data8[0] = read_one_byte(0x0D);
      return buff.data16;
    }
    
    uint8_t detect_magnet(void)
    {
      uint8_t ret_val;
      ret_val = read_one_byte(_stat);
      if(ret_val & 0x20)
      {
          ret_val = 1;
      }else
      {
          ret_val = 0;
      }    
      return ret_val;
    }

    接下来就是主函数部分:

    读取磁铁检测寄存器,读取角度信息,通过串口打印到串口助手。

    int main(void)
    {
      uint16_t raw_angle = 0;
      float angle = 0.0f;
      PLATFORM_Init();
    
      printf("\r\nTest %s", __FUNCTION__);
    
      I2C_Configure();
    
      while (1)
      {
          raw_angle = read_raw_angle();
          angle = raw_angle * _PI / 2048;
          printf("as5600:%d, %d, %f\n", detect_magnet(), raw_angle, angle);
          PLATFORM_LED_Toggle(LED1);
          PLATFORM_DelayMS(10);
      }
    }

    结果如下:

    编码器数据.png

由于手动转动的磁铁,所以位置曲线看起来并不是很均匀。

总结

以上内容都是基于MM32的例程修改,库函数使用起来还是十分方便的,但是由于粗心还是小小折磨了一下。

例程中串口打印功能配的是串口1,对应的时钟配置代码如下:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

开发板的串口调试对应的串口为串口3,我修改后的代码如下:

RCC_APB2PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);

细心的小伙伴一定知道是什么原因。
!!!简直造孽啊!!!
代码自取:MM32F5375-AS5600
————————————————————————————————
以上就是此次使用IIC读取AS5600磁编码器的全部内容。

推荐阅读
关注数
0
文章数
1
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息