1. 读取原始角度数据
任务目标
通过SPI接口读取AS5048磁编码器的14位原始角度数据(0~16383),并验证通信数据的有效性。本案例使用STM32 HAL库实现主机端读取,适用于任何支持HAL SPI的STM32系列。
硬件连接与依赖
- AS5048与MCU连接:CS→PA4,SCK→PA5,MOSI→PA7,MISO→PA6(以SPI1为例)
- AS5048的CSN引脚需由GPIO控制(非硬件SPI NSS)
- SPI配置:模式1(CPOL=0,CPHA=1),8位数据,主模式,最高速率10MHz
- AS5048供电3.3V,VIO3P3接3.3V
关键实现
AS5048 SPI协议为16位帧:前8位为命令/寄存器地址(最高位为读写标志,1=读),后8位为数据。读取角度寄存器(0x3FFF)时,发送0xFFFF后接收到的16位数据中,高14位为角度值。数据有效性通过第14位(EF,Error Flag)和第15位(OFS,Offset Flag)判断——正常工作时EF=0,OFS=0。
完整代码
// as5048.h
#ifndef AS5048_H
#define AS5048_H
#include "main.h"
#define AS5048_ANGLE_REG 0x3FFF
#define AS5048_ERR_FLAG 0x4000 // bit14
#define AS5048_OFS_FLAG 0x8000 // bit15
typedef struct {
SPI_HandleTypeDef *hspi;
GPIO_TypeDef *cs_port;
uint16_t cs_pin;
uint16_t last_raw_angle;
uint8_t error;
} AS5048_t;
void AS5048_Init(AS5048_t *dev, SPI_HandleTypeDef *hspi,
GPIO_TypeDef *cs_port, uint16_t cs_pin);
uint8_t AS5048_ReadAngle(AS5048_t *dev, uint16_t *angle);
uint8_t AS5048_CheckParity(uint16_t data);
#endif
// as5048.c
#include "as5048.h"
void AS5048_Init(AS5048_t *dev, SPI_HandleTypeDef *hspi,
GPIO_TypeDef *cs_port, uint16_t cs_pin) {
dev->hspi = hspi;
dev->cs_port = cs_port;
dev->cs_pin = cs_pin;
dev->last_raw_angle = 0;
dev->error = 0;
HAL_GPIO_WritePin(cs_port, cs_pin, GPIO_PIN_SET);
}
uint8_t AS5048_CheckParity(uint16_t data) {
uint8_t parity = 0;
for (int i = 0; i < 16; i++) {
if (data & (1 << i)) parity ^= 1;
}
return parity;
}
uint8_t AS5048_ReadAngle(AS5048_t *dev, uint16_t *angle) {
uint8_t tx_data[2] = {0xFF, 0xFF};
uint8_t rx_data[2] = {0, 0};
uint16_t raw = 0;
HAL_GPIO_WritePin(dev->cs_port, dev->cs_pin, GPIO_PIN_RESET);
HAL_Delay(1); // 确保CS建立时间
if (HAL_SPI_TransmitReceive(dev->hspi, tx_data, rx_data, 2, 100) != HAL_OK) {
HAL_GPIO_WritePin(dev->cs_port, dev->cs_pin, GPIO_PIN_SET);
dev->error = 1;
return 0;
}
HAL_GPIO_WritePin(dev->cs_port, dev->cs_pin, GPIO_PIN_SET);
raw = ((uint16_t)rx_data[0] << 8) | rx_data[1];
// 校验:EF位和OFS位必须为0,偶校验必须通过
if (raw & AS5048_ERR_FLAG) {
dev->error = 2; // 磁铁未检测到或信号过弱
return 0;
}
if (raw & AS5048_OFS_FLAG) {
dev->error = 3; // 坐标偏移未完成
return 0;
}
if (AS5048_CheckParity(raw) != 0) {
dev->error = 4; // 奇偶校验失败
return 0;
}
dev->last_raw_angle = raw & 0x3FFF; // 取低14位
*angle = dev->last_raw_angle;
dev->error = 0;
return 1;
}
// main.c 调用示例
AS5048_t encoder;
uint16_t angle = 0;
void setup(void) {
AS5048_Init(&encoder, &hspi1, GPIOA, GPIO_PIN_4);
}
void loop(void) {
if (AS5048_ReadAngle(&encoder, &angle)) {
printf("角度: %u (0~16383)\r\n", angle);
} else {
printf("读取失败, 错误码: %u\r\n", encoder.error);
}
HAL_Delay(100);
}
运行与验证
- 将代码加入STM32CubeMX生成的工程,SPI1配置为模式1、8位、主模式,速率分频后≤10MHz
- 编译下载后,打开串口助手(波特率115200),观察输出
- 通过条件:缓慢旋转磁铁,串口输出的角度值在0~16383之间连续变化,无跳变到65535或错误码输出;当磁铁移开时,程序报错码2(EF位置位)
- 可用逻辑分析仪抓取SPI时序:CS低电平期间应有16个SCK脉冲,MISO上返回0xFFFF格式数据帧
常见问题
- 读回全0或全1:检查SPI模式是否为CPOL=0/CPHA=1,CS引脚是否配置为推挽输出
- 角度跳变:确认磁铁中心与芯片中心对齐,气隙在0.5~3mm内
- 偶校验失败:检查电源纹波,SPI线长建议<10cm,必要时降低SPI速率