HAL STM32 硬件I2C方式读取AS5600磁编码器获取角度例程
- 📍相关篇《STM32 软件I2C方式读取AS5600磁编码器获取角度例程》
✨stm32使用硬件I2C去读取角度数据,通过STM32CubeMX工具配置工程,读取角度数据,只需要调用一个函数,即可完成数据的读取。了解函数的用法以及从设备地址命令,上手十分快速和简单。
- 📌AS5600资料:
https://pan.baidu.com/s/15UMUH5_ppb2FTju7AJgFyw
📗AS5600寄存器描述
- 📄AS5600寄存器汇总:
- 🌿ZPOS/MPOS/MANG寄存器:这些寄存器用于配置开始位置(ZPOS)和停止位置(MPOS)或最大角度(MANG)。默认范围为全0到360度,但当配置了一个较窄的范围时,输出的全分辨率将自动缩放到所配置的角度范围。角度范围必须大于18度。
- 🌿ANGLE/RAW ANGLE 寄存器(0x0c,0x0d):RAW角度寄存器包含未缩放和未修改的角度。缩放后和过滤后的输出值在角度寄存器中可用。(原始值范围:0 - 4095)
- 🌿ANGLE角度值(0x0e,0x0f):角度值范围:0-360
- 🌿STATUS 状态寄存器:状态寄存器提供指示AS5600的当前状态的位。(当前磁场强度)
- 🌿AGC寄存器:AS5600在一个闭环中使用自动增益控制来补偿由于温度变化、IC和磁体之间的气隙以及磁体退化而引起的磁场强度的变化。AGC寄存器表示增益。对于最健壮的性能,增益值应该在其范围的中心。物理系统的气隙可以被调整以达到这个值。在5V操作中,AGC范围为0-255次。在3.3V模式下,AGC范围减少到0-128个计数。
- 🌿MAGNITUDE寄存器:MAGNITUDE寄存器表示内部CORDIC的幅度值。
- 🌿Burn_Angle命令(ZPOS,MPOS):MCU可以使用BURN_ANGLE命令执行ZPOS和MPOS的永久编程。要执行BURN_ANGLE命令,请将值0x80写入寄存器0xFF。BURN_ANGLE命令最多可以执行3次。ZMCO显示了ZPOS和MPOS被永久写入的多少次。
- 🌿磁场Bz和典型的间隙
典型的间隙在0.5 mm到3 mm之间,这取决于所选的磁铁。一个更大和更强的磁铁允许一个更大的气隙。使用AGC值作为导轨,通过调整磁体与AS5600之间的距离,使AGC值在其范围的中心,可以找到最佳的气隙。当使用直径为6mm的磁铁时,参考磁铁的旋转轴从包装中心的最大允许位移为0.25 mm。
📑功能概要
- 🖍首先对AS5600设备地址进行扫描,并打印设备地址,然后从指定设备的指定寄存器地址读取2个字节数据。
🛠STM32CubeMX工程配置
- 🌿勾选I2C,参数默认即可。
- 🌿使能一路串口,方便查看数据信息。
📙业务代码完善
- 📄main函数内容:
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t Raw_num[2];
// Read angular measurements
uint16_t Angle = 0;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("Scanning I2C bus:\r\n");
HAL_StatusTypeDef result;
uint8_t i;
for (i=1; i<128; i++)
{
/*
* the HAL wants a left aligned i2c address
* &hi2c1 is the handle
* (uint16_t)(i<<1) is the i2c address left aligned
* retries 2
* timeout 2
AS5600 i2c address:(0x6c = 0x36 << 1)
*/
result = HAL_I2C_IsDeviceReady(&hi2c1, (uint16_t)(i<<1), 2, 2);
if (result != HAL_OK) // HAL_ERROR or HAL_BUSY or HAL_TIMEOUT
{
printf("."); // No ACK received at that address
}
if (result == HAL_OK)
{
printf("0x%X", i); // Received an ACK at that address
}
}
printf("\r\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while(1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_I2C_Mem_Read(&hi2c1, AS5600_SLAVE_ADDRESS, addr_in, I2C_MEMADD_SIZE_8BIT, Raw_num, 2,100);
int value = (Raw_num[0]<<8)|Raw_num[1];
Angle = (value * 360)/4096;//换算成角度
printf("Angle = %d degrees.\n", Angle);
HAL_Delay(500);
}
/* USER CODE END 3 */
}
- 🔖或者根据上面的寄存器,直接读取角度寄存器值:
HAL_I2C_Mem_Read(&hi2c1, AS5600_SLAVE_ADDRESS, addr_in, I2C_MEMADD_SIZE_8BIT, 0x0e, 2,100);
- 🌿开启串口打印,在usart.c中添加一下内容:(在调用printf的地方,包含
stdio.h
头文件,Keil option中勾选MicroLib
选项)
#include <stdio.h>
//使用printf()发送数据,需要对printf函数进行重定向,且只能使用USART1。
// 重定向fputc函数,使用printf()发送数据
int fputc(int ch, FILE *f)
{
// 参数1:串口句柄,参数2:要发送的数据;参数3:要发生数据的长度;参数4:超时等待时间
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 100);
return ch;
}
- 🔖串口输出:
-
📚HAL_I2C_Mem_Read(阻塞方式)读取测试工程
- 🔖基于stm32f103
链接:https://pan.baidu.com/s/1aN1n26SNdVSn6Q1CcaKrgg?pwd=48ok
提取码:48ok
📗HAL_I2C_Mem_Read_DMA和HAL_I2C_Mem_Read_IT方式读取数据
- 🔧在STM32CubeMX中,配置I2C时,在DMA选项中,添加
RX
配置:
- 🌿勾选事件中断
- 🔖完成以上参数内容配置后,在工程代码中可以使用
HAL_I2C_Mem_Read_DMA
和HAL_I2C_Mem_Read_IT
函数都可以读取角度原始数据值。
- 🌿添加读I2C设备是否在线函数。(可以省略,默认只查询一次。)
HAL_StatusTypeDef I2C_WaitUntilDeviceReady(I2C_HandleTypeDef *hi2c,uint16_t DevAddress,uint32_t Timeout){
uint32_t tickstart = HAL_GetTick(); //获取当前时间
while(HAL_GetTick()-tickstart <= Timeout){ //如果没有超时就一直尝试
if(HAL_I2C_IsDeviceReady(&hi2c1, DevAddress,1, Timeout) == HAL_OK){ //如果准备好了就return
return HAL_OK;
}
}
return HAL_TIMEOUT; //否则return一个错误
}
- 🌾main函数内容
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t Raw_num[2];
// Read angular measurements
uint16_t Angle = 0;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("Scanning I2C bus:\r\n");
HAL_StatusTypeDef result;
uint8_t i;
for (i=1; i<128; i++)
{
/*
* the HAL wants a left aligned i2c address
* &hi2c1 is the handle
* (uint16_t)(i<<1) is the i2c address left aligned
* retries 2
* timeout 2
AS5600 i2c address:(0x6c = 0x36 << 1)
*/
result = HAL_I2C_IsDeviceReady(&hi2c1, (uint16_t)(i<<1), 2, 2);
if (result != HAL_OK) // HAL_ERROR or HAL_BUSY or HAL_TIMEOUT
{
printf("."); // No ACK received at that address
}
if (result == HAL_OK)
{
printf("0x%X", i); // Received an ACK at that address
}
}
printf("\r\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while(1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(I2C_WaitUntilDeviceReady(&hi2c1,AS5600_SLAVE_ADDRESS, 5)==HAL_OK)//检测设备是否在线,设置5ms超时
HAL_I2C_Mem_Read_DMA(&hi2c1, AS5600_SLAVE_ADDRESS, addr_in, I2C_MEMADD_SIZE_8BIT, Raw_num, 2);
int value = (Raw_num[0]<<8)|Raw_num[1];
Angle = (value * 360)/4096;//换算成角度
printf("Angle = %d degrees.\n", Angle);
HAL_Delay(500);
}
/* USER CODE END 3 */
}