1. 电机控制中ADC采样时序的核心矛盾与设计思路
搞电机控制的人都有一个共识:算法写得再漂亮,如果ADC采样时刻没对准,整个控制环路就是在噪声上跳舞。我接触过不少用STM32F103RCT6跑无刷电机FOC驱动的项目,也调过DSP28379的双核电机控制代码,发现一个规律——新手往往把精力全砸在PID参数整定和SVPWM算法上,却忽略了ADC采样时序这个底层环节。结果就是电流波形毛刺大、转矩脉动明显、低速时尤其容易失步。
1.1 为什么ADC采样时序是FOC控制的命门
FOC矢量控制的核心思路是把三相电流通过Clarke变换和Park变换映射到dq旋转坐标系上,然后对d轴和q轴电流分别做PI调节。这个过程中,电流采样的准确性直接决定了Park变换后d-q轴电流的可信度。如果采样时刻落在MOSFET开关瞬间,那采到的就是开关噪声和振铃,而不是真实的相电流。
举个直观的例子:假设PWM频率是20kHz,一个PWM周期50微秒。在这50微秒里,MOSFET有开通关断的瞬态过程,持续时间通常在几百纳秒到一两微秒之间。如果ADC采样窗口恰好覆盖了这个瞬态区间,采样值可能偏离真实电流30%以上。对于电流环带宽要求1kHz以上的应用来说,这种偏差足以让整个系统振荡。
所以ADC采样时序优化的目标很明确:在PWM周期内找到一个电流最稳定、噪声最小的时刻进行采样。这个时刻通常位于PWM中心对齐模式下的计数器峰值或谷值附近,此时上下桥臂的开关状态已经稳定,续流过程也基本结束。
1.2 中心对齐PWM与边沿对齐PWM的时序差异
在讨论采样时刻之前,得先把PWM模式说清楚。STM32和DSP28379都支持边沿对齐和中心对齐两种PWM模式,它们在ADC触发时机上有本质区别。
边沿对齐模式下,计数器从0计到ARR值然后归零,PWM波形是单边变化的。这种模式下,开关噪声集中在计数器归零或达到ARR的那个时刻。如果你在计数器归零时触发ADC,采样窗口很容易被开关噪声污染。
中心对齐模式下,计数器先从0计到ARR,再从ARR减到0,PWM波形对称。这种模式的好处是:在计数器达到峰值和谷值时,三相桥臂的开关状态是对称的,电流纹波最小。更重要的是,中心对齐模式下可以方便地在计数器峰值和谷值分别触发ADC采样,实现双电阻或三电阻电流采样方案。
我实测下来,同样硬件条件下,中心对齐模式的电流采样信噪比边沿对齐模式高出6到10个dB。这个差距在低速小电流工况下尤其明显,直接影响到无感FOC的启动成功率。
1.3 采样方案选型:单电阻、双电阻还是三电阻
ADC采样时序的设计跟电流采样方案强相关。市面上常见的方案有三种:
| 采样方案 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 单电阻 | 在直流母线负极串一个采样电阻,通过不同开关组合重构三相电流 | 成本最低,只需一个ADC通道 | 采样窗口窄,时序要求极苛刻,低速时盲区大 | 低成本风机、水泵 |
| 双电阻 | 在下桥臂两个相线上各串一个采样电阻 | 成本适中,采样窗口较宽 | 需要两个ADC通道同步采样,第三相电流需计算 | 大多数BLDC/PMSM FOC应用 |
| 三电阻 | 三个下桥臂各串一个采样电阻 | 采样窗口最宽,可直接采到三相电流 | 成本最高,需要三个ADC通道 | 高性能伺服、精密控制 |
对于大多数用STM32F103RCT6或DSP28379做BLDC/PMSM FOC控制的场景,我推荐双电阻方案。它在成本和性能之间取得了比较好的平衡,而且STM32F103RCT6有两个独立的12位ADC,可以配置成同步规则组模式,正好满足双电阻同步采样的需求。
单电阻方案虽然便宜,但那个采样窗口窄得让人抓狂。在20kHz PWM下,有效采样窗口可能只有一两微秒,稍微有点振铃就采不准。除非成本压力极大,否则不建议新手碰单电阻。
2. ADC采样时序的关键参数计算与配置要点
选定了采样方案,接下来就是具体的参数计算和寄存器配置。这部分是实打实的硬功夫,算错一个参数,后面怎么调都白搭。
2.1 PWM频率与ADC采样窗口的时间预算
先确定PWM频率。电机控制中常用的PWM频率范围是10kHz到20kHz。频率太低,电流纹波大,电机噪音明显;频率太高,开关损耗增加,MOSFET发热严重。对于大多数中小功率BLDC电机,16kHz是个比较甜点的值。
以16kHz PWM为例,一个PWM周期是62.5微秒。中心对齐模式下,半周期是31.25微秒。ADC采样窗口需要在这个半周期内找到合适的位置。
假设MOSFET的开通时间为100纳秒,关断时间为200纳秒,振铃持续时间约500纳秒。那么从开关动作结束到电流稳定,大约需要700到800纳秒。保守一点,留1微秒的稳定时间。
在中心对齐模式下,计数器峰值对应的是所有下桥臂关断、上桥臂开通的状态(或者相反,取决于PWM极性配置)。对于下桥臂电阻采样方案,我们需要在下桥臂开通时采样。所以采样时刻应该选在计数器谷值附近,此时下桥臂处于开通状态,采样电阻上有电流流过。
具体计算:计数器从0计到ARR再回到0,谷值在计数器为0的时刻。但计数器为0时,开关动作刚刚发生,噪声还没稳定。所以实际采样点应该稍微延迟一点,比如在计数器值为ARR的5%到10%的位置触发ADC。
以STM32F103RCT6为例,假设系统时钟72MHz,PWM频率16kHz,中心对齐模式,ARR值计算如下:
// STM32F103RCT6 PWM配置示例 // 系统时钟72MHz,PWM频率16kHz,中心对齐模式 // 计数时钟 = 72MHz / 1 = 72MHz (不分频) // 中心对齐模式下,PWM频率 = 计数时钟 / (2 * ARR) // 所以 ARR = 72MHz / (2 * 16000) = 2250 #define PWM_ARR 2250 // ADC触发点设置在计数器谷值后约5%的位置 // 即计数器从0开始计数到ARR的5%处触发 // 触发阈值 = 2250 * 0.05 = 112.5,取整为113 #define ADC_TRIGGER_THRESHOLD 113这个计算过程看着简单,但实际配置时有个坑:STM32F103RCT6的高级定时器TIM1支持ADC触发事件,但触发源的选择和触发极性的配置容易搞混。我见过不少人把触发源配成了更新事件,结果ADC在每个PWM周期结束时才采样,那时候电流已经换相了。
2.2 ADC采样时间与转换时间的匹配
ADC采样时间是指采样保持电容充电的时间,转换时间是指逐次逼近寄存器完成转换的时间。这两个时间加起来必须小于PWM半周期内可用的采样窗口。
STM32F103RCT6的ADC时钟最高14MHz,采样时间可配置为1.5、7.5、13.5、28.5、41.5、55.5、71.5、239.5个ADC时钟周期。转换时间固定为12.5个ADC时钟周期。
假设ADC时钟为14MHz,采样时间选7.5个周期,转换时间12.5个周期,总时间20个周期,约1.43微秒。这个时间在16kHz PWM的半周期31.25微秒内绰绰有余。
但要注意,如果用了双ADC同步模式,两个ADC的转换时间需要匹配。STM32F103RCT6的ADC1和ADC2可以配置成同步规则组模式,此时两个ADC同时启动转换,转换时间由主ADC决定。
注意:ADC采样时间不是越短越好。采样时间太短,采样保持电容充电不充分,采样值会偏低。对于电机电流采样,源阻抗通常较低(采样电阻一般几毫欧到几十毫欧),7.5个周期的采样时间足够。但如果加了RC滤波,源阻抗增大,就需要增加采样时间。
2.3 死区时间对采样窗口的影响
死区时间是防止上下桥臂直通而插入的延迟。死区时间太短,直通风险大;死区时间太长,输出电压畸变严重,电流波形失真。
对于下桥臂电阻采样方案,死区时间会影响采样窗口的有效宽度。在死区期间,上下桥臂都关断,电流通过体二极管续流。此时采样电阻上没有电流流过(或者只有很小的反向电流),采样值不能反映真实相电流。
所以采样时刻必须避开死区时间。假设死区时间设置为500纳秒,那么从下桥臂开通到电流稳定,需要等待死区时间加上振铃时间,大约1.2到1.5微秒。在16kHz PWM下,半周期31.25微秒,扣除死区时间和振铃时间,有效采样窗口还有将近30微秒,足够安排采样点。
但如果PWM频率提高到40kHz,半周期只有12.5微秒,扣除死区时间和振铃时间,有效窗口就只剩10微秒左右了。这时候采样点的位置就需要更精确地计算,不能随便设。
3. 实操过程:从寄存器配置到波形验证
理论算清楚了,接下来就是动手配置。我以STM32F103RCT6驱动BLDC电机为例,把整个ADC采样时序的配置过程走一遍。
3.1 定时器TIM1的中心对齐PWM配置
TIM1是STM32F103RCT6的高级定时器,支持互补输出和死区插入,是驱动三相桥臂的首选。
// TIM1中心对齐PWM配置 void TIM1_PWM_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; // 使能TIM1时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); // 时基配置:中心对齐模式,ARR=2250,不分频 TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1; TIM_TimeBaseStructure.TIM_Period = PWM_ARR; // 2250 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); // 通道1配置:PWM模式1 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_Pulse = 0; // 初始占空比0 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; TIM_OC1Init(TIM1, &TIM_OCInitStructure); TIM_OC2Init(TIM1, &TIM_OCInitStructure); TIM_OC3Init(TIM1, &TIM_OCInitStructure); // 死区时间配置:约500ns // 死区时间 = DTG[7:0] * Tdtg,Tdtg = 1/72MHz ≈ 13.89ns // 500ns / 13.89ns ≈ 36,取DTG=36 TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; TIM_BDTRInitStructure.TIM_DeadTime = 36; TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable; TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure); // 使能TIM1 TIM_Cmd(TIM1, ENABLE); TIM_CtrlPWMOutputs(TIM1, ENABLE); }这段配置里有个关键点:TIM_CounterMode_CenterAligned1表示计数器先增后减,在达到ARR时产生更新事件。中心对齐模式1和模式2的区别在于输出比较标志的设置时机,对于ADC触发来说,模式1和模式2都可以用,但触发点的计算方式略有不同。
3.2 ADC触发源配置与采样时刻设定
TIM1支持多种ADC触发事件,包括更新事件、比较事件、刹车事件等。对于中心对齐PWM,我们通常用比较事件来触发ADC,这样可以精确控制采样时刻。
// TIM1 ADC触发配置 void TIM1_ADC_Trigger_Init(void) { // 选择比较通道4作为ADC触发源 // 比较通道4不输出到引脚,专门用于ADC触发 TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_OC4Ref); // 配置比较通道4 // 在计数器从0增加到ADC_TRIGGER_THRESHOLD时触发 TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable; TIM_OCInitStructure.TIM_Pulse = ADC_TRIGGER_THRESHOLD; // 113 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC4Init(TIM1, &TIM_OCInitStructure); }这里用比较通道4来触发ADC,而不是用更新事件。原因在于:更新事件发生在计数器归零或达到ARR的时刻,此时开关动作刚刚发生,噪声还没稳定。而比较通道4可以在计数器达到任意值时触发,我们可以把它设置在计数器谷值后的一小段延迟处,避开开关噪声。
ADC_TRIGGER_THRESHOLD设为113,对应计数器从0增加到113时触发。在中心对齐模式下,计数器从0增加到ARR再减到0,所以计数器值为113时,对应的是谷值后的一小段时间。这个时间大约是113/72MHz ≈ 1.57微秒,正好避开了死区时间和振铃时间。
3.3 双ADC同步规则组配置
STM32F103RCT6有两个ADC,可以配置成同步规则组模式,同时采样两个下桥臂电阻上的电压。
// ADC双同步规则组配置 void ADC_Dual_Init(void) { ADC_InitTypeDef ADC_InitStructure; // 使能ADC1和ADC2时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); // ADC时钟 = 72MHz / 6 = 12MHz // ADC1配置 ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult; // 同步规则组模式 ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC4; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); // ADC2配置 ADC_Init(ADC2, &ADC_InitStructure); // 配置ADC1通道0(假设采样电阻接在PA0) ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_7Cycles5); // 配置ADC2通道1(假设采样电阻接在PA1) ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 1, ADC_SampleTime_7Cycles5); // 使能ADC1和ADC2的外部触发 ADC_ExternalTrigConvCmd(ADC1, ENABLE); ADC_ExternalTrigConvCmd(ADC2, ENABLE); // 使能ADC1和ADC2 ADC_Cmd(ADC1, ENABLE); ADC_Cmd(ADC2, ENABLE); // ADC校准 ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); ADC_ResetCalibration(ADC2); while(ADC_GetResetCalibrationStatus(ADC2)); ADC_StartCalibration(ADC2); while(ADC_GetCalibrationStatus(ADC2)); }这里有个细节需要注意:ADC_ExternalTrigConv_T1_CC4表示用TIM1的比较通道4事件触发ADC。在同步规则组模式下,ADC1是主ADC,ADC2是从ADC,两者同时启动转换。转换完成后,ADC1和ADC2的结果分别存放在各自的规则数据寄存器中。
3.4 采样结果读取与电流重构
ADC转换完成后,需要在中断或DMA中读取结果,并重构三相电流。
// ADC中断服务函数 void ADC1_2_IRQHandler(void) { if(ADC_GetITStatus(ADC1, ADC_IT_EOC) != RESET) { // 读取ADC1和ADC2的转换结果 uint16_t adc1_value = ADC_GetConversionValue(ADC1); uint16_t adc2_value = ADC_GetConversionValue(ADC2); // 转换为电流值 // 假设采样电阻为0.01欧姆,运放增益为10,ADC参考电压3.3V // 电流 = (ADC值 / 4096 * 3.3V) / (0.01 * 10) float current_a = (adc1_value / 4096.0f * 3.3f) / (0.01f * 10.0f); float current_b = (adc2_value / 4096.0f * 3.3f) / (0.01f * 10.0f); // 第三相电流由基尔霍夫电流定律计算 float current_c = -current_a - current_b; // 保存电流值供FOC算法使用 g_motor.current_a = current_a; g_motor.current_b = current_b; g_motor.current_c = current_c; ADC_ClearITPendingBit(ADC1, ADC_IT_EOC); } }这段代码里,电流计算公式中的参数需要根据实际硬件调整。采样电阻的精度和运放增益的稳定性直接影响电流采样精度。我一般建议用1%精度的采样电阻,运放选低温漂的型号。
4. 常见问题与排查技巧实录
ADC采样时序调起来,问题往往不是单一出现的,而是多个因素交织在一起。下面整理几个我实际踩过的坑和排查思路。
4.1 电流波形毛刺大、噪声明显
这是最常见的问题。表现是示波器上看电流波形,上面叠加了高频毛刺,FFT分析发现开关频率及其谐波分量很大。
排查思路:
检查采样时刻是否避开了开关瞬间。用示波器同时看PWM驱动信号和ADC采样触发信号,确认采样点是否落在开关动作之后。如果采样点太靠近开关瞬间,调整
ADC_TRIGGER_THRESHOLD的值,增大延迟。检查ADC采样时间是否足够。如果采样时间太短,采样保持电容充电不充分,采样值会偏低且不稳定。尝试增大采样时间,比如从7.5个周期增加到13.5个周期。
检查硬件滤波是否到位。采样电阻两端通常需要加RC滤波,截止频率一般设为PWM频率的1/10到1/5。比如16kHz PWM,RC截止频率设为1.6kHz到3.2kHz。电容选100pF到1nF,电阻选100欧姆到1k欧姆。
检查地线布局。电机控制板的地线噪声很大,ADC的模拟地和数字地要分开,最后单点接地。采样电阻的接地端要尽量靠近ADC的模拟地引脚。
4.2 低速时电流采样不准、无感FOC启动困难
低速时相电流幅值小,采样电阻上的压降可能只有几毫伏,ADC量化误差和噪声的影响被放大。
排查思路:
检查运放增益是否足够。低速时电流小,需要更高的增益来充分利用ADC的动态范围。但增益太高,高速大电流时会饱和。可以考虑用可变增益放大器,或者在不同速度段切换增益。
检查ADC参考电压是否稳定。STM32F103RCT6的ADC参考电压通常直接接VDDA,如果VDDA上有噪声,采样值会波动。建议在VDDA引脚附近加100nF和10uF电容滤波。
检查采样窗口是否足够宽。低速时PWM占空比小,下桥臂开通时间短,采样窗口窄。如果采样窗口太窄,可能采不到有效的电流值。这时候可以考虑用双电阻方案,或者调整PWM调制策略,在低速时插入额外的采样脉冲。
检查无感FOC的转子初始位置检测算法。低速启动困难不一定是ADC采样的问题,也可能是转子初始位置检测不准。可以先用霍尔传感器或有感方案验证电流采样是否正常,再排查无感算法。
4.3 ADC采样值与实际电流偏差大
表现是ADC读出来的电流值和用电流钳测出来的值对不上,偏差可能达到10%以上。
排查思路:
检查采样电阻的精度和温漂。采样电阻的精度直接影响电流采样精度。1%精度的电阻在温度变化时阻值会漂移,导致采样值偏差。建议用0.5%或更高精度的电阻,或者用温度系数低的合金电阻。
检查运放电路的增益误差。运放电路的增益由反馈电阻决定,反馈电阻的精度和温漂也会影响增益。建议用1%精度的金属膜电阻。
检查ADC的增益误差和偏移误差。STM32F103RCT6的ADC有增益误差和偏移误差,可以通过校准来补偿。在初始化时执行ADC校准,可以减小偏移误差。增益误差可以通过软件补偿,比如用两点校准法。
检查采样时刻的电流是否真实。如果采样时刻落在续流阶段,采到的电流可能不是真实的相电流。用示波器观察采样电阻上的电压波形,确认采样时刻是否在电流平稳段。
4.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 电流波形毛刺大 | 采样时刻靠近开关瞬间 | 示波器看PWM和ADC触发信号 | 调整触发阈值,增大延迟 |
| 低速采样不准 | 采样窗口窄、增益不足 | 检查PWM占空比和运放增益 | 增大增益或调整调制策略 |
| 采样值偏差大 | 电阻精度低、运放增益误差 | 用万用表测电阻和运放输出 | 更换高精度电阻,软件校准 |
| ADC无触发 | 触发源配置错误 | 检查TIM1触发源和ADC外部触发配置 | 重新配置触发源和极性 |
| 双ADC不同步 | 同步模式配置错误 | 检查ADC_Mode和触发配置 | 配置为RegSimult模式 |
| 电流值跳变 | 地线噪声大 | 检查模拟地和数字地布局 | 分开布线,单点接地 |
4.5 几个容易被忽略的实操细节
第一个细节:ADC采样时刻的微调。理论计算的触发阈值不一定是最优的,实际调试时需要用示波器观察采样电阻上的电压波形,找到电流最平稳的那个时刻。我一般会在理论值附近正负20%的范围内扫描,找到信噪比最高的点。
第二个细节:PWM死区时间的补偿。死区时间会导致输出电压畸变,进而影响电流波形。在FOC算法中,可以根据电流方向对死区时间进行补偿,减小电流畸变。补偿量需要根据实际死区时间和开关频率计算。
第三个细节:ADC采样与FOC算法执行时间的配合。ADC采样完成后,FOC算法需要在一个PWM周期内完成Clarke变换、Park变换、PI调节、反Park变换和SVPWM计算。如果算法执行时间太长,可能来不及在下一个PWM周期更新占空比。STM32F103RCT6的主频是72MHz,跑FOC算法大概需要10到20微秒,在16kHz PWM下是够用的。但如果算法复杂度过高,就需要优化代码或提高主频。
第四个细节:温度对采样精度的影响。采样电阻和运放的温漂会导致采样精度随温度变化。在高温环境下,采样值可能偏差5%以上。如果应用对精度要求高,可以考虑用温度传感器监测温度,做温度补偿。
5. 进阶优化:从能用到好用的几个关键提升
基础配置跑通之后,如果想让电流采样更稳、控制性能更好,还有几个进阶优化方向。
5.1 过采样与均值滤波
STM32F103RCT6的ADC支持过采样,可以对同一个通道连续采样多次然后取平均,提高有效分辨率。在电机控制中,可以在一个PWM周期内对同一个采样电阻采样多次,然后取平均,减小噪声影响。
但要注意,过采样会增加ADC转换时间。如果PWM频率是16kHz,半周期31.25微秒,ADC采样时间7.5个周期加转换时间12.5个周期共20个周期,约1.67微秒。如果过采样4次,总时间约6.67微秒,还在半周期内。但如果过采样16次,总时间约26.7微秒,就接近半周期了,需要仔细计算时间预算。
我一般建议过采样4次或8次,在噪声抑制和转换时间之间取平衡。过采样后的值需要右移相应的位数,比如4次过采样右移1位,8次过采样右移1.5位(实际是右移1位再除以2的平方根,但工程上通常直接右移)。
5.2 采样时刻的动态调整
固定采样时刻在大多数工况下都能工作,但在某些特殊工况下,比如高速弱磁区,电流波形畸变严重,固定采样时刻可能采到畸变的电流值。这时候可以考虑动态调整采样时刻,根据电机转速和电流幅值实时调整触发阈值。
动态调整的策略是:在低速时,采样时刻可以靠近PWM中心;在高速时,采样时刻需要提前,避开电流换相引起的畸变。具体调整量需要根据电机参数和PWM频率计算,一般通过实验标定。
5.3 电流采样与转子位置估计的联合优化
对于无感FOC控制,电流采样和转子位置估计是相互影响的。电流采样不准会导致转子位置估计偏差,转子位置估计偏差又会导致电流控制不准。联合优化的思路是:用电流采样值来校正转子位置估计,用转子位置估计来优化电流采样时刻。
具体实现上,可以在滑模观测器或龙伯格观测器中引入电流采样误差作为反馈,提高转子位置估计精度。同时,根据转子位置估计值调整ADC采样时刻,使采样时刻始终落在电流最平稳的区间。
这个优化方向比较复杂,需要对无感FOC算法有深入理解。我建议先把基础的有感FOC跑通,再逐步过渡到无感FOC,最后再考虑联合优化。
5.4 不同MCU平台的移植要点
STM32F103RCT6和DSP28379在ADC采样时序配置上有不少差异。STM32F103RCT6的ADC触发源选择比较灵活,但ADC时钟最高只有14MHz,采样时间配置选项有限。DSP28379的ADC时钟更高,采样时间配置更精细,但触发源配置更复杂,需要配置EPWM的SOC事件。
从STM32F103RCT6移植到DSP28379时,需要注意以下几点:
ADC时钟频率不同。STM32F103RCT6的ADC时钟最高14MHz,DSP28379的ADC时钟可以到50MHz以上。采样时间配置需要重新计算。
触发源配置方式不同。STM32F103RCT6用TIM1的比较事件触发ADC,DSP28379用EPWM的SOC事件触发ADC。SOC事件的配置需要设置触发源、触发分频和触发优先级。
中断处理方式不同。STM32F103RCT6的ADC中断是固定的,DSP28379的ADC中断可以配置为多个中断源共享一个中断向量。需要仔细配置中断使能和优先级。
数据读取方式不同。STM32F103RCT6的ADC结果存放在规则数据寄存器中,DSP28379的ADC结果存放在结果寄存器中,可以配置为DMA传输或中断读取。
移植时建议先在DSP28379上跑一个简单的ADC采样测试,确认采样时序正确后,再移植FOC算法。不要一上来就把整个FOC算法搬过去,那样出了问题很难定位。
5.5 实测波形分析与调优记录
最后分享一个我实际调试的案例。用STM32F103RCT6驱动一个24V BLDC电机,PWM频率16kHz,双电阻采样,目标电流环带宽1kHz。
初始配置:ADC触发阈值设为50,采样时间7.5个周期。示波器观察采样电阻电压波形,发现采样时刻落在振铃区间,电流波形毛刺明显。
第一次调整:触发阈值从50增加到113,采样时间从7.5个周期增加到13.5个周期。毛刺有所减小,但低速时仍有明显噪声。
第二次调整:在采样电阻两端加RC滤波,R=470欧姆,C=470pF,截止频率约720kHz。毛刺进一步减小,但低速时电流采样值仍有跳变。
第三次调整:将ADC参考电压的滤波电容从100nF增加到1uF,并在VDDA引脚加10uF钽电容。低速电流采样跳变明显减小。
第四次调整:启用过采样,每个PWM周期采样4次取平均。电流波形变得平滑,电流环带宽实测达到1.2kHz,满足设计要求。
这个案例说明,ADC采样时序优化不是一蹴而就的,需要反复调整和验证。每次调整只改一个参数,观察效果,再决定下一步。不要一次改多个参数,那样出了问题不知道是哪个参数引起的。
提示:调试ADC采样时序时,示波器是最重要的工具。建议用四通道示波器,同时观察PWM驱动信号、ADC触发信号、采样电阻电压和电流钳输出。这样可以直观地看到采样时刻和电流波形的关系,快速定位问题。