ADC采集流程

ADC采集

举例说明:例如吹面传感器,现在我们找到它的原理图,可以看到吹面1使用的是10k的上拉电阻,

例如当前1度,那传感器阻值26.82K,加上上拉电阻10k是36.82k,那我们计算电压值

$$U1=\frac{R1}{R1+R2}×U总$$

这里R1是26.82k,R1+R2=36.82k,U总是5v,

R1 R2 U总 结果
26.82 10 5 3.642042368
x x0 x1 y0 y1 结果
4.272460938 4.249474632 4.395551257 -15 -20 -15.78678931
x x0 x1 y0 y1 结果
4.272460938 4.202551834 4.358426005 -25 -30 -27.24248517

然后可以看到使用47k接到MCU端

吹面传感器1 是哪个 ADC 通道,查找后发现是PA7复用ADC0_IN3,也就是通道三,代码上也可以看得到

BlowFace1 对应的是 ADC0 的通道 ADC_CH_3

• 这个信息在 sources/platform/pladc_config.c 中:

• 这行是 pladc_adc0_config[8],说明:

◦ 原始 ADC 读数写入 pladc_BlowFace1_temp_volt

◦ 滤波结果写入 pladc_BlowFace1_temp_volt_filt

◦ 滤波系数 fof_k = 0.125*32768,即一阶滤波权重 0.125

它在哪里初始化

pladc_init()

• 在 sources/platform/pladc.c

• 启动时由 plmcu_init() 调用(从系统初始化流程进入)

• pladc_init() 做这些事情:

pladc_adc0_init();
pladc_adc1_init();
for (uint8 i = 0; i < 8; i++) {
    pladc_task();
}

pladc_adc0_init() / pladc_adc1_init()

• 负责配置 ADC0 / ADC1 通道

• 将 pladc_adc0_config[] / pladc_adc1_config[] 中的 channel 写入 ADC 硬件

• 如果启用了 DMA,则配置 ADC DMA 传输

• 最后触发一次软件转换 Adc_Hal_SwTriggerRegularConvert(…)

初始化滤波器

• 在 pladc_init() 中还有这两段:

first_order_filter_init(&pladc_adc0_fof[config_index], *(config->adc_var_raw), config->fof_k);
*(config->adc_var_filt) = first_order_filter(&pladc_adc0_fof[config_index], *(config->adc_var_raw));

• 也就是说:

◦ 把当前原始值加载到滤波器内部状态

◦ 让滤波器输出一个初始稳定值

• 对 BlowFace1 来说,会用 pladc_BlowFace1_temp_volt 初始化 pladc_BlowFace1_temp_volt_filt

如何获得原始值 & 滤波值

关键函数:pladc_task()

• 也在 sources/platform/pladc.c

• 周期性被任务调用,通常是 2ms/次

• 作用:

◦ 读取 ADC 硬件/DMA 的最新原始值

◦ 执行缩放 / 补偿

◦ 计算滤波值

◦ 触发下一次 ADC 转换

pladc_task() 的操作流程

3.1 读取原始 ADC 值

• 对 ADC0 的每个配置项执行:

• 对 BlowFace1:

◦ numerator = 1

◦ denominator = 1

◦ offset = 0

• 所以:

◦ adc_result = pladc_adc0_buff[8]

◦ 直接就是 ADC 原始采样值

3.2 写入原始变量

• 如果 adc_var_raw != NULL,则执行:

◦ *(config->adc_var_raw) = adc_result;

• 对 BlowFace1:

◦ pladc_BlowFace1_temp_volt = adc_result;

这里的 pladc_BlowFace1_temp_volt是 ADC 原始读数,不是最后的温度值。

3.3 计算滤波值

• 如果 adc_var_filt != NULL:

◦ if (config->fof_k == 32768) 直接复制

◦ 否则 *(config->adc_var_filt) = first_order_filter(…);

• 对 BlowFace1:

◦ fof_k = 0.125*32768 = 4096

◦ 走 first_order_filter(&pladc_adc0_fof[8], pladc_BlowFace1_temp_volt)

一阶滤波的含义

• 滤波公式大致是:

◦ y_new = y_old + k * (x_new - y_old)

• 其中 k = 0.125

• 也就是说:

◦ 新输出 = 旧输出 + 12.5% × (当前原始值 - 旧输出)

• 这个目的:

◦ 抑制噪声

◦ 让传感器输出更平滑

• 结果写入:pladc_BlowFace1_temp_volt_filt

应用层如何把滤波值转换成温度

关键变量

在 sources/application/apl_control_analog_sensor.c:

这个变量表示:

• 单位是 °C × 128

• 也就是说:

◦ 真实温度 = AplControl_s16_BlowFace1Temp / 128

关键函数:AplControl_TempSensorUpdate()

• 这是周期性更新函数

• 它把 pladc_BlowFace1_temp_volt_filt转成 AplControl_s16_BlowFace1Temp

对应代码:

这个函数做什么?

• linear_interprotion_xuint16_yint16(…)是查表+线性插值

如果输入 ADC 小于表头,直接返回第一个温度。

  1. 如果输入 ADC 大于表尾,直接返回最后一个温度。
  2. 否则用二分法找到输入落在哪两个电压点之间,然后线性插值。

公式是:y = y0 + (y1 - y0) * (x - x0) / (x1 - x0)

• 输入:

◦ x_axis:电压查表 X_VOLT_AIR_OUTLET_TEMP

◦ y_axis:温度查表 Y_AIR_OUTLET_TEMP

◦ x:滤波后的 ADC 数值 pladc_BlowFace1_temp_volt_filt

• 输出:

◦ 对应温度值,单位是 1/128°C

为什么要这么做?

• ADC 原始值是“电压/ADC码”

• 传感器输出的电压与温度关系不是线性的

• 所以用了查表 + 插值,把电压码直接映射成温度值

一个完整流程例子(假设)

设定

• BlowFace1 真实温度 = 25°C

• 假设对应 ADC_CH_3 的原始值为 1638

执行过程

  1. ADC0 采集到 1638
  2. pladc_task() 中:

◦ pladc_BlowFace1_temp_volt = 1638

◦ pladc_BlowFace1_temp_volt_filt = first_order_filter(…, 1638)

◦ 如果已经稳定,pladc_BlowFace1_temp_volt_filt ≈ 1638

  1. AplControl_TempSensorUpdate() 里:

◦ linear_interprotion_xuint16_yint16(…, 1638)

◦ 返回值假设是 3200

◦ 则 AplControl_s16_BlowFace1Temp = 3200

◦ 真实温度 = 3200 / 128 = 25°C

最后怎么发到整车 CAN

关键代码在canfd1_tx.c

这两步是什么意思

• 第一步:范围钳位

◦ 保证 AplControl_s16_BlowFace1Temp 在输出表允许的最小值与最大值之间

• 第二步:格式转换为 CAN 数据

◦ 先除 128:把 1/128°C 转成 °C

◦ 再加 40:把 -40150°C 映射到 0190

◦ 再除 0.1:把温度转换成 CAN 协议的 0.1°C 单位

如果 AplControl_s16_BlowFace1Temp = 3200

• 3200 / 128 = 25°C

• 25 + 40 = 65

• 65 / 0.1 = 650

• 因此 TMC_TfaceVal_FLRaw = 650

CAN 接收端解码

接收端通常反过来解:

• raw * 0.1 - 40

• 650 * 0.1 - 40 = 25°C

总结流程

  1. ADC0_CH_3 采集 BlowFace1
  2. pladc_init() 初始化 ADC 和滤波器
  3. pladc_task() 周期读取 pladc_adc0_buff[8]
  4. 结果存给 pladc_BlowFace1_temp_volt
  5. 一阶滤波结果存给 pladc_BlowFace1_temp_volt_filt
  6. AplControl_TempSensorUpdate() 将滤波值查表转换成 AplControl_s16_BlowFace1Temp
  7. canfd1_tx.c 将它转换成 TMC_TfaceVal_FLRaw 并发送 CAN
  8. 关键函数作用一览

• pladc_init()

◦ 配置 ADC 硬件

◦ 初始化 ADC 值

◦ 初始化滤波器状态

• pladc_task()

◦ 读取 DMA/ADC 原始数据

◦ 计算 adc_result

◦ 存储原始值

◦ 计算滤波值

◦ 触发下一次 ADC 转换

• AplControl_TempSensorUpdate()

◦ 用查表将滤波后的 ADC 值转换成温度

◦ 输出到 AplControl_s16_BlowFace1Temp

• canfd1_tx.c 的转换段

◦ 钳位

◦ 把 1/128°C 转成 CAN 的 0.1°C 数据

debug

fofk=0.3

fofk=0.125

经过不同fofk值的对比发现,

fofk系数越大,滤波能力越弱,滤波结果达到目标值越快,

相反,fofk越小,滤波能力越强,滤波结果达到目标值越慢