|
学习梁大师无感无刷直流电机驱动源代码心得(二) 三、分析程序运行流程和机制 梁大师无刷无感直流电动机驱动有几个版本,本稿是依据本论题首页“三相无刷电机驱动-STC8H-无HALL-Ver3-PID控制-OLED显示-串口绘图”进行梳理,助力初学者鉴赏梁大师作品。下面开始抛砖引玉,错误之处请大佬们批评指正。 1、补全部分代码注解 第100行至105行代码定义PWM输出对应的引脚(IO口) 第120行与122行重复了,定义电机状态枚举型数据 第144行代码定义了存储计数毫秒变量当值等于4时,4ms定时标志B_4ms=1 第145行代码定义了存储计数毫秒变量,当值等于500时,500毫秒标志B_500ms=1 第149行代码ADC6_I_zero存储电流平均值,貌似只在显示图像时使用,没参与控制电机。 第153行代码定时器3益处标志,B_Timer3_OverFlow 第175至184行代码跟串口有关,不涉及电机控制 第189至197行delay_ms是延时毫秒函数。 第209至219行delay_N_10us是延时10微秒函数 第222至225行Delay_500ns是延时500纳秒函数 第234行代码CMPCR1 = 0;比较器控制寄存器清零复位 第295行ADC转换完成后,完成标志硬件自动置1即ADC_FLAG=1;~ADC_FLAG=0;ADC_CONTR &= ~ADC_FLAG,ADC_CONTR=0x00;即ADC控制寄存器清零复位。 第295行返回16位数ADC转换值,ADC_RES存高字节,ADC_RESL存低字节,ADC_RES * 256即左移8位变16位数。 第326、334、341、349、356、364行代码:PWMA_ENO= 0x00;表示PWM输出使能寄存器清零复位。 第337至440行代码是PWM初始化设置,三个pwm通道没设置比较值设置为0(PWMA_CCRn = 0;n=1,2,3),PWMA_IER全部注释掉,即未开通PWMA使能中断功能,更新中断,捕获比较中断。 第491行代码设置定时器0不分频工作 第830行代码设置芯片引脚P2.3为准双向口 第831行代码设置芯片引脚P3.0-P3.5,P3.7为准双向口 第835至837行代码初始化PWM\ADC\CMP比较器 第853行代码初始化PID函数 2、程序运行流程(第一阶段开环强拖) 程序运行入口函数是void main(void),程序从第826行开始逐行运行。先初始化PWM、ADC、CMP比较器、PID函数,接着执行第855至861行初始化LCD屏和串口,接着执行863至867行代码计算电流,这里循环128次,梁大师解释说是他独特算法,既规避了小数计算而又不会出现截断误差。((adc6_I *7)>>3) + Get_ADC10bitResult(6)=adc6_I ×7÷8+Get_ADC10bitResult(6);最后值趋近第六通道ADC的八倍;ADC6_I_zero定义是16位数,ADC转换出来的数是10位,乘以8后,相当于右边移3位,从10位变13位精度数。 接着程序顺序执行到第873行,进入死循环。第875至907行执行有关串口(串口和绘图跟驱动电机无多大关系,后面均略过不解析);由于前面第844行代码run_mode = MOTOR_IDLE,程序从第909行跳到执行第948至952行代码,然后返回三次从第875行执行,当第四次执行第898行代码,cnt_4ms = 4,将cnt_4ms置0复位,4ms时隙标志置1即B_4ms = 1;由于run_mode = MOTOR_IDLE,程序依然跳转执行第948至952行代码,然后转到执行第957至1005行大括号内代码:进入大括号后先复位4ms时隙标志B_4ms = 0;接着累加一次cnt_500ms,未到125,跳转执行第966行,将adc6_I、adc7_U、adc11_VR进行分别将ADC第6、7、11通道转换出来的ADC值乘以8分之七雷加,多次循环后将趋势为8倍;然后程序执行973至976行代码,通过adc11_VR值设置电机位置SetPosition;执行978、979两行代码累加PhaseTime4sum、PWM_Value两个数,但此时两数均为0;第980行代码累加换相时间PhaseSumCnt;此时TimeOut初始值等于0,程序跳转执行第991行代码,由于前面976行代码设置了SetPosition,程序执行993至998行代码,这里把run_mode = ROLL_CHECK;电机进入转动检测模式,PWMA_IER = 0x01开启了PWM更新中断,即这时候PWM中断以42.6微秒一次频率自动调用。到这里,man主函数里大循环依然继续,每1毫秒进入执行898行代码累加设置4毫秒标志,当4毫秒标志B_4ms = 1时,程序进入执行960行代码,累加设置500ms时隙标志,执行973至980行代码;当500毫秒标志为1时B_500ms = 1,执行1009至1112行代码绘图。与此同时PWM中断服务函数定期自动调用执行,即系统会自动跳转第583行执行PWM中断服务代码(第584至756行之间代码)。梁大师解释说第587至590行代码是连续检测8次,屏蔽干扰抗干扰,或PWM的影响,可靠检测到比较器状态。 当程序第一次进入PWM中断服务函数时,run_mode在main函数大循环里设置为ROLL_CHECK,程序执行593行判断条件成立执行594至676行之间代码:这时两种情况,一种情况是比较器顺利检测到过零信号,电机不需要强拖启动,另一种是系统检测不到过零信号需要强拖启动。这里先按照需要强拖启动逻辑分析:这时系统通过不断自动调用PWM中断服务函数,执行累加StartTime,当StartTime超过ROLL_MaxTime 最大值为2849ms时,程序设置RollCheckIndex = 0;run_mode = PRE_POSITION;检测电机为预设位置,开始进入曲线强拖阶段(这个阶段第603到667行之间代码会被执行,但都假设没启动成功)。当程序再次进入PWM中断服务函数时,从第585行执行到593行,再跳转678行,此时程序执行682至688行代码,设置电机预设启动角angle,设置预定位占空比,全部打开PWM输出,装载PWM曲线强拉占空比,LoadPwm()(跳转执行566至574行之间代码),并将检测索引RollCheckIndex = 1,接着跳转执行722行代码AdcConvert(),即跳转执行558至564行之间代码;接着程序跳到755行复位中断标志PWMA_SR1 = 0,跳出PWM中断服务函数。这个时候,系统依然是main主循环和PWM中断服务函数在被执行。后续系统循环调用PWM中断服务函数时,程序从第585行执行到593行,再跳转678行,再跳转690行,累加变量SartCnt,再跳转到722行,跳转到755行后跳出PWM中断服务函数,直到变量SartCnt等于PRE_STATE_TIME1×23(预定位1时间),程序执行694-677行代码,调整检测索引RollCheckIndex = 2;接着系统再次调用PWM中断服务函数时,程序从第585行执行到593行,再跳转678行,再跳转690行,再跳转700行,累加变量SartCnt,等候预定位2时间,然后依然按相同套路,调用PWM中断服务函数,执行711-721之间代码,调整检测索引RollCheckIndex = 3;接着按类似步骤累加变量SartCnt,等预定位3时间,改变电机状态为启动,run_mode = STARTING;紧接着程序再次进入PWM中断服务函数,程序从从第585行执行到593行,跳转到678行,再跳转到726行,每4次累加一次SartCnt计数,强拖电机直至SartCnt > StartTime,结束强拖,设置run_mode = ROLL_CHECK;RollCheckIndex = 0;让程序下一次调用PWM中断服务函数时进入转动检测模式,检测电机过零信号。具体流程是进入PWM中断函数,程序从584行执行到593行,再多次轮番执行594-676行之间代码,期间程序设置比较器CMP+选择检测电机悬空相,相应改变检测索引RollCheckIndex,接着程序跳到755行复位中断标志PWMA_SR1 = 0; 跳出PWM中断服务函数。这个期间,系统在main大循环正常执行外,还定时调用PWM中断服务函数和比较器中断服务函数,直到run_mode = MOTOR_RUN为止,程序进入闭环pid驱动电机。
|