第四章 ADC模块与传感器采样
ADC模块,说白了就是微控制器的"眼睛"和"耳朵"。在汽车电子里,电流、电压、温度这些模拟量,都得靠它转成数字信号,CPU才能读懂。今天我就跟你聊聊AURIX的ADC怎么用,以及我在电流采样中踩过的那些坑。
本章核心知识点:ADC内核配置、同步采样、结果处理、过采样技术、抗干扰设计
4.1 ADC内核配置——别小看这一步
AURIX的ADC模块挺特别的。它有好几个独立的内核,每个都能独立工作。我刚开始用的时候,以为随便配一个就行,结果发现采样精度差得离谱。
配置ADC内核,主要看这几个参数:
- 分辨率:8位、10位、12位可选。我一般用12位,精度够用
- 转换时间:跟时钟频率挂钩。太快了精度下降,太慢了跟不上控制周期
- 采样时间:这个特别关键。采样时间不够,输入电容没充满,结果肯定不准
- 触发源:软件触发、硬件触发、定时器触发
嗯,这里要注意。采样时间不是越长越好。我在一个电机控制项目里,把采样时间设成了1μs,结果电流环跑不到目标频率。后来改成300ns,效果刚刚好。
// AURIX ADC内核配置示例
// 配置ADC0组0,12位分辨率,300ns采样时间
IfxAdc_G0_Config adcConfig;
IfxAdc_G0_initModuleConfig(&adcConfig, &MODULE_ADC0);
adcConfig.group[0].resolution = IfxAdc_Resolution_12bit;
adcConfig.group[0].sampleTime = IfxAdc_SampleTime_3; // 约300ns
adcConfig.group[0].clockDivider = 4; // 时钟分频
IfxAdc_G0_initModule(&adcModule, &adcConfig);
4.2 同步采样——多相电流采样的关键
做电机控制的朋友都知道,三相电流得同时采。如果分时采样,电流已经变了,算出来的矢量就不准了。
AURIX的同步采样怎么做?说白了就是让多个ADC内核同时触发转换。我记得第一次做FOC控制,三相电流采出来相位差了好几十度,电机嗡嗡响。后来才发现是没配同步。
同步采样的配置要点:
- 多个ADC内核使用同一个触发源
- 触发源通常来自定时器(比如GPT12或CCU6)
- 所有通道的采样时间要一致
我的经验:同步采样时,触发信号要加一点延迟。因为ADC采样瞬间会有电流尖峰,延迟几十纳秒能避开这个干扰。这个延迟值,我一般通过示波器实测来确定。
// 同步采样配置 - 使用CCU6触发
// ADC0组0和ADC1组0同时触发
IfxAdc_G0_Config adcConfig0, adcConfig1;
// 配置ADC0组0
adcConfig0.group[0].triggerConfig.triggerSource = IfxAdc_TriggerSource_ccu6;
adcConfig0.group[0].triggerConfig.triggerChannel = IfxAdc_TriggerChannel_0;
// 配置ADC1组0
adcConfig1.group[0].triggerConfig.triggerSource = IfxAdc_TriggerSource_ccu6;
adcConfig1.group[0].triggerConfig.triggerChannel = IfxAdc_TriggerChannel_0;
4.3 结果处理——别直接拿来用
ADC转换完的数据,直接拿来算电流?我劝你别这么干。原始数据里噪声多得很,得先处理一下。
我常用的结果处理方法:
- 数字滤波:简单移动平均或中值滤波
- 偏移校准:ADC本身有偏移误差,得减去零点值
- 增益校准:用标准电压源校准,修正增益误差
- 数据对齐:多通道数据要按顺序排列好
为什么会这样?因为ADC内部有寄生电容,每次转换完会残留一点电荷。连续采样时,这个残留会影响下一次结果。我做过测试,不加滤波的话,噪声能到±5个LSB。
// 结果处理示例 - 移动平均滤波
#define FILTER_LEN 8
uint16_t filterBuffer[FILTER_LEN];
uint8_t filterIndex = 0;
uint16_t adcFilter(uint16_t rawValue)
{
uint32_t sum = 0;
uint8_t i;
filterBuffer[filterIndex++] = rawValue;
if(filterIndex >= FILTER_LEN) filterIndex = 0;
for(i = 0; i < FILTER_LEN; i++)
{
sum += filterBuffer[i];
}
return (uint16_t)(sum / FILTER_LEN);
}
4.4 过采样技术——用时间换精度
有时候硬件分辨率不够用,怎么办?过采样是个好办法。说白了就是多采几次,然后平均。每多采4次,分辨率能提高1位。
过采样的原理:
- 采样次数 = 4^N,N是想要提高的位数
- 比如想从12位提高到14位,需要采16次
- 累加后右移N位
注意:过采样不是万能的。如果信号本身噪声很小,过采样效果就不明显。另外,过采样会占用大量CPU时间,别在实时性要求高的地方用太多。
// 过采样实现 - 12位提高到14位
#define OVERSAMPLE_RATIO 16 // 4^2,提高2位
uint16_t oversampleRead(uint8_t channel)
{
uint32_t sum = 0;
uint8_t i;
for(i = 0; i < OVERSAMPLE_RATIO; i++)
{
sum += adcReadChannel(channel);
}
return (uint16_t)(sum >> 2); // 右移2位,得到14位结果
}
4.5 我在电流采样中的抗干扰设计
这部分是我最想跟你分享的。电流采样是电机控制的命门,采不准,控制就全乱套了。
我曾经在一个项目里,电流采样噪声大到控制不住电机。折腾了两周,最后发现是PCB布局的问题。从那以后,我总结了一套抗干扰设计方法:
4.5.1 硬件层面的抗干扰
- 差分采样:用差分输入代替单端输入,共模噪声能抑制掉
- RC滤波:在ADC输入端加RC低通滤波,截止频率设在开关频率的1/10
- 隔离布局:模拟地和数字地分开,单点连接
- 屏蔽走线:采样信号线两侧加地线屏蔽
4.5.2 软件层面的抗干扰
- 采样时刻选择:避开PWM开关时刻,在开关管导通稳定后采样
- 多次采样取中值:采3次取中间值,能滤掉脉冲干扰
- 异常值剔除:设定合理范围,超出范围的数据直接丢弃
避坑指南:我曾经在采样时刻上吃过亏。PWM开关瞬间,电流会有很大的尖峰。如果这时候采样,结果能差30%以上。后来我把采样时刻设在PWM周期的中间点,问题就解决了。
// 抗干扰采样函数
#define MIN_CURRENT 0
#define MAX_CURRENT 4095 // 12位ADC
uint16_t robustCurrentSample(uint8_t channel)
{
uint16_t samples[3];
uint16_t temp;
uint8_t i, j;
// 采3次
for(i = 0; i < 3; i++)
{
samples[i] = adcReadChannel(channel);
}
// 冒泡排序取中值
for(i = 0; i < 2; i++)
{
for(j = 0; j < 2 - i; j++)
{
if(samples[j] > samples[j+1])
{
temp = samples[j];
samples[j] = samples[j+1];
samples[j+1] = temp;
}
}
}
// 检查中值是否在合理范围
if(samples[1] < MIN_CURRENT || samples[1] > MAX_CURRENT)
{
return 0; // 异常值,返回0
}
return samples[1]; // 返回中值
}
4.6 本章知识体系
下面这张图,是我画的知识结构图。你看一眼,就能把本章内容串起来。
你看这张图,从ADC内核配置开始,到同步采样、结果处理、过采样,最后落到抗干扰设计。每一步都环环相扣。说白了,ADC采样就是个系统工程,硬件和软件都得照顾到。
最后说一句:我做了这么多年汽车电子,最大的体会就是——ADC采样没有银弹。每个项目都有自己的特点,你得根据实际情况来调整。多动手、多测试,慢慢就能找到感觉。
公众号:蓝海资料掘金营,微信deep3321