当前位置: 首页 > news >正文

AS5600 驱动(HAL库400K硬件IIC+DMA、1MHZ软件IIC)

芯片:Stm32F103C8T6

AS5600读编码器角度主要流程:

   1、先用一次带寄存器地址的 mem_read 把设备的内部地址指针定位到 RAW_ANGLE 的高字节,此次通讯一共五个字节,然后后续只做纯 readSTART + Addr|R + 2 字节 + STOP)就能连续读取角度,省去了每次都写寄存器地址的开销。AS5600资料里明确说明 ANGLE / RAW ANGLE / MAGNITUDE 这些输出寄存器可以“重复读取而不用再写地址;

  2、只做纯 read,此次通讯一共三个字节

    然后就是读编码器的方法了,AS5600最高支持1MHZ的IIC通讯,但是Stm32F103C8T6的IIC最大只有400KHZ,因此我们有HAL库400K硬件IIC阻塞读、HAL库400K硬件IIC+DMA非阻塞读和1MHZ软件IIC阻塞读这几种方法,实测发现HAL库400K硬件IIC阻塞读差不多80-90us,1MHZ软件IIC阻塞读差不多44-48us,而HAL库400K硬件IIC+DMA非阻塞读只需要6-7us左右,因此这里重点介绍DMA读取的方法,关于软件IIC实现可以看下面的代码链接

 完整代码链接:AS5600驱动: 关于AS5600驱动以及软件IIC实现 - Gitee.com

AS5600驱动代码:

.c:
#include "AS5600.h"
#include "arm_math.h"
#include "Soft_IIC.h"
#define abs(x) ((x)>0?(x):-(x))
#define _2PI 6.28318530718f/********************* IIC Adapter *************************/
static int i2cWrite(uint8_t dev_addr, uint8_t *pData, uint32_t count) {int status;int i2c_time_out = I2C_TIME_OUT_BASE + count * I2C_TIME_OUT_BYTE; status = HAL_I2C_Master_Transmit(&AS5600_I2C_HANDLE, (dev_addr<<1), pData, count, i2c_time_out);//status = softi2c_master_write(&g_softi2c, dev_addr, pData, count);return status;
}static int i2cRead(uint8_t dev_addr, uint8_t *pData, uint32_t count) {int status;int i2c_time_out = I2C_TIME_OUT_BASE + count * I2C_TIME_OUT_BYTE;status = HAL_I2C_Master_Receive(&AS5600_I2C_HANDLE, ((dev_addr<<1) | 1), pData, count, i2c_time_out);//status = softi2c_master_read(&g_softi2c, dev_addr, pData, count);return status;
}static inline int i2c_Mem_Read(uint8_t dev_addr, uint8_t *pData, uint32_t count) {int status;int i2c_time_out = I2C_TIME_OUT_BASE + count * I2C_TIME_OUT_BYTE;status = HAL_I2C_Mem_Read(&AS5600_I2C_HANDLE, (dev_addr<<1), AS5600_RAW_ANGLE_REGISTER, I2C_MEMADD_SIZE_8BIT, pData, count, i2c_time_out);//status = softi2c_master_mem_read(&g_softi2c, dev_addr, AS5600_RAW_ANGLE_REGISTER, 1, pData, count);return status;
}/******************* General Function **********************/
static inline int bsp_as5600GetRawAngle(uint16_t *raw_angle) {int ret;uint8_t buffer[2] = {0};
//  uint8_t raw_angle_register = AS5600_RAW_ANGLE_REGISTER;
//  ret = i2cWrite(AS5600_RAW_ADDR, &raw_angle_register, 1);ret = i2cRead(AS5600_RAW_ADDR, buffer, 2);*raw_angle = ((uint16_t)buffer[0] << 8) | (uint16_t)buffer[1];return ret;
}int  bsp_as5600GetAngle(volatile float *Angle) {int ret;uint16_t angle_data;ret =	bsp_as5600GetRawAngle(&angle_data);*Angle = (angle_data / (float)AS5600_RESOLUTION)*_2PI;return ret;
}// Read STATUS register (1 byte)
int AS5600_ReadStatus(uint8_t *status)
{int ret;uint8_t reg = AS5600_STATUS_REGISTER;ret = i2cWrite(AS5600_RAW_ADDR, &reg, 1);if (ret != HAL_OK) return ret;ret = i2cRead(AS5600_RAW_ADDR, status, 1);return ret;
}// Execute BURN_ANGLE (write 0x80 into 0xFF). Caller must ensure MD=1 and hardware power requirements.
// WARNING: irreversible and limited number of times. Check datasheet before using.
int AS5600_BurnAngle(void)
{uint8_t buf[2];int ret;buf[0] = AS5600_BURN_REGISTER;buf[1] = 0x80U; // BURN_ANGLE commandret = i2cWrite(AS5600_RAW_ADDR, buf, 2);if (ret != HAL_OK) return ret;// datasheet recommends waiting a bit and optionally verifying; wait small timeHAL_Delay(5);return HAL_OK;
}//配置AS5600的起始位置(ZPOS)
int bsp_AS5600_SetZero(uint8_t Burn)
{int ret;uint16_t RAWangle, ZPOS_RAWangle; uint8_t buf[3];ret = bsp_as5600GetRawAngle(&RAWangle);if (ret != HAL_OK) return ret;uint8_t msb = (RAWangle >> 8) & 0x0F; // ZPOS(11:8)uint8_t lsb = RAWangle & 0xFF;        // ZPOS(7:0)buf[0] = AS5600_ZPOS11_8_REGISTER; // start registerbuf[1] = msb;buf[2] = lsb;ret = i2cWrite(AS5600_RAW_ADDR, buf, 3);if (ret != HAL_OK) return ret;HAL_Delay(2);/******* Verify *******/uint8_t buffer[2] = {0};uint8_t raw_angle_register = AS5600_ZPOS11_8_REGISTER;ret = i2cWrite(AS5600_RAW_ADDR, &raw_angle_register, 1);ret = i2cRead(AS5600_RAW_ADDR, buffer, 2);ZPOS_RAWangle = ((uint16_t)buffer[0] << 8) | (uint16_t)buffer[1];if((Burn == 1)&&(ret == HAL_OK)&&(ZPOS_RAWangle == RAWangle)){uint8_t status;if (AS5600_ReadStatus(&status) == HAL_OK) {if (status & AS5600_STATUS_MD_MASK) {// magnet detected -> allowed to burn// double-check power, caps, magnet position before calling:ret = AS5600_BurnAngle();} else {// magnet not detected: do not burn}}} return ret;
}/******************* User Function **********************/Encoder_AS5600_t   Encoder_AS5600;void bsp_as5600Init(void) {/* init i2c interface */uint8_t buffer[2] = {0};i2c_Mem_Read(AS5600_RAW_ADDR, buffer, 2);  //先定位到RAWangle寄存器,后续直接iic_read/* init var */Encoder_AS5600.rotation_circles = 0;bsp_as5600GetAngle(&Encoder_AS5600.old_angle);Encoder_AS5600.n_timeout = 4;Encoder_AS5600.dma_transfer_complete = true;
}int bsp_as5600_DMAGetAngle(volatile float *Angle) {HAL_StatusTypeDef st;/*DMA 通讯*/if(Encoder_AS5600.dma_transfer_complete){Encoder_AS5600.DMA_cnt = 0;Encoder_AS5600.dma_transfer_complete = false;st = HAL_I2C_Master_Receive_DMA(&AS5600_I2C_HANDLE, AS5600_READ_ADDR, Encoder_AS5600.DMA_rxbuffer, 2);}else{Encoder_AS5600.DMA_cnt++;}/*DMA 超时判断*/if(Encoder_AS5600.DMA_cnt >= Encoder_AS5600.n_timeout){Encoder_AS5600.DMA_cnt = 0;// 简单复位 I2C 状态(依 HAL 版本而异)__HAL_I2C_DISABLE(&AS5600_I2C_HANDLE);__HAL_I2C_ENABLE(&AS5600_I2C_HANDLE);st = HAL_I2C_Master_Receive_DMA(&AS5600_I2C_HANDLE, AS5600_READ_ADDR, Encoder_AS5600.DMA_rxbuffer, 2);}*Angle = Encoder_AS5600.angle;/*获取编码器角度*/return st;
}// DMA 传输完成回调函数
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
{if (hi2c == &AS5600_I2C_HANDLE) // 确保是我们的 I²C 设备{uint16_t raw_angle = ((uint16_t)Encoder_AS5600.DMA_rxbuffer[0] << 8) | (uint16_t)Encoder_AS5600.DMA_rxbuffer[1];Encoder_AS5600.angle = (raw_angle/(float)AS5600_RESOLUTION)*_2PI;Encoder_AS5600.dma_transfer_complete = true;}
}.h:
#ifndef __BSP_AS5600_H
#define __BSP_AS5600_H#include "i2c.h"
#include <stdbool.h>#define AS5600_I2C_HANDLE hi2c1#define I2C_TIME_OUT_BASE   10
#define I2C_TIME_OUT_BYTE   1/*
注意:AS5600的地址0x36是指的是原始7位设备地址,而ST I2C库中的设备地址是指原始设备地址左移一位得到的设备地址
*/#define AS5600_RAW_ADDR    0x36
#define AS5600_ADDR        (AS5600_RAW_ADDR << 1)
#define AS5600_WRITE_ADDR  (AS5600_RAW_ADDR << 1)
#define AS5600_READ_ADDR   ((AS5600_RAW_ADDR << 1) | 1)#define AS5600_RESOLUTION 4096 //12bit Resolution 
#define AS5600_RAW_ANGLE_REGISTER  0x0C  //only read#define AS5600_STATUS_REGISTER  0x0B               //only read
// Many implementations use 0x20 for MD (bit5). If unsure, confirm with your datasheet revision.
#define AS5600_STATUS_MD_MASK   0x20U#define AS5600_ZPOS11_8_REGISTER 0x01
#define AS5600_ZPOS7_0_REGISTER 0x02#define AS5600_BURN_REGISTER  0xFF               //only write
#define Burn_Angle  0x80
#define Burn_Setting  0x80
//在寄存器0xFF内写入值0x80来执行烧录角度命令。烧录角度命令最多可以执行三次  
//在寄存器0xFF内写入值0x40来执行烧录设置命令。只有在ZPOS和MPOS从未被永久性写入时(ZMCO = 00)才可对MANG进行写入。 烧录设置命令只能被执行一次。 typedef struct {volatile float angle;        volatile float old_angle;float angle_init;   //初始角度float angle_zero_offset;       //机械零点和电气零点偏移量float eleangle;     //根据电机极对数换算的电角度float       Speed_angle_deta;   //速度角度值(计算速度),即两次角度之差float       Speed_RPM;         //电机旋转速度 uint8_t       Move_State;        //电机旋转状态  1为正转 0为反转uint8_t       Sample_Mode;        //采样模式,分为速度采样和位置采样、uint32_t      rotation_circles;   //转过的整圈数  只算一个方向,正转一圈加1,反转一圈减1float         rotation_angle;uint32_t      rotation_circles_absolute;   //转过的整圈数,正反转都增加,为正值float         rotation_angle_absolute;/*** DMA variable***/volatile bool dma_transfer_complete;uint8_t DMA_rxbuffer[2];uint8_t DMA_cnt;                    // 等待DMA获取次数uint8_t n_timeout;                  // 超时阈值(n)}Encoder_AS5600_t;
extern   Encoder_AS5600_t   Encoder_AS5600;#define  AS5600_DEFAULTS {0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,  2,0,0,0,0,0} // 初始化参数int AS5600_ReadAngle_SoftI2C(volatile float *Angle);	void bsp_as5600Init(void);
int bsp_as5600GetRawAngle(uint16_t *raw_angle) ;
int  bsp_as5600GetAngle(volatile float *Angle) ;
int bsp_AS5600_SetZero(uint8_t Burn);int bsp_as5600_DMAGetAngle(volatile float *Angle) ;
#endif /* __BSP_AS5600_H */

我们通过在/********************* IIC Adapter *************************/中可以更换我们的IIC具体实现,/******************* General Function **********************/中就是HAL库IIC阻塞读,/******************* User Function **********************/中就是IIC+DMA非阻塞读

使用示例:

    我们上电先强拖电机到电角度零点,获取电角度偏移量(AS5600也支持写入电角度零点,这里不做具体介绍),然后在main或者自己的foc中断中调用bsp_as5600GetAngle(&Encoder_AS5600.angle);或者bsp_as5600_DMAGetAngle(&Encoder_AS5600.angle);获取AS5600编码器角度即可

void main_user(void)
{.../******* 用户区初始化  **********///SoftI2C_RegisterAndInit(1000000, SystemCoreClock);bsp_as5600Init();//校准传感器与电机零点偏移角度HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3);TIM1->CCR1 = PWM_HalfPerMax * 13/10;  //  A  U   // d轴强拖,形成SVPWM模型中的基础矢量1,即对应转子零度位置TIM1->CCR2 = PWM_HalfPerMax;  //  B  VTIM1->CCR3 = PWM_HalfPerMax;  //  C  WHAL_Delay(200);     float angle_zero_offset;bsp_as5600GetAngle(&angle_zero_offset);Encoder_AS5600.angle_zero_offset = - angle_zero_offset;TIM1->CCR1 = PWM_HalfPerMax;  //  A  U   // 松开电机TIM1->CCR2 = PWM_HalfPerMax;  //  B  VTIM1->CCR3 = PWM_HalfPerMax;  //  C  Wbsp_as5600Init();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */uint32_t previousMillis = 0;const uint32_t interval = 10; // 单位 ms 间隔while (1){// 获取当前的系统时间uint32_t currentMillis = HAL_GetTick();// 检查是否已达到间隔时间if (currentMillis - previousMillis >= interval) {previousMillis = currentMillis;  // 更新上次执行的时间bsp_as5600GetAngle(&Encoder_AS5600.angle);//bsp_as5600_DMAGetAngle(&Encoder_AS5600.angle);}}
}

    上面几种方法都试了一下,开环强拖电机用IIC读AS5600编码器角度,能正常读取,截图如下:

http://www.dtcms.com/a/449573.html

相关文章:

  • Oracle OCP认证考试题目详解082系列第1题
  • 做网站公司是干什么的安徽工程建设信息网实名制查询
  • Java EE初阶启程记12---synchronized 原理
  • 设计模式简要介绍
  • Python 数据结构综合速查:列表 / 字典 / 集合 / 元组对比
  • 宁波建设工程报名网站搭建一个网站的具体步骤
  • 第十七章:遍历万象,步步为营——Iterator的迭代艺术
  • 记一次vcenter server 无法同步主机的故障处理过程
  • 手搓20颗芯片|专栏开篇:从0到1搭建芯片设计与UVM验证体系
  • 《 Linux 点滴漫谈: 三 》Linux 的骨架:文件系统与目录结构的完整图谱
  • 跨境自建站模板库存网站建设公司
  • 【Web安全】转义字符注入?转义也会失效的SQL注入
  • 虚拟机中建设iis网站网站推广洛阳
  • python+vue高校新生报到管理系统设计(源码+文档+调试+基础修改+答疑)
  • 中秋连连看小游戏开发完整教程
  • 产品图案设计网站一起做网店网站入驻收费
  • traffic-filter inbound acl 概念及题目
  • Python3 XML 解析
  • 驾驭涌现的艺术:自组织系统——解锁复杂世界的创新与适应力
  • 青岛做外贸网站建设西安网站建设培训中心
  • 【MES架构师与C#高级工程师(设备控制方向)两大职业路径的技术】
  • MySQL 8.0.26崩溃恢复全解析
  • 北京哪个网站最好湖南网络营销
  • 【Linux】MobaXterm 工具介绍
  • 2025-10-6学习笔记
  • 【面板数据】各国数字服务贸易进出口额数据集(2005-2023年)
  • dede怎么做商城网站个人网站免费制作平台
  • Oracle OCP认证考试题目详解082系列第57题
  • 嵌入式开发学习日志36——stm32之USART串口通信前述
  • Linux中capability权能管理的实现