AM32电调学习解读五:tenKhzRoutine
最近在学习AM32电调的2.18版本的源码,我用的硬件是AT32F421,整理了部分流程处理,内容的颗粒度是按自己的需要整理的,发出来给有需要的人参考。按自己的理解整理的,技术能力有限,可能理解有误,欢迎纠正。
注:lida2003博主是个大牛。写的无刷电调的理论和AM32相关知识点介绍的比较系统,介绍的很详细,有需要的同学可以去参考。我对电调这块是外行,只是刚入门学习。这里重点是代码理解的整理分析,他哪里写了很多原理性的知识。
https://blog.csdn.net/lida2003/category_12753961.html?spm=1001.2014.3001.5482
这是第五篇,介绍tenKhzRoutine函数,原来这个函数是10Khz的,2.18版本实际上是10Khz,只是名称未修改。这个函数主要处理:油门置低解锁、串口上报标志、启动阶段反电动势判断换相、PID调速、加速度处理、adjusted_duty_cycle生效、油门超时计数等功能。
流程图
代码
void tenKhzRoutine() //20khz 函数{ // 20khz as of 2.00 to be renamedduty_cycle = duty_cycle_setpoint;tenkhzcounter++; //计数器的递增ledcounter++;one_khz_loop_counter++;if (!armed)//输入信号未解锁{if (cell_count == 0)//还未计算出电池数量{if (inputSet){if (adjusted_input == 0){armed_timeout_count++;if (armed_timeout_count > LOOP_FREQUENCY_HZ) //油门置低超过1秒{ // one secondif (zero_input_count > 30)//油门置低连续30次{armed = 1; //置解锁标志位#ifdef USE_LED_STRIP// send_LED_RGB(0,0,0);delayMicros(1000);send_LED_RGB(0, 255, 0);
#endif#ifdef USE_RGB_LEDGPIOB->BRR = LL_GPIO_PIN_3; // turn on greenGPIOB->BSRR = LL_GPIO_PIN_8; // turn on greenGPIOB->BSRR = LL_GPIO_PIN_5;
#endifif ((cell_count == 0) && LOW_VOLTAGE_CUTOFF) //只有开启了低电压保护并且没计算过cell_count,才需要计算{cell_count = battery_voltage / 370; //battery_voltage单位是0.01V,一个电池按3.7V算,计算出电池数量cell_countfor (int i = 0; i < cell_count; i++) //有几个电池响几下{playInputTune();delayMillis(100);RELOAD_WATCHDOG_COUNTER(); //时间比较长,这里需要喂狗,否则可能复位}}else {
#ifdef MCU_AT415play_tone_flag = 4;#elseplayInputTune(); //没开低电压保护则发一个音
#endif}if (!servoPwm)//如果不是servoPwm信号则关闭双向车模式{eepromBuffer.rc_car_reverse = 0;}}else {inputSet = 0;//解锁失败,清在位状态,重新检测armed_timeout_count = 0;}}}else {armed_timeout_count = 0;}}}}if (eepromBuffer.telemetry_on_interval)//开启了串口上报功能{telem_ms_count++;if (telem_ms_count > ((telemetry_interval_ms - 1 + eepromBuffer.telemetry_on_interval) * 20))//这里根据telemetry_on_interval参数,实现多个ESC错开上报{// telemetry_on_interval = 1 is a boolean, but it can also be 2 or more to indicate an identifier// by making the interval just slightly different with an unique identifier, we can guarantee that many ESCs can communicate on just one signal// there will be some collisions but not as many as if two ESCs always tried to talk at once.send_telemetry = 1;telem_ms_count = 0;}}#ifndef BRUSHED_MODEif (!stepper_sine){
#ifndef CUSTOM_RAMPif (old_routine && running)//在tenKhzRoutine函数中50us定时调用,运转时同步驱动阶段定时读取比较器的反电动势状态{// send_LED_RGB(255, 0, 0);maskPhaseInterrupts();//启动阶段不使用比较器中断判断过零点,所以需要禁用比较器中断getBemfState(); //读取比较器输出计算bemfcounterif (!zcfound){if (rising){if (bemfcounter > min_bemf_counts_up) //bemfcounter满足门限,认为是过零点{GPIOB->scr=GPIO_PINS_2;GPIOB->clr=GPIO_PINS_2;zcfound = 1; //找到过零点了,可以换相了zcfoundroutine(); //换相操作}}else {if (bemfcounter > min_bemf_counts_down)//bemfcounter满足门限,认为是过零点{GPIOB->scr=GPIO_PINS_2;GPIOB->clr=GPIO_PINS_2;zcfound = 1;//找到过零点了,可以换相了zcfoundroutine(); //换相操作}}}}#endif if (one_khz_loop_counter > PID_LOOP_DIVIDER)//1毫秒PID调速{ // 1khz PID loopone_khz_loop_counter = 0;if (use_current_limit && running) //限流PID调速{use_current_limit_adjust -= (int16_t) (doPidCalculations(¤tPid, actual_current, eepromBuffer.limits.current * 2 * 100) / 10000);if (use_current_limit_adjust < minimum_duty_cycle){use_current_limit_adjust = minimum_duty_cycle;}if (use_current_limit_adjust > 2000){use_current_limit_adjust = 2000;}}if (eepromBuffer.stall_protection && running)//失速PID调速{ // this boosts throttle as the rpm gets lower, for crawlers// and rc cars only, do not use for multirotors.stall_protection_adjust += (doPidCalculations(&stallPid, commutation_interval, stall_protect_target_interval));if (stall_protection_adjust > 150 * 10000){stall_protection_adjust = 150 * 10000;}if (stall_protection_adjust <= 0){stall_protection_adjust = 0;}}if (use_speed_control_loop && running) //恒速PID调速{input_override += doPidCalculations(&speedPid, e_com_time, target_e_com_time);if (input_override > 2047 * 10000){input_override = 2047 * 10000;}if (input_override < 0){input_override = 0;}if (zero_crosses < 100){speedPid.integral = 0;}}}if (maximum_throttle_change_ramp)//加速度处理{// max_duty_cycle_change = map(k_erpm, low_rpm_level,// high_rpm_level, 1, 40);
#ifdef VOLTAGE_BASED_RAMP //基于电压的加速度,电压越高加速度需要越低。特别对于大功率电调uint16_t voltage_based_max_change = map(battery_voltage, 800, 2200, 10, 1);if (average_interval > 200) //转速越高加速度越大{max_duty_cycle_change = voltage_based_max_change;}else {max_duty_cycle_change = voltage_based_max_change * 3;}#elseif (zero_crosses < 150 || last_duty_cycle < 150)//启动阶段加速度{max_duty_cycle_change = RAMP_SPEED_STARTUP;}else //转速越高加速度越大{if (average_interval > 500) {max_duty_cycle_change = RAMP_SPEED_LOW_RPM; //低转速加速度}else {max_duty_cycle_change = RAMP_SPEED_HIGH_RPM; //高转速加速度}}#endif#ifdef CUSTOM_RAMP// max_duty_cycle_change = eepromBuffer[30];
#endif//根据加速度调整duty_cycleif ((duty_cycle - last_duty_cycle) > max_duty_cycle_change){duty_cycle = last_duty_cycle + max_duty_cycle_change; //duty_cycle变化太大了需要限制if (commutation_interval > 500){fast_accel = 1; //早期版本的变量,最新版本已经不用了,原来的用法是在低转速的时候减小检测到过零点到换相的等待时间temp_advance = eepromBuffer.advance_level; //目前temp_advance在代码中没有变化,这里不需要再几个分支都赋值}else {fast_accel = 0;}}else if ((last_duty_cycle - duty_cycle) > max_duty_cycle_change){duty_cycle = last_duty_cycle - max_duty_cycle_change; //duty_cycle变化太大了需要限制fast_accel = 0;temp_advance = eepromBuffer.advance_level;}else {if (duty_cycle < 300 && commutation_interval < 300){temp_advance = eepromBuffer.advance_level;}else {temp_advance = eepromBuffer.advance_level;}fast_accel = 0;//duty_cycle变化在范围内不需要限制}}//根据duty_cycle计算adjusted_duty_cycleif ((armed && running) && input > 47){if (eepromBuffer.variable_pwm) //变频场景adjusted_duty_cycle计算{//tim1_arr的变频映射处理,在Main函数中了,这里不需要执行了}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; //制动激活adjusted_duty_cycle计算}else {adjusted_duty_cycle = ((duty_cycle * tim1_arr) / 2000); //制动未激活adjusted_duty_cycle计算}}last_duty_cycle = duty_cycle;//计算的tim1_arr、adjusted_duty_cycle值生效SET_AUTO_RELOAD_PWM(tim1_arr);SET_DUTY_CYCLE_ALL(adjusted_duty_cycle);}#endif // ndef brushed_mode#if defined(FIXED_DUTY_MODE) || defined(FIXED_SPEED_MODE)//恒定Duty模式和恒定转速模式,在检测到配置线插入一段时间后复位MCUif (getInputPinState()){signaltimeout++;if (signaltimeout > LOOP_FREQUENCY_HZ){NVIC_SystemReset();}}else {signaltimeout = 0;}#elsesignaltimeout++; //其他模式这里只做计数器累计,复位处理移到Main函数中#endif}