4. 多圈角度累积

任务目标

使用AS5048磁编码器实现多圈角度累积。AS5048单圈分辨率为14位(0°~360°),当转子连续旋转超过一圈时,原始角度值会在0°附近发生跳变(如从359.9°跳变到0.1°)。本案例通过检测该跳变方向,累加圈数,输出连续的多圈角度值。

核心原理

设当前读取的原始角度为raw(0~360),上一次角度为prev。定义角度差delta = raw - prev:

  • 若 delta < -180°:说明发生了正向过零(从接近360°跳变到接近0°),圈数turns加1;
  • 若 delta > 180°:说明发生了反向过零(从接近0°跳变到接近360°),圈数turns减1;
  • 否则,未跨零,圈数不变。

连续角度 angle_continuous = turns * 360 + raw。

硬件与依赖

  • STM32F103 开发板(或其他带SPI的MCU),AS5048编码器模块;
  • AS5048 SPI读取函数(本案例提供AS5048_ReadRaw(),返回0~16383的14位原始值);
  • 角度换算:raw_deg = raw * 360.0 / 16384.0。

完整代码

#include <stdint.h>
#include <stdio.h>

// 模拟SPI读取AS5048原始值(14位,0~16383)
// 实际使用时替换为硬件SPI读取函数
uint16_t AS5048_ReadRaw(void);

// 多圈累积器结构
typedef struct {
    float   prev_deg;      // 上一次角度(度)
    int32_t turns;         // 累积圈数
    float   continuous;    // 连续角度输出
    uint8_t initialized;   // 首次读取标志
} MultiTurn_t;

// 初始化累积器
void MultiTurn_Init(MultiTurn_t *mt) {
    mt->prev_deg = 0.0f;
    mt->turns = 0;
    mt->continuous = 0.0f;
    mt->initialized = 0;
}

// 更新累积角度,输入raw为14位原始值
void MultiTurn_Update(MultiTurn_t *mt, uint16_t raw) {
    float deg = (float)raw * 360.0f / 16384.0f;  // 转换为0~360度

    if (!mt->initialized) {
        // 首次读取,无历史跳变
        mt->prev_deg = deg;
        mt->continuous = deg;
        mt->initialized = 1;
        return;
    }

    float delta = deg - mt->prev_deg;

    // 检测过零跳变
    if (delta < -180.0f) {
        mt->turns++;          // 正向过零(359→0)
    } else if (delta > 180.0f) {
        mt->turns--;          // 反向过零(0→359)
    }

    mt->prev_deg = deg;
    mt->continuous = (float)mt->turns * 360.0f + deg;
}

// 使用示例
int main(void) {
    MultiTurn_t mt;
    MultiTurn_Init(&mt);

    // 模拟输入序列:350°→355°→359°→1°→5°(正向旋转跨零)
    uint16_t raw_seq[] = {
        (uint16_t)(350.0f / 360.0f * 16384),
        (uint16_t)(355.0f / 360.0f * 16384),
        (uint16_t)(359.0f / 360.0f * 16384),
        (uint16_t)(1.0f   / 360.0f * 16384),
        (uint16_t)(5.0f   / 360.0f * 16384)
    };

    for (int i = 0; i < 5; i++) {
        MultiTurn_Update(&mt, raw_seq[i]);
        printf("raw=%4d deg=%7.2f  continuous=%9.2f\n",
               raw_seq[i],
               (float)raw_seq[i] * 360.0f / 16384.0f,
               mt.continuous);
    }
    return 0;
}

运行与验证

  1. 将上述代码在STM32工程中编译,AS5048_ReadRaw()替换为实际SPI读取函数(读取14位数据并返回);
  2. 串口输出观察continuous值;
  3. 手动缓慢正向旋转编码器轴超过一圈,观察输出:

预期输出(模拟序列):

raw=15909 deg=350.00  continuous=350.00
raw=16148 deg=355.00  continuous=355.00
raw=16320 deg=359.00  continuous=359.00
raw=45    deg=1.00    continuous=361.00
raw=227   deg=5.00    continuous=365.00

通过条件:当角度从359°跳变到1°时,continuous从359°变为361°(而非1°),说明圈数已正确累加。反向旋转时,continuous应平滑递减(如从5°→359°时变为-1°)。若连续旋转多圈,continuous应始终单调递增/递减,无跳变。

关键说明

  • 跳变阈值设为180°可区分正反向旋转;若电机转速极快导致相邻采样间隔内角度变化超过180°,需提高采样频率;
  • AS5048上电时的初始角度作为0圈基准,累积从该点开始;
  • 若需掉电保存圈数,需配合外部存储或磁极对计数,本案例仅演示运行中的多圈累积。