1. 读取AS5048角度数据
任务目标
通过SPI接口读取AS5048磁编码器的14位原始角度值(0~16383),将其转换为0~360.0°的浮点角度,并在终端打印结果以验证数据正确性。本案例使用STM32 HAL库实现主机端SPI通信,AS5048作为从设备。
硬件连接与依赖
- MCU:STM32F407(或其他支持HAL库的STM32系列)
- 传感器:AS5048B(14位磁角编码器,SPI接口)
- 连接:
SCK→PA5,MISO→PA6,MOSI→PA7,CS→PA4(软件控制片选) - 库依赖:STM32CubeMX生成的HAL库,SPI1已配置为模式0(CPOL=0,CPHA=1),时钟分频≤4MHz
关键实现说明
AS5048的SPI帧为16位:前2位为命令/状态位(读取命令为0x3FFF),后14位为数据。主机发送16位命令后,从机在下一个16位时钟周期返回数据。因此每次读取需要连续两次SPI传输:第一次发送读命令并丢弃返回,第二次发送任意值(如0x0000)并接收有效角度数据。片选在每次16位传输之间必须拉高再拉低,以触发从机更新输出寄存器。
完整代码
// main.c 中用户代码区(SPI1已初始化,CS引脚PA4配置为输出)
#include <stdio.h>
#include <math.h>
#define AS5048_CS_LOW() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET)
#define AS5048_CS_HIGH() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)
// 读取AS5048原始角度值(14位)
uint16_t AS5048_ReadAngleRaw(void) {
uint16_t cmd = 0x3FFF; // 读角度寄存器命令
uint16_t rx1 = 0, rx2 = 0;
AS5048_CS_LOW();
HAL_SPI_TransmitReceive(&hspi1, (uint8_t*)&cmd, (uint8_t*)&rx1, 1, 100);
AS5048_CS_HIGH();
// 第二次传输获取实际数据
uint16_t dummy = 0x0000;
AS5048_CS_LOW();
HAL_SPI_TransmitReceive(&hspi1, (uint8_t*)&dummy, (uint8_t*)&rx2, 1, 100);
AS5048_CS_HIGH();
return rx2 & 0x3FFF; // 屏蔽高2位,保留14位数据
}
// 将原始值转换为角度(0~360°)
float AS5048_RawToDegrees(uint16_t raw) {
return (float)raw * 360.0f / 16384.0f;
}
// 主循环中调用示例
int main(void) {
// ... HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_SPI1_Init(); 等初始化代码 ...
while (1) {
uint16_t raw = AS5048_ReadAngleRaw();
float deg = AS5048_RawToDegrees(raw);
printf("Raw: %5u, Angle: %.2f°\n", raw, deg);
HAL_Delay(500); // 每500ms读取一次
}
}
运行与验证
- 使用STM32CubeMX生成工程,配置SPI1为全双工主机,CPOL=Low、CPHA=2Edge(即模式0),预分频使SCK≤4MHz;PA4设为GPIO输出。
- 将代码复制到main.c对应位置,串口重定向至USART1(波特率115200)。
- 编译烧录后,打开串口终端,观察输出。
通过条件:缓慢旋转磁铁(或编码器转轴),串口打印的Raw值在0~16383之间连续变化,Angle值在0.00°~360.00°之间对应变化,且无跳变或卡死。若用手固定磁铁在某位置,多次读取的Raw值波动不超过±3 LSB(对应约±0.07°),则SPI通信与数据转换正确。
常见问题
- 数据始终为0或0x3FFF:检查CS时序是否满足两次传输间拉高;确认SPI模式为CPOL=0/CPHA=1(部分库标注为Mode 1)。
- 角度跳变剧烈:检查SCK频率是否超过4MHz上限,或电源纹波过大(建议在VDD3V3与GND间加100nF去耦电容)。
- 串口无输出:确认printf重定向已实现(使用HAL_UART_Transmit或syscall重写)。