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(&currentPid, 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_DIVIDER2pwmSin[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开源代码之工程结构

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值