1/*!2 \file hall_encoder.h3 \brief 三路 120° 线性霍尔径向磁铁角度解算4*/56#ifndef HALL_ENCODER_H7#define HALL_ENCODER_H89#include <stdint.h>1011/*!12 机械安装约定,从上往下看、逆时针为正:13 - U1 / PA0 / ADC_IN0 放在 0°14 - U2 / PA1 / ADC_IN1 放在 120°15 - U4 / PA4 / ADC_IN4 放在 240°16 径向充磁磁铁的转角为 θ 时,三路输出交流分量是 cos(θ)、cos(θ-120°)、cos(θ-240°)。17 相位顺序和 PCB 不一致时,只改下面三个下标。转动方向反了就把 HALL_ANGLE_SIGN 改成 -1。18*/19#define HALL_PHASE_0_DEG 020#define HALL_PHASE_120_DEG 121#define HALL_PHASE_240_DEG 222#define HALL_ANGLE_SIGN 12324/*! 低于该峰值(ADC 计数)认为磁场太弱,角度只作参考 */25#define HALL_AMP_WEAK 802627/*! 校准结束时,任一路峰峰值低于该计数就认为没有转满一圈 */28#define HALL_CAL_SPAN_MIN 4002930/*! Q12 增益,4096 表示 1.0 倍 */31#define HALL_CAL_GAIN_ONE 4096U3233#define HALL_CAL_OK 0U34#define HALL_CAL_IDLE 1U35#define HALL_CAL_WEAK 2U3637#define HALL_FLAG_WEAK 0x01U38#define HALL_FLAG_CAL_VALID 0x02U39#define HALL_FLAG_CAL_RUN 0x04U40#define HALL_FLAG_OUT 0x08U4142/*!43 \brief 一次采样结果44*/45typedef struct {46 uint16_t raw[3]; /*!< U1、U2、U4 的 12 位 ADC 原码 */47 int32_t angle_cdeg; /*!< 0..35999,单位 0.01°,已减去机械零点 */48 int32_t amplitude; /*!< 单路交流峰值,单位 ADC 计数 */49} hall_sample_t;5051/*!52 \brief 三路偏置和相对增益53 偏置是一圈里的 (min+max)/2。增益以 U1 的峰峰值为基准,Q12。54*/55typedef struct {56 int16_t offset[3];57 uint16_t gain_q12[3];58 uint8_t valid;59} hall_cal_t;6061/*!62 \brief 配置 PA0/PA1/PA4 为模拟输入,并启动扫描 + DMA63 \param[in] none64 \param[out] none65 \retval none66*/67void hall_encoder_init(void);6869/*!70 \brief 读取最近一组三路转换,并解算角度71 \param[out] sample: 原码、角度和幅度72 \retval none73*/74void hall_encoder_read(hall_sample_t *sample);7576/*!77 \brief 复制最近一组三路 ADC 原码,不更新角度校准78 \param[out] raw: U1、U2、U4,各 12 位79 \retval none80*/81void hall_encoder_copy_raw(uint16_t raw[3]);8283/*!84 \brief 弱磁、校准有效、正在校准85 \param[in] sample: 最近一次解算86 \retval HALL_FLAG_* 的组合87*/88uint8_t hall_encoder_flags(const hall_sample_t *sample);8990/*!91 \brief 装入已保存的校准,valid 为 0 时恢复成三路平均值92 \param[in] cal: 偏置和增益93 \param[out] none94 \retval none95*/96void hall_encoder_cal_apply(const hall_cal_t *cal);9798/*!99 \brief 读出当前校准100 \param[out] cal: 偏置、增益和是否有效101 \retval none102*/103void hall_encoder_cal_get(hall_cal_t *cal);104105/*!106 \brief 开始记录三路最小/最大,转满一圈后再结束107 \param[in] none108 \param[out] none109 \retval none110*/111void hall_encoder_cal_begin(void);112113/*!114 \brief 用记录到的峰峰值生成偏置和增益115 \param[in] none116 \param[out] none117 \retval HALL_CAL_OK、HALL_CAL_IDLE 或 HALL_CAL_WEAK118*/119uint8_t hall_encoder_cal_finish(void);120121/*!122 \brief 丢掉校准,回到三路平均值123 \param[in] none124 \param[out] none125 \retval none126*/127void hall_encoder_cal_clear(void);128129/*!130 \brief 设置要从原始角度里减掉的机械零点131 \param[in] zero_cdeg: 0..35999132 \param[out] none133 \retval none134*/135void hall_encoder_zero_set(uint16_t zero_cdeg);136137/*!138 \brief 当前机械零点139 \param[in] none140 \param[out] none141 \retval 0..35999,单位 0.01°142*/143uint16_t hall_encoder_zero_get(void);144145/*!146 \brief 把此刻的角度记成 0°147 \param[in] none148 \param[out] none149 \retval none150*/151void hall_encoder_zero_capture(void);152153#endif /* HALL_ENCODER_H */