4. FOC控制原理与电流环设计
ADC采样,说白了就是FOC控制系统的“眼睛”。你想想看,电机转得再快、算法算得再准,如果电流电压采回来就是错的,那后面全是白搭。我在刚接触C2000的时候,就吃过这个亏——PWM波形看着漂亮,电机却嗡嗡响,查了两天才发现是ADC触发时序没对齐。
这一章,我们就来把ADC的底细摸清楚。从SOC配置到过采样,从触发源到校准,我会把项目中踩过的坑、总结的经验,一股脑儿倒出来。
4.1 ADC模块的核心原理
C2000的ADC模块,本质上是一个逐次逼近型(SAR)转换器。它不像Δ-Σ型那样慢,也不像Flash型那样贵,刚好在速度和精度之间找到了平衡点。
我个人习惯把ADC的工作流程拆成三步:
- 采样保持:模拟信号被采样电容“抓住”
- 逐次比较:内部DAC逐位逼近,找到数字值
- 结果存储:转换结果写入结果寄存器
这里有个关键参数——采样窗口。窗口太短,电容充不满,采样值偏小;窗口太长,又浪费转换时间。我一般建议在FOC应用里,采样窗口设为6-8个ADC时钟周期,具体要看输入阻抗。
核心要点: C2000的ADC是12位精度,但实际有效位数(ENOB)受噪声和采样窗口影响,通常只能到10.5-11位。别被数据手册的12位忽悠了。
4.2 SOC配置:启动转换的“扳机”
SOC,全称Start-of-Conversion,就是告诉ADC“可以开始干活了”的信号。C2000的SOC机制很灵活,每个ADC模块有多个SOC通道,每个通道可以独立配置触发源和采样通道。
我记得第一次配置SOC时,被那堆寄存器搞得头大。后来总结了一个口诀:“SOCx = 触发源 + 采样通道 + 采样窗口”。就这么简单。
| SOC通道 | 触发源 | 采样通道 | 采样窗口 |
|---|---|---|---|
| SOC0 | PWM1_ADCSOCA | ADCINA0 | 7个周期 |
| SOC1 | PWM1_ADCSOCB | ADCINA1 | 7个周期 |
| SOC2 | CPU定时器0 | ADCINB0 | 10个周期 |
配置代码也很直接:
// 配置SOC0:PWM触发,采样通道A0,窗口7个周期
AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 4; // PWM1_ADCSOCA
AdcRegs.ADCSOC0CTL.bit.CHSEL = 0; // ADCINA0
AdcRegs.ADCSOC0CTL.bit.ACQPS = 6; // 采样窗口 = 7个周期
小技巧: 如果你用多个SOC通道,记得把优先级高的通道放在前面。C2000的SOC优先级是编号越小越优先,SOC0最高。
4.3 PWM触发ADC采样:FOC的“心跳”
在FOC控制里,ADC采样必须和PWM同步。为什么?因为电流采样需要在PWM载波的特定时刻进行,才能避开开关噪声。
我习惯的做法是:在PWM载波的谷底或峰值触发ADC。这样采样时刻刚好是开关管切换的“安静期”,噪声最小。
具体配置分两步:
- PWM模块:设置EPWM1的SOC触发事件,比如CTR=ZERO(载波归零时触发)
- ADC模块:将SOC的触发源指向对应的PWM事件
// PWM配置:在载波归零时产生ADCSOCA信号
EPwm1Regs.ETSEL.bit.SOCAEN = 1; // 使能SOCA
EPwm1Regs.ETSEL.bit.SOCASEL = 1; // CTR=ZERO时触发
EPwm1Regs.ETPS.bit.SOCAPRD = 1; // 每个事件触发一次
这里有个坑——触发延迟。从PWM事件产生到ADC真正开始采样,中间有几十纳秒的延迟。如果你用高频PWM(比如100kHz),这个延迟就不能忽略。我曾经在一个200kHz的PWM项目里,因为没算延迟,电流采样总是偏在开关噪声上,电机抖得像筛子。
避坑指南: 我曾经在PWM频率超过80kHz时,发现ADC采样值波动很大。后来用示波器一量,发现ADC触发信号和开关管切换刚好重叠。解决办法是把触发点从CTR=ZERO改成CTR=PRD,或者加一个小的延迟偏移。
4.4 过采样技术:用时间换精度
过采样,说白了就是“多采几次,取平均”。C2000的ADC硬件支持过采样,不需要CPU干预。
为什么需要过采样?因为单次采样的噪声太大。尤其是在电机控制环境里,IGBT开关、PWM斩波、电机反电动势,到处都是噪声源。过采样可以把这些噪声平均掉,提高信噪比。
C2000的过采样机制是这样的:
- 硬件自动对同一个通道连续采样N次
- 累加后右移(相当于除以N)
- 结果存入结果寄存器
我一般用4倍或8倍过采样。再高就没意义了,因为噪声已经被平均得差不多了,反而浪费转换时间。
| 过采样倍数 | 有效位数提升 | 转换时间开销 | 推荐场景 |
|---|---|---|---|
| 2x | +0.5位 | 2倍 | 一般电流采样 |
| 4x | +1.0位 | 4倍 | 相电流采样 |
| 8x | +1.5位 | 8倍 | 母线电压采样 |
| 16x | +2.0位 | 16倍 | 温度/慢速信号 |
配置代码示例:
// 使能过采样,4倍过采样
AdcRegs.ADCCTL2.bit.RESOLUTION = 0; // 12位模式
AdcRegs.ADCCTL1.bit.INTPULSEPOS = 1; // 中断在转换结束后产生
AdcRegs.ADCSOC0CTL.bit.ACQPS = 6; // 采样窗口
// 过采样配置(以4倍为例)
AdcRegs.ADCOVERSAMPLE.bit.OVERSAMPLE = 2; // 4倍过采样
经验之谈: 过采样不是万能的。如果你的噪声是低频漂移(比如温度引起的),过采样反而会“平均”掉有用信号。我一般先用示波器看噪声频谱,再决定要不要用过采样。
4.5 采样数据的读取与校准
数据读回来了,但直接拿来用?别急,还有两步要走:读取和校准。
4.5.1 数据读取方式
C2000提供两种读取方式:
- 轮询:循环检查ADC中断标志位,简单但浪费CPU
- 中断:转换完成后自动触发中断,效率高
我强烈建议用中断方式。FOC控制里,CPU本来就忙得够呛,别再让它傻等了。
// 中断方式读取
interrupt void adc_isr(void)
{
// 读取结果
uint16_t ia = AdcResult.ADCRESULT0;
uint16_t ib = AdcResult.ADCRESULT1;
// 转换为实际电流值
float ia_amp = (ia * 3.3 / 4096.0 - 1.65) / gain;
// 清除中断标志
AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}
4.5.2 校准:别信“出厂值”
C2000的ADC出厂时做过校准,但那个校准值只是“大概准”。如果你要精度,必须自己做校准。
我一般做两步校准:
- 偏移校准:输入接地,读到的值应该是0,但实际会有偏移。把这个偏移值记下来,后续采样值减去它。
- 增益校准:输入一个已知电压(比如1.65V),读到的值应该对应2048,但实际会有偏差。计算一个增益系数,后续采样值乘以它。
校准代码示例:
// 偏移校准
#define ADC_OFFSET 12 // 实测偏移值
#define ADC_GAIN 1.002 // 实测增益系数
uint16_t adc_calibrated_read(uint16_t raw)
{
float calibrated = (raw - ADC_OFFSET) * ADC_GAIN;
if(calibrated < 0) calibrated = 0;
if(calibrated > 4095) calibrated = 4095;
return (uint16_t)calibrated;
}
注意: 校准值会随温度变化。如果你做的是工业级产品,建议在-40°C到85°C范围内做温度补偿。我曾经有一个项目,冬天调试好好的,夏天批量生产时电流采样全偏了,就是因为没做温度校准。
4.6 本章知识体系总览
下面这张图,把ADC采样与触发的核心流程串起来了。你可以把它当作一个“检查清单”,配置时对着走,不容易漏。
嗯,这一章的内容就到这里。ADC采样看起来是基础,但基础不牢,地动山摇。我见过太多工程师在ADC上翻车,最后查来查去,发现就是触发时序没配好,或者校准没做。希望你能把这些经验带走,少走弯路。