当前位置: 首页 > news >正文

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(&currentPid, 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}

相关文章:

  • 二十、案例特训专题3【系统设计篇】web架构设计
  • nginx相关面试题30道
  • 【嵙大o】C++作业合集
  • 【Linux】利用多路转接epoll机制、ET模式,基于Reactor设计模式实现
  • Python 中 if 和 else 基础知识的详解和使用
  • 一种基于条件约束注意力生成对抗网络的水下图像增强模型
  • SIGIR 2025 多tokenizer的生成式推荐 MTGRec
  • 七、xlib窗口渲染
  • C#接口(Interface)全方位讲解:定义、特性、应用与实践
  • 2901. 最长相邻不相等子序列 II
  • vLLM - 控制生成过程中返回对数概率信息 logprobs的输出和解释
  • [人月神话_5] 兵器库 | 整体部分 | 祸起萧墙
  • Nginx配置与命令
  • ubuntu中已经存在python3.12.3, 如何安装python3.10.8且命令python3版本切换为python3.10.8
  • 得力标签打印机系统集成方案的技术应用与场景实践
  • 02 Nginx虚拟主机
  • 如何畅通需求收集渠道,获取用户反馈?
  • 软考IPSEC案例分析
  • Linux进程信号(三)之信号产生2
  • 短剧小程序系统开发源码上架,短剧项目市场分析
  • 河北邯郸回应被曝涉生猪未检疫、注水问题:将严厉查处违法行为
  • 周国辉谈花开岭现象 :年轻的公益人正在用行动点亮希望
  • 释新闻|拜登确诊恶性前列腺癌,预后情况如何?
  • 泽连斯基与美国副总统及国务卿会谈,讨论伊斯坦布尔谈判等问题
  • 《掩耳盗邻》:富人劫富,是犯罪,也是赎罪?
  • 外交部驻港公署正告美政客:威胁恫吓撼动不了中方维护国家安全的决心