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 小于表头,直接返回第一个温度。
- 如果输入 ADC 大于表尾,直接返回最后一个温度。
- 否则用二分法找到输入落在哪两个电压点之间,然后线性插值。
公式是: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
执行过程
- ADC0 采集到 1638
- pladc_task() 中:
◦ pladc_BlowFace1_temp_volt = 1638
◦ pladc_BlowFace1_temp_volt_filt = first_order_filter(…, 1638)
◦ 如果已经稳定,pladc_BlowFace1_temp_volt_filt ≈ 1638
- 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
总结流程
- ADC0_CH_3 采集 BlowFace1
- pladc_init() 初始化 ADC 和滤波器
- pladc_task() 周期读取 pladc_adc0_buff[8]
- 结果存给 pladc_BlowFace1_temp_volt
- 一阶滤波结果存给 pladc_BlowFace1_temp_volt_filt
- AplControl_TempSensorUpdate() 将滤波值查表转换成 AplControl_s16_BlowFace1Temp
- canfd1_tx.c 将它转换成 TMC_TfaceVal_FLRaw 并发送 CAN
- 关键函数作用一览
• 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越小,滤波能力越强,滤波结果达到目标值越慢