D223 ADC数据处理流水线:从原始采样值到工程单位的完整转换链

一颗ADC芯片输出的只是数字编码,如何把它变成用户看得懂的电压值?本文从代码层面完整解析D223的ADC数据处理流水线:原始值→滑动平均→量程转换→校准插值→工程单位。


一、数据处理流水线总览

D223的ADC数据从硬件到用户显示,经过以下完整流水线word_4note_63

复制代码
AD7606原始16位数据
    │
    ├── 256点滑动平均滤波
    │   ├── 16位均值 → getAdcFilter16[]
    │   └── 24位累加和 → getAdcFilter24[]
    │
    ├── 量程转换(±5V / ±10V)
    │   ├── 16位 → mV
    │   ├── 24位 → μV
    │   └── 电流模式 → μA
    │
    ├── 两点线性插值校准
    │   └── 消除系统误差
    │
    ├── 校正系数与零点偏移
    │   └── 微调
    │
    └── 传感器单位转换
        └── V, mV, A, mA, ℃, N, kg, Pa ...

二、Step 1:256点滑动平均滤波

2.1 数据结构

D223的ADC数据缓冲区word_4

c 复制代码
u16 getAdc_Buf256[8][256];    // 8通道×256点滑动窗口
u16 getAdcFilter16[8];         // 16位滤波值
u32 getAdcFilter24[8];         // 24位精度提升值
u16 getAdc_Buf200[8][200];    // 波形显示缓存
u16 getAdc_Buf1000[8][1000];  // 连续数据读取缓存

2.2 滑动平均算法

每收到一次新的ADC采样,数据进入滑动窗口,计算256点累加和word_4

c 复制代码
void modbus_getDeviceDatas(void) {
    for(u8 i = 0; i < 8; i++) {
        // Step1: 256点滑动平均
        u32 sumTotal = 0;
        for(u16 j = 0; j < 256; j++)
            sumTotal += _uadc.getAdc_Buf256[i][j];
        
        _uadc.getAdcFilter16[i] = sumTotal / 256;   // 16位均值
        _uadc.getAdcFilter24[i] = sumTotal;          // 24位累加和(不除!)
    }
}

2.3 为什么不除以256就能得到24位?

这是整个流水线中最精妙的设计word_4

  • AD7606是16位ADC,单次采样值范围:0~65535(2^16)
  • 256个采样值累加:最大 65535 × 256 = 16,776,960 ≈ 2^24
  • 累加结果不除以256,直接保留24位精度

效果

  • 16位均值:sumTotal / 256,范围0~65535,精度±1 LSB
  • 24位累加:sumTotal,范围0~16,776,960,精度提升到±1/256 LSB
  • 有效位数(ENOB)提升约4位(log2(256) = 8,实际约4位有效提升)
  • 信噪比提升约24dB

关键:24位精度不是ADC硬件直接给出的,而是通过256次过采样累加获得的。代价是采样率降低256倍------以时间换精度word_4

2.4 滤波效果

256点滑动平均等效于一个低通FIR滤波器:

  • 截止频率约为采样率/512
  • 对白噪声的抑制:20×log10(√256) = 24dB
  • 对50Hz工频干扰也有一定抑制效果

三、Step 2:量程转换

3.1 ±10V量程转换

AD7606在±10V量程下的数据编码word_4

ADC原始值 对应电压
0x0000 (0) -10V
0x8000 (32768) 0V
0xFFFF (65535) +10V

16位转换公式word_4

c 复制代码
// ±10V量程
int16 adc16 = (int16)_uadc.getAdcFilter16[i] - 32768;  // 去偏置
_modbus._inputReg.adc_mV_Data16[i] = adc16 / 3.2768;    // → mV
// 3.2768 = 32768 / 10000(满量程10V = 10000mV)

24位转换公式word_4

c 复制代码
// ±10V量程
int32 adc24 = (int32)_uadc.getAdcFilter24[i] - 8388608;  // 去偏置
_modbus._inputReg.adc_uV_Data24[i] = adc24 / 0.8388608 / 10;  // → μV
// 8388608 = 2^23(24位中位值)
// 0.8388608 = 8388608 / 10000000

3.2 ±5V量程转换

±5V量程下,系数相应调整word_4

c 复制代码
// ±5V量程
// 16位: 系数 = 6.5536 = 32768 / 5000
// 24位: 系数 = 1.6777216 = 8388608 / 5000000

3.3 上位机端的转换

C#上位机中的24位ADC数据转换word_3

csharp 复制代码
// Setting.cs
if (_prxData.adcRange == 1)  // ±5V量程
    value = (SWAPS32(adcValue) - 8388608) / 83886.08 / 10;
else                          // ±10V量程
    value = (SWAPS32(adcValue) - 8388608) / 167772.16 / 10;
// 8388608 = 2^23, 24位ADC中位值

3.4 Modbus寄存器编码

D223/G511的Modbus寄存器中,24位ADC原始值用两个16位寄存器表示word_17

量程 0x000000 0x00800000 0x00FFFFFF
±5V -5V 0V +5V
±10V -10V 0V +10V

3.5 电流信号转换

当信号类型为电流时,通过240Ω取样电阻将电流转换为电压word_4

c 复制代码
// 电流模式(4-20mA环路,240Ω取样电阻)
_modbus._inputReg.adc_uA_Data16[i] = adc16 / 3.2768 / 240 * 1000;  // → μA

转换链:ADC数字值 → mV电压 → ÷240Ω × 1000 → μA电流word_4


四、Step 3:两点线性插值校准

4.1 校准公式

两点线性插值是D223校准的核心算法word_4word_3

c 复制代码
double calc_adcCalibData(double data, double d1, double a1, 
                         double d2, double a2) {
    return (((data - d1) * (a2 - a1)) / (d2 - d1)) + a1;
}

参数说明word_4

  • data:当前ADC原始数字量
  • d1, a1:校准点A的数字量和模拟量
  • d2, a2:校准点B的数字量和模拟量

4.2 校准执行流程

固件中的校准执行word_4

c 复制代码
double getCalibAdcDatas(u8 widthByte, u8 ch, s32 data) {
    double adcFloat = 0;
    
    if(校准点A使能 && 校准点B使能) {
        // 使用用户标定的两点进行线性插值
        adcFloat = calc_adcCalibData(data,
            _framDatas._adcCalibDatasPointA[ch].calibDigital,
            _framDatas._adcCalibDatasPointA[ch].calibAnalog,
            _framDatas._adcCalibDatasPointB[ch].calibDigital,
            _framDatas._adcCalibDatasPointB[ch].calibAnalog);
        adcFloat *= 0.00001;  // 缩放到实际工程单位
    } else {
        // 使用默认理想转换曲线(无校准)
        if(±10V量程)
            adcFloat = data * 10.0 / 8388608.0 - 10.0;  // 24位
        else
            adcFloat = data * 5.0 / 8388608.0 - 5.0;     // 24位
    }
    
    return adcFloat;
}

4.3 校准参数存储

每通道独立存储两组校准数据word_7

c 复制代码
// C#上位机中的校准参数结构
public static Int32[] calib_adcCalib_digitalA = new Int32[8];  // A点数字量
public static Int32[] calib_adcCalib_analogA = new Int32[8];   // A点模拟量(×100000)
public static byte[]   calib_adcCalib_enableA = new byte[8];   // A点使能
public static Int32[] calib_adcCalib_digitalB = new Int32[8];  // B点数字量
public static Int32[] calib_adcCalib_analogB = new Int32[8];   // B点模拟量
public static byte[]   calib_adcCalib_enableB = new byte[8];   // B点使能
public static Int32[] correctFactor = new Int32[8];             // 校正系数(×100000)
public static Int32[] calibZero = new Int32[8];                 // 零点偏移(×100000)

模拟量乘以100000存储为整数,避免浮点运算精度损失word_7

4.4 校正系数与零点偏移

在两点校准之后,还叠加校正系数和零点偏移word_4

c 复制代码
adcFloat = adcFloat * (correctFactor * 0.00001) + (calibZero * 0.00001);
  • correctFactor:乘法校正系数,默认100000(即1.0)
  • calibZero:加法零点偏移,默认0

五、Step 4:传感器单位转换

5.1 支持的传感器单位

D223支持以下传感器单位word_3word_6

类别 单位
电压 V, mV
电流 A, mA
温度 ℃, m℃, ℉
力/重量 N, kg, g
转速 G, K, mK
压力 MPa, kPa, hPa, Pa

共17种预置单位word_3

注意:D223支持最大256个自定义单位,可以任意修改note_259。这意味着用户可以根据实际传感器定义任意工程单位。

5.2 上位机单位选择

C#上位机中,每个通道可以独立选择传感器单位word_6

csharp 复制代码
public static byte[] sensorUnit = new byte[8];  // 每通道单位索引
public static string[] sensorUnitList = {
    "V", "mV", "A", "mA", "℃", "m℃",
    "N", "kg", "g", "G", "K", "mK",
    "MPa", "kPa", "hPa", "Pa", "℉"
};

六、完整转换示例

示例:±10V量程下测量1V电压

假设AD7606输出16位原始值 = 39322(对应约1V)word_5

复制代码
Step1: 256点滑动平均
  假设256次采样的累加和 = 39322 × 256 = 10,066,432
  getAdcFilter16 = 10,066,432 / 256 = 39322  (16位均值)
  getAdcFilter24 = 10,066,432                 (24位累加和)

Step2: 量程转换(±10V)
  16位mV值 = (39322 - 32768) / 3.2768 = 6554 / 3.2768 = 2000 mV = 2V
  24位μV值 = (10066432 - 8388608) / 0.8388608 / 10 = 1677824 / 8.388608 = 200000 μV = 0.2V
  
  注意:这里的示例假设了理想线性,实际值取决于信号和噪声
  
Step3: 两点校准(假设已标定)
  校准点A: d1=32768, a1=0V(0V输入时的ADC值)
  校准点B: d2=65535, a2=10V(10V输入时的ADC值)
  校准值 = (39322 - 32768) × (10 - 0) / (65535 - 32768) + 0 = 2.003V
  
Step4: 单位转换
  传感器选择"V" → 显示 2.003 V
  传感器选择"mV" → 显示 2003 mV

七、精度层次总结

D223的ADC数据处理实现了多层精度保障word_4note_244

层次 方法 精度
AD7606硬件 16位SAR ADC ±0.5 LSB INL/DNL
256点过采样 软件滑动平均 24位等效精度
量程转换 数学运算 无损(浮点计算)
两点校准 线性插值 消除系统误差
校正系数 乘法+加法微调 微米级微调
硬件精度 未标定 ±0.05%
标定后精度 两点标定 0.01% FSR

八、与其他型号的数据处理对比

特性 DABL7606 DABL-G511 DABM-D223
过采样方式 256点滑动平均 256点滑动平均 256点滑动平均
精度模式 16位/24位 16位/24位 16位/24位
校准方式 两点线性插值 两点线性插值 两点线性插值
参数存储 FRAM FRAM FRAM
自定义单位 17种预置 17种预置 256种自定义
数据流 SPI1 DMA直读 SPI1 DMA直读 QSPI四线DMA

三款产品的数据处理算法基本一致,核心差异在于数据传输通道------D223通过QSPI四线DMA读取FPGA FIFO,带宽远高于SPI1直读note_63


九、总结

D223的ADC数据处理流水线是一个从硬件到软件、从原始值到工程值的完整转换链:

复制代码
AD7606 16位原始值
    ↓ 256点滑动平均(+8位精度)
24位累加值
    ↓ 量程转换(±5V/±10V → mV/μV)
工程电压值
    ↓ 两点线性插值(消除系统误差)
校准电压值
    ↓ 校正系数 + 零点偏移(微调)
最终电压值
    ↓ 传感器单位转换(V/mV/℃/Pa...)
用户显示值

每一步都有明确的数学公式和代码实现,整个流水线透明可控,便于用户理解和定制。


下篇预告:《D223上位机C#开发实战:从帧解析到波形显示的完整实现》

相关推荐
FPGA小迷弟1 小时前
Vivado中高速收发器GTX/GTH的配置与调试实战
fpga开发·fpga·硬件开发
FPGA小迷弟1 小时前
Vivado ILA与VIO调试工具实战指南:从入门到精通
fpga开发·fpga·硬件开发
nnerddboy1 小时前
Rust教程04:引用、借用与切片
开发语言·后端·rust
数智大号2 小时前
从“芯“出发,筑牢文印安全防线——联想至像以全链路自主可控回应国家安全之问
arm开发·安全
jerryinwuhan2 小时前
《Python数据预处理》第四章
开发语言·python
NutShell Wang2 小时前
「音画同生」时代开启:2026 年 8 月 AI 视频生成四大发布复盘
人工智能·开源·aigc·ai agent·智能体·vibe coding
长江&后浪2 小时前
防火墙的描述
开发语言·网络·php
Dr.kangder2 小时前
嵌入式面试总结(十八)——JTAG调试
嵌入式硬件·面试·职场和发展·架构·嵌入式
观无2 小时前
若依EasyExcel实现单元格合并
开发语言·前端·javascript