AM32开源代码之代码分析 - 正选控制
1. 源由
BLDC 控制方式通常有以下几种:
- 梯形120°
- 梯形150°
- 正弦180°
- 矢量控制
本章将重点介绍正选控制方式。
2. 框架设计
2.1 初始化&调用
调用setInput
获取输入值
- 轮询
main
└──> setInput
- 中断
main
└──> enableCorePeripherals
└──> EXTI4_15_IRQHandler
EXTI4_15_IRQHandler
└──> processDshot
└──> setInput
2.2 输入处理
通过setInput
函数依据配置参数进行入参处理:
- bi_direction: 双向驱动
- dshot: dshot数字协议
- RC_CAR_REVERSE: 遥控车反向功能
- forward: 前进方向
- prop_brake_active: 制动模式
- return_to_center: 摇杆中心位置标记
setInput
│ /*
│ * 双向驱动 (Bi-directional Drive)
│ */
├──> if (bi_direction) { // 如果启用了双向驱动
│ │ │ /*
│ │ │ * 非dshot数字协议 (Non-dshot Digital Protocol)
│ │ │ */
│ │ ├──> if (dshot == 0) { // 如果未使用dshot协议
│ │ │ └──> if (RC_CAR_REVERSE) { // 如果启用了遥控车反向功能
│ │ │ │ │ /* 47 --> 2047 */
│ │ │ │ ├──> if (newinput > (1000 + (servo_dead_band << 1))) { // 如果输入大于1000加死区偏移
│ │ │ │ │ ├──> if (forward == dir_reversed) { // 如果当前方向与目标方向相反
│ │ │ │ │ │ ├──> adjusted_input = 0; // 将输入调整为0
│ │ │ │ │ │ ├──> prop_brake_active = 1; // 激活制动
│ │ │ │ │ │ └──> if (return_to_center) { // 如果需要回到中心位置
│ │ │ │ │ │ ├──> forward = 1 - dir_reversed; // 切换前进方向
│ │ │ │ │ │ ├──> prop_brake_active = 0; // 取消制动
│ │ │ │ │ │ └──> return_to_center = 0; // 取消回到中心位置标记
│ │ │ │ │ └──> if (prop_brake_active == 0) { // 如果未激活制动
│ │ │ │ │ ├──> return_to_center = 0; // 取消回到中心位置标记
│ │ │ │ │ └──> adjusted_input = map(newinput, 1000 + (servo_dead_band << 1), 2000, 47, 2047); // 线性映射输入值
│ │ │ │ │
│ │ │ │ │ /* 2047 --> 47 */
│ │ │ │ ├──> if (newinput < (1000 - (servo_dead_band << 1))) { // 如果输入小于1000减去死区偏移
│ │ │ │ │ ├──> if (forward == (1 - dir_reversed)) { // 如果当前方向与目标方向一致
│ │ │ │ │ │ ├──> adjusted_input = 0; // 将输入调整为0
│ │ │ │ │ │ ├──> prop_brake_active = 1; // 激活制动
│ │ │ │ │ │ └──> if (return_to_center) { // 如果需要回到中心位置
│ │ │ │ │ │ ├──> forward = dir_reversed; // 切换前进方向
│ │ │ │ │ │ ├──> prop_brake_active = 0; // 取消制动
│ │ │ │ │ │ └──> return_to_center = 0; // 取消回到中心位置标记
│ │ │ │ │ └──> if (prop_brake_active == 0) { // 如果未激活制动
│ │ │ │ │ ├──> return_to_center = 0; // 取消回到中心位置标记
│ │ │ │ │ └──> adjusted_input = map(newinput, 0, 1000 - (servo_dead_band << 1), 2047, 47); // 线性映射输入值
│ │ │ │ │
│ │ │ │ │ /* 0 */
│ │ │ │ └──> if (newinput >= (1000 - (servo_dead_band << 1)) && newinput <= (1000 + (servo_dead_band << 1))) { // 如果输入在死区范围内
│ │ │ │ ├──> adjusted_input = 0; // 将输入调整为0
│ │ │ │ └──> if (prop_brake_active) { // 如果制动已激活
│ │ │ │ ├──> prop_brake_active = 0; // 取消制动
│ │ │ │ └──> return_to_center = 1; // 标记回到中心位置
│ │ │ └──> else { // 如果未启用遥控车反向功能
│ │ │ │ /* 47 --> 2047 */
│ │ │ ├──> if (newinput > (1000 + (servo_dead_band << 1))) { // 如果输入大于1000加死区偏移
│ │ │ │ ├──> if (forward == dir_reversed) { // 如果当前方向与目标方向相反
│ │ │ │ │ │ └──> if (((commutation_interval > reverse_speed_threshold) && (duty_cycle < 200)) || stepper_sine) { // 如果满足条件,切换前进方向
│ │ │ │ │ │ ├──> forward = 1 - dir_reversed; // 切换前进方向
│ │ │ │ │ │ ├──> zero_crosses = 0; // 重置过零次数
│ │ │ │ │ │ ├──> old_routine = 1; // 标记为旧例程
│ │ │ │ │ │ ├──> maskPhaseInterrupts(); // 屏蔽相位中断
│ │ │ │ │ │ └──> brushed_direction_set = 0; // 重置刷子方向设置
│ │ │ │ │ └──> else { // 如果不满足条件
│ │ │ │ │ └──> newinput = 1000; // 将输入调整为1000
│ │ │ │ └──> adjusted_input = map(newinput, 1000 + (servo_dead_band << 1), 2000, 47, 2047); // 线性映射输入值
│ │ │ │
│ │ │ │ /* 2047 --> 47 */
│ │ │ ├──> if (newinput < (1000 - (servo_dead_band << 1))) { // 如果输入小于1000减去死区偏移
│ │ │ │ ├──> if (forward == (1 - dir_reversed)) { // 如果当前方向与目标方向一致
│ │ │ │ │ │ └──> if (((commutation_interval > reverse_speed_threshold) && (duty_cycle < 200)) || stepper_sine) { // 如果满足条件,切换前进方向
│ │ │ │ │ │ ├──> zero_crosses = 0; // 重置过零次数
│ │ │ │ │ │ ├──> old_routine = 1; // 标记为旧例程
│ │ │ │ │ │ ├──> forward = dir_reversed; // 切换前进方向
│ │ │ │ │ │ ├──> maskPhaseInterrupts(); // 屏蔽相位中断
│ │ │ │ │ │ └──> brushed_direction_set = 0; // 重置刷子方向设置
│ │ │ │ │ └──> else { // 如果不满足条件
│ │ │ │ │ └──> newinput = 1000; // 将输入调整为1000
│ │ │ │ └──> adjusted_input = map(newinput, 0, 1000 - (servo_dead_band << 1), 2047, 47); // 线性映射输入值
│ │ │ │
│ │ │ │ /* 0 */
│ │ │ └──> if (newinput >= (1000 - (servo_dead_band << 1)) && newinput <= (1000 + (servo_dead_band << 1))) { // 如果输入在死区范围内
│ │ │ ├──> adjusted_input = 0; // 将输入调整为0
│ │ │ └──> brushed_direction_set = 0; // 重置刷子方向设置
│ │ │
│ │ │ /*
│ │ │ * dshot数字协议 (Dshot Digital Protocol)
│ │ │ */
│ │ └──> if (dshot) { // 如果使用dshot协议
│ │ │
│ │ │ /* 47 --> 2047 */
│ │ ├──> if (newinput > 1047) { // 如果输入大于1047
│ │ │ ├──> if (forward == dir_reversed) { // 如果当前方向与目标方向相反
│ │ │ │ │ └──> if (((commutation_interval > reverse_speed_threshold) && (duty_cycle < 200)) || stepper_sine) { // 如果满足条件,切换前进方向
│ │ │ │ │ ├──> forward = 1 - dir_reversed; // 切换前进方向
│ │ │ │ │ ├──> zero_crosses = 0; // 重置过零次数
│ │ │ │ │ ├──> old_routine = 1; // 标记为旧例程
│ │ │ │ │ ├──> maskPhaseInterrupts(); // 屏蔽相位中断
│ │ │ │ │ └──> brushed_direction_set = 0; // 重置刷子方向设置
│ │ │ │ └──> else { // 如果不满足条件
│ │ │ │ └──> newinput = 0; // 将输入调整为0
│ │ │ └──> adjusted_input = ((newinput - 1048) * 2 + 47) - reversing_dead_band; // 计算调整后的输入值,并减去反向死区
│ │ │
│ │ │ /* 47 --> 2047 ??? */
│ │ ├──> if (newinput <= 1047 && newinput > 47) { // 如果输入在47和1047之间
│ │ │ ├──> if (forward == (1 - dir_reversed)) { // 如果当前方向与目标方向一致
│ │ │ │ │ └──> if (((commutation_interval > reverse_speed_threshold) && (duty_cycle < 200)) || stepper_sine) { // 如果满足条件,切换前进方向
│ │ │ │ │ ├──> zero_crosses = 0; // 重置过零次数
│ │ │ │ │ ├──> old_routine = 1; // 标记为旧例程
│ │ │ │ │ ├──> forward = dir_reversed; // 切换前进方向
│ │ │ │ │ ├──> maskPhaseInterrupts(); // 屏蔽相位中断
│ │ │ │ │ └──> brushed_direction_set = 0; // 重置刷子方向设置
│ │ │ │ └──> else { // 如果不满足条件
│ │ │ │ └──> newinput = 0; // 将输入调整为0
│ │ │ └──> adjusted_input = ((newinput - 48) * 2 + 47) - reversing_dead_band; // 计算调整后的输入值,并减去反向死区
│ │ │
│ │ │ /* 0 */
│ │ └──> if (newinput < 48) { // 如果输入小于48
│ │ ├──> adjusted_input = 0; // 将输入调整为0
│ │ └──> brushed_direction_set = 0; // 重置刷子方向设置
│ │
│ │ /*
│ │ * 单向驱动 (Unidirectional Drive)
│ │ */
│ └──> else { // 如果未启用双向驱动
│ └──> adjusted_input = newinput; // 将输入直接作为调整后的输入
│
│ /*
│ * BEMF超时 & 转子锁死保护
│ * 如果发生了BEMF超时且启用了转子锁死保护,则关闭所有输出并屏蔽相位中断,输入值设为0,并将bemf_timeout_happened变量设为102。
│ */
├──> if ((bemf_timeout_happened > bemf_timeout) && stuck_rotor_protection) {
│ │ ├──> allOff(); // 关闭所有输出
│ │ ├──> maskPhaseInterrupts(); // 屏蔽相位中断
│ │ ├──> input = 0; // 将输入值设为0
│ │ └──> bemf_timeout_happened = 102; // 设置bemf_timeout_happened变量为102
│ └──> else {
│ │ /*
│ │ * 正弦启动模式
│ │ * 如果使用正弦启动,基于输入值调整输入。
│ │ */
│ └──> if (use_sin_start) {
│ │ ├──> if (adjusted_input < 30) { // 死区?
│ │ │ └──> input = 0; // 如果调整后的输入值小于30,则设为0
│ │ ├──> if (adjusted_input > 30 && adjusted_input < (sine_mode_changeover_thottle_level * 20)) {
│ │ │ └──> input = map(adjusted_input, 30, (sine_mode_changeover_thottle_level * 20), 47, 160); // 线性映射输入值
│ │ └──> if (adjusted_input >= (sine_mode_changeover_thottle_level * 20)) {
│ │ └──> input = map(adjusted_input, (sine_mode_changeover_thottle_level * 20), 2047, 160, 2047); // 继续线性映射输入值
│ │ /*
│ │ * 非正弦启动模式
│ │ * 如果没有使用正弦启动,按以下逻辑处理。
│ │ */
│ └──> else {
│ └──> if (use_speed_control_loop) { // 使用速度控制循环
│ │ └──> if (drive_by_rpm) { // 如果使用转速驱动
│ │ │ ├──> target_e_com_time = 60000000 / map(adjusted_input, 47, 2047, MINIMUM_RPM_SPEED_CONTROL, MAXIMUM_RPM_SPEED_CONTROL) / (motor_poles / 2); // 计算目标换向时间
│ │ │ └──> if (adjusted_input < 47) { // 死区?
│ │ │ │ ├──> input = 0; // 输入设为0
│ │ │ │ ├──> speedPid.error = 0; // 重置PID误差
│ │ │ │ └──> input_override = 0; // 重置输入覆盖值
│ │ │ └──> else {
│ │ │ ├──> input = (uint16_t)input_override; // PID控制覆盖输入
│ │ │ ├──> if (input_override > 2047) {
│ │ │ │ └──> input = 2047; // 限制最大输入值
│ │ │ └──> if (input_override < 48) {
│ │ │ └──> input = 48; // 限制最小输入值
│ │ └──> else {
│ │ ├──> input = (uint16_t)input_override; // PID控制覆盖输入
│ │ ├──> if (input_override > 2047) {
│ │ │ └──> input = 2047; // 限制最大输入值
│ │ └──> if (input_override < 48) {
│ │ └──> input = 48; // 限制最小输入值
│ └──> else {
│ └──> input = adjusted_input; // 直接使用调整后的输入值
│ /*
│ * 主流程控制
│ */
└──> if (!stepper_sine) { // 如果不是步进正弦模式
├──> if (input >= 47 + (80 * use_sin_start) && armed) { // 如果输入大于特定值且系统已解锁
│ ├──> if (running == 0) { // 如果系统未运行
│ │ ├──> allOff(); // 关闭所有输出
│ │ ├──> if (!old_routine) {
│ │ │ └──> startMotor(); // 启动电机
│ │ ├──> running = 1; // 设置系统为运行状态
│ │ └──> last_duty_cycle = min_startup_duty; // 记录最后一次的占空比
│ ├──> if (use_sin_start) {
│ │ │ └──> duty_cycle_setpoint = map(input, 137, 2047, minimum_duty_cycle+40, 2000); // 线性映射占空比
│ │ └──> else {
│ │ └──> duty_cycle_setpoint = map(input, 47, 2047, minimum_duty_cycle, 2000); // 线性映射占空比
│ └──> if (!RC_CAR_REVERSE) { // 如果不启用遥控车倒车
│ └──> prop_brake_active = 0; // 关闭比例制动
│
├──> if (input < 47 + (80 * use_sin_start)) { // 如果输入小于特定值
│ └──> if (play_tone_flag != 0) { // 如果需要播放音调
│ ├──> switch (play_tone_flag) { // 根据标志位播放对应音调
│ │ ├──> case 1: playDefaultTone(); // 播放默认音调
│ │ ├──> case 2: playChangedTone(); // 播放变化音调
│ │ ├──> case 3: playBeaconTune3(); // 播放信标音调
│ │ ├──> case 4: playInputTune2(); // 播放输入音调
│ │ └──> case 5: playDefaultTone(); // 播放默认音调
│ └──> play_tone_flag = 0; // 重置音调标志位
│
├──> if (!comp_pwm) { // 如果不使用复合PWM
│ │ ├──> duty_cycle_setpoint = 0; // 占空比设为0
│ │ ├──> if (!running) { // 如果系统未运行
│ │ │ ├──> old_routine = 1; // 标记为旧例程
│ │ │ ├──> zero_crosses = 0; // 重置零交叉次数
│ │ │ └──> if (brake_on_stop) { // 如果停机时制动
│ │ │ │ └──> fullBrake(); // 全力制动
│ │ │ └──> else {
│ │ │ └──> if (!prop_brake_active) {
│ │ │ └──> allOff(); // 关闭所有输出
│ │ │
│ │ └──> if (RC_CAR_REVERSE && prop_brake_active) { // 如果启用了遥控车倒车且比例制动激活
│ │ ├──> prop_brake_duty_cycle = (getAbsDif(1000, newinput) + 1000); // 计算比例制动占空比
│ │ └──> if (prop_brake_duty_cycle >= (TIMER1_MAX_ARR - 1)) {
│ │ │ └──> fullBrake(); // 全力制动
│ │ └──> else {
│ │ └──> proportionalBrake(); // 使用比例制动
│ └─> else {
│ ├──> if (!running) { // 如果系统未运行
│ │ ├──> old_routine = 1; // 标记为旧例程
│ │ ├──> zero_crosses = 0; // 重置零交叉次数
│ │ ├──> bad_count = 0; // 重置错误计数
│ │ ├──> if (brake_on_stop) { // 如果停机时制动
│ │ │ │ └──> if (!use_sin_start) { // 如果不使用正弦启动
│ │ │ │ ├──> prop_brake_duty_cycle = (1980) + drag_brake_strength * 2; // 计算拖动制动占空比
│ │ │ │ ├──> proportionalBrake(); // 使用比例制动
│ │ │ │ └──> prop_brake_active = 1; // 激活比例制动
│ │ │ └──> else {
│ │ │ └──> allOff(); // 关闭所有输出
│ │ └──> duty_cycle_setpoint = 0; // 占空比设为0
│ │
│ ├──> phase_A_position = ((step - 1) * 60) + enter_sine_angle; // 计算A相位置
│ ├──> if (phase_A_position > 359) {
│ │ └──> phase_A_position -= 360; // 确保A相位置在0-359度范围内
│ │
│ ├──> phase_B_position = phase_A_position + 119; // 计算B相位置
│ ├──> if (phase_B_position > 359) {
│ │ └──> phase_B_position -= 360; // 确保B相位置在0-359度范围内
│ │
│ ├──> phase_C_position = phase_A_position + 239; // 计算C相位置
│ ├──> if (phase_C_position > 359) {
│ │ └──> phase_C_position -= 360; // 确保C相位置在0-359度范围内
│ │
│ ├──> if (use_sin_start == 1) {
│ │ └──> stepper_sine = 1; // 启用步进正弦
│ └──> duty_cycle_setpoint = 0; // 占空比设为0
│
└──> if (!prop_brake_active) { // 如果比例制动未激活
├──> if (input >= 47 && (zero_crosses < (30 >> stall_protection))) { // 输入大于特定值且零交叉次数少于设定值
│ ├──> if (duty_cycle_setpoint < min_startup_duty) {
│ │ └──> duty_cycle_setpoint = min_startup_duty; // 占空比设为最小启动占空比
│ └──> if (duty_cycle_setpoint > startup_max_duty_cycle) {
│ └──> duty_cycle_setpoint = startup_max_duty_cycle; // 占空比设为启动最大占空比
├──> if (duty_cycle_setpoint > duty_cycle_maximum) {
│ └──> duty_cycle_setpoint = duty_cycle_maximum; // 限制占空比为最大值
├──> if (use_current_limit) { // 如果使用电流限制
│ └──> if (duty_cycle_setpoint > use_current_limit_adjust) {
│ └──> duty_cycle_setpoint = use_current_limit_adjust; // 限制占空比为电流限制后的值
└──> if (stall_protection_adjust > 0 && input > 47) { // 如果启用了失速保护调整且输入大于47
└──> duty_cycle_setpoint = duty_cycle_setpoint + (uint16_t)stall_protection_adjust; // 调整占空比以启用失速保护
2.3 定时处理
- inputSet: 是否有输入
- cell_count: 电池节数(默认为0)
- zero_input_count: 无输入(无中断,或者模拟量输入太小)
tenKhzRoutine
│
│ /*
│ * 更新频率设置为20kHz,从2.00开始,需重命名
│ */
├──> duty_cycle = duty_cycle_setpoint; // 更新占空比为目标值
├──> tenkhzcounter++; // 10kHz计数器增加
├──> one_khz_loop_counter++; // 1kHz循环计数器增加
│
│ /*
│ * 在未解锁情况下计算`armed_timeout_count`,并提示音
│ */
├──> if (!armed) { // 如果系统未解锁
│ └──> if (cell_count == 0) { // 如果电池单元数为0
│ └──> if (inputSet) { // 如果输入设置有效
│ │ └──> if (adjusted_input == 0) { // 如果调整后的输入为0
│ │ ├──> armed_timeout_count++; // 超时计数器增加
│ │ └──> if (armed_timeout_count > LOOP_FREQUENCY_HZ) { // 如果超时计数器超过1秒
│ │ └──> if (zero_input_count > 30) { // 如果零输入计数器超过30
│ │ │ ├──> armed = 1; // 系统解锁???
│ │ │ ├──> if ((cell_count == 0) && LOW_VOLTAGE_CUTOFF) { // 如果电池单元数为0且低电压截止
│ │ │ │ │ ├──> cell_count = battery_voltage / 370; // 根据电池电压计算电池单元数
│ │ │ │ │ └──> for (int i = 0; i < cell_count; i++) { // 为每个电池单元执行操作
│ │ │ │ │ ├──> playInputTune(); // 播放输入音调
│ │ │ │ │ ├──> delayMillis(100); // 延时100毫秒
│ │ │ │ │ └──> RELOAD_WATCHDOG_COUNTER(); // 重新加载看门狗计数器
│ │ │ │ └──> else { // 如果不满足低电压截止条件
│ │ │ │ └──> playInputTune(); // 播放输入音调
│ │ │ └──> if (!servoPwm) { // 如果伺服PWM信号无效
│ │ │ └──> RC_CAR_REVERSE = 0; // 反向控制设置为0
│ │ └──> else { // 如果调整后的输入不为0
│ │ ├──> inputSet = 0; // 输入设置无效
│ │ └──> armed_timeout_count = 0; // 重置超时计数器
│ └──> else { // 如果输入设置无效
│ └──> armed_timeout_count = 0; // 重置超时计数器
│
│ /*
│ * 遥测报文发送计时
│ */
├──> if (TLM_ON_INTERVAL) { // 如果开启了遥测定时
│ ├──> telem_ms_count++; // 遥测计数器增加
│ └──> if (telem_ms_count > telemetry_interval_ms * 20) { // 如果遥测计数器超过设定时间
│ ├──> send_telemetry = 1; // 设置发送遥测数据标志
│ └──> telem_ms_count = 0; // 重置遥测计数器
│
│ /*
│ * 处理步进电机正弦波的相关逻辑
│ */
├──> if (!stepper_sine) { // 如果未使用步进电机正弦波控制
│ │
│ ├──> if (old_routine && running) { // 如果旧的例程正在运行
│ │ ├──> maskPhaseInterrupts(); // 遮蔽相位中断
│ │ ├──> getBemfState(); // 获取反电动势状态
│ │ └──> if (!zcfound) { // 如果未找到零交叉点
│ │ └──> if (rising) { // 如果是上升沿
│ │ │ └──> if (bemfcounter > min_bemf_counts_up) { // 如果反电动势计数超过最小值
│ │ │ ├──> zcfound = 1; // 找到零交叉点
│ │ │ └──> zcfoundroutine(); // 执行零交叉例程
│ │ └──> else { // 如果是下降沿
│ │ └──> if (bemfcounter > min_bemf_counts_down) { // 如果反电动势计数超过最小值
│ │ ├──> zcfound = 1; // 找到零交叉点
│ │ └──> zcfoundroutine(); // 执行零交叉例程
│ │
│ ├──> if (one_khz_loop_counter > PID_LOOP_DIVIDER) { // 如果1kHz循环计数器超过设定值
│ │ ├──> one_khz_loop_counter = 0; // 重置1kHz循环计数器
│ │ ├──> if (use_current_limit && running) { // 如果启用了电流限制且系统正在运行
│ │ │ ├──> use_current_limit_adjust -= (int16_t)(doPidCalculations(¤tPid, actual_current, CURRENT_LIMIT * 100)/ 10000); // 调整电流限制
│ │ │ ├──> if (use_current_limit_adjust < minimum_duty_cycle) { // 如果调整后的电流限制低于最小占空比
│ │ │ │ └──> use_current_limit_adjust = minimum_duty_cycle; // 设置为最小占空比
│ │ │ └──> if (use_current_limit_adjust > tim1_arr) { // 如果调整后的电流限制高于最大值
│ │ │ └──> use_current_limit_adjust = tim1_arr; // 设置为最大值
│ │ │
│ │ ├──> if (stall_protection && running) { // 如果启用了失速保护且系统正在运行
│ │ │ ├──> stall_protection_adjust += (doPidCalculations(&stallPid, commutation_interval, stall_protect_target_interval))/ 10000; // 调整失速保护
│ │ │ ├──> if (stall_protection_adjust > 150) { // 如果失速保护调整值超过150
│ │ │ │ └──> stall_protection_adjust = 150; // 设置为150
│ │ │ └──> if (stall_protection_adjust <= 0) { // 如果失速保护调整值小于等于0
│ │ │ └──> stall_protection_adjust = 0; // 设置为0
│ │ │
│ │ └──> if (use_speed_control_loop && running) { // 如果启用了速度控制循环且系统正在运行
│ │ ├──> input_override += doPidCalculations(&speedPid, e_com_time, target_e_com_time) / 10000; // 调整输入
│ │ ├──> if (input_override > 2047) { // 如果调整后的输入超过2047
│ │ │ └──> input_override = 2047; // 设置为2047
│ │ ├──> if (input_override < 0) { // 如果调整后的输入小于0
│ │ │ └──> input_override = 0; // 设置为0
│ │ └──> if (zero_crosses < 100) { // 如果零交叉次数小于100
│ │ └──> speedPid.integral = 0; // 重置速度PID的积分项
│ │
│ ├──> if (maximum_throttle_change_ramp) { // 如果启用了最大油门变化斜坡
│ │ ├──> if (zero_crosses < 150 || last_duty_cycle < 150) { // 如果零交叉次数小于150或上一个占空比小于150
│ │ │ │ └──> max_duty_cycle_change = RAMP_SPEED_STARTUP; // 设置为启动斜坡速度
│ │ │ └──> else { // 否则
│ │ │ │ └──> if (average_interval > 500) { // 如果平均间隔大于500
│ │ │ │ └──> max_duty_cycle_change = RAMP_SPEED_LOW_RPM; // 设置为低转速斜坡速度
│ │ │ └──> else { // 否则
│ │ │ └──> max_duty_cycle_change = RAMP_SPEED_HIGH_RPM; // 设置为高转速斜坡速度
│ │ │
│ │ └──> if ((duty_cycle - last_duty_cycle) > max_duty_cycle_change) { // 如果当前占空比与上一个占空比的差值大于最大变化值
│ │ │ │ └──> duty_cycle = last_duty_cycle + max_duty_cycle_change; // 调整占空比
│ │ │ │ │ └──> if (commutation_interval > 500) { // 如果换向间隔大于500
│ │ │ │ │ ├──> fast_accel = 1; // 启用快速加速
│ │ │ │ │ └──> temp_advance = advance_level; // 设置临时提前角
│ │ │ │ └──> else { // 否则
│ │ │ │ └──> fast_accel = 0; // 禁用快速加速
│ │ └──> else if ((last_duty_cycle - duty_cycle) > max_duty_cycle_change) { // 如果上一个占空比与当前占空比的差值大于最大变化值
│ │ │ ├──> duty_cycle = last_duty_cycle - max_duty_cycle_change; // 调整占空比
│ │ │ ├──> fast_accel = 0; // 禁用快速加速
│ │ │ └──> temp_advance = advance_level; // 设置临时提前角
│ │ └──> else { // 否则
│ │ ├──> if(duty_cycle < 300 && commutation_interval < 300){ // 如果占空比和换向间隔都小于300
│ │ │ │ └──> temp_advance = advance_level; // 设置临时提前角
│ │ │ └──> else { // 否则
│ │ │ └──> temp_advance = advance_level; // 设置临时提前角
│ │ └──> fast_accel = 0; // 禁用快速加速
│ │
│ ├──> if ((armed && running) && input > 47) { // 如果系统已解锁且正在运行,且输入大于47
│ │ │ └──> adjusted_duty_cycle = ((duty_cycle * tim1_arr) / 2000) + 1; // 调整占空比
│ │ └──> else { // 否则
│ │ └──> if (prop_brake_active) { // 如果启动了电动刹车
│ │ │ └──> adjusted_duty_cycle = TIMER1_MAX_ARR - ((prop_brake_duty_cycle * tim1_arr) / 2000) + 1; // 调整占空比以考虑刹车
│ │ └──> else { // 否则
│ │ └──> adjusted_duty_cycle = ((duty_cycle * tim1_arr) / 2000); // 正常调整占空比
│ │
│ ├──> last_duty_cycle = duty_cycle; // 更新上一个占空比
│ ├──> SET_AUTO_RELOAD_PWM(tim1_arr); // 设置自动重载PWM
│ └──> SET_DUTY_CYCLE_ALL(adjusted_duty_cycle); // 设置所有通道的占空比
│
└──> signaltimeout++; // 信号超时计数器增加
2.4 主程序
main
│
│ /*
│ * 初始化跳转后执行的代码
│ */
├──> initAfterJump(); // 初始化跳转后的一些设置
├──> initCorePeripherals(); // 初始化核心外设
├──> enableCorePeripherals(); // 启用核心外设
│
│ /*
│ * 从EEPROM加载设置
│ */
├──> loadEEpromSettings(); // 加载EEPROM设置
├──> if((*(uint32_t*)(0x08000FE0)) == 0xf8){ // 检查特定内存地址的值是否为0xf8
│ └──> eeprom_address = (uint32_t)0x0800F800; // 如果为0xf8,设置EEPROM地址
├──> if (VERSION_MAJOR != eepromBuffer[3] || VERSION_MINOR != eepromBuffer[4]) { // 检查固件版本
│ ├──> eepromBuffer[3] = VERSION_MAJOR; // 更新版本号
│ ├──> eepromBuffer[4] = VERSION_MINOR; // 更新版本号
│ ├──> for (int i = 0; i < 12; i++) { // 将固件名称保存到EEPROM缓冲区
│ │ └──> eepromBuffer[5 + i] = (uint8_t)FIRMWARE_NAME[i];
│ └──> saveEEpromSettings(); // 保存EEPROM设置
│
│ /*
│ * 检查方向并设置“forward”变量
│ */
├──> if (dir_reversed == 1) { // 如果方向反转
│ │ └──> forward = 0; // 设置为不向前
│ └──> else {
│ └──> forward = 1; // 设置为向前
│
│ /*
│ * 设置定时器和PWM
│ */
├──> tim1_arr = TIMER1_MAX_ARR; // 设置定时器最大自动重装值
├──> if (!comp_pwm) { // 如果不使用互补PWM
│ └──> use_sin_start = 0; // 禁用正弦启动
│
│ /*
│ * 如果启用RC车模式,覆盖许多参数
│ */
├──> if (RC_CAR_REVERSE) { // 检查是否为RC车模式
│ ├──> throttle_max_at_low_rpm = 1000; // 低转速时最大油门限制
│ ├──> bi_direction = 1; // 启用双向模式
│ ├──> use_sin_start = 0; // 禁用正弦启动
│ ├──> low_rpm_throttle_limit = 1; // 启用低转速油门限制
│ ├──> VARIABLE_PWM = 0; // 禁用可变PWM
│ ├──> comp_pwm = 0; // 禁用互补PWM
│ ├──> stuck_rotor_protection = 0; // 禁用转子卡死保护
│ ├──> minimum_duty_cycle = minimum_duty_cycle + 50; // 增加最小占空比
│ ├──> stall_protect_minimum_duty = stall_protect_minimum_duty + 50; // 增加卡死保护最小占空比
│ └──> min_startup_duty = min_startup_duty + 50; // 增加最小启动占空比
│
│ /*
│ * 播放启动音调并初始化看门狗计时器
│ */
├──> playStartupTune(); // 播放启动音调
├──> zero_input_count = 0; // 重置输入计数
├──> MX_IWDG_Init(); // 初始化看门狗
├──> RELOAD_WATCHDOG_COUNTER(); // 重置看门狗计数器
│
│ /*
│ * 处理ADC输入或接收Dshot信号
│ */
├──> #ifdef USE_ADC_INPUT
│ │ ├──> armed_count_threshold = 5000; // 设置激活计数阈值
│ │ └──> inputSet = 1; // 设置输入已设置标志
│ └──> #else
│ ├──> receiveDshotDma(); // 接收Dshot DMA信号
│ └──> if (drive_by_rpm) { // 如果以RPM控制
│ └──> use_speed_control_loop = 1; // 启用速度控制循环
│
├──> setInputPullUp(); // 设置输入上拉
│
├──> #ifdef USE_INVERTED_HIGH
│ ├──> min_startup_duty = min_startup_duty + 100; // 增加最小启动占空比
│ └──> minimum_duty_cycle = minimum_duty_cycle + 100; // 增加最小占空比
│
│ /*
│ * 无限循环,主控制逻辑
│ */
└──> while (1) {
├──> RELOAD_WATCHDOG_COUNTER(); // 重置看门狗计数器,防止系统复位
├──> e_com_time = ((commutation_intervals[0]
│ + commutation_intervals[1]
│ + commutation_intervals[2]
│ + commutation_intervals[3]
│ + commutation_intervals[4]
│ + commutation_intervals[5]) + 4) >> 1; // 计算换向间隔时间,单位是0.5微秒
├──> if (VARIABLE_PWM) {
│ └──> tim1_arr = map(commutation_interval, 96, 200, TIMER1_MAX_ARR / 2, TIMER1_MAX_ARR); // 根据换向间隔调整PWM频率
│
├──> if (signaltimeout > (LOOP_FREQUENCY_HZ >> 1)) { // 如果信号超时超过半秒,且系统处于激活状态
│ ├──> if (armed) {
│ │ ├──> allOff(); // 关闭所有输出
│ │ ├──> armed = 0; // 取消激活状态
│ │ ├──> input = 0; // 重置输入信号
│ │ ├──> inputSet = 0; // 重置输入设定
│ │ ├──> zero_input_count = 0; // 重置空输入计数
│ │ ├──> SET_DUTY_CYCLE_ALL(0); // 将所有占空比设为0
│ │ ├──> resetInputCaptureTimer(); // 重置输入捕获定时器
│ │ │ └──> for (int i = 0; i < 64; i++) {
│ │ │ └──> dma_buffer[i] = 0; // 清空DMA缓冲区
│ │ └──> NVIC_SystemReset(); // 复位系统
│ └──> if (signaltimeout > LOOP_FREQUENCY_HZ << 1) { // 如果未激活状态且信号超时超过2秒
│ ├──> allOff(); // 关闭所有输出
│ ├──> armed = 0; // 取消激活状态
│ ├──> input = 0; // 重置输入信号
│ ├──> inputSet = 0; // 重置输入设定
│ ├──> zero_input_count = 0; // 重置空输入计数
│ ├──> SET_DUTY_CYCLE_ALL(0); // 将所有占空比设为0
│ ├──> resetInputCaptureTimer(); // 重置输入捕获定时器
│ ├──> for (int i = 0; i < 64; i++) {
│ │ └──> dma_buffer[i] = 0; // 清空DMA缓冲区
│ └──> NVIC_SystemReset(); // 复位系统
│
├──> if (tenkhzcounter > LOOP_FREQUENCY_HZ) { // 如果计数器超过一秒,进行遥测和电流计算
│ ├──> consumed_current = (float)actual_current / 360 + consumed_current; // 累加消耗的电流
│ ├──> switch (dshot_extended_telemetry) {
│ │ ├──> case 1:
│ │ │ ├──> send_extended_dshot = 0b0010 << 8 | degrees_celsius; // 发送温度数据
│ │ │ ├──> dshot_extended_telemetry = 2; // 更新遥测状态
│ │ │ └──> break;
│ │ ├──> case 2:
│ │ │ ├──> send_extended_dshot = 0b0110 << 8 | (uint8_t)actual_current / 50; // 发送实际电流数据
│ │ │ ├──> dshot_extended_telemetry = 3; // 更新遥测状态
│ │ │ └──> break;
│ │ └──> case 3:
│ │ ├──> send_extended_dshot = 0b0100 << 8 | (uint8_t)(battery_voltage / 25); // 发送电池电压数据
│ │ ├──> dshot_extended_telemetry = 1; // 重置遥测状态
│ │ └──> break;
│ └──> tenkhzcounter = 0; // 重置计数器
│
├──> if ((zero_crosses > 1000) || (adjusted_input == 0)) {
│ └──> bemf_timeout_happened = 0; // 复位反电动势超时标志
│
├──> if (zero_crosses > 100 && adjusted_input < 200) {
│ └──> bemf_timeout_happened = 0; // 复位反电动势超时标志
│
├──> if (use_sin_start && adjusted_input < 160) {
│ └──> bemf_timeout_happened = 0; // 复位反电动势超时标志
│
├──> if (crawler_mode) {
│ │ └──> if (adjusted_input < 400) {
│ │ └──> bemf_timeout_happened = 0; // 复位反电动势超时标志
│ └──> else {
│ │ └──> if (adjusted_input < 150) { // 如果启动占空比过低,防止电机烧毁
│ │ └──> bemf_timeout = 100; // 设置反电动势超时时间
│ └──> else {
│ └──> bemf_timeout = 10; // 设置反电动势超时时间
│
├──> average_interval = e_com_time / 3; // 计算平均换向间隔
├──> if (desync_check && zero_crosses > 10) {
│ ├──> if ((getAbsDif(last_average_interval, average_interval) > average_interval >> 1) && (average_interval < 2000)) { // 检查反相情况
│ │ ├──> zero_crosses = 0; // 重置零交叉计数
│ │ ├──> desync_happened++; // 增加反相计数
│ │ ├──> if ((!bi_direction && (input > 47)) || commutation_interval > 1000) {
│ │ │ └──> running = 0; // 停止电机运行
│ │ ├──> old_routine = 1; // 标记使用旧的控制流程
│ │ ├──> if (zero_crosses > 100) {
│ │ │ └──> average_interval = 5000; // 设置大间隔
│ │ └──> last_duty_cycle = min_startup_duty / 2; // 降低启动占空比
│ ├──> desync_check = 0; // 复位反相检查标志
│ └──> last_average_interval = average_interval; // 更新上次平均换向间隔
│
├──> if (send_telemetry) {
│ ├──> makeTelemPackage(degrees_celsius, battery_voltage, actual_current, (uint16_t)consumed_current, e_rpm); // 生成遥测数据包
│ ├──> send_telem_DMA(); // 通过DMA发送遥测数据
│ └──> send_telemetry = 0; // 复位发送遥测标志
│
├──> adc_counter++; // ADC计数器自增
├──> if (adc_counter > 200) { // 每200次循环执行ADC和遥测
│ ├──> ADC_DMA_Callback(); // 触发ADC的DMA回调
│ ├──> LL_ADC_REG_StartConversion(ADC1); // 开始ADC转换
│ ├──> converted_degrees = __LL_ADC_CALC_TEMPERATURE(3300, ADC_raw_temp, LL_ADC_RESOLUTION_12B); // 计算温度
│ ├──> degrees_celsius = converted_degrees; // 更新摄氏温度
│ ├──> battery_voltage = ((7 * battery_voltage) + ((ADC_raw_volts * 3300 / 4095 * VOLTAGE_DIVIDER) / 100)) >> 3; // 更新电池电压
│ ├──> smoothed_raw_current = getSmoothedCurrent(); // 获取平滑后的电流
│ ├──> actual_current = ((smoothed_raw_current * 3300 / 41) - (CURRENT_OFFSET * 100)) / (MILLIVOLT_PER_AMP); // 计算实际电流
│ ├──> if (actual_current < 0) { // 防止电流为负
│ │ └──> actual_current = 0; // 电流小于0时,设置为0
│ ├──> if (LOW_VOLTAGE_CUTOFF) { // 低电压保护
│ │ └──> if (battery_voltage < (cell_count * low_cell_volt_cutoff)) { // 检查是否低于电压截止阈值
│ │ │ ├──> low_voltage_count++; // 低电压计数器自增
│ │ │ └──> if (low_voltage_count > (20000 - (stepper_sine * 900))) { // 如果低电压计数超过设定值
│ │ │ ├──> input = 0; // 清零输入
│ │ │ ├──> allOff(); // 关闭所有输出
│ │ │ ├──> maskPhaseInterrupts(); // 屏蔽相位中断
│ │ │ ├──> running = 0; // 停止运行标志
│ │ │ ├──> zero_input_count = 0; // 清零输入计数
│ │ │ └──> armed = 0; // 解除武装状态
│ │ └──> else { // 如果电压恢复
│ │ └──> low_voltage_count = 0; // 清零低电压计数器
│ ├──> adc_counter = 0; // 重置ADC计数器
│ └──> if (ADC_raw_input < 10) { // 如果输入小于阈值
│ │ └──> zero_input_count++; // 空输入计数器自增
│ └──> else { // 否则
│ └──> zero_input_count = 0; // 重置空输入计数器
│
├──> signaltimeout = 0; // 重置信号超时计数器
├──> ADC_smoothed_input = (((10 * ADC_smoothed_input) + ADC_raw_input) / 11); // 平滑处理输入数据
├──> newinput = ADC_smoothed_input / 2; // 计算新输入值
├──> if (newinput > 2000) { // 限制最大输入值
│ └──> newinput = 2000; // 将输入限制在2000以内
├──> stuckcounter = 0; // 重置卡滞计数器
│
└──> if (stepper_sine == 0) { // 如果不是步进波形
│ ├──> e_rpm = running * (600000 / e_com_time); // 计算电气转速(e_rpm),单位是十转/分钟
│ ├──> k_erpm = e_rpm / 10; // 计算每个电气转速(k_erpm)
│ │
│ │ /*
│ │ * 某些硬件默认开启保护,但可能在低速时稍微降低响应速度
│ │ */
│ ├──> if (low_rpm_throttle_limit) {
│ │ │ │ // 为了提高性能,降低高转速限制,将其设置为源代码中的保守值
│ │ │ └──> duty_cycle_maximum = map(k_erpm, low_rpm_level, high_rpm_level, throttle_max_at_low_rpm, throttle_max_at_high_rpm);
│ │ └──> else {
│ │ └──> duty_cycle_maximum = 2000; // 否则设置最大占空比为2000
│ │
│ ├──> if (degrees_celsius > TEMPERATURE_LIMIT) { // 如果温度超过限制
│ │ ├──> duty_cycle_maximum = map(degrees_celsius, TEMPERATURE_LIMIT - 10, TEMPERATURE_LIMIT + 10,
│ │ └──> throttle_max_at_high_rpm / 2, 1); // 根据温度调整最大占空比
│ │
│ ├──> if (zero_crosses < 100 && commutation_interval > 500) { // 如果零交叉次数少于100且换相间隔大于500
│ │ │ └──> filter_level = 12; // 设置滤波级别为12
│ │ └──> else {
│ │ └──> filter_level = map(average_interval, 100, 500, 3, 12); // 根据平均间隔调整滤波级别
│ │
│ ├──> if (commutation_interval < 50) { // 如果换相间隔小于50
│ │ └──> filter_level = 2; // 设置滤波级别为2
│ │
│ ├──> auto_advance_level = map(duty_cycle, 100, 2000, 13, 23); // 根据占空比调整自动提前级别
│ │
│ └──> if (INTERVAL_TIMER_COUNT > 45000 && running == 1) { // 如果定时器计数大于45000且电机在运行
│ ├──> bemf_timeout_happened++; // BEMF超时计数器增加
│ ├──> maskPhaseInterrupts(); // 屏蔽相位中断
│ ├──> old_routine = 1; // 标记为旧例程
│ ├──> if (input < 48) { // 如果输入小于48
│ │ ├──> running = 0; // 停止电机运行
│ │ └──> commutation_interval = 5000; // 设置换相间隔为5000
│ ├──> zero_crosses = 0; // 重置零交叉次数
│ └──> zcfoundroutine(); // 调用零交叉找到例程
└──> else { // 如果是步进波形
└──> if (input > 48 && armed) { // 如果输入大于48且电机已激活
│ └──>if (input > 48 && input < 137) { // 如果输入在48到137之间(步进波形)
│ │ ├──> if (do_once_sinemode) { // 如果只执行一次的正弦模式
│ │ │ ├──> DISABLE_COM_TIMER_INT(); // 禁用换相定时器中断
│ │ │ ├──> maskPhaseInterrupts(); // 屏蔽相位中断
│ │ │ ├──> SET_DUTY_CYCLE_ALL(0); // 设置所有通道占空比为0
│ │ │ ├──> allpwm(); // 执行所有PWM操作
│ │ │ └──> do_once_sinemode = 0; // 清除只执行一次标志
│ │ ├──> advanceincrement(); // 增加提前量
│ │ ├──> step_delay = map(input, 48, 120, 7000 / motor_poles, 810 / motor_poles); // 根据输入设置步进延迟
│ │ ├──> delayMicros(step_delay); // 延迟指定时间
│ │ └──> e_rpm = 600 / step_delay; // 计算电气转速(e_rpm),单位是百转/分钟
│ │
│ └──> else { // 如果输入大于200
│ ├──> do_once_sinemode = 1; // 设置为只执行一次正弦模式
│ ├──> advanceincrement(); // 增加提前量
│ ├──> if (input > 200) { // 如果输入大于200
│ │ ├──> phase_A_position = 0; // 设置相位A位置为0
│ │ └──> step_delay = 80; // 设置步进延迟为80
│ ├──> delayMicros(step_delay); // 延迟指定时间
│ └──> if (phase_A_position == 0) { // 如果相位A位置为0
│ ├──> stepper_sine = 0; // 禁用步进波形
│ ├──> running = 1; // 启动电机
│ ├──> old_routine = 1; // 标记为旧例程
│ ├──> commutation_interval = 9000; // 设置换相间隔为9000
│ ├──> average_interval = 9000; // 设置平均间隔为9000
│ ├──> last_average_interval = average_interval; // 记录最后的平均间隔
│ ├──> SET_INTERVAL_TIMER_COUNT(9000); // 设置定时器计数为9000
│ ├──> zero_crosses = 20; // 设置零交叉次数为20
│ ├──> prop_brake_active = 0; // 禁用比例制动
│ ├──> step = changeover_step; // 设置步进
│ ├──> if (stall_protection) { // 如果启用卡死保护
│ │ └──> last_duty_cycle = stall_protect_minimum_duty; // 设置最后的占空比
│ ├──> commutate(); // 执行换相操作
│ └──> generatePwmTimerEvent(); // 生成PWM定时器事件
└──>else { // 如果不是步进模式
├──> do_once_sinemode = 1; // 设置为只执行一次正弦模式
├──> if (brake_on_stop) { // 如果在停止时启用刹车
│ │ ├──> duty_cycle = (TIMER1_MAX_ARR - 19) + drag_brake_strength * 2; // 计算占空比
│ │ ├──> adjusted_duty_cycle = TIMER1_MAX_ARR - ((duty_cycle * tim1_arr) / TIMER1_MAX_ARR) + 1; // 调整占空比
│ │ ├──> proportionalBrake(); // 执行比例刹车
│ │ ├──> SET_DUTY_CYCLE_ALL(adjusted_duty_cycle); // 设置所有通道的占空比
│ │ └──> prop_brake_active = 1; // 启用比例刹车
│ └──> else { // 否则
│ ├──> SET_DUTY_CYCLE_ALL(0); // 设置所有通道占空比为0
│ └──> allOff(); // 关闭所有输出
└──> e_rpm = 0; // 设置电气转速为0
3. 重要函数
3.1 advanceincrement
advanceincrement
├──> 如果 (!forward) {
│ │ │
│ │ ├──> phase_A_position++;
│ │ ├──> 如果 (phase_A_position > 359) {
│ │ │ └──> phase_A_position = 0; // 当 phase_A_position 超过 359 时,重置为 0
│ │ │
│ │ ├──> phase_B_position++;
│ │ ├──> 如果 (phase_B_position > 359) {
│ │ │ └──> phase_B_position = 0; // 当 phase_B_position 超过 359 时,重置为 0
│ │ │
│ │ ├──> phase_C_position++;
│ │ └──> 如果 (phase_C_position > 359) {
│ │ └──> phase_C_position = 0; // 当 phase_C_position 超过 359 时,重置为 0
│ │
│ └──> 否则 {
│ │
│ ├──> phase_A_position--;
│ ├──> 如果 (phase_A_position < 0) {
│ │ └──> phase_A_position = 359; // 当 phase_A_position 小于 0 时,设置为 359
│ │
│ ├──> phase_B_position--;
│ ├──> 如果 (phase_B_position < 0) {
│ │ └──> phase_B_position = 359; // 当 phase_B_position 小于 0 时,设置为 359
│ │
│ ├──> phase_C_position--;
│ └──> 如果 (phase_C_position < 0) {
│ └──> phase_C_position = 359; // 当 phase_C_position 小于 0 时,设置为 359
├──> 调用 setPWMCompare1(
│ (((2 * pwmSin[phase_A_position] / SINE_DIVIDER) + gate_drive_offset) * TIMER1_MAX_ARR / 2000) * sine_mode_power / 10);
├──> 调用 setPWMCompare2(
│ (((2 * pwmSin[phase_B_position] / SINE_DIVIDER) + gate_drive_offset) * TIMER1_MAX_ARR / 2000) * sine_mode_power / 10);
└──> 调用 setPWMCompare3(
(((2 * pwmSin[phase_C_position] / SINE_DIVIDER) + gate_drive_offset) * TIMER1_MAX_ARR / 2000) * sine_mode_power / 10);
3.2 setPWMComparex
( ( 2 ∗ p w m S i n [ p h a s e _ A _ p o s i t i o n ] S I N E _ D I V I D E R + g a t e _ d r i v e _ o f f s e t ) ∗ T I M E R 1 _ M A X _ A R R / 2000 ) ) ∗ s i n e _ m o d e _ p o w e r / 10 ((\frac {2 * pwmSin[phase\_A\_position]} {SINE\_DIVIDER} + gate\_drive\_offset)*TIMER1\_MAX\_ARR/2000))*sine\_mode\_power/10 ((SINE_DIVIDER2∗pwmSin[phase_A_position]+gate_drive_offset)∗TIMER1_MAX_ARR/2000))∗sine_mode_power/10
(((2 * pwmSin[phase_A_position] / SINE_DIVIDER) + gate_drive_offset) * TIMER1_MAX_ARR / 2000) * sine_mode_power / 10
#ifndef SINE_DIVIDER
#define SINE_DIVIDER 2
#endif
#define DEAD_TIME 60
uint16_t gate_drive_offset = DEAD_TIME;
#define TIM1_AUTORELOAD 1999
uint16_t TIMER1_MAX_ARR = TIM1_AUTORELOAD; // maximum auto reset register value
uint8_t sine_mode_power = 5;
int16_t pwmSin[] = {
180, 183, 186, 189, 193, 196, 199, 202, 205, 208, 211, 214, 217, 220, 224,
227, 230, 233, 236, 239, 242, 245, 247, 250, 253, 256, 259, 262, 265, 267,
270, 273, 275, 278, 281, 283, 286, 288, 291, 293, 296, 298, 300, 303, 305,
307, 309, 312, 314, 316, 318, 320, 322, 324, 326, 327, 329, 331, 333, 334,
336, 337, 339, 340, 342, 343, 344, 346, 347, 348, 349, 350, 351, 352, 353,
354, 355, 355, 356, 357, 357, 358, 358, 359, 359, 359, 360, 360, 360, 360,
360, 360, 360, 360, 360, 359, 359, 359, 358, 358, 357, 357, 356, 355, 355,
354, 353, 352, 351, 350, 349, 348, 347, 346, 344, 343, 342, 340, 339, 337,
336, 334, 333, 331, 329, 327, 326, 324, 322, 320, 318, 316, 314, 312, 309,
307, 305, 303, 300, 298, 296, 293, 291, 288, 286, 283, 281, 278, 275, 273,
270, 267, 265, 262, 259, 256, 253, 250, 247, 245, 242, 239, 236, 233, 230,
227, 224, 220, 217, 214, 211, 208, 205, 202, 199, 196, 193, 189, 186, 183,
180, 177, 174, 171, 167, 164, 161, 158, 155, 152, 149, 146, 143, 140, 136,
133, 130, 127, 124, 121, 118, 115, 113, 110, 107, 104, 101, 98, 95, 93,
90, 87, 85, 82, 79, 77, 74, 72, 69, 67, 64, 62, 60, 57, 55,
53, 51, 48, 46, 44, 42, 40, 38, 36, 34, 33, 31, 29, 27, 26,
24, 23, 21, 20, 18, 17, 16, 14, 13, 12, 11, 10, 9, 8, 7,
6, 5, 5, 4, 3, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 5, 5,
6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 20, 21, 23,
24, 26, 27, 29, 31, 33, 34, 36, 38, 40, 42, 44, 46, 48, 51,
53, 55, 57, 60, 62, 64, 67, 69, 72, 74, 77, 79, 82, 85, 87,
90, 93, 95, 98, 101, 104, 107, 110, 113, 115, 118, 121, 124, 127, 130,
133, 136, 140, 143, 146, 149, 152, 155, 158, 161, 164, 167, 171, 174, 177
};
3.3 commutate
commutate
├──> if (forward == 1) { // 如果 forward 等于 1
│ │ └──> step++; // 步骤增加
│ │ ├──> if (step > 6) { // 如果步骤大于 6
│ │ │ ├──> step = 1; // 步骤重置为 1
│ │ │ └──> desync_check = 1; // 标记需要进行同步检查
│ │ └──> rising = step % 2; // 根据步骤值的奇偶性设置 rising
│ └──> else { // 如果 forward 不等于 1
│ ├──> step--; // 步骤减少
│ ├──> if (step < 1) { // 如果步骤小于 1
│ │ ├──> step = 6; // 步骤设置为 6
│ │ └──> desync_check = 1; // 标记需要进行同步检查
│ └──> rising = !(step % 2); // 根据步骤值的奇偶性设置 rising(取反)
│
├──> __disable_irq(); // 禁用中断,防止 dshot 中断
├──> if (!prop_brake_active) { // 如果 prop_brake 不活跃
│ └──> comStep(step); // 执行 comStep 函数,传入当前步骤
├──> __enable_irq(); // 重新启用中断
│
├──> changeCompInput(); // 更改补偿输入
├──> if (average_interval > 1700) { // 如果平均时间间隔大于 1700
│ └──> old_routine = 1; // 设置 old_routine 为 1
│
├──> bemfcounter = 0; // 将 bemfcounter 重置为 0
├──> zcfound = 0; // 将 zcfound 重置为 0
├──> commutation_intervals[step - 1] = commutation_interval; // 将当前换向间隔保存到数组中,用于计算平均值
└──> #ifdef USE_PULSE_OUT
└──> if (rising) { // 如果 rising 为真
│ └──> GPIOB->scr = GPIO_PINS_8; // 设置 GPIOB 的第 8 个引脚为输出
└──> else { // 否则
└──> GPIOB->clr = GPIO_PINS_8; // 清除 GPIOB 的第 8 个引脚的输出
3.4 getBemfState
getBemfState
├──> uint8_t current_state = 0; // 初始化当前状态为0
├──> current_state = !getCompOutputLevel(); // 获取补偿输出电平并取反,得到当前状态
│
└──> if (rising) { // 如果是上升沿
│ └──> if (current_state) { // 如果当前状态为真
│ │ └──> bemfcounter++; // 计数器加1
│ └──> else { // 如果当前状态为假
│ ├──> bad_count++; // 错误计数器加1
│ └──> if (bad_count > bad_count_threshold) { // 如果错误计数超过阈值
│ └──> bemfcounter = 0; // 重置计数器
└──> else { // 如果不是上升沿
└──> if (!current_state) { // 如果当前状态为假
│ └──> bemfcounter++; // 计数器加1
└──> else { // 如果当前状态为真
├──> bad_count++; // 错误计数器加1
└──> if (bad_count > bad_count_threshold) { // 如果错误计数超过阈值
└──> bemfcounter = 0; // 重置计数器
4. 总结
根据以上分析,可知AM32支持正选控制逻辑,具体的相位、转速、开关、PWM值后续再做进一步分析。
5. 参考资料
【1】BLDC ESC 无刷直流电子调速器简介
【2】BLDC ESC 无刷直流电子调速器工作原理
【3】BLDC ESC 无刷直流电子调速器工作过程
【4】BLDC ESC 无刷直流电子调速器驱动方式
【5】AM32开源代码之工程结构