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 renamed

		duty_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 second

							if (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_LED
								GPIOB->BRR			= LL_GPIO_PIN_3; // turn on green
								GPIOB->BSRR 		= LL_GPIO_PIN_8; // turn on green
								GPIOB->BSRR 		= LL_GPIO_PIN_5;
#endif

								if ((cell_count == 0) && LOW_VOLTAGE_CUTOFF) //只有开启了低电压保护并且没计算过cell_count,才需要计算
								{
									cell_count			= battery_voltage / 370;  //battery_voltage单位是0.01V,一个电池按3.7V算,计算出电池数量cell_count

									for (int i = 0; i < cell_count; i++)  //有几个电池响几下
									{
										playInputTune();
										delayMillis(100);
										RELOAD_WATCHDOG_COUNTER();		//时间比较长,这里需要喂狗,否则可能复位
									}
								}
								else 
								{
#ifdef MCU_AT415
									play_tone_flag		= 4;

#else

									playInputTune();	//没开低电压保护则发一个音
#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_MODE

		if (!stepper_sine)
		{
#ifndef CUSTOM_RAMP

			if (old_routine && running)//在tenKhzRoutine函数中50us定时调用,运转时同步驱动阶段定时读取比较器的反电动势状态
			{
				//				send_LED_RGB(255, 0, 0);
				maskPhaseInterrupts();//启动阶段不使用比较器中断判断过零点,所以需要禁用比较器中断
				getBemfState();		//读取比较器输出计算bemfcounter

				if (!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 loop
				one_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;
				}

#else

				if (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_cycle
				if ((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_cycle
			if ((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模式和恒定转速模式,在检测到配置线插入一段时间后复位MCU
		if (getInputPinState())
		{
			signaltimeout++;

			if (signaltimeout > LOOP_FREQUENCY_HZ)
			{
				NVIC_SystemReset();
			}
		}
		else 
		{
			signaltimeout		= 0;
		}

#else

		signaltimeout++; //其他模式这里只做计数器累计,复位处理移到Main函数中

#endif
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hyhsandy1803

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值