国产化无人机电调:基于 AT32F421G8U7 比较器的 BLDC 无感转速测量方案全解析(上)

引言:无人机电调的 “无感” 革命与 AT32 的适配性

在无人机系统中,电子调速器(ESC)是连接飞控与无刷直流电机(BLDC)的 “桥梁”,其核心任务是精准控制电机转速,直接影响无人机的飞行稳定性、续航与操控响应。传统有感 BLDC 方案需额外安装霍尔传感器或编码器,不仅增加成本与重量,还降低了无人机在恶劣环境(如沙尘、振动)下的可靠性 —— 这也是 “无感 BLDC 方案” 成为主流的核心原因。

无感 BLDC 方案的关键在于无需外部传感器,通过电机自身的电气信号反推转子位置与转速,而 “反电动势过零检测法” 是最成熟、成本最低的无感方案。本文的核心主角 ——AT32F421G8U7(雅特力国产化 32 位 MCU),凭借内置高性价比的比较器模块(文档 3.17 节)、120MHz 主频(文档 2. 规格说明)、宽温工作范围(-40~+105℃,文档 4.4 节),完美适配无人机电调的 “低成本、高实时性、高可靠性” 需求。

本文将从原理到实践,全方位解析如何基于 AT32F421G8U7 的比较器模块实现 BLDC 无感转速测量,涵盖硬件设计、软件实现、工程调试与无人机电调落地,所有内容严格基于DS文档,确保方案的可行性与国产化适配性。

一、原理篇:读懂 BLDC 无感转速测量的 “核心密码”

要掌握比较器方案,需先理清 BLDC 电机的工作逻辑、反电动势的产生机制,以及过零检测与转速计算的内在联系 —— 这是后续硬件 / 软件设计的 “理论基石”。

1.1 BLDC 电机基础:从结构到换相的 “底层逻辑”

BLDC 电机(无刷直流电机)本质是 “电子换向的同步电机”,其核心是通过定子绕组的电流切换,驱动永磁转子旋转。理解以下 3 个核心点,即可掌握 BLDC 的工作原理:

核心概念定义与作用与转速测量的关联
电机结构定子(3 组对称绕组,星形 / 三角形连接)+ 转子(永磁体,N/S 极交替)绕组是反电动势的 “产生源”,转子位置直接决定反电动势的波形相位
换相逻辑需按 “6 步换相法” 切换定子绕组电流(如 U→V→W→U…),每步对应 60° 电角度换相点与反电动势过零点存在固定 30° 电角度差 —— 过零检测的核心就是 “捕捉这个差值,间接定位换相点”
电角度与机械角度电角度 = 机械角度 × 极对数(P);例:4 极电机(P=2),机械转 1 圈 = 720° 电角度转速计算需结合极对数,过零间隔对应的是电角度变化,需转换为机械转速(rpm)

关键结论:BLDC 电机的转子位置与定子绕组的反电动势波形强相关 —— 只要能检测反电动势的 “特征点”(过零点),就能反推转子位置与转速,无需外部传感器。

1.2 反电动势:BLDC 的 “自带位置信号”

当 BLDC 电机旋转时,转子永磁体切割定子绕组,会在绕组两端产生 “反向电压”,即反电动势(Back EMF)。其特性完全匹配无感检测的需求,具体参数如下表:

反电动势特性具体描述对无感检测的意义
波形特性近似正弦波 / 梯形波,与转子转速成正比(转速越高,反电动势峰值越大)过零点位置固定(与转子磁极轴线对齐),可作为 “位置基准”
过零点定义反电动势电压从 “低于零点” 跳变为 “高于零点”(上升沿)或反之(下降沿)的时刻过零点对应转子磁极经过定子绕组轴线的瞬间,是转速计算的 “时间基准点”
与供电电压的关系反电动势峰值 < 电机供电电压(否则电机无法加速)需通过分压电路将反电动势降至 AT32 的安全输入范围(2.4~3.6V,文档 2. 规格说明)
未通电绕组的特性电机运行时,未通电的绕组(悬空绕组)反电动势波形最完整,无电流干扰过零检测需选择 “悬空绕组” 的反电动势 —— 这也是 “6 步换相法” 中过零检测的核心逻辑

通俗比喻:反电动势就像 BLDC 电机的 “呼吸”—— 转子每转一圈,3 相绕组的反电动势就会产生固定次数的 “呼吸起伏”(过零点),通过计数 “起伏间隔”,就能知道电机转得有多快。

1.3 过零检测:从 “电压对比” 到 “转速计算” 的桥梁

无感转速测量的核心是 “检测反电动势过零点”,而实现这一目标的关键工具,就是 AT32F421G8U7 的比较器模块。我们先理清 “过零检测” 的完整逻辑链:

1.3.1 过零检测的核心逻辑:“基准” 与 “信号” 的对比

反电动势本身是 “相对电压”,需一个 “零点基准” 才能判断 “过零”—— 这个基准就是电机中点电压(Vmid)

  • 若电机绕组为星形连接,可直接引出中点,Vmid = 电机供电电压(Vbat)/ 2(如 12V 供电,Vmid=6V);
  • 若电机无中点引出,需通过 “电源分压” 模拟 Vmid(如 2 个等值电阻对 Vbat 分压,再滤波)。

过零检测的本质的是:用比较器将 “反电动势(Vemf)” 与 “零点基准(Vmid)” 进行实时对比,当 Vemf 跨越 Vmid 时,即判定为 “过零时刻”。具体逻辑如下表:

比较器输入输入信号来源比较逻辑过零判定结果
正极输入(INP)BLDC 绕组反电动势(如 A 相)Vemf(INP) > Vmid(INM) → 比较器输出高电平上升沿过零(转子从 N 极→S 极)
负极输入(INM)零点基准电压(Vmid)Vemf(INP) < Vmid(INM) → 比较器输出低电平下降沿过零(转子从 S 极→N 极)
1.3.2 转速计算:从 “时间间隔” 到 “rpm” 的转换

捕捉到过零时刻后,需通过 “时间间隔” 反推转速。核心公式基于 “电机转速与过零间隔成反比” 的关系,具体推导如下:

1.4 AT32F421G8U7 比较器:为何是 “无感方案的最优解”

AT32F421G8U7 内置 1 个轨到轨比较器(COMP)(文档 3.17 节),其特性完美匹配无人机电调的需求 —— 相比 “ADC 采样过零” 方案,比较器方案具有 “实时性高、CPU 占用低、抗干扰强” 的优势。

1.4.1 比较器核心特性(基于文档表 44)

文档 3.17 节明确了比较器的关键参数,这些参数直接决定过零检测的精度与可靠性,需在设计中重点关注:

参数名称取值范围(文档表 44)推荐配置配置理由(无人机电调场景)
供电电压(VDDA)2.4~3.6V3.3V与 AT32 主供电(VDD)一致,避免电压差导致的测量误差(文档 458 页:VDD 与 VDDA 最大差 300mV)
传播延迟(tD)高速模式:40~100ns高速模式电调需快速响应转速变化(≤10ms),高速模式延迟最小,避免过零时刻捕捉偏差
迟滞电压(Vhys)低迟滞:5~17mV低迟滞反电动势过零区域电压变化平缓,低迟滞可提高检测灵敏度;同时避免高迟滞导致的相位偏差
启动时间(tSTART)高速模式:1.0~3.5μs高速模式电机启动时需快速进入过零检测状态,高速模式启动最快,避免启动阶段转速丢失
工作电流(IDDA)高速模式:40~61μA高速模式无人机电调对功耗敏感,高速模式电流仅数十微安,无明显功耗压力
1.4.2 比较器 vs ADC:两种过零方案的对比

为何选择比较器而非 ADC?下表从 “无人机电调需求” 出发,对比两种方案的优劣:

对比维度比较器方案(本文方案)ADC 采样方案结论(无人机电调场景)
实时性硬件比较,延迟 40~100ns(文档表 44)软件采样 + 数据处理,延迟≥10μs比较器更优,满足电调 “毫秒级响应” 需求
CPU 占用仅中断时占用 CPU(记录时刻)需周期性采样 + 滤波 + 过零判断,占用高比较器更优,释放 CPU 处理换相、PID 控制等核心任务
抗干扰能力支持硬件迟滞(5~70mV),抗噪声强需软件滤波,易受高频噪声干扰比较器更优,适应无人机复杂电磁环境
硬件复杂度仅需分压 + 滤波,电路简单需多通道 ADC + 复杂软件算法比较器更优,降低硬件成本与故障率

关键结论:在无人机电调的 “实时性、低功耗、抗干扰” 需求下,AT32F421G8U7 的比较器方案是 “性价比最高的无感选择”。

二、硬件篇:AT32F421G8U7 的 “硬件适配设计”

硬件是方案落地的基础,需严格遵循 AT32F421G8U7 的电气特性(文档 6.3 节)、引脚定义(文档表 5),设计反电动势采集、零点基准、保护电路,确保信号准确、硬件可靠。

2.1 核心引脚定义:AT32 与 BLDC 的 “信号连接”

根据文档表 5(引脚定义),AT32F421G8U7 的 PA0、PA1、PA4、PA5 引脚支持比较器功能,是无感转速测量的 “核心引脚”。需明确每个引脚的功能与硬件连接:

引脚编号引脚名称比较器通道(文档表 5)核心功能硬件连接方式文档依据(关键特性)
PA0GPIOA_0COMP_INP2(正极输入)A 相反电动势采集经分压电路连接 BLDC A 相绕组模拟模式下支持 0~3.3V 输入(文档表 5、6.3.13 节)
PA1GPIOA_1COMP_INP1(负极输入)零点基准电压(Vmid)采集经分压 + 滤波电路连接电机中点或电源分压点模拟模式下无 5V 容忍性,需严格控制电压≤3.3V(文档 393 页)
PA4GPIOA_4COMP_INM4(正极输入)B 相反电动势采集经分压电路连接 BLDC B 相绕组同 PA0,支持模拟输入(文档表 5)
PA5GPIOA_5COMP_INP0(正极输入)C 相反电动势采集经分压电路连接 BLDC C 相绕组同 PA0,支持模拟输入(文档表 5)
NVIC 中断COMP_IRQn-比较器过零中断软件配置 NVIC 优先级,抢占优先级 1(高于普通外设)文档 3.4 节(NVIC 支持 16 级优先级)

关键注意点

  • PA0/PA1/PA4/PA5 必须配置为 “模拟输入模式”(GPIO_MODE_ANALOG),此时引脚无 5V 电平容忍性(文档 393 页注),输入电压不得超过 VDDA+0.3V(即 3.6V),否则会损坏引脚;
  • 比较器的 “正极输入(INP)” 可切换(A→B→C 相),“负极输入(INM)” 固定为 PA1(Vmid),需通过软件实现相位切换(后续软件篇详解)。

2.2 反电动势采集电路:“高压” 转 “安全信号”

BLDC 电机的反电动势峰值通常等于电机供电电压(如 12V、24V),远超 AT32 的 VDDA 范围(2.4~3.6V),需通过分压电路将其降至 0~3.3V,同时保证信号不失真。

2.2.1 分压电路设计原理

分压电路的核心是 “两个串联电阻”,根据欧姆定律,输出电压(Vout)与输入电压(Vin,即反电动势)的关系为:\(Vout = Vin \times \frac{R2}{R1+R2}\) 设计需满足两个核心要求:

  1. 最大 Vout ≤ 3.3V(AT32 安全输入上限);
  2. 分压电阻总阻值适中(10kΩ~16kΩ),避免输入阻抗过低导致反电动势信号衰减(文档 6.3.17 节:比较器输入阻抗较高,无需额外匹配)。
2.2.2 分压电路参数计算(以 12V 电机为例)

假设电机供电电压 Vbat=12V(反电动势峰值≤12V),目标 Vout_max=3.3V,计算电阻参数:

  1. 代入公式:3.3V = 12V × (R2/(R1+R2)) → R1/R2 ≈ 2.63;
  2. 选择 R2=4.7kΩ(精度 1%),则 R1=12kΩ(12/4.7≈2.55,接近 2.63,误差可接受);
  3. 总阻值 R1+R2=16.7kΩ,符合 “10kΩ~16kΩ” 范围,无信号衰减风险。
2.2.3 滤波电路设计:抑制 “高频噪声”

无人机飞行时,电机线会产生高频噪声(如 PWM 开关噪声),若直接输入比较器,会导致 “过零误触发”。需在分压后增加RC 滤波电路,滤除高频噪声。

滤波参数推荐配置设计依据
电容(C)10nF(陶瓷电容)滤除 100kHz 以上高频噪声,且体积小、成本低
电阻(Rf)1kΩ(限流电阻)避免电容充放电电流过大损坏 AT32 引脚,同时辅助滤波
滤波截止频率(fc)≈15.9kHz计算公式:fc=1/(2πRC),15.9kHz 远低于反电动势的基波频率(电机转速 1000rpm 时,基波频率≈50Hz),不影响过零检测
2.2.4 反电动势采集电路示意图与器件选型

电路示意图

plaintext

BLDC A相绕组 → R1(12kΩ,1%) → R2(4.7kΩ,1%) → GND  
                          ↓  
                          Rf(1kΩ) → C(10nF) → GND  
                          ↓  
                          AT32 PA0(COMP_INP2)

器件选型表

器件类型型号推荐参数要求文档依据
分压电阻(R1/R2)0805 封装 12kΩ/4.7kΩ精度 1%(避免温漂导致分压比偏差),功率≥1/16W(实际功耗仅 0.1mW,远低于额定)文档 6.3.13 节(GPIO 输入阻抗要求,避免电阻过小导致电流过大)
滤波电阻(Rf)0805 封装 1kΩ精度 5%,功率≥1/16W无特殊要求,仅需限流、辅助滤波
滤波电容(C)0805 封装 10nFX7R 材质(温漂 ±15%,适应 - 55~+125℃),耐压≥6.3V文档 6.3.12 节(电气敏感性,避免电容失效导致噪声侵入)

2.3 零点基准电路:“精准的电压标尺”

零点基准电压(Vmid)是过零检测的 “标尺”,其稳定性直接决定过零检测的精度。若电机无中点引出,需通过 “电源分压” 模拟 Vmid,设计如下:

2.3.1 基准电路设计原理

模拟 Vmid 的核心是 “对电机供电电压(Vbat)分压”,确保 Vmid=Vbat/2,且电压稳定、无噪声。电路需满足:

  1. 分压电阻精度高(1%),避免温漂导致 Vmid 偏移;
  2. 增加滤波电容,抑制 Vbat 的纹波噪声;
  3. 串联限流电阻,保护 AT32 PA1 引脚。
2.3.2 基准电路参数计算(以 12V 电机为例)

目标 Vmid=6V(Vbat=12V/2),需分压至 AT32 的安全范围(3.3V),因此需 “两级分压”:

  1. 第一级:对 12V 分压至 6V(Vmid1),选择 R3=R4=10kΩ(1%),则 Vmid1=12V×(10k/(10k+10k))=6V;
  2. 第二级:对 6V 分压至 3.3V(Vmid2,输入 AT32 PA1),选择 R5=5.6kΩ、R6=6.8kΩ(1%),则 Vmid2=6V×(6.8k/(5.6k+6.8k))≈3.27V(接近 3.3V,误差≤1%);
  3. 滤波:在 R6 两端并联 100nF 陶瓷电容 + 1μF 钽电容,滤除高低频噪声。
2.3.3 基准电路示意图与器件选型

电路示意图

plaintext

Vbat(12V) → R3(10kΩ) → R4(10kΩ) → GND  
                ↓(Vmid1=6V)  
                R5(5.6kΩ) → R6(6.8kΩ) → GND  
                              ↓(Vmid2≈3.27V)  
                              C1(100nF)→ GND  
                              C2(1μF)→ GND  
                              ↓  
                              AT32 PA1(COMP_INM1)

器件选型表

器件类型型号推荐参数要求文档依据
分压电阻(R3/R4/R5/R6)0805 封装 10kΩ/5.6kΩ/6.8kΩ精度 1%,功率≥1/16W文档 6.3.19 节(温度传感器特性,避免电阻温漂导致 Vmid 偏移)
高频滤波电容(C1)0805 封装 100nFX7R 材质,耐压≥6.3V滤除 Vbat 的高频纹波(如 PWM 开关噪声)
低频滤波电容(C2)0805 封装 1μF钽电容(ESR 低,滤波效果好),耐压≥6.3V滤除 Vbat 的低频纹波(如电池放电导致的电压波动)

2.4 硬件保护电路:“避免意外损坏”

无人机电调工作在高电压、大电流环境,需设计保护电路,避免 AT32 或电机损坏。核心保护措施如下表:

保护类型设计方案器件选型文档依据
过压保护在反电动势分压电路输入端并联 TVS 管SMAJ15CA(15V,双向)文档表 6(绝对最大电压:GPIO 输入电压≤6V(FT 引脚),TVS 管可钳位尖峰电压至 15V 以下)
过流保护在 AT32 引脚串联 100Ω 限流电阻0805 封装 100Ω,1%文档表 7(绝对最大电流:I/O 引脚灌电流≤25mA,限流电阻可避免过流)
静电保护(ESD)PCB 布局时增加 ESD 防护环无器件,PCB 设计实现文档表 31(ESD 绝对最大值:人体模型 6000V,防护环可增强 ESD 能力)
电源去耦在 AT32 VDD/VDDA 引脚旁并联电容100nF 陶瓷电容 + 4.7μF 钽电容文档 4.3.6 节(供电方案图,去耦电容可稳定电源,减少噪声)

2.5 PCB 设计规范:“信号纯净的关键”

PCB 布局不合理会导致噪声侵入、信号衰减,直接影响比较器的过零检测精度。需遵循以下规范,参考文档 6.3.12 节(电气敏感性)、7.7 节(热特性):

PCB 设计项规范要求原因分析
模拟信号布线1. 反电动势采集线(PA0/PA4/PA5)、基准线(PA1)需短而直,长度≤5cm; 2. 线宽≥0.2mm; 3. 远离功率线(如电机相线、PWM 驱动线)≥2mm缩短路径减少信号衰减;远离功率线避免电磁干扰(EMI)
接地设计1. 模拟地(AGND)与数字地(DGND)单点连接; 2. 比较器相关电路的地单独铺铜,再连接至 AGND避免数字地噪声(如 CPU、定时器)干扰模拟信号,确保 Vmid 稳定
电源布线1. VDD/VDDA 线宽≥0.5mm; 2. 去耦电容靠近 AT32 引脚(距离≤3mm)保证供电电流充足,去耦电容快速滤除电源噪声
散热设计1. AT32 芯片下方铺铜(面积≥1cm²); 2. 功率器件(如 MOS 管)单独铺散热铜皮文档 7.7 节(热特性:LQFP48 封装 θJA=87℃/W,铺铜可降低结温,避免高温失效)
防护设计1. 电机接口增加 TVS 管、自恢复保险丝; 2. PCB 边缘增加防护圈避免电机侧的高压、大电流冲击 AT32 电路

三、软件篇:基于 AT32 HAL 库的 “代码实现”

软件是方案的 “灵魂”,需基于 AT32 HAL 库,实现比较器、GPIO、定时器的初始化,以及过零中断捕捉、转速计算。所有代码均标注文档依据,确保配置合规、逻辑正确。

3.1 软件开发环境搭建

首先需搭建适配 AT32F421G8U7 的开发环境,确保编译、下载、调试正常:

工具 / 软件版本 / 型号配置说明
集成开发环境(IDE)Keil MDK 5.38安装 AT32F421 系列器件包(可从雅特力官网下载)
编译器ARM Compiler 6优化等级选择 “-O1”(平衡代码大小与执行速度)
调试器J-Link V11连接 AT32 SWD 接口(PA13=SWDIO,PA14=SWCLK,文档表 5)
固件库AT32F421 HAL 库 V1.0.1基于文档功能开发,确保外设驱动与芯片特性匹配

3.2 全局变量与宏定义:“代码的基础配置”

定义核心参数(如电机极对数、比较器延迟)、状态变量(如过零时刻、转速),确保代码可维护:

c

运行

#include "at32f421_hal.h"

/* -------------------------- 宏定义(基于文档参数) -------------------------- */
#define MOTOR_POLE_PAIRS  2       // 电机极对数(4极电机,文档3.10节转速计算需用到)
#define COMP_DELAY_US     1       // 比较器传播延迟补偿(高速模式≤100ns,近似1μs,文档表44)
#define PHASE_NUM         3       // 电机相数(A/B/C三相)
#define ZERO_CROSS_BUFF   5       // 过零时刻缓存长度(每相5个点,用于滤波)
#define CALC_INTERVAL_MS  10      // 转速计算间隔(10ms,平衡实时性与CPU占用)

/* -------------------------- 相位枚举(代码可读性) -------------------------- */
typedef enum {
    PHASE_A = 0,  // PA0/A相(COMP_INP2)
    PHASE_B,      // PA4/B相(COMP_INM4)
    PHASE_C       // PA5/C相(COMP_INP0)
} Motor_PhaseTypeDef;

/* -------------------------- 全局变量(状态记录) -------------------------- */
COMP_HandleTypeDef hcomp1;                  // 比较器句柄(文档3.17节,仅1个比较器)
TIM_HandleTypeDef htim14;                   // 定时器句柄(TMR14,文档3.10.2节)
Motor_PhaseTypeDef curr_phase = PHASE_A;    // 当前检测相位(初始A相)
uint32_t zero_cross_time[PHASE_NUM][ZERO_CROSS_BUFF] = {0}; // 过零时刻缓存(每相5个点)
uint8_t zero_cross_cnt[PHASE_NUM] = {0};     // 每相过零计数器
float motor_speed_rpm = 0.0f;                // 最终转速(rpm)
uint32_t prev_calc_time = 0;                 // 上一次转速计算时刻(ms)

3.3 核心外设初始化:“硬件功能的激活”

需依次初始化 GPIO(模拟输入)、比较器(过零检测)、定时器(时刻记录),每个初始化函数均严格遵循文档配置要求。

3.3.1 GPIO 初始化(模拟输入模式)

功能:将 PA0/PA1/PA4/PA5 配置为模拟输入,为比较器提供纯净的模拟信号,参考文档 3.15 节(GPIO 特性)、表 5(引脚定义)。

c

运行

/**
  * @brief  GPIO初始化(比较器输入引脚:PA0/A相、PA1/基准、PA4/B相、PA5/C相)
  * @文档依据  3.15节(GPIO模式)、表5(引脚模拟功能)、6.3.13节(GPIO电气特性)
  * @param  无
  * @retval 无
  */
void GPIO_COMP_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* 1. 使能GPIOA时钟(文档3.15节:GPIO时钟需单独使能) */
    __HAL_RCC_GPIOA_CLK_ENABLE();

    /* 2. 配置PA0/PA1/PA4/PA5为模拟输入模式 */
    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;  // 模拟输入模式(比较器需模拟信号)
    GPIO_InitStruct.Pull = GPIO_NOPULL;       // 无上下拉(避免影响输入电平,文档719页)
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

关键配置说明

  • GPIO_MODE_ANALOG:必须配置为模拟模式,才能将引脚信号接入比较器(文档表 5 明确标注这些引脚支持模拟输入);
  • GPIO_NOPULL:模拟输入模式下禁止上下拉,否则会引入额外电流,导致反电动势或基准电压偏移(文档 719 页)。
3.3.2 定时器初始化(TMR14,1μs 计时)

功能:精确记录过零时刻,为转速计算提供时间基准,参考文档 3.10.2 节(TMR14 特性)、表 37(定时器参数)。

c

运行

/**
  * @brief  TMR14初始化(1μs计时,用于过零时刻记录)
  * @文档依据  3.10.2节(TMR14为16位通用定时器)、表37(定时器时钟=2×APB1)、6.3.15节(定时器特性)
  * @param  无
  * @retval 无
  */
void TIM14_Init(void)
{
    TIM_MasterConfigTypeDef sMasterConfig = {0};

    /* 1. 使能TMR14时钟(APB1总线,文档3.10.2节) */
    __HAL_RCC_TIM14_CLK_ENABLE();

    /* 2. TMR14核心配置:1μs计数,最大计数值65535μs(≈65ms) */
    htim14.Instance = TIM14;
    // 分频系数:APB1时钟=120MHz,TIM14时钟=2×APB1=240MHz(文档表37)
    // 240MHz/(239+1)=1MHz → 计数周期=1μs
    htim14.Init.Prescaler = 239;
    htim14.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数
    htim14.Init.Period = 0xFFFF;                 // 最大计数值(65535)
    htim14.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    if (HAL_TIM_Base_Init(&htim14) != HAL_OK)
    {
        Error_Handler(); // 初始化失败,需处理(如复位)
    }

    /* 3. 定时器主模式配置(无触发输出,仅计时) */
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    if (HAL_TIMEx_MasterConfigSynchronization(&htim14, &sMasterConfig) != HAL_OK)
    {
        Error_Handler();
    }

    /* 4. 启动定时器 */
    if (HAL_TIM_Base_Start(&htim14) != HAL_OK)
    {
        Error_Handler();
    }
}

关键配置说明

  • Prescaler = 239:根据文档表 37,APB1 时钟 = 120MHz 时,TIM14 的时钟 = 2×APB1=240MHz,分频后为 1MHz(1μs 计数),确保过零时刻记录精度;
  • Period = 0xFFFF:最大计数值 65535μs,若电机转速过低(如 < 100rpm),过零间隔可能超过 65ms,需在软件中处理定时器溢出(后续转速计算模块详解)。
3.3.3 比较器初始化(COMP1,过零检测)

功能:配置比较器的输入通道、模式、中断,实现反电动势与基准电压的实时比较,参考文档 3.17 节(比较器特性)、表 44(比较器参数)、3.4 节(NVIC 中断)。

c

运行

/**
  * @brief  比较器1初始化(A/B/C相切换+过零中断)
  * @文档依据  3.17节(比较器模式、迟滞、中断)、表44(高速模式参数)、表5(比较器通道)、3.4节(NVIC)
  * @param  无
  * @retval 无
  */
void COMP1_Init(void)
{
    COMP_InitTypeDef COMP_InitStruct = {0};
    COMP_InputConfigTypeDef COMP_InputConfigStruct = {0};

    /* 1. 使能比较器时钟(文档3.17节:COMP时钟需单独使能) */
    __HAL_RCC_COMP_CLK_ENABLE();

    /* 2. 比较器基础配置:高速模式、低迟滞、边沿中断 */
    hcomp1.Instance = COMP1;
    // 模式:高速模式(传播延迟40~100ns,文档表44,满足实时性)
    COMP_InitStruct.Mode = COMP_MODE_HIGH_SPEED;
    // 迟滞:低迟滞(5~17mV,文档表44,提高灵敏度,抑制噪声)
    COMP_InitStruct.Hysteresis = COMP_HYSTERESIS_LOW;
    // 输出极性:非反相(INP>INM时输出高,符合过零逻辑)
    COMP_InitStruct.OutputPolarity = COMP_OUTPUTPOLARITY_NON_INVERTED;
    // 无消隐(无需电机换相消隐,简化逻辑)
    COMP_InitStruct.BlankingSource = COMP_BLANKINGSOURCE_NONE;
    // 关闭窗口模式(仅需单阈值比较)
    COMP_InitStruct.WindowMode = COMP_WINDOWMODE_DISABLE;
    // 中断触发:上升沿+下降沿(捕捉所有过零点)
    COMP_InitStruct.TriggerMode = COMP_TRIGGERMODE_IT_RISING_FALLING;
    if (HAL_COMP_Init(&hcomp1, &COMP_InitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    /* 3. 初始输入通道配置:A相(PA0=INP2)→ 基准(PA1=INM1) */
    COMP_InputConfigStruct.PositiveInput = COMP_POSITIVEINPUT_INP2; // PA0=INP2(文档表5)
    COMP_InputConfigStruct.NegativeInput = COMP_NEGATIVEINPUT_INP1; // PA1=INM1(文档表5)
    if (HAL_COMP_ConfigInput(&hcomp1, &COMP_InputConfigStruct) != HAL_OK)
    {
        Error_Handler();
    }

    /* 4. 使能比较器中断(NVIC配置) */
    // 中断优先级:抢占优先级1,子优先级0(高于普通外设,避免中断丢失)
    HAL_NVIC_SetPriority(COMP_IRQn, 1, 0);
    HAL_NVIC_EnableIRQ(COMP_IRQn);

    /* 5. 启动比较器 */
    if (HAL_COMP_Start(&hcomp1) != HAL_OK)
    {
        Error_Handler();
    }
}

关键配置说明

  • COMP_MODE_HIGH_SPEED:选择高速模式,传播延迟仅 40~100ns(文档表 44),确保过零时刻捕捉无明显延迟;
  • COMP_HYSTERESIS_LOW:低迟滞模式(5~17mV),既能避免噪声导致的误触发,又不会因迟滞过大导致过零相位偏差;
  • COMP_TRIGGERMODE_IT_RISING_FALLING:同时捕捉上升沿和下降沿过零,增加转速计算的采样点,提高精度。

3.4 过零中断服务函数:“捕捉过零时刻的核心”

当比较器检测到反电动势过零时,会触发COMP_IRQHandler中断服务函数。函数需完成 “中断标志清除、过零时刻记录、相位切换” 三大任务,参考文档 3.17 节(比较器中断)、3.4 节(NVIC)。

c

运行

/**
  * @brief  比较器中断服务函数(过零时刻捕捉+相位切换)
  * @文档依据  3.17节(比较器中断标志)、表5(相位通道切换)、3.10.2节(定时器值读取)
  * @param  无
  * @retval 无
  */
void COMP_IRQHandler(void)
{
    COMP_InputConfigTypeDef COMP_InputConfigStruct = {0};
    uint32_t curr_time = 0;

    /* 1. 检查并清除比较器边沿中断标志(避免重复触发) */
    if (__HAL_COMP_GET_FLAG(&hcomp1, COMP_FLAG_EDGE) != RESET)
    {
        __HAL_COMP_CLEAR_FLAG(&hcomp1, COMP_FLAG_EDGE);

        /* 2. 读取当前定时器值(记录过零时刻,单位:μs) */
        curr_time = __HAL_TIM_GET_COUNTER(&htim14);

        /* 3. 记录当前相的过零时刻(循环缓存,覆盖旧数据) */
        if (zero_cross_cnt[curr_phase] < ZERO_CROSS_BUFF)
        {
            zero_cross_time[curr_phase][zero_cross_cnt[curr_phase]] = curr_time;
            zero_cross_cnt[curr_phase]++;
        }
        else
        {
            // 缓存满,循环覆盖(保留最新5个时刻)
            for (uint8_t i = 0; i < ZERO_CROSS_BUFF - 1; i++)
            {
                zero_cross_time[curr_phase][i] = zero_cross_time[curr_phase][i + 1];
            }
            zero_cross_time[curr_phase][ZERO_CROSS_BUFF - 1] = curr_time;
        }

        /* 4. 切换至下一相检测(A→B→C→A循环,文档表5通道配置) */
        curr_phase = (curr_phase + 1) % PHASE_NUM;
        switch (curr_phase)
        {
            case PHASE_A:
                // A相:PA0=COMP_INP2(文档表5)
                COMP_InputConfigStruct.PositiveInput = COMP_POSITIVEINPUT_INP2;
                break;
            case PHASE_B:
                // B相:PA4=COMP_INM4(文档表5)
                COMP_InputConfigStruct.PositiveInput = COMP_POSITIVEINPUT_INM4;
                break;
            case PHASE_C:
                // C相:PA5=COMP_INP0(文档表5)
                COMP_InputConfigStruct.PositiveInput = COMP_POSITIVEINPUT_INP0;
                break;
            default:
                COMP_InputConfigStruct.PositiveInput = COMP_POSITIVEINPUT_INP2;
                break;
        }
        // 基准通道固定:PA1=COMP_INM1(文档表5)
        COMP_InputConfigStruct.NegativeInput = COMP_NEGATIVEINPUT_INP1;
        HAL_COMP_ConfigInput(&hcomp1, &COMP_InputConfigStruct);
    }

    /* 5. HAL库中断处理(必要步骤,确保中断正常) */
    HAL_COMP_IRQHandler(&hcomp1);
}

关键逻辑说明

  • 相位切换:通过COMP_InputConfigStruct.PositiveInput切换比较器的正极输入通道,实现 A→B→C 相的轮流检测,确保电机运行时总有一相是 “悬空绕组”,反电动势波形完整;
  • 循环缓存:保留最新 5 个过零时刻,后续转速计算时可通过 “滑动平均” 滤波,减少单次过零误差的影响。

3.5 转速计算模块:“从时刻到 rpm 的转换”

转速计算的核心是 “处理过零时刻间隔,代入公式计算”,需解决 “定时器溢出、比较器延迟补偿、滤波” 三大问题,参考文档 3.10 节(定时器精度)、3.17 节(比较器延迟)。

c

运行

/**
  * @brief  转速计算(基于A相过零间隔,滑动平均滤波)
  * @文档依据  3.10节(定时器溢出处理)、3.17节(比较器延迟补偿)、6.3.15节(定时器精度)
  * @param  无
  * @retval 无
  */
void Motor_Speed_Calc(void)
{
    uint32_t curr_time_ms = HAL_GetTick(); // 当前系统时间(ms)
    uint32_t delta_t = 0;                  // 过零间隔(μs)
    uint32_t t1 = 0, t2 = 0;               // 相邻过零时刻(μs)
    float avg_delta_t = 0.0f;              // 平均过零间隔(μs)
    uint8_t valid_cnt = 0;                 // 有效过零间隔数量

    /* 1. 每CALC_INTERVAL_MS(10ms)计算一次,避免频繁占用CPU */
    if (curr_time_ms - prev_calc_time < CALC_INTERVAL_MS)
    {
        return;
    }
    prev_calc_time = curr_time_ms;

    /* 2. 检查A相过零数据是否足够(至少2个时刻才能计算间隔) */
    if (zero_cross_cnt[PHASE_A] < 2)
    {
        motor_speed_rpm = 0.0f; // 数据不足,转速为0
        return;
    }

    /* 3. 计算A相相邻过零间隔,处理定时器溢出(65535μs) */
    avg_delta_t = 0.0f;
    valid_cnt = 0;
    for (uint8_t i = 1; i < zero_cross_cnt[PHASE_A]; i++)
    {
        t1 = zero_cross_time[PHASE_A][i - 1];
        t2 = zero_cross_time[PHASE_A][i];

        // 处理定时器溢出:若t2 < t1,说明溢出,间隔=(65536 - t1) + t2
        if (t2 >= t1)
        {
            delta_t = t2 - t1;
        }
        else
        {
            delta_t = (0xFFFF + 1 - t1) + t2;
        }

        /* 4. 过滤异常间隔(排除误触发,如间隔<100μs或>100ms) */
        if (delta_t > 100 && delta_t < 100000)
        {
            // 补偿比较器延迟(文档表44:高速模式≤100ns,近似1μs)
            delta_t += COMP_DELAY_US;
            avg_delta_t += delta_t;
            valid_cnt++;
        }
    }

    /* 5. 计算平均间隔,代入公式计算转速 */
    if (valid_cnt > 0)
    {
        avg_delta_t /= valid_cnt; // 滑动平均,减少误差
        // 转速公式:n = 60×10^6 / (2×P×Δt)
        motor_speed_rpm = (60.0f * 1000000.0f) / (2 * MOTOR_POLE_PAIRS * avg_delta_t);
    }
    else
    {
        motor_speed_rpm = 0.0f; // 无有效间隔,转速为0
    }

    /* 6. 调试:打印转速(需配置USART,文档3.12节) */
    // printf("Motor Speed: %.1f rpm\r\n", motor_speed_rpm);
}

关键处理说明

  • 定时器溢出处理:当 t2 <t1 时,说明定时器已溢出(从 65535 计数到 0),间隔需计算为 “溢出部分 + 当前部分”,避免转速计算错误;
  • 延迟补偿:根据文档表 44,比较器高速模式传播延迟≤100ns,近似补偿 1μs,减少系统误差;
  • 异常过滤:排除过短(<100μs,可能是噪声误触发)或过长(>100ms,可能是电机停转)的间隔,确保转速计算可靠。

3.6 主函数与初始化流程:“代码的入口”

主函数负责 “初始化外设、启动任务、主循环处理”,确保软件流程清晰、稳定运行:

c

运行

/**
  * @brief  主函数
  * @文档依据  1.介绍(需结合HAL库)、3.5节(系统时钟)、各外设初始化依据
  * @param  无
  * @retval int
  */
int main(void)
{
    /* 1. HAL库初始化(初始化定时器、中断控制器等) */
    HAL_Init();

    /* 2. 系统时钟配置(120MHz,文档3.5节时钟树、表27 PLL特性) */
    SystemClock_Config();

    /* 3. 外设初始化(按依赖顺序:GPIO→TIM→COMP) */
    GPIO_COMP_Init();  // GPIO模拟输入初始化
    TIM14_Init();      // 定时器初始化(计时)
    COMP1_Init();      // 比较器初始化(过零检测)

    /* 4. 主循环(持续处理转速计算,可添加其他任务如PID控制) */
    while (1)
    {
        Motor_Speed_Calc(); // 转速计算(每10ms一次)
        // 其他任务:如电机换相控制、转速闭环PID、故障检测等
    }
}

/**
  * @brief  系统时钟配置(120MHz,文档3.5节、表27 PLL特性)
  * @文档依据  3.5节(时钟管理)、表27(PLL输入2~16MHz,输出≤120MHz)、6.3.10节(闪存等待周期)
  * @param  无
  * @retval 无
  */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /* 1. 外部高速时钟(HSE=8MHz,文档3.5节) */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    // PLL配置:HSE为输入(8MHz),倍频15倍→120MHz(表27:PLL_OUT≤120MHz)
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL15;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    /* 2. 总线时钟配置(文档2.规格说明:APB1/APB2最大120MHz) */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 系统时钟=PLL时钟(120MHz)
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;        // HCLK=120MHz
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;         // APB1=120MHz
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;         // APB2=120MHz
    // 闪存等待周期:>96MHz时需3个等待周期(文档6.3.10节,表28)
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
    {
        Error_Handler();
    }
}

/**
  * @brief  错误处理函数(初始化失败时调用)
  * @param  无
  * @retval 无
  */
void Error_Handler(void)
{
    while (1)
    {
        // 错误指示:如点亮LED,方便调试
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_2); // 假设PA2接LED
        HAL_Delay(500);
    }
}

关键配置说明

  • 系统时钟:根据文档表 27(PLL 特性),PLL 输入时钟范围 2~16MHz,输出≤120MHz,选择 HSE=8MHz×15=120MHz,满足 AT32 的最高主频,确保软件实时性;
  • 闪存等待周期:文档 6.3.10 节(表 28)明确,当 HCLK>96MHz 时,闪存需 3 个等待周期,否则会导致代码执行错误,需配置FLASH_LATENCY_3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值