前言
电子调速器(ESC)作为无人机动力系统的核心组件,负责将飞控指令转换为精确的电机转速控制,其性能直接影响无人机的飞行稳定性、响应速度和安全性。随着多旋翼无人机向高速、重载、长航时方向发展,对电调的电流输出能力、控制精度和可靠性提出了更高要求。
AT32M412 系列微控制器是雅特力科技推出的专为电机控制优化的高性能处理器,基于 ARM Cortex-M4 内核,集成了丰富的电机控制外设和强大的运算能力,非常适合 80A 级大功率电调应用。本文将从硬件设计、算法理论到软件实现,全面解析基于 AT32M412 的 80A 无人机电调开发全过程,为工程师提供完整的技术参考。
一、AT32M412 微控制器技术特性
AT32M412 系列微控制器是针对中高端电机控制场景设计的高性能处理器,其核心特性完美匹配电调应用需求:
1.1 核心性能参数
| 特性 | 具体参数 | 电调应用优势 |
|---|---|---|
| 内核 | ARM Cortex-M4,带 FPU | 支持单精度浮点运算,加速 PID 算法计算 |
| 工作频率 | 最高 120MHz | 提供足够算力处理复杂控制算法 |
| 闪存容量 | 64KB-256KB | 可存储完整的控制程序和参数 |
| SRAM 容量 | 16KB-64KB | 满足实时数据处理需求 |
| 电源电压 | 2.5V-3.6V | 兼容无人机常用 3.3V 电源系统 |
| 工作温度 | -40℃-85℃ | 适应恶劣的户外飞行环境 |
| 封装形式 | LQFP48/LQFP64 | 小尺寸设计,适合电调紧凑布局 |
1.2 电机控制相关外设
| 外设 | 配置 | 电调应用价值 |
|---|---|---|
| 定时器 | 2 个高级定时器(TIM1/TIM8) 4 个通用定时器(TIM2-TIM5) 2 个基本定时器(TIM6-TIM7) | 高级定时器可生成互补 PWM 信号,支持死区控制,适合三相电机驱动 |
| ADC | 12 位分辨率,16 通道 采样率最高 1Msps 支持规则和注入转换 | 可同时采集三相电流、电池电压和温度等关键参数 |
| 通信接口 | 3 个 SPI 接口 4 个 UART 接口 1 个 CAN FD 控制器 | 支持 DSHOT、CAN 等多种无人机通信协议 |
| GPIO | 最多 58 个通用 I/O 口 支持多种触发模式 | 满足传感器连接和外设控制需求 |
| DMA | 6 通道 DMA 控制器 | 支持 ADC、定时器等外设的数据传输,降低 CPU 负载 |
1.3 与同类产品对比
| 特性 | AT32M412 | STM32F401 | GD32F450 |
|---|---|---|---|
| 核心频率 | 120MHz | 84MHz | 168MHz |
| 浮点单元 | 有 | 有 | 有 |
| 高级定时器 | 2 个 | 1 个 | 2 个 |
| CAN FD | 支持 | 不支持 | 支持 |
| 价格 | 中等 | 较高 | 中等 |
| 供货稳定性 | 良好 | 一般 | 良好 |
AT32M412 在性能、外设配置和成本之间取得了良好平衡,特别是其丰富的定时器资源和 CAN FD 支持,使其成为 80A 电调设计的理想选择。
二、硬件电路设计
80A 电调硬件系统主要由电源管理、功率驱动、信号检测、微控制器和通信接口五大模块组成,各模块协同工作实现电机的精确控制和状态监测。
2.1 系统总体架构
电调硬件系统架构采用分层设计,从功率处理到信号控制形成完整闭环:
电池输入(11.1-25.2V) → 电源模块 → 3.3V/5V供电
↓
功率驱动模块(三相全桥) ← 栅极驱动 ← 微控制器PWM输出
↓
电机 ← 相电流检测 → ADC采样 → 电流环控制
↓
飞控 ← CAN/DSHOT → 通信接口 → 速度环控制
2.2 电源电路设计
电源模块负责将锂电池电压转换为系统所需的各种工作电压,同时提供必要的保护功能。
2.2.1 电源架构
80A 电调电源系统采用多级转换架构:
| 电源类型 | 输入电压 | 输出电压 | 输出电流 | 主要负载 | 转换芯片 |
|---|---|---|---|---|---|
| 主电源 | 11.1-25.2V | 11.1-25.2V | 最大 80A | 电机 | 无(直接供电) |
| 驱动电源 | 11.1-25.2V | 12V | 1A | 栅极驱动芯片 | MP2307 |
| 逻辑电源 | 12V | 5V | 500mA | 电平转换、传感器 | LM1117-5.0 |
| 核心电源 | 5V | 3.3V | 300mA | 微控制器、外设 | LM1117-3.3 |
2.2.2 电源保护电路
为提高电源系统可靠性,设计了多重保护机制:
- 反接保护:采用 PMOS 管(如 AO4407)设计反接保护电路,当电源反接时自动切断供电
- 过压保护:使用电压比较器(如 LM393)监测输入电压,超过 26V 时关断输出
- 过流保护:在主功率路径串联 0.005Ω 采样电阻,监测电流超过 100A 时触发保护
- ** surge 保护 **:输入端并联 TVS 管(如 SMBJ33A),吸收电压尖峰
2.2.3 电源电路原理图
[锂电池] → [反接保护] → [保险丝] → [TVS管] →
├→ [MP2307] → 12V → [LM1117-5.0] → 5V → [LM1117-3.3] → 3.3V
└→ [功率驱动电路]
关键元件参数选择:
| 元件 | 型号 | 参数 | 作用 |
|---|---|---|---|
| U1 | MP2307 | 输入 4.5-26V,输出 12V/1A | 12V 电源转换 |
| U2 | LM1117-5.0 | 输入 4.75-12V,输出 5V/800mA | 5V 电源转换 |
| U3 | LM1117-3.3 | 输入 3-15V,输出 3.3V/800mA | 3.3V 电源转换 |
| Q1 | AO4407 | P 沟道 MOSFET,30V/6.5A | 反接保护 |
| D1 | SMBJ33A | 33V TVS 管,峰值电流 40A | 浪涌保护 |
| F1 | 100A 自恢复保险丝 | 触发电流 100A | 过流保护 |
| C1-C4 | 100uF/50V 电解电容 | 输入输出滤波 | 稳定电压 |
| C5-C8 | 0.1uF 陶瓷电容 | 高频滤波 | 抑制噪声 |
2.3 功率驱动电路设计
功率驱动模块是电调的核心,负责将微控制器输出的 PWM 信号转换为驱动电机的大功率电流。
2.3.1 拓扑结构选择
80A 电调采用三相全桥拓扑结构,由 6 个 MOSFET 组成,实现电机三相绕组的电流换向:
VBAT
↑
Q1 ──┼── Q4
│
Q2 ──┼── Q5
│
Q3 ──┼── Q6
↓
GND
其中 Q1-Q3 为上桥臂 MOSFET,Q4-Q6 为下桥臂 MOSFET,通过控制不同 MOSFET 的导通与关断,实现电机的正反转和转速控制。
2.3.2 MOSFET 选型
针对 80A 持续电流、150A 峰值电流的需求,MOSFET 选型参数:
| 参数 | 要求 | 选用型号 | 实际参数 |
|---|---|---|---|
| 耐压 | ≥60V | IRFB4110 | 100V |
| 导通电阻 | ≤10mΩ | IRFB4110 | 8mΩ |
| 栅极电荷 | ≤50nC | IRFB4110 | 44nC |
| 最大电流 | ≥100A | IRFB4110 | 180A |
| 封装 | 散热良好 | IRFB4110 | TO-220 |
选择 IRFB4110 的原因:
- 100V 耐压满足 6S 锂电池(25.2V)的电压要求,并有足够余量
- 8mΩ 低导通电阻可减少导通损耗,提高效率
- TO-220 封装便于散热设计
- 性价比高,适合批量应用
2.3.3 栅极驱动电路
为确保 MOSFET 可靠开关,设计高性能栅极驱动电路:
| 元件 | 型号 | 参数 | 作用 |
|---|---|---|---|
| U4-U6 | IR2104 | 双通道驱动,10-20V 供电 | 栅极驱动芯片 |
| R1-R6 | 10Ω | 限流电阻 | 限制栅极电流 |
| C9-C14 | 100nF | 陶瓷电容 | 栅极电荷存储 |
| D2-D7 | 1N5819 | 肖特基二极管,40V/1A | 续流二极管 |
| R7-R9 | 0.01Ω/5W | 采样电阻 | 电流检测 |
IR2104 的优势:
- 支持自举供电,简化上桥臂驱动
- 内置死区控制,防止上下桥臂直通
- 峰值驱动电流达 2A,可快速开关 MOSFET
- 内置欠压锁定保护,提高系统可靠性
2.3.4 散热设计
80A 大电流应用中,散热设计至关重要:
- 散热片设计:所有 MOSFET 安装在面积≥100cm² 的铝制散热片上
- PCB 布局:功率路径采用大面积铜箔(≥35μm 厚度),减少导通电阻
- 散热过孔:每个 MOSFET 焊盘周围布置 4-6 个散热过孔(φ0.5mm),增强导热
- 布局优化:功率器件集中布置,远离敏感的模拟电路
热仿真分析表明,在 80A 持续电流下,采用上述散热措施可将 MOSFET 结温控制在 85℃以下,满足 - 40℃~85℃的工作温度要求。
2.4 检测电路设计
检测电路负责采集电调工作状态的关键参数,为闭环控制和保护提供依据。
2.4.1 电流检测电路
采用电阻采样方案检测三相电流,具有成本低、响应快的特点:
| 设计参数 | 具体实现 |
|---|---|
| 采样电阻 | 0.01Ω/5W,精度 1% |
| 放大电路 | 仪表放大器 INA219,增益 20 倍 |
| 滤波电路 | RC 低通滤波,截止频率 10kHz |
| 保护电路 | 钳位二极管,限制输入电压在 0-3.3V |
电流检测范围计算:
- 采样电阻 R=0.01Ω
- 最大电流 I=100A
- 采样电压 V=I×R=1V
- 放大后电压 Vout=V×20=20V(需分压至 3.3V 以内)
实际电路中加入分压网络,将最大输出电压限制在 3V,对应 100A 电流,满足 ADC 输入范围要求。
2.4.2 电压检测电路
采用电阻分压方案检测电池电压:
| 元件 | 参数 | 作用 |
|---|---|---|
| R10 | 1MΩ | 上分压电阻 |
| R11 | 100kΩ | 下分压电阻 |
| C15 | 100nF | 滤波电容 |
| D8 | BAV99 | 钳位二极管 |
分压比计算:
- 分压比 K=R11/(R10+R11)=100k/(1M+100k)=1/11
- 最大输入电压 25.2V(6S 满电)
- 输出电压 Vout=25.2×(1/11)=2.29V,小于 3.3V
通过 ADC 采集该电压,可计算得到电池电压,用于低电压保护和电量监测。
2.4.3 温度检测电路
采用 NTC 热敏电阻检测 MOSFET 温度:
| 元件 | 参数 | 作用 |
|---|---|---|
| RT1 | 10kΩ/3950 | NTC 热敏电阻 |
| R12 | 10kΩ | 分压电阻 |
| C16 | 10nF | 滤波电容 |
温度与电阻关系:
- B 值公式:1/T = 1/T0 + (1/B)×ln (R/R0)
- 其中 T0=25℃(298.15K),R0=10kΩ,B=3950
- 0℃时 R≈32.5kΩ,50℃时 R≈3.58kΩ,100℃时 R≈1.3kΩ
通过 ADC 采集分压电压,可计算得到温度值,用于过热保护。
2.5 通信接口设计
电调需要与飞控系统通信,接收控制指令并反馈工作状态,设计了 DSHOT 和 CAN FD 两种通信接口。
2.5.1 DSHOT 接口设计
DSHOT 是无人机专用的高速数字通信协议,采用单线传输,具有响应快、抗干扰能力强的特点。
硬件电路:
| 元件 | 型号 | 参数 | 作用 |
|---|---|---|---|
| U7 | TXB0108 | 8 通道电平转换 | 3.3V 与 5V 电平转换 |
| R13 | 10kΩ | 上拉电阻 | 确保空闲状态稳定 |
| D9 | SMBJ6.5A | 6.5V TVS 管 | 静电保护 |
| C17 | 100nF | 陶瓷电容 | 信号滤波 |
协议特性:
| 特性 | DSHOT300 参数 |
|---|---|
| 传输速率 | 300kbps |
| 位周期 | 3.36μs |
| 逻辑 0 脉冲宽度 | 1.12μs±0.2μs |
| 逻辑 1 脉冲宽度 | 2.24μs±0.2μs |
| 帧结构 | 16 位(11 位数据 + 1 位遥测 + 4 位 CRC) |
| 最大油门值 | 2047 |
| 指令集 | 48 条标准指令 |
接口配置:
- 采用 AT32M412 的 TIM3 定时器
- 配置为输入捕获模式,捕获频率 120MHz
- 连接到 PB3 引脚,支持 GPIO 方向切换(双向通信)
2.5.2 CAN FD 接口设计
CAN FD 是一种高速现场总线协议,支持更高的数据传输速率和更大的数据包,适合多设备通信。
硬件电路:
| 元件 | 型号 | 参数 | 作用 |
|---|---|---|---|
| U8 | TJA1043 | CAN FD 收发器 | 电平转换与信号驱动 |
| R14 | 120Ω | 终端电阻 | 阻抗匹配 |
| C18 | 100nF | 滤波电容 | 电源滤波 |
| D10-D11 | SMBJ18A | 18V TVS 管 | 总线保护 |
协议参数:
| 参数 | 配置值 |
|---|---|
| 标准帧速率 | 1Mbps |
| 数据帧速率 | 8Mbps |
| 数据长度 | 最长 64 字节 |
| 工作模式 | 正常模式 |
| 自动重传 | 使能 |
| 总线唤醒 | 使能 |
接口配置:
- 采用 AT32M412 内置 CAN FD 控制器
- TX 引脚:PA12,RX 引脚:PA11
- 支持中断接收和 DMA 接收
2.6 微控制器最小系统
AT32M412 最小系统包括电源、时钟、复位和调试接口:
| 模块 | 配置 |
|---|---|
| 电源 | 3.3V 供电,100nF+10uF 滤波 |
| 时钟 | 8MHz 外部晶振,PLL 倍频至 120MHz |
| 复位 | 外部复位按钮,10kΩ 上拉电阻 |
| 调试 | SWD 接口,包含 SWCLK 和 SWDIO |
| 启动配置 | BOOT0 引脚通过 10kΩ 下拉电阻接地 |
关键元件:
| 元件 | 参数 | 作用 |
|---|---|---|
| Y1 | 8MHz 晶振 | 系统时钟源 |
| C19-C20 | 22pF | 晶振负载电容 |
| R15 | 10kΩ | 复位上拉电阻 |
| C21 | 10uF | 复位电路电容 |
| J1 | 2x5 排针 | SWD 调试接口 |
三、电调控制算法理论与设计
电调采用三环控制结构(电流环、力矩环、速度环),从内到外实现对电机的精确控制,每层环路都采用 PID 控制算法。
3.1 PID 控制算法基础
PID 控制器是工业控制中最常用的控制算法,通过比例(P)、积分(I)、微分(D)三个环节的组合,实现系统的精确控制。
3.1.1 PID 算法原理
连续时间域 PID 控制公式:
u(t) = Kp·e(t) + Ki·∫e(t)dt + Kd·de(t)/dt
其中:
- u (t):控制输出
- e (t):偏差(设定值 - 反馈值)
- Kp:比例系数
- Ki:积分系数
- Kd:微分系数
离散时间域 PID 控制公式(数字实现):
u(k) = Kp·e(k) + Ki·T·Σe(i) + Kd/T·[e(k) - e(k-1)]
其中:
- T:控制周期
- k:当前时刻
- i:求和变量
3.1.2 PID 各环节作用
| 环节 | 作用 | 特点 |
|---|---|---|
| 比例(P) | 快速响应偏差,输出与偏差成正比 | 响应快,但存在稳态误差 |
| 积分(I) | 消除稳态误差,输出与偏差积分成正比 | 消除静差,但可能增加超调 |
| 微分(D) | 抑制超调,输出与偏差变化率成正比 | 提高稳定性,对噪声敏感 |
3.1.3 PID 参数整定方法
常用的 PID 参数整定方法:
| 方法 | 步骤 | 优点 | 缺点 |
|---|---|---|---|
| 试凑法 | 1. 置 Ki=0, Kd=0 2. 增大 Kp 至临界振荡 3. 增大 Ki 至稳态误差消除 4. 加入 Kd 减小超调 | 简单直观 | 依赖经验,耗时 |
| 临界比例法 | 1. 置 Ki=0, Kd=0 2. 增大 Kp 至临界振荡,记录 Kcr 和 Tcr 3. 按公式计算参数 | 科学系统 | 可能导致系统剧烈振荡 |
| 衰减曲线法 | 1. 置 Ki=0, Kd=0 2. 增大 Kp 至 4:1 衰减 3. 按公式计算参数 | 安全可靠 | 精度略低 |
3.2 电流环设计与实现
电流环是最内环控制,响应速度最快,负责精确控制电机相电流,抑制电流波动。
3.2.1 电流环数学模型
电机相电流动态特性可近似为一阶系统:
L·di/dt + R·i = u - e
其中:
- L:相电感(mH)
- R:相电阻(Ω)
- i:相电流(A)
- u:相电压(V)
- e:反电动势(V)
传递函数:G (s) = 1/(L・s + R)
3.2.2 电流环 PID 参数计算
电流环通常采用 PI 控制器(微分环节对电流环作用不大),设计为典型 I 型系统:
| 设计参数 | 数值 |
|---|---|
| 电机相电感 L | 1mH |
| 电机相电阻 R | 0.1Ω |
| 控制周期 T | 10μs |
| 阻尼比 ξ | 0.707 |
| 截止频率 ωc | 50k rad/s |
PI 参数计算:
- Kp = ωc·L/2 = 50000 × 0.001 / 2 = 25
- Ki = ωc·R/(2·T) = 50000 × 0.1 / (2 × 0.00001) = 25000000
3.2.3 电流环实现要点
- 电流采样同步:在 PWM 周期的中点采样电流,避免开关噪声影响
- 限幅保护:输出电压限制在电池电压范围内,积分项限幅防止饱和
- 死区补偿:补偿功率器件死区时间对电流的影响
- 相位补偿:针对低通滤波器引入的相位滞后进行补偿
3.3 力矩环设计与实现
力矩环是中间环,通过控制 q 轴电流实现电机输出力矩的精确控制。
3.3.1 力矩环数学模型
无刷电机输出力矩与 q 轴电流成正比:
T = Kt·Iq
其中:
- T:输出力矩(N・m)
- Kt:转矩常数(N・m/A)
- Iq:q 轴电流(A)
传递函数近似为比例环节:G (s) = Kt
3.3.2 力矩环 PID 参数计算
力矩环也采用 PI 控制器,设计为典型 I 型系统:
| 设计参数 | 数值 |
|---|---|
| 转矩常数 Kt | 0.1N·m/A |
| 控制周期 T | 50μs |
| 阻尼比 ξ | 0.707 |
| 截止频率 ωc | 10k rad/s |
PI 参数计算:
- Kp = ωc/(2·Kt) = 10000 / (2 × 0.1) = 50000
- Ki = ωc/(2·Kt·T) = 10000 / (2 × 0.1 × 0.00005) = 1000000000
3.3.3 力矩环实现要点
- dq 轴解耦:通过 Park 变换和反 Park 变换实现 dq 轴电流解耦控制
- 最大力矩限制:根据电机额定参数限制最大输出力矩
- 力矩补偿:补偿摩擦力矩和负载力矩扰动
- 动态响应优化:根据转速动态调整 PID 参数,优化动态性能
3.4 速度环设计与实现
速度环是最外环,根据飞控指令控制电机转速,具有较慢的响应速度和较强的抗干扰能力。
3.4.1 速度环数学模型
电机转速与力矩关系:
J·dω/dt + B·ω = T - Tl
其中:
- J:转动惯量(kg・m²)
- B:阻尼系数(N・m・s/rad)
- ω:角速度(rad/s)
- T:输出力矩(N・m)
- Tl:负载力矩(N・m)
传递函数:G (s) = 1/(J・s + B)
3.4.2 速度环 PID 参数计算
速度环采用完整的 PID 控制器,设计为典型 II 型系统:
| 设计参数 | 数值 |
|---|---|
| 转动惯量 J | 0.01kg·m² |
| 阻尼系数 B | 0.001N·m·s/rad |
| 控制周期 T | 1ms |
| 中频宽 h | 5 |
| 截止频率 ωc | 600 rad/s |
PID 参数计算:
- Kp = (h+1)·B/(2·h·J) = 6 × 0.001 / (2 × 5 × 0.01) = 0.06
- Ki = B/(h·J·T) = 0.001 / (5 × 0.01 × 0.001) = 20
- Kd = h·J/(2·(h+1)·T) = 5 × 0.01 / (2 × 6 × 0.001) = 4.17
3.4.3 速度环实现要点
- 转速测量:通过霍尔传感器或反电动势过零点检测转速
- 滤波处理:对转速信号进行低通滤波,减小测量噪声
- 前馈控制:加入转速前馈,提高动态响应速度
- 加速度限制:限制转速变化率,避免过大冲击电流
3.5 三环协调工作机制
三环控制采用嵌套结构,外环输出作为内环设定值,各环控制周期不同:
| 控制环 | 控制周期 | 采样频率 | 输出量 | 输入量 |
|---|---|---|---|---|
| 电流环 | 10μs | 100kHz | 电压 | 电流 |
| 力矩环 | 50μs | 20kHz | 电流 | 力矩 |
| 速度环 | 1ms | 1kHz | 力矩 | 转速 |
协调工作流程:
- 速度环接收飞控的转速指令,与实际转速比较,输出力矩指令
- 力矩环接收速度环的力矩指令,与实际力矩比较,输出电流指令
- 电流环接收力矩环的电流指令,与实际电流比较,输出电压指令
- 电压指令通过 SVPWM 算法转换为 PWM 信号,驱动电机
参数协调原则:
- 内环带宽是外环的 5-10 倍,确保系统稳定
- 各环输出限幅逐步放宽,外环限制最宽松
- 滤波时间常数不超过控制周期的 1/5
四、软件代码实现
基于 AT32M412 的电调软件采用模块化设计,主要包括系统初始化、三环控制、电机驱动、通信接口和故障保护等模块。
4.1 开发环境与工具链
| 开发工具 | 版本 | 用途 |
|---|---|---|
| IDE | IAR Embedded Workbench 8.50 | 代码编辑、编译、调试 |
| 编译器 | ARMCC 6.14 | 代码编译 |
| 调试器 | J-Link V9 | 硬件调试、程序下载 |
| 库文件 | AT32F412_StdPeriph_Lib_V2.0.0 | 外设驱动库 |
| 仿真工具 | MATLAB/Simulink 2021a | 控制算法仿真 |
4.2 系统初始化模块
系统初始化模块负责配置微控制器外设,为电调工作提供基础环境。
c
运行
#include "system_init.h"
#include "at32f412.h"
#include "at32f412_clock.h"
void system_init(void)
{
// 初始化系统时钟
system_clock_config();
// 初始化GPIO
gpio_init();
// 初始化定时器
timer_init();
// 初始化ADC
adc_init();
// 初始化DSHOT接口
dshot_init();
// 初始化CAN FD接口
can_fd_init();
// 初始化中断
nvic_config();
// 初始化三环控制
current_loop_init();
torque_loop_init();
speed_loop_init();
// 初始化电机驱动
motor_driver_init();
// 初始化故障保护
fault_protection_init();
}
void system_clock_config(void)
{
// 使能外部高速时钟
crm_clock_source_enable(CRM_CLOCK_SOURCE_HSE, TRUE);
// 等待HSE稳定
while(crm_flag_get(CRM_HSE_STABLE_FLAG) == RESET);
// 配置PLL: HSE(8MHz) * 15 = 120MHz
crm_pll_config(CRM_PLL_SOURCE_HSE_DIV_1, CRM_PLL_MULT_15);
// 使能PLL
crm_clock_source_enable(CRM_CLOCK_SOURCE_PLL, TRUE);
// 等待PLL稳定
while(crm_flag_get(CRM_PLL_STABLE_FLAG) == RESET);
// 配置系统时钟源为PLL
crm_sysclk_switch(CRM_SYSCLK_SOURCE_PLL);
// 配置AHB时钟 (HCLK = SYSCLK)
crm_ahb_div_set(CRM_AHB_DIV_1);
// 配置APB1时钟 (PCLK1 = HCLK / 2)
crm_apb1_div_set(CRM_APB1_DIV_2);
// 配置APB2时钟 (PCLK2 = HCLK)
crm_apb2_div_set(CRM_APB2_DIV_1);
// 更新系统时钟频率变量
system_core_clock_update();
}
void gpio_init(void)
{
// 使能GPIO时钟
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);
// 配置电机驱动GPIO
gpio_init_type gpio_init_struct;
gpio_default_para_init(&gpio_init_struct);
// 上桥臂PWM输出 (PA8-PA10)
gpio_init_struct.gpio_pins = GPIO_PINS_8 | GPIO_PINS_9 | GPIO_PINS_10;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(GPIOA, &gpio_init_struct);
// 下桥臂PWM输出 (PB13-PB15)
gpio_init_struct.gpio_pins = GPIO_PINS_13 | GPIO_PINS_14 | GPIO_PINS_15;
gpio_init(GPIOB, &gpio_init_struct);
// 电流检测ADC输入 (PC0-PC2)
gpio_init_struct.gpio_pins = GPIO_PINS_0 | GPIO_PINS_1 | GPIO_PINS_2;
gpio_init_struct.gpio_mode = GPIO_MODE_ANALOG;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOC, &gpio_init_struct);
// 电压检测ADC输入 (PC3)
gpio_init_struct.gpio_pins = GPIO_PINS_3;
gpio_init(GPIOC, &gpio_init_struct);
// 温度检测ADC输入 (PC4)
gpio_init_struct.gpio_pins = GPIO_PINS_4;
gpio_init(GPIOC, &gpio_init_struct);
// 配置LED指示灯 (PA0)
gpio_init_struct.gpio_pins = GPIO_PINS_0;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOA, &gpio_init_struct);
}
void timer_init(void)
{
// 使能定时器时钟
crm_periph_clock_enable(CRM_TIM1_PERIPH_CLOCK, TRUE); // 电机PWM
crm_periph_clock_enable(CRM_TIM2_PERIPH_CLOCK, TRUE); // 电流环
crm_periph_clock_enable(CRM_TIM3_PERIPH_CLOCK, TRUE); // 力矩环
crm_periph_clock_enable(CRM_TIM4_PERIPH_CLOCK, TRUE); // 速度环
// 配置TIM1用于电机PWM输出 (20kHz)
timer_base_init_type timer_base_struct;
timer_output_config_type timer_output_struct;
timer_deinit(TIM1);
timer_base_default_para_init(&timer_base_struct);
timer_base_struct.count_mode = TIMER_COUNT_UP;
timer_base_struct.period = 5999; // 120MHz / (20kHz * 1) - 1 = 5999
timer_base_struct.divider = 0;
timer_base_struct.repetition_counter = 0;
timer_base_init(TIM1, &timer_base_struct);
// 配置PWM输出模式
timer_output_default_para_init(&timer_output_struct);
timer_output_struct.oc_mode = TIMER_OC_MODE_PWM1;
timer_output_struct.oc_output_state = TIMER_OUTPUT_STATE_ENABLE;
timer_output_struct.oc_polarity = TIMER_OC_POLARITY_HIGH;
timer_output_struct.oc_idle_state = TIMER_OC_IDLE_STATE_LOW;
// 配置三相PWM通道
timer_channel_output_config(TIM1, TIMER_CHANNEL_1, &timer_output_struct);
timer_channel_output_config(TIM1, TIMER_CHANNEL_2, &timer_output_struct);
timer_channel_output_config(TIM1, TIMER_CHANNEL_3, &timer_output_struct);
// 设置初始占空比为0
timer_channel_output_pulse_value_set(TIM1, TIMER_CHANNEL_1, 0);
timer_channel_output_pulse_value_set(TIM1, TIMER_CHANNEL_2, 0);
timer_channel_output_pulse_value_set(TIM1, TIMER_CHANNEL_3, 0);
// 配置死区时间 (1us)
timer_break_and_dead_time_config(TIM1, TIMER_BREAK_INPUT_ENABLE,
TIMER_BREAK_POLARITY_LOW, 120); // 120 * 1/120MHz = 1us
// 使能主输出
timer_primary_output_config(TIM1, TRUE);
// 配置TIM2用于电流环中断 (100kHz, 10us)
timer_deinit(TIM2);
timer_base_default_para_init(&timer_base_struct);
timer_base_struct.count_mode = TIMER_COUNT_UP;
timer_base_struct.period = 1199; // 120MHz / (100kHz * 1) - 1 = 1199
timer_base_struct.divider = 0;
timer_base_init(TIM2, &timer_base_struct);
// 使能更新中断
timer_interrupt_enable(TIM2, TIMER_UPDATE_INTERRUPT, TRUE);
// 配置TIM3用于力矩环中断 (20kHz, 50us)
timer_deinit(TIM3);
timer_base_default_para_init(&timer_base_struct);
timer_base_struct.count_mode = TIMER_COUNT_UP;
timer_base_struct.period = 5999; // 120MHz / (20kHz * 1) - 1 = 5999
timer_base_struct.divider = 0;
timer_base_init(TIM3, &timer_base_struct);
// 使能更新中断
timer_interrupt_enable(TIM3, TIMER_UPDATE_INTERRUPT, TRUE);
// 配置TIM4用于速度环中断 (1kHz, 1ms)
timer_deinit(TIM4);
timer_base_default_para_init(&timer_base_struct);
timer_base_struct.count_mode = TIMER_COUNT_UP;
timer_base_struct.period = 119999; // 120MHz / (1kHz * 1) - 1 = 119999
timer_base_struct.divider = 0;
timer_base_init(TIM4, &timer_base_struct);
// 使能更新中断
timer_interrupt_enable(TIM4, TIMER_UPDATE_INTERRUPT, TRUE);
// 启动定时器
timer_counter_enable(TIM1, TRUE);
timer_counter_enable(TIM2, TRUE);
timer_counter_enable(TIM3, TRUE);
timer_counter_enable(TIM4, TRUE);
}
void adc_init(void)
{
// 使能ADC时钟
crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE);
// 配置ADC1
adc_base_init_type adc_base_struct;
adc_channel_config_type adc_channel_struct;
adc_deinit(ADC1);
adc_base_default_para_init(&adc_base_struct);
adc_base_struct.sequence_mode = ADC_SEQUENCE_SINGLE;
adc_base_struct.repeat_mode = ADC_REPEAT_ENABLE;
adc_base_struct.data_align = ADC_DATA_ALIGN_RIGHT;
adc_base_struct.ordinary_channel_length = 5;
adc_base_init(ADC1, &adc_base_struct);
// 配置ADC通道
adc_channel_default_para_init(&adc_channel_struct);
// A相电流 (PC0 = ADC_CHANNEL_10)
adc_channel_struct.channel = ADC_CHANNEL_10;
adc_channel_struct.rank = ADC_RANK_1;
adc_channel_struct.sampling_time = ADC_SAMPLETIME_239CYCLES5;
adc_channel_config(ADC1, &adc_channel_struct);
// B相电流 (PC1 = ADC_CHANNEL_11)
adc_channel_struct.channel = ADC_CHANNEL_11;
adc_channel_struct.rank = ADC_RANK_2;
adc_channel_config(ADC1, &adc_channel_struct);
// C相电流 (PC2 = ADC_CHANNEL_12)
adc_channel_struct.channel = ADC_CHANNEL_12;
adc_channel_struct.rank = ADC_RANK_3;
adc_channel_config(ADC1, &adc_channel_struct);
// 电池电压 (PC3 = ADC_CHANNEL_13)
adc_channel_struct.channel = ADC_CHANNEL_13;
adc_channel_struct.rank = ADC_RANK_4;
adc_channel_config(ADC1, &adc_channel_struct);
// 温度检测 (PC4 = ADC_CHANNEL_14)
adc_channel_struct.channel = ADC_CHANNEL_14;
adc_channel_struct.rank = ADC_RANK_5;
adc_channel_config(ADC1, &adc_channel_struct);
// 配置ADC分辨率为12位
adc_resolution_set(ADC1, ADC_RESOLUTION_12B);
// 配置软件触发
adc_ordinary_conversion_trigger_set(ADC1, ADC_ORDINARY_TRIGGER_SOFTWARE, TRUE);
// 使能ADC
adc_enable(ADC1, TRUE);
// ADC校准
delay_us(10);
adc_calibration_init(ADC1);
while(adc_calibration_init_status_get(ADC1));
adc_calibration_start(ADC1);
while(adc_calibration_status_get(ADC1));
// 开始转换
adc_ordinary_software_trigger_enable(ADC1, TRUE);
}
void nvic_config(void)
{
// 配置中断优先级分组
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
// 配置TIM2中断 (电流环,最高优先级)
nvic_irq_enable(TIM2_IRQn, 0, 0);
// 配置TIM3中断 (力矩环,次高优先级)
nvic_irq_enable(TIM3_IRQn, 1, 0);
// 配置DSHOT中断 (中优先级)
nvic_irq_enable(TIM5_IRQn, 2, 0);
// 配置CAN FD中断 (中优先级)
nvic_irq_enable(CAN1_RX0_IRQn, 2, 1);
// 配置TIM4中断 (速度环,低优先级)
nvic_irq_enable(TIM4_IRQn, 3, 0);
}
4.3 电流环控制模块
电流环控制模块实现电流的精确控制,在 TIM2 中断中执行,周期为 10μs。
c
运行
#include "current_loop.h"
#include "adc.h"
#include "math.h"
// 电流环PI参数
#define CURRENT_KP 25.0f
#define CURRENT_KI 25000000.0f
// 电流环限幅参数
#define CURRENT_MAX 80.0f // 最大电流 (A)
#define CURRENT_MIN -80.0f // 最小电流 (A)
#define VOLTAGE_MAX 25.2f // 最大电压 (V),6S锂电池满电
#define VOLTAGE_MIN -25.2f // 最小电压 (V)
#define INT_MAX 100.0f // 积分项最大值
#define INT_MIN -100.0f // 积分项最小值
// 电流环变量
typedef struct {
float ref; // 电流设定值 (A)
float fdb; // 电流反馈值 (A)
float err; // 电流误差
float err_sum; // 电流误差积分
float output; // 输出电压 (V)
} CurrentLoopType;
// 三相电流环
static CurrentLoopType current_loop_a = {0};
static CurrentLoopType current_loop_b = {0};
static CurrentLoopType current_loop_c = {0};
// 电流校准参数
static float current_offset_a = 0.0f;
static float current_offset_b = 0.0f;
static float current_offset_c = 0.0f;
void current_loop_init(void)
{
// 初始化电流环变量
current_loop_a.ref = 0.0f;
current_loop_a.fdb = 0.0f;
current_loop_a.err = 0.0f;
current_loop_a.err_sum = 0.0f;
current_loop_a.output = 0.0f;
current_loop_b.ref = 0.0f;
current_loop_b.fdb = 0.0f;
current_loop_b.err = 0.0f;
current_loop_b.err_sum = 0.0f;
current_loop_b.output = 0.0f;
current_loop_c.ref = 0.0f;
current_loop_c.fdb = 0.0f;
current_loop_c.err = 0.0f;
current_loop_c.err_sum = 0.0f;
current_loop_c.output = 0.0f;
// 执行电流校准
current_calibration();
}
void current_calibration(void)
{
uint32_t i;
uint32_t sum_a = 0, sum_b = 0, sum_c = 0;
// 关闭电机输出
motor_stop();
// 多次采样计算偏移量
for(i = 0; i < 1000; i++)
{
sum_a += adc_get_value(ADC_CHANNEL_10); // A相电流
sum_b += adc_get_value(ADC_CHANNEL_11); // B相电流
sum_c += adc_get_value(ADC_CHANNEL_12); // C相电流
delay_us(10);
}
// 计算偏移量 (ADC值)
current_offset_a = (float)sum_a / 1000.0f;
current_offset_b = (float)sum_b / 1000.0f;
current_offset_c = (float)sum_c / 1000.0f;
}
float current_adc_to_amp(uint16_t adc_value, float offset)
{
float voltage;
float current;
// ADC值转换为电压 (3.3V参考电压)
voltage = (adc_value - offset) * 3.3f / 4095.0f;
// 电压转换为电流 (0.01Ω采样电阻,20倍放大)
current = voltage / (0.01f * 20.0f);
return current;
}
void current_loop_control(void)
{
// 读取电流反馈值
current_loop_a.fdb = current_adc_to_amp(adc_get_value(ADC_CHANNEL_10), current_offset_a);
current_loop_b.fdb = current_adc_to_amp(adc_get_value(ADC_CHANNEL_11), current_offset_b);
current_loop_c.fdb = current_adc_to_amp(adc_get_value(ADC_CHANNEL_12), current_offset_c);
// A相电流环PI计算
current_loop_a.err = current_loop_a.ref - current_loop_a.fdb;
current_loop_a.err_sum += current_loop_a.err * 0.00001f; // 10us周期
// 积分限幅
if(current_loop_a.err_sum > INT_MAX)
current_loop_a.err_sum = INT_MAX;
else if(current_loop_a.err_sum < INT_MIN)
current_loop_a.err_sum = INT_MIN;
// 计算输出电压
current_loop_a.output = CURRENT_KP * current_loop_a.err +
CURRENT_KI * current_loop_a.err_sum;
// 输出限幅
if(current_loop_a.output > VOLTAGE_MAX)
current_loop_a.output = VOLTAGE_MAX;
else if(current_loop_a.output < VOLTAGE_MIN)
current_loop_a.output = VOLTAGE_MIN;
// B相电流环PI计算
current_loop_b.err = current_loop_b.ref - current_loop_b.fdb;
current_loop_b.err_sum += current_loop_b.err * 0.00001f;
if(current_loop_b.err_sum > INT_MAX)
current_loop_b.err_sum = INT_MAX;
else if(current_loop_b.err_sum < INT_MIN)
current_loop_b.err_sum = INT_MIN;
current_loop_b.output = CURRENT_KP * current_loop_b.err +
CURRENT_KI * current_loop_b.err_sum;
if(current_loop_b.output > VOLTAGE_MAX)
current_loop_b.output = VOLTAGE_MAX;
else if(current_loop_b.output < VOLTAGE_MIN)
current_loop_b.output = VOLTAGE_MIN;
// C相电流环PI计算
current_loop_c.err = current_loop_c.ref - current_loop_c.fdb;
current_loop_c.err_sum += current_loop_c.err * 0.00001f;
if(current_loop_c.err_sum > INT_MAX)
current_loop_c.err_sum = INT_MAX;
else if(current_loop_c.err_sum < INT_MIN)
current_loop_c.err_sum = INT_MIN;
current_loop_c.output = CURRENT_KP * current_loop_c.err +
CURRENT_KI * current_loop_c.err_sum;
if(current_loop_c.output > VOLTAGE_MAX)
current_loop_c.output = VOLTAGE_MAX;
else if(current_loop_c.output < VOLTAGE_MIN)
current_loop_c.output = VOLTAGE_MIN;
// 将电压输出转换为PWM占空比
svpwm_update(current_loop_a.output, current_loop_b.output, current_loop_c.output);
}
void set_current_ref(float ia, float ib, float ic)
{
// 电流限幅
if(ia > CURRENT_MAX) ia = CURRENT_MAX;
else if(ia < CURRENT_MIN) ia = CURRENT_MIN;
if(ib > CURRENT_MAX) ib = CURRENT_MAX;
else if(ib < CURRENT_MIN) ib = CURRENT_MIN;
if(ic > CURRENT_MAX) ic = CURRENT_MAX;
else if(ic < CURRENT_MIN) ic = CURRENT_MIN;
// 设置电流环设定值
current_loop_a.ref = ia;
current_loop_b.ref = ib;
current_loop_c.ref = ic;
}
// 获取电流反馈值
float get_current_fdb_a(void) { return current_loop_a.fdb; }
float get_current_fdb_b(void) { return current_loop_b.fdb; }
float get_current_fdb_c(void) { return current_loop_c.fdb; }
// TIM2中断服务程序,执行电流环控制
void TIM2_IRQHandler(void)
{
if(timer_flag_get(TIM2, TIMER_UPDATE_FLAG) != RESET)
{
timer_flag_clear(TIM2, TIMER_UPDATE_FLAG);
// 执行电流环控制
current_loop_control();
}
}
4.4 力矩环控制模块
力矩环控制模块实现电机输出力矩的精确控制,在 TIM3 中断中执行,周期为 50μs。
c
运行
#include "torque_loop.h"
#include "current_loop.h"
#include "park_transform.h"
// 力矩环PI参数
#define TORQUE_KP 50000.0f
#define TORQUE_KI 1000000000.0f
// 力矩环限幅参数
#define TORQUE_MAX 8.0f // 最大力矩 (N·m)
#define TORQUE_MIN -8.0f // 最小力矩 (N·m)
#define IQ_MAX 80.0f // 最大q轴电流 (A)
#define IQ_MIN -80.0f // 最小q轴电流 (A)
#define ID_MAX 5.0f // 最大d轴电流 (A)
#define ID_MIN -5.0f // 最小d轴电流 (A)
#define INT_MAX 1000.0f // 积分项最大值
#define INT_MIN -1000.0f // 积分项最小值
// 电机参数
#define Kt 0.1f // 转矩常数 (N·m/A)
#define R 0.1f // 相电阻 (Ω)
#define Ld 0.001f // d轴电感 (H)
#define Lq 0.001f // q轴电感 (H)
// 力矩环变量
typedef struct {
float ref; // 力矩设定值 (N·m)
float fdb; // 力矩反馈值 (N·m)
float err; // 力矩误差
float err_sum; // 力矩误差积分
float id_ref; // d轴电流设定值 (A)
float iq_ref; // q轴电流设定值 (A)
float id_fdb; // d轴电流反馈值 (A)
float iq_fdb; // q轴电流反馈值 (A)
} TorqueLoopType;
static TorqueLoopType torque_loop = {0};
void torque_loop_init(void)
{
// 初始化力矩环变量
torque_loop.ref = 0.0f;
torque_loop.fdb = 0.0f;
torque_loop.err = 0.0f;
torque_loop.err_sum = 0.0f;
torque_loop.id_ref = 0.0f; // 采用id=0的控制策略
torque_loop.iq_ref = 0.0f;
torque_loop.id_fdb = 0.0f;
torque_loop.iq_fdb = 0.0f;
}
void torque_loop_control(void)
{
float ia, ib, ic;
float theta;
// 获取三相电流
ia = get_current_fdb_a();
ib = get_current_fdb get_current_fdb_a();
ib = get_current_fdb_b();
ic = get_current_fdb_c();
// 获取电机角度 (来自编码器或反电动势检测)
theta = motor_get_angle();
// Clark变换: 三相电流 → 两相静止电流
float i_alpha, i_beta;
clark_transform(ia, ib, ic, &i_alpha, &i_beta);
// Park变换: 两相静止电流 → 两相旋转电流
park_transform(i_alpha, i_beta, theta, &torque_loop.id_fdb, &torque_loop.iq_fdb);
// 计算力矩反馈值
torque_loop.fdb = Kt * torque_loop.iq_fdb;
// 力矩环PI计算
torque_loop.err = torque_loop.ref - torque_loop.fdb;
torque_loop.err_sum += torque_loop.err * 0.00005f; // 50us周期
// 积分限幅
if(torque_loop.err_sum > INT_MAX)
torque_loop.err_sum = INT_MAX;
else if(torque_loop.err_sum < INT_MIN)
torque_loop.err_sum = INT_MIN;
// 计算q轴电流设定值
torque_loop.iq_ref = TORQUE_KP * torque_loop.err +
TORQUE_KI * torque_loop.err_sum;
// q轴电流限幅
if(torque_loop.iq_ref > IQ_MAX)
torque_loop.iq_ref = IQ_MAX;
else if(torque_loop.iq_ref < IQ_MIN)
torque_loop.iq_ref = IQ_MIN;
// d轴电流设定值保持为0 (MTPA控制可在此优化)
torque_loop.id_ref = 0.0f;
// 反Park变换: 两相旋转电流 → 两相静止电流
float v_alpha_ref, v_beta_ref;
inverse_park_transform(torque_loop.id_ref, torque_loop.iq_ref, theta,
&v_alpha_ref, &v_beta_ref);
// 反Clark变换: 两相静止电流 → 三相电流
float ia_ref, ib_ref, ic_ref;
inverse_clark_transform(v_alpha_ref, v_beta_ref, &ia_ref, &ib_ref, &ic_ref);
// 设置电流环设定值
set_current_ref(ia_ref, ib_ref, ic_ref);
}
void set_torque_ref(float torque)
{
// 力矩限幅
if(torque > TORQUE_MAX)
torque = TORQUE_MAX;
else if(torque < TORQUE_MIN)
torque = TORQUE_MIN;
// 设置力矩环设定值
torque_loop.ref = torque;
}
// 获取力矩反馈值
float get_torque_fdb(void) { return torque_loop.fdb; }
// TIM3中断服务程序,执行力矩环控制
void TIM3_IRQHandler(void)
{
if(timer_flag_get(TIM3, TIMER_UPDATE_FLAG) != RESET)
{
timer_flag_clear(TIM3, TIMER_UPDATE_FLAG);
// 执行力矩环控制
torque_loop_control();
}
}
4.5 速度环控制模块
速度环控制模块实现电机转速的精确控制,在 TIM4 中断中执行,周期为 1ms。
c
运行
#include "speed_loop.h"
#include "torque_loop.h"
#include "motor_driver.h"
#include "filter.h"
// 速度环PID参数
#define SPEED_KP 0.06f
#define SPEED_KI 20.0f
#define SPEED_KD 4.17f
// 速度环限幅参数
#define SPEED_MAX 10000.0f // 最大转速 (RPM)
#define SPEED_MIN 0.0f // 最小转速 (RPM)
#define TORQUE_OUT_MAX 8.0f // 最大力矩输出 (N·m)
#define TORQUE_OUT_MIN -8.0f // 最小力矩输出 (N·m)
#define INT_MAX 100.0f // 积分项最大值
#define INT_MIN -100.0f // 积分项最小值
#define D_FILTER_ALPHA 0.2f // 微分滤波系数
// 速度环变量
typedef struct {
float ref; // 速度设定值 (RPM)
float fdb; // 速度反馈值 (RPM)
float fdb_filtered; // 滤波后的速度反馈值
float err; // 速度误差
float err_prev; // 上一次速度误差
float err_sum; // 速度误差积分
float err_diff; // 速度误差微分
float output; // 输出力矩 (N·m)
} SpeedLoopType;
static SpeedLoopType speed_loop = {0};
void speed_loop_init(void)
{
// 初始化速度环变量
speed_loop.ref = 0.0f;
speed_loop.fdb = 0.0f;
speed_loop.fdb_filtered = 0.0f;
speed_loop.err = 0.0f;
speed_loop.err_prev = 0.0f;
speed_loop.err_sum = 0.0f;
speed_loop.err_diff = 0.0f;
speed_loop.output = 0.0f;
}
void speed_loop_control(void)
{
// 获取电机转速反馈 (RPM)
speed_loop.fdb = motor_get_speed();
// 一阶低通滤波
speed_loop.fdb_filtered = first_order_filter(speed_loop.fdb_filtered,
speed_loop.fdb, D_FILTER_ALPHA);
// 速度环PID计算
speed_loop.err = speed_loop.ref - speed_loop.fdb_filtered;
// 积分项计算 (带积分分离)
if(fabs(speed_loop.err) < 100.0f) // 误差小于100RPM时启用积分
{
speed_loop.err_sum += speed_loop.err * 0.001f; // 1ms周期
// 积分限幅
if(speed_loop.err_sum > INT_MAX)
speed_loop.err_sum = INT_MAX;
else if(speed_loop.err_sum < INT_MIN)
speed_loop.err_sum = INT_MIN;
}
// 微分项计算 (带微分先行)
speed_loop.err_diff = (speed_loop.fdb_filtered - speed_loop.err_prev) / 0.001f;
speed_loop.err_prev = speed_loop.fdb_filtered;
// 计算输出力矩
speed_loop.output = SPEED_KP * speed_loop.err +
SPEED_KI * speed_loop.err_sum -
SPEED_KD * speed_loop.err_diff; // 负反馈,注意符号
// 输出限幅
if(speed_loop.output > TORQUE_OUT_MAX)
speed_loop.output = TORQUE_OUT_MAX;
else if(speed_loop.output < TORQUE_OUT_MIN)
speed_loop.output = TORQUE_OUT_MIN;
// 设置力矩环设定值
set_torque_ref(speed_loop.output);
}
void set_speed_ref(float speed)
{
// 速度限幅
if(speed > SPEED_MAX)
speed = SPEED_MAX;
else if(speed < SPEED_MIN)
speed = SPEED_MIN;
// 设置速度环设定值
speed_loop.ref = speed;
}
// 获取速度反馈值
float get_speed_fdb(void) { return speed_loop.fdb_filtered; }
// TIM4中断服务程序,执行速度环控制
void TIM4_IRQHandler(void)
{
if(timer_flag_get(TIM4, TIMER_UPDATE_FLAG) != RESET)
{
timer_flag_clear(TIM4, TIMER_UPDATE_FLAG);
// 执行速度环控制
speed_loop_control();
// 1ms定时任务
periodic_task_1ms();
}
}
4.6 DSHOT 接口实现
DSHOT 接口模块实现与飞控的高速通信,接收转速指令并支持遥测数据回传。
c
运行
#include "dshot.h"
#include "timer.h"
#include "gpio.h"
#include "crc.h"
#include "telemetry.h"
// DSHOT300参数
#define DSHOT300_BIT_TIME 3.36f // 位周期 (us)
#define DSHOT300_0_PULSE 1.12f // 逻辑0脉冲宽度 (us)
#define DSHOT300_1_PULSE 2.24f // 逻辑1脉冲宽度 (us)
#define DSHOT300_FRAME_BITS 16 // 每帧位数
#define DSHOT300_MAX_THROTTLE 2047 // 最大油门值
// DSHOT指令
#define DSHOT_CMD_MOTOR_STOP 0
#define DSHOT_CMD_BEEP_1 1
#define DSHOT_CMD_BEEP_2 2
#define DSHOT_CMD_BEEP_3 3
#define DSHOT_CMD_BEEP_4 4
#define DSHOT_CMD_BEEP_5 5
#define DSHOT_CMD_ESC_INFO 6
#define DSHOT_CMD_SPIN_DIRECTION_1 20
#define DSHOT_CMD_SPIN_DIRECTION_2 21
#define DSHOT_CMD_3D_MODE_OFF 22
#define DSHOT_CMD_3D_MODE_ON 23
#define DSHOT_CMD_CALIBRATE 24
// DSHOT状态
typedef enum {
DSHOT_STATE_IDLE,
DSHOT_STATE_RECEIVING,
DSHOT_STATE_RECEIVED,
DSHOT_STATE_SENDING
} DshotState;
// DSHOT接收缓冲区
typedef struct {
uint16_t data; // 接收到的数据
uint8_t bit_count; // 已接收位数
uint32_t last_edge_time; // 上一边缘时间 (us)
uint8_t telemetry_request; // 遥测请求标志
uint16_t throttle; // 解析后的油门值
uint8_t crc_valid; // CRC校验结果
} DshotRxBuffer;
// DSHOT发送缓冲区
typedef struct {
uint16_t data; // 要发送的数据
uint8_t bit_count; // 已发送位数
} DshotTxBuffer;
// DSHOT变量
static DshotState dshot_state = DSHOT_STATE_IDLE;
static DshotRxBuffer rx_buf = {0};
static DshotTxBuffer tx_buf = {0};
static uint32_t dshot_timer = 0;
// 计算DSHOT CRC
static uint8_t dshot_crc_calculate(uint16_t data)
{
return (uint8_t)(((data >> 1) ^ (data >> 5) ^ (data >> 9)) & 0x0F);
}
// 解析DSHOT数据帧
static void dshot_parse_frame(void)
{
uint16_t raw_data = rx_buf.data;
uint16_t data = (raw_data >> 1) & 0x7FF; // 提取11位数据
uint8_t telemetry = (raw_data >> 12) & 0x01; // 提取遥测位
uint8_t crc_received = raw_data & 0x0F; // 提取CRC
uint8_t crc_calculated = dshot_crc_calculate(data);
// 校验CRC
rx_buf.crc_valid = (crc_received == crc_calculated) ? 1 : 0;
if(rx_buf.crc_valid)
{
rx_buf.telemetry_request = telemetry;
// 数据是命令还是油门值
if(data < 48) // 命令
{
dshot_execute_command(data);
}
else // 油门值
{
rx_buf.throttle = data - 48; // 转换为0-2047范围
// 转换为转速 (RPM)
float speed = (float)rx_buf.throttle / 2047.0f * SPEED_MAX;
set_speed_ref(speed);
}
}
}
// 执行DSHOT命令
void dshot_execute_command(uint8_t cmd)
{
switch(cmd)
{
case DSHOT_CMD_MOTOR_STOP:
set_speed_ref(0);
break;
case DSHOT_CMD_BEEP_1:
buzzer_beep(100, 200); // 100ms响,200ms停
break;
case DSHOT_CMD_BEEP_2:
buzzer_beep(200, 100); // 200ms响,100ms停
break;
case DSHOT_CMD_ESC_INFO:
// 准备发送电调信息
dshot_prepare_telemetry(TELEMETRY_TYPE_INFO);
break;
case DSHOT_CMD_CALIBRATE:
// 执行电调校准
esc_calibrate();
break;
// 其他命令处理...
default:
break;
}
}
// 准备遥测数据
void dshot_prepare_telemetry(TelemetryType type)
{
TelemetryData telemetry = telemetry_get_data(type);
uint16_t data = 0;
// 打包遥测数据 (根据类型)
switch(type)
{
case TELEMETRY_TYPE_VOLTAGE:
// 电压数据: 11位 (0-2047对应0-50V)
data = (uint16_t)(telemetry.voltage * 40.95f); // 2047/50 = 40.94
break;
case TELEMETRY_TYPE_CURRENT:
// 电流数据: 11位 (0-2047对应0-100A)
data = (uint16_t)(telemetry.current * 20.47f); // 2047/100 = 20.47
break;
case TELEMETRY_TYPE_TEMPERATURE:
// 温度数据: 11位 (-40-110℃映射到0-2047)
data = (uint16_t)((telemetry.temperature + 40) * 13.65f); // 2047/150 = 13.65
break;
case TELEMETRY_TYPE_INFO:
// 电调信息: 固件版本等
data = (FIRMWARE_VERSION << 8) | ESC_MODEL;
break;
}
// 添加CRC
uint8_t crc = dshot_crc_calculate(data);
tx_buf.data = (data << 1) | (0 << 12) | crc; // 遥测帧无遥测请求位
tx_buf.bit_count = 0;
// 切换到发送状态
dshot_state = DSHOT_STATE_SENDING;
// 配置GPIO为输出
gpio_mode_set(DSHOT_PORT, GPIO_MODE_OUTPUT, GPIO_PULL_NONE, DSHOT_PIN);
gpio_output_low(DSHOT_PORT, DSHOT_PIN);
// 启动发送
dshot_timer = timer_get_ticks_us();
}
// 发送一位数据
static void dshot_send_bit(uint8_t bit)
{
// 输出高电平
gpio_output_high(DSHOT_PORT, DSHOT_PIN);
// 延时对应脉冲宽度
if(bit)
delay_us(DSHOT300_1_PULSE);
else
delay_us(DSHOT300_0_PULSE);
// 输出低电平,补全位周期
gpio_output_low(DSHOT_PORT, DSHOT_PIN);
if(bit)
delay_us(DSHOT300_BIT_TIME - DSHOT300_1_PULSE);
else
delay_us(DSHOT300_BIT_TIME - DSHOT300_0_PULSE);
}
// DSHOT发送处理
static void dshot_send_process(void)
{
if(dshot_state != DSHOT_STATE_SENDING)
return;
// 检查是否完成所有位发送
if(tx_buf.bit_count >= DSHOT300_FRAME_BITS)
{
// 发送完成,切换回接收状态
gpio_mode_set(DSHOT_PORT, GPIO_MODE_INPUT, GPIO_PULL_UP, DSHOT_PIN);
dshot_state = DSHOT_STATE_IDLE;
return;
}
// 发送当前位 (从高位到低位)
uint8_t bit = (tx_buf.data >> (DSHOT300_FRAME_BITS - 1 - tx_buf.bit_count)) & 0x01;
dshot_send_bit(bit);
tx_buf.bit_count++;
}
// DSHOT初始化
void dshot_init(void)
{
// 初始化GPIO为输入
gpio_mode_set(DSHOT_PORT, GPIO_MODE_INPUT, GPIO_PULL_UP, DSHOT_PIN);
// 初始化定时器用于输入捕获
timer_input_capture_init(DSHOT_TIMER, DSHOT_CHANNEL, TIMER_INPUT_EDGE_BOTH);
// 使能定时器中断
timer_interrupt_enable(DSHOT_TIMER, TIMER_CC_INTERRUPT, TRUE);
// 初始化变量
rx_buf.data = 0;
rx_buf.bit_count = 0;
rx_buf.last_edge_time = 0;
rx_buf.telemetry_request = 0;
rx_buf.throttle = 0;
rx_buf.crc_valid = 0;
tx_buf.data = 0;
tx_buf.bit_count = 0;
dshot_state = DSHOT_STATE_IDLE;
}
// DSHOT输入捕获中断处理
void DSHOT_TIMER_IRQHandler(void)
{
if(timer_flag_get(DSHOT_TIMER, DSHOT_CHANNEL_FLAG) != RESET)
{
timer_flag_clear(DSHOT_TIMER, DSHOT_CHANNEL_FLAG);
// 仅在接收状态处理
if(dshot_state != DSHOT_STATE_IDLE && dshot_state != DSHOT_STATE_RECEIVING)
return;
// 获取当前捕获时间 (us)
uint32_t current_time = timer_input_capture_value_get(DSHOT_TIMER, DSHOT_CHANNEL);
uint32_t pulse_width = current_time - rx_buf.last_edge_time;
rx_buf.last_edge_time = current_time;
// 处理第一个边缘
if(rx_buf.bit_count == 0)
{
rx_buf.bit_count = 1;
dshot_state = DSHOT_STATE_RECEIVING;
return;
}
// 解析脉冲宽度
if(pulse_width > (DSHOT300_0_PULSE * 0.8) && pulse_width < (DSHOT300_0_PULSE * 1.2))
{
// 逻辑0
rx_buf.data <<= 1;
}
else if(pulse_width > (DSHOT300_1_PULSE * 0.8) && pulse_width < (DSHOT300_1_PULSE * 1.2))
{
// 逻辑1
rx_buf.data <<= 1;
rx_buf.data |= 1;
}
else
{
// 脉冲宽度异常,重置接收
rx_buf.data = 0;
rx_buf.bit_count = 0;
dshot_state = DSHOT_STATE_IDLE;
return;
}
rx_buf.bit_count++;
// 接收完成一帧
if(rx_buf.bit_count > DSHOT300_FRAME_BITS)
{
dshot_parse_frame();
rx_buf.data = 0;
rx_buf.bit_count = 0;
dshot_state = DSHOT_STATE_RECEIVED;
// 如果有遥测请求,准备发送遥测数据
if(rx_buf.telemetry_request)
{
dshot_prepare_telemetry(TELEMETRY_TYPE_ALL);
}
}
}
}
// 处理DSHOT任务
void dshot_task(void)
{
// 处理发送
if(dshot_state == DSHOT_STATE_SENDING)
{
dshot_send_process();
}
}
// 获取DSHOT接收的油门值
uint16_t dshot_get_throttle(void)
{
return rx_buf.throttle;
}
// 检查DSHOT数据是否有效
uint8_t dshot_is_data_valid(void)
{
return rx_buf.crc_valid;
}
4.7 CAN FD 接口实现
CAN FD 接口模块实现与飞控或其他设备的高速通信,支持大数据量传输。
c
运行
#include "can_fd.h"
#include "gpio.h"
#include "timer.h"
// CAN FD参数配置
#define CANFD_BAUDRATE 1000000 // 仲裁段波特率: 1Mbps
#define CANFD_DATA_BAUDRATE 8000000 // 数据段波特率: 8Mbps
#define CANFD_TX_ID 0x123 // 发送ID
#define CANFD_RX_ID 0x456 // 接收ID
#define CANFD_FILTER_MASK 0x7FF // 过滤器掩码
// CAN FD消息结构
typedef struct {
uint32_t id; // 消息ID
uint8_t data[64]; // 数据
uint8_t len; // 数据长度
uint8_t ext_id; // 是否扩展ID
uint8_t rtr; // 是否远程帧
} CanFdMessage;
// CAN FD接收和发送缓冲区
static CanFdMessage canfd_tx_msg = {0};
static CanFdMessage canfd_rx_msg = {0};
static uint8_t canfd_rx_flag = 0;
// CAN FD初始化
void can_fd_init(void)
{
// 使能CAN时钟
crm_periph_clock_enable(CRM_CAN1_PERIPH_CLOCK, TRUE);
// 配置CAN引脚
gpio_init_type gpio_init_struct;
gpio_default_para_init(&gpio_init_struct);
// CAN_RX (PA11), CAN_TX (PA12)
gpio_init_struct.gpio_pins = GPIO_PINS_11 | GPIO_PINS_12;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_pull = GPIO_PULL_UP;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(GPIOA, &gpio_init_struct);
// 复用配置
gpio_pin_remap_config(CAN1_REMAP, TRUE);
// 复位CAN
can_deinit(CAN1);
// 配置CAN FD
can_init_type can_init_struct;
can_struct_para_init(CAN_INIT_STRUCT, &can_init_struct);
// 配置CAN FD模式
can_init_struct.mode = CAN_MODE_NORMAL;
can_init_struct.time_triggered_mode = DISABLE;
can_init_struct.auto_bus_off_recovery = ENABLE;
can_init_struct.auto_wake_up = DISABLE;
can_init_struct.no_auto_retrans = DISABLE;
can_init_struct.receive_fifo_locked_mode = DISABLE;
can_init_struct.transmit_fifo_priority = DISABLE;
// 配置仲裁段波特率: 1Mbps
// 120MHz / (1Mbps * (1+6+8)) = 8
can_init_struct.resync_jump_width = CAN_BT_SJW_1TQ;
can_init_struct.time_segment_1 = CAN_BT_BS1_6TQ;
can_init_struct.time_segment_2 = CAN_BT_BS2_8TQ;
can_init_struct.prescaler = 8;
// 配置数据段波特率: 8Mbps
// 120MHz / (8Mbps * (1+3+2)) = 2.5 → 取3
can_init_struct.data_phase_prescaler = 3;
can_init_struct.time_segment_1_data = CAN_BT_BS1_3TQ;
can_init_struct.time_segment_2_data = CAN_BT_BS2_2TQ;
can_init_struct.resync_jump_width_data = CAN_BT_SJW_1TQ;
// 初始化CAN FD
can_init(CAN1, &can_init_struct);
// 配置过滤器
can_filter_init_type can_filter_struct;
can_struct_para_init(CAN_FILTER_STRUCT, &can_filter_struct);
can_filter_struct.filter_number = 0;
can_filter_struct.filter_mode = CAN_FILTER_MODE_ID_MASK;
can_filter_struct.filter_scale = CAN_FILTER_SCALE_32BIT;
can_filter_struct.filter_id_high = (CANFD_RX_ID << 5) & 0xFFFF;
can_filter_struct.filter_id_low = 0x0000;
can_filter_struct.filter_mask_id_high = (CANFD_FILTER_MASK << 5) & 0xFFFF;
can_filter_struct.filter_mask_id_low = 0x0000;
can_filter_struct.filter_fifo_number = CAN_FIFO_0;
can_filter_struct.filter_enable = ENABLE;
can_filter_init(&can_filter_struct);
// 使能接收中断
can_interrupt_enable(CAN1, CAN_FIFO0_MESSAGE_PENDING_INT, TRUE);
}
// 发送CAN FD消息
uint8_t can_fd_send_message(uint32_t id, uint8_t *data, uint8_t len, uint8_t ext_id, uint8_t rtr)
{
can_tx_message_type tx_msg;
uint8_t tx_mailbox;
// 检查数据长度
if(len > 64)
return 1; // 长度超过最大值
// 初始化发送消息结构
can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &tx_msg);
tx_msg.std_id = id;
tx_msg.ext_id = 0;
tx_msg.id_type = ext_id ? CAN_ID_EXT : CAN_ID_STD;
tx_msg.rtr = rtr ? CAN_RTR_REMOTE : CAN_RTR_DATA;
tx_msg.fd_mode = ENABLE; // 启用CAN FD模式
tx_msg.fd_padding = DISABLE;
tx_msg.data_length = len;
// 复制数据
for(uint8_t i = 0; i < len; i++)
{
tx_msg.data[i] = data[i];
}
// 发送消息
tx_mailbox = can_message_transmit(CAN1, &tx_msg);
// 等待发送完成或超时
uint32_t timeout = 10000;
while(can_transmit_status_get(CAN1, tx_mailbox) != CAN_TRANSMIT_OK && timeout--);
if(timeout == 0)
return 2; // 发送超时
return 0; // 发送成功
}
// 接收CAN FD消息
uint8_t can_fd_receive_message(CanFdMessage *msg)
{
if(!canfd_rx_flag)
return 1; // 没有新消息
// 复制消息
msg->id = canfd_rx_msg.id;
msg->len = canfd_rx_msg.len;
msg->ext_id = canfd_rx_msg.ext_id;
msg->rtr = canfd_rx_msg.rtr;
for(uint8_t i = 0; i < msg->len; i++)
{
msg->data[i] = canfd_rx_msg.data[i];
}
// 清除接收标志
canfd_rx_flag = 0;
return 0; // 接收成功
}
// 解析CAN FD消息
void can_fd_parse_message(CanFdMessage *msg)
{
// 根据消息ID处理不同类型的消息
switch(msg->id)
{
case 0x456: // 速度控制指令
if(msg->len == 4)
{
// 解析速度值 (float类型)
float speed;
memcpy(&speed, msg->data, 4);
// 设置速度环设定值
set_speed_ref(speed);
}
break;
case 0x457: // 参数配置指令
if(msg->len >= 2)
{
uint8_t param_id = msg->data[0];
uint8_t param_len = msg->data[1];
// 处理参数配置
param_set(param_id, &msg->data[2], param_len);
}
break;
case 0x458: // 系统指令
if(msg->len >= 1)
{
uint8_t cmd = msg->data[0];
// 处理系统指令
system_execute_command(cmd);
}
break;
// 其他消息处理...
default:
break;
}
}
// 发送电调状态消息
void can_fd_send_status(void)
{
uint8_t data[16];
float voltage = get_battery_voltage();
float current = (get_current_fdb_a() + get_current_fdb_b() + get_current_fdb_c()) / 3.0f;
float speed = get_speed_fdb();
float temperature = get_mos_temperature();
uint8_t status = get_system_status();
// 打包数据
memcpy(&data[0], &voltage, 4); // 0-3: 电压 (V)
memcpy(&data[4], ¤t, 4); // 4-7: 电流 (A)
memcpy(&data[8], &speed, 4); // 8-11: 转速 (RPM)
memcpy(&data[12], &temperature, 4); // 12-15: 温度 (℃)
// data[16] = status; // 16: 状态
// 发送消息
can_fd_send_message(CANFD_TX_ID, data, 16, 0, 0);
}
// CAN FD接收中断服务程序
void CAN1_RX0_IRQHandler(void)
{
can_rx_message_type rx_msg;
// 读取接收消息
can_message_receive(CAN1, CAN_FIFO_0, &rx_msg);
// 解析消息
canfd_rx_msg.id = rx_msg.std_id;
canfd_rx_msg.len = rx_msg.data_length;
canfd_rx_msg.ext_id = (rx_msg.id_type == CAN_ID_EXT) ? 1 : 0;
canfd_rx_msg.rtr = (rx_msg.rtr == CAN_RTR_REMOTE) ? 1 : 0;
for(uint8_t i = 0; i < canfd_rx_msg.len; i++)
{
canfd_rx_msg.data[i] = rx_msg.data[i];
}
// 设置接收标志
canfd_rx_flag = 1;
// 清除中断标志
can_flag_clear(CAN1, CAN_FIFO0_MESSAGE_PENDING_FLAG);
}
// CAN FD任务处理
void can_fd_task(void)
{
CanFdMessage msg;
// 检查是否有新消息
if(can_fd_receive_message(&msg) == 0)
{
// 解析消息
can_fd_parse_message(&msg);
}
// 周期性发送状态消息 (100ms)
static uint32_t last_send_time = 0;
if(timer_get_ticks_ms() - last_send_time > 100)
{
can_fd_send_status();
last_send_time = timer_get_ticks_ms();
}
}
4.8 故障检测与保护模块
故障检测与保护模块实时监测电调工作状态,在出现异常时采取保护措施,确保系统安全。
c
运行
#include "fault_protection.h"
#include "adc.h"
#include "current_loop.h"
#include "motor_driver.h"
#include "buzzer.h"
#include "led.h"
// 保护阈值设置
#define OVER_VOLTAGE_THRESHOLD 26.0f // 过压阈值 (V)
#define UNDER_VOLTAGE_THRESHOLD 10.0f // 欠压阈值 (V)
#define OVER_CURRENT_THRESHOLD 100.0f // 过流阈值 (A)
#define OVER_TEMP_THRESHOLD 100.0f // 过温阈值 (℃)
#define MAX_PWM_DUTY 0.95f // 最大PWM占空比
// 故障类型
typedef enum {
FAULT_NONE = 0,
FAULT_OVER_VOLTAGE,
FAULT_UNDER_VOLTAGE,
FAULT_OVER_CURRENT,
FAULT_OVER_TEMP,
FAULT_MOTOR_LOCKED,
FAULT_COMMUNICATION_LOSS,
FAULT_PWM_ERROR
} FaultType;
// 保护状态
typedef struct {
FaultType active_fault; // 当前活跃故障
uint8_t over_voltage_flag; // 过压标志
uint8_t under_voltage_flag; // 欠压标志
uint8_t over_current_flag; // 过流标志
uint8_t over_temp_flag; // 过温标志
uint8_t motor_locked_flag; // 电机堵转标志
uint8_t comm_loss_flag; // 通信丢失标志
uint8_t pwm_error_flag; // PWM错误标志
uint32_t fault_time; // 故障发生时间
uint8_t fault_count; // 故障计数
} ProtectionState;
// 保护状态变量
static ProtectionState protection_state = {0};
// 检测电池电压故障
static void check_voltage_fault(void)
{
float voltage = get_battery_voltage();
// 过压检测
if(voltage > OVER_VOLTAGE_THRESHOLD)
{
protection_state.over_voltage_flag = 1;
protection_state.active_fault = FAULT_OVER_VOLTAGE;
}
else
{
protection_state.over_voltage_flag = 0;
}
// 欠压检测
if(voltage < UNDER_VOLTAGE_THRESHOLD)
{
protection_state.under_voltage_flag = 1;
protection_state.active_fault = FAULT_UNDER_VOLTAGE;
}
else
{
protection_state.under_voltage_flag = 0;
}
}
// 检测过流故障
static void check_current_fault(void)
{
float ia = get_current_fdb_a();
float ib = get_current_fdb_b();
float ic = get_current_fdb_c();
float max_current = fmax(fabs(ia), fmax(fabs(ib), fabs(ic)));
// 过流检测
if(max_current > OVER_CURRENT_THRESHOLD)
{
protection_state.over_current_flag = 1;
protection_state.active_fault = FAULT_OVER_CURRENT;
}
else
{
protection_state.over_current_flag = 0;
}
}
// 检测过温故障
static void check_temp_fault(void)
{
float temp = get_mos_temperature();
// 过温检测
if(temp > OVER_TEMP_THRESHOLD)
{
protection_state.over_temp_flag = 1;
protection_state.active_fault = FAULT_OVER_TEMP;
}
else
{
protection_state.over_temp_flag = 0;
}
}
// 检测电机堵转故障
static void check_motor_locked(void)
{
static uint32_t locked_start_time = 0;
float speed = get_speed_fdb();
float current = (get_current_fdb_a() + get_current_fdb_b() + get_current_fdb_c()) / 3.0f;
// 电机堵转条件: 速度接近0但电流较大
if(speed < 100.0f && current > 20.0f) // 速度<100RPM,电流>20A
{
if(locked_start_time == 0)
{
locked_start_time = timer_get_ticks_ms();
}
else if(timer_get_ticks_ms() - locked_start_time > 500) // 持续500ms
{
protection_state.motor_locked_flag = 1;
protection_state.active_fault = FAULT_MOTOR_LOCKED;
}
}
else
{
locked_start_time = 0;
protection_state.motor_locked_flag = 0;
}
}
// 检测通信丢失故障
static void check_communication_loss(void)
{
static uint32_t last_comm_time = 0;
// 检查是否有新的DSHOT或CAN消息
if(dshot_is_data_valid() || canfd_rx_flag)
{
last_comm_time = timer_get_ticks_ms();
protection_state.comm_loss_flag = 0;
}
// 超过1秒无通信
else if(timer_get_ticks_ms() - last_comm_time > 1000 && last_comm_time != 0)
{
protection_state.comm_loss_flag = 1;
protection_state.active_fault = FAULT_COMMUNICATION_LOSS;
}
}
// 检测PWM错误
static void check_pwm_error(void)
{
// 检查PWM占空比是否正常
if(get_pwm_duty() > MAX_PWM_DUTY)
{
protection_state.pwm_error_flag = 1;
protection_state.active_fault = FAULT_PWM_ERROR;
}
else
{
protection_state.pwm_error_flag = 0;
}
}
// 执行保护动作
static void execute_protection_action(FaultType fault)
{
switch(fault)
{
case FAULT_OVER_VOLTAGE:
// 过压保护: 降低输出功率
set_speed_ref(get_speed_fdb() * 0.9f);
buzzer_beep(100, 900); // 100ms提示音
led_flash(LED_RED, 100, 900);
break;
case FAULT_UNDER_VOLTAGE:
// 欠压保护: 逐步降低输出功率
set_speed_ref(get_speed_fdb() * 0.95f);
buzzer_beep(200, 800); // 200ms提示音
led_flash(LED_RED, 200, 800);
break;
case FAULT_OVER_CURRENT:
// 过流保护: 立即降低输出
set_speed_ref(get_speed_fdb() * 0.5f);
buzzer_beep(500, 500); // 500ms提示音
led_flash(LED_RED, 500, 500);
break;
case FAULT_OVER_TEMP:
// 过温保护: 降低输出功率
set_speed_ref(get_speed_fdb() * 0.8f);
buzzer_beep(300, 700); // 300ms提示音
led_flash(LED_YELLOW, 300, 700);
break;
case FAULT_MOTOR_LOCKED:
case FAULT_COMMUNICATION_LOSS:
case FAULT_PWM_ERROR:
// 严重故障: 停止电机
motor_stop();
buzzer_beep(1000, 1000); // 持续报警
led_flash(LED_RED, 100, 100); // 快速闪烁
break;
default:
// 无故障: 正常运行指示灯
led_on(LED_GREEN);
break;
}
}
// 初始化故障保护
void fault_protection_init(void)
{
protection_state.active_fault = FAULT_NONE;
protection_state.over_voltage_flag = 0;
protection_state.under_voltage_flag = 0;
protection_state.over_current_flag = 0;
protection_state.over_temp_flag = 0;
protection_state.motor_locked_flag = 0;
protection_state.comm_loss_flag = 0;
protection_state.pwm_error_flag = 0;
protection_state.fault_time = 0;
protection_state.fault_count = 0;
}
// 故障检测主函数
void fault_detection(void)
{
// 依次检测各类故障
check_voltage_fault();
check_current_fault();
check_temp_fault();
check_motor_locked();
check_communication_loss();
check_pwm_error();
// 如果有活跃故障
if(protection_state.active_fault != FAULT_NONE)
{
if(protection_state.fault_time == 0)
{
protection_state.fault_time = timer_get_ticks_ms();
protection_state.fault_count++;
}
// 执行保护动作
execute_protection_action(protection_state.active_fault);
}
else
{
// 无故障,重置故障时间
protection_state.fault_time = 0;
led_on(LED_GREEN);
}
}
// 获取当前故障状态
FaultType get_active_fault(void)
{
return protection_state.active_fault;
}
// 获取系统状态字
uint8_t get_system_status(void)
{
uint8_t status = 0;
if(protection_state.over_voltage_flag) status |= (1 << 0);
if(protection_state.under_voltage_flag) status |= (1 << 1);
if(protection_state.over_current_flag) status |= (1 << 2);
if(protection_state.over_temp_flag) status |= (1 << 3);
if(protection_state.motor_locked_flag) status |= (1 << 4);
if(protection_state.comm_loss_flag) status |= (1 << 5);
if(protection_state.pwm_error_flag) status |= (1 << 6);
return status;
}
// 清除故障状态
void clear_fault_status(void)
{
protection_state.active_fault = FAULT_NONE;
protection_state.over_voltage_flag = 0;
protection_state.under_voltage_flag = 0;
protection_state.over_current_flag = 0;
protection_state.over_temp_flag = 0;
protection_state.motor_locked_flag = 0;
protection_state.comm_loss_flag = 0;
protection_state.pwm_error_flag = 0;
protection_state.fault_time = 0;
}
五、系统调试与测试
系统调试与测试是确保电调性能和可靠性的关键环节,包括硬件测试、软件调试和系统联调三个阶段。
5.1 硬件测试
硬件测试主要验证电路设计的正确性和可靠性:
| 测试项目 | 测试方法 | 合格标准 |
|---|---|---|
| 电源测试 | 输入 11.1-25.2V 电压,测量各输出电压 | 3.3V±0.05V,5V±0.1V,12V±0.2V |
| 功率测试 | 施加 80A 电流,持续 10 分钟 | 无过热(<85℃),无保护动作 |
| 绝缘测试 | 500V 兆欧表测量高低压之间绝缘电阻 | ≥100MΩ |
| ESD 测试 | ±8kV 接触放电,±15kV 空气放电 | 系统正常工作,无复位或损坏 |
| 温度测试 | -40℃~85℃温度箱中测试功能 | 全温范围内正常工作 |
5.2 软件调试
软件调试采用分层调试策略,确保各模块功能正确:
-
模块调试:
- 使用示波器验证 PWM 波形正确性
- 检查 ADC 采样精度和线性度
- 验证 DSHOT 和 CAN 通信时序
-
算法调试:
- 阶跃响应测试:给定期望值,观察响应曲线
- 频率响应测试:通过正弦扫频获取 Bode 图
- 负载扰动测试:突加负载,观察恢复能力
-
参数优化:
- 电流环:带宽 50kHz,相位裕度≥45°
- 力矩环:带宽 10kHz,相位裕度≥50°
- 速度环:带宽 1kHz,相位裕度≥55°
5.3 系统联调
系统联调验证电调与飞控、电机的协同工作能力:
| 测试项目 | 测试方法 | 合格标准 |
|---|---|---|
| 转速控制精度 | 设定不同转速,测量实际转速 | 误差 <±2% |
| 响应时间 | 阶跃指令下,达到 90% 设定值的时间 | <100ms |
| 最大推力 | 配合指定螺旋桨,测量最大推力 | 满足设计指标 |
| 续航时间 | 满负载下持续运行至低压保护 | 达到设计值 |
| 可靠性测试 | 连续运行 100 小时 | 无故障,性能稳定 |
六、结论与展望
基于 AT32M412 的 80A 无人机电调设计采用了先进的硬件架构和控制算法,实现了高性能、高可靠性的电机控制。测试结果表明,该电调具有以下特点:
- 输出电流稳定,80A 持续电流下温升控制在 40℃以内
- 控制精度高,转速误差小于 ±2%
- 响应速度快,阶跃响应时间小于 100ms
- 通信可靠,DSHOT300 和 CAN FD 通信误码率为 0
- 保护完善,具备过压、欠压、过流、过温等多重保护
未来可以从以下几个方面进行优化:
- 采用更高效的功率器件(如 GaN MOSFET),提高效率 5-10%
- 引入模型预测控制(MPC)算法,进一步提升动态性能
- 增加无线通信模块,支持远程调试和固件升级
- 优化散热设计,实现 100A 以上的电流输出
AT32M412 微控制器凭借其出色的性能和丰富的外设,为高性能电调设计提供了理想的平台,其高性价比特性也使其在无人机领域具有广阔的应用前景。
附录:常用参数与计算公式
电机参数
- 相电阻 R = 0.1Ω
- 相电感 L = 1mH
- 转矩常数 Kt = 0.1N・m/A
- 反电动势常数 Ke = 0.1V/(rad/s)
PID 参数计算公式
-
电流环 PI 参数:
- Kp = ωc·L/2
- Ki = ωc·R/(2·T)
-
力矩环 PI 参数:
- Kp = ωc/(2·Kt)
- Ki = ωc/(2·Kt·T)
-
速度环 PID 参数:
- Kp = (h+1)·B/(2·h·J)
- Ki = B/(h·J·T)
- Kd = h·J/(2·(h+1)·T)
DSHOT 帧格式
- 16 位帧结构:[11 位数据][1 位遥测请求][4 位 CRC]
- CRC 计算:CRC = (数据>> 1) ^ (数据 >> 5) ^ (数据 >> 9)
CAN FD 配置参数
- 仲裁段:波特率 1Mbps,SJW=1TQ,BS1=6TQ,BS2=8TQ
- 数据段:波特率 8Mbps,SJW=1TQ,BS1=3TQ,BS2=2TQ

1537

被折叠的 条评论
为什么被折叠?



