【STM32+HAL】I2C+DMA读取AS5600编码器

一、DMA的应用

有关更多DMA的应用,详见【STM32+HAL】DMA应用

二、HAL库配置

1、开启I2C

开启对应DMA及中断

2、开启串口通信

至此,HAL库配置完毕

三、DMA版(高效但不稳定)

1、as5600.c
cpp 复制代码
#include "AS5600.h"
#include "math.h"



float angle_prev=0;
int full_rotations=0; // full rotation tracking;
uint8_t data[2]={0};

float x1;
float x2;

//发送单字节时序
void AS5600_Write_Reg(uint16_t reg, unsigned char value)
{
	HAL_I2C_Mem_Write(&hi2c1, AS5600_ADDRESS, reg, I2C_MEMADD_SIZE_8BIT, &value, 1, 50);
}


//发送多字节时序
void AS5600_Write_Regs(uint16_t reg, unsigned char *value, unsigned char len)
{
	HAL_I2C_Mem_Write(&hi2c1, AS5600_ADDRESS, reg, I2C_MEMADD_SIZE_8BIT, value, len, 50);
}



//IIC读多字节
void AS5600_Read_DMA(uint8_t regAddress, uint8_t* pData, uint16_t Size) {
    // 启动I2C DMA接收
    if (HAL_I2C_Mem_Read_DMA(&hi2c1, AS5600_ADDRESS, regAddress, I2C_MEMADD_SIZE_8BIT, pData, Size) != HAL_OK) {
        // 错误处理,例如打印错误信息
        printf("I2C DMA read failed\r\n");
    }
}





//得到弧度制的角度,范围在0-6.28
float GetAngle_Without_Track(void)
{
	float angle_d;
	int16_t in_angle;
//	AS5600_Read_DMA( Angle_Hight_Register_Addr, data, DATA_SIZE);
	in_angle = ((int16_t)data[0] <<8) | (data[1]);
	angle_d = (float)in_angle * (2.0f*PI) / 4096;
	return angle_d;
	//angle_d为弧度制,范围在0-6.28
}




//得到弧度制的带圈数角度
float GetAngle(void)
{
    float val = GetAngle_Without_Track();
    float d_angle = val - angle_prev;
    //计算旋转的总圈数
    //通过判断角度变化是否大于80%的一圈(0.8f*6.28318530718f)来判断是否发生了溢出
		//如果发生了,则将full_rotations增加1(如果d_angle小于0)或减少1(如果d_angle大于0)。
    if(fabs(d_angle) > (0.8f*2.0f*PI) ) full_rotations += ( d_angle > 0 ) ? -1 : 1;
    angle_prev = val;
    return (float)full_rotations * 2.0f * PI + angle_prev;
}


// DMA传输完成回调函数
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c) {
    if (hi2c->Instance == I2C1) {
		x1=GetAngle_Without_Track();
		x2=GetAngle();

	// 重新启动DMA接收以实现连续读取
		AS5600_Read_DMA( Angle_Hight_Register_Addr, data, DATA_SIZE);
    }
}
2、main.c
cpp 复制代码
/* USER CODE BEGIN Includes */
#include "AS5600.h"
#include "stdio.h"
/* USER CODE END Includes */

/* USER CODE BEGIN PV */
extern uint8_t data[2];

extern float x1;
extern float x2;
/* USER CODE END PV */

  /* USER CODE BEGIN 2 */
	printf("Hello World\r\n");
	HAL_Delay(500);
	AS5600_Read_DMA(Angle_Hight_Register_Addr, data, DATA_SIZE);  // 启动I2C DMA接收
  /* USER CODE END 2 */


  /* USER CODE BEGIN WHILE */
  while (1)
  {
		printf("degree:%.4f\r\n",x1);
        printf("circle:%.4f\r\n",x2);
		HAL_Delay(50);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

四、不用DMA版(低效率但稳定)

1、AS5600.c
cpp 复制代码
#include "AS5600.h"
#include "math.h"



float angle_prev=0; 
int full_rotations=0; // full rotation tracking;
float angle_d;				//GetAngle_Without_Track()的返回值
float angle_cd;				//GetAngle()的返回值


//发送单字节时序
void AS5600_Write_Reg(uint16_t reg, uint8_t *value)
{
	HAL_I2C_Mem_Write(&hi2c1, AS5600_ADDRESS, reg, I2C_MEMADD_SIZE_8BIT, value, 1, 50);
}


//发送多字节时序
void AS5600_Write_Regs(uint16_t reg, uint8_t *value, uint8_t len)
{
	HAL_I2C_Mem_Write(&hi2c1, AS5600_ADDRESS, reg, I2C_MEMADD_SIZE_8BIT, value, len, 50);
}


//IIC读多字节
void AS5600_Read_Reg(uint16_t reg, uint8_t* buf, uint8_t len)
{
	HAL_I2C_Mem_Read(&hi2c1, AS5600_ADDRESS, reg, I2C_MEMADD_SIZE_8BIT, buf, len, 50);
}




//得到弧度制的角度,范围在0-6.28
float GetAngle_Without_Track(void)
{   
	int16_t in_angle;
	uint8_t temp[DATA_SIZE]={0};
	AS5600_Read_Reg( Angle_Hight_Register_Addr, temp, DATA_SIZE);
	in_angle = ((int16_t)temp[0] <<8) | (temp[1]);
	
	angle_d = (float)in_angle * (2.0f*PI) / 4096;
//angle_d为弧度制,范围在0-6.28	
	return angle_d;
}




//得到弧度制的带圈数角度
float GetAngle(void)
{
    float val = angle_d;
    float d_angle = val - angle_prev;
    //计算旋转的总圈数
    //通过判断角度变化是否大于80%的一圈(0.8f*6.28318530718f)来判断是否发生了溢出,如果发生了,则将full_rotations增加1(如果d_angle小于0)或减少1(如果d_angle大于0)。
    if(fabs(d_angle) > (0.8f*2.0f*PI) ) full_rotations += ( d_angle > 0 ) ? -1 : 1; 
    angle_prev = val;
	
		angle_cd = full_rotations * (2.0f*PI) + angle_prev;
	return angle_cd;
//    return (float)full_rotations * 6.28318530718f + angle_prev;
}



void Track(void)
{
	GetAngle_Without_Track();
	GetAngle();
}
2、main.c
cpp 复制代码
/* USER CODE BEGIN PV */
extern uint8_t data[2];

extern float angle_d;				//GetAngle_Without_Track()的返回值
extern float angle_cd;				//GetAngle()的返回值
/* USER CODE END PV */

  /* USER CODE BEGIN WHILE */
  while (1)
  {
		Track();
		printf("%.3f   %.3f\r\n",angle_d,angle_cd);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

五、巨人之肩

STM32 HAL库 AS5600编码器程序

六、源码提供

资源【STM32+HAL】I2C+DMA读取AS5600编码器

【STM32+HAL】I2C读取AS5600编码器【不加DMA版本】

相关推荐
DIY机器人工房3 小时前
【科普】STM32CubeMX是配置工具,STM32CubeIDE是集成开发环境,二者互补但定位不同,前者负责初始化配置,后者专注代码开发调试。
单片机·嵌入式硬件·嵌入式·diy机器人工房
努力做小白4 小时前
Linux驱动20 --- FFMPEG视频API
linux·驱动开发·单片机·嵌入式硬件·ffmpeg·lvgl
得单片机的运12 小时前
STM32的蓝牙通讯(HAL库)
stm32·单片机·嵌入式硬件·蓝牙
国科安芯13 小时前
抗辐照芯片在低轨卫星星座CAN总线通讯及供电系统的应用探讨
运维·网络·人工智能·单片机·自动化
weixin_4526006914 小时前
GC8872刷式直流电机驱动器详解:3.6A驱动能力与PWM控制
stm32·单片机·嵌入式硬件·智能家居·音响·电动工具
Despacito0o17 小时前
STM32 I2C通信完整教程:从协议原理到硬件实现
stm32·单片机·嵌入式硬件
你好,奋斗者!18 小时前
小电流驱动大电流:原理、实现方式与应用前景
stm32·单片机·嵌入式硬件·电路设计
XINVRY-FPGA21 小时前
XCZU4EV-1FBVB900E Xilinx FPGA AMD Zynq UltraScale+ MPSoC EV(Embedded Vision)
arm开发·嵌入式硬件·计算机视觉·fpga开发·硬件架构·硬件工程·fpga
猫猫的小茶馆21 小时前
【STM32】FreeRTOS 任务的删除(三)
java·linux·stm32·单片机·嵌入式硬件·mcu·51单片机
学不动CV了21 小时前
单片机ADC采集机理层面详细分析(二)
c语言·arm开发·stm32·单片机·嵌入式硬件·开源·51单片机