广告

实现ADC自适应分辨率的三个解决方案

2025-06-18 17:16:19 Damian Bonicatto,Phoenix Bonicatto  阅读:
如果我们想设计一个带有自适应分辨率的系统要怎么实现?

ADC分辨率的影响及其参考

工程师总是希望从电路中获得最大效益,这一点对于模数转换器(ADC)也是如此。为了最大限度地提高ADC的性能,可能最需要关注的规格就是分辨率。然而,令人遗憾的是,一旦我们选定了ADC及其参考电压源,我们就定义了最大的单次读取分辨率。例如,假设我们使用一个10位ADC和一个5V参考电压源。这意味着我们的读数分辨率为5V/(1023),即每个数字步长4.888mV。但是,如果我们只有这个ADC系统,并且必须将其应用于输出为0至1V的传感器,该怎么办?ADC分辨率是4.888mV,但这也就意味着只有1V/4.888ms,或约205个可用步长,因此实际上我们是将传感器的分辨率降低至205分之1。 CI1ednc

如果我们设计一个设备,用于测量通过串联电阻施加直流阶跃电压时电感两端的电压,结果会怎样?如下图(图1)的曲线所示,在最初的几秒钟内,我们可能会得到不错的数据点读数,但之后,由于斜率较平缓,许多数据点的值都会相同。换句话说,相对误差会很高。CI1ednc

CI1ednc

图1:电路中电感器电压随时间变化的示例曲线,该电路通过串联电阻施加直流阶跃电压以测量电感器两端的电压。请注意,3秒后斜率趋于平缓,这将增加测量的相对误差。CI1ednc

有两种最简单的方法可以改变这种情况:CI1ednc

  • 将ADC更改为位数更多的ADC(例如12、14或16位),或者
  • 改变ADC的参考电压。

(还有一些更奇特的方法可以改变分辨率,例如使用Δ-Σ转换器。)改变位数意味着需要使用外部ADC或其他微控制器。那么,如果我们设计一个带有可调参考电压的系统会怎么样?这种分辨率可以根据需要自动调整——我们可以称之为自适应分辨率。CI1ednc

自适应分辨率demo

让我们先来看一个简单的方法。Microchip ATMEGA328P的内部ADC参考电压有三种设置选项:Vcc电压、内部1.1V参考电压和外部参考引脚(REF)。因此,为了演示,最简单的设置是使用Arduino Nano,它使用了ATMEGA328P芯片。CI1ednc

该demo使用其中一个模拟输入引脚(可连接到10位ADC)来测量电压或传感器输出。这里的关键技巧是将参考电压设置为Vcc(本设计中为​​+5V),并读取模拟输入的ADC读数。CI1ednc

如果读数转换为电压后大于1.1V,则使用该值作为测量值。如果不大于1.1V,则将参考电压更改为内部1.1V电压,然后重新读取读数。现在,假设您的传感器或测量电压相对于采样率变化较慢,那么您获得的读数分辨率将高于使用5V参考电压时获得的读数分辨率。CI1ednc

参照我们的电感器示例,图2说明了自适应分辨率如何随着电压下降而变化。CI1ednc

CI1ednc

图2:使用Microchip ATMEGA328P内部ADC时自适应分辨率的变化,参考Vcc电压为5V,内部参考电压为1.1V。CI1ednc

自适应分辨率代码

下面是一段C语言代码,用于演示自适应分辨率的概念。CI1ednc

[题外话:作为测试,我使用Copilot AI编写了基础代码,它的表现出奇地好,变量名和注释都很好,而且布局也很简洁。它还能正确地将ADC数字信号转换为模拟电压。当我尝试让Copilot添加一些逻辑更改时,代码就会变得比较混乱,所以当时我手动编写了修改和清理代码。]CI1ednc

// Define the analog input pinCI1ednc

const int analogPin = A0;CI1ednc

// Variable to store the reference voltage (in mV)CI1ednc

const float referenceVoltage5V = 4753.0; // Enter the actual mv value hereCI1ednc

const float referenceVoltage1p1V = 1099.0; // Enter the actual mv value hereCI1ednc

// Types and variable to track reference stateCI1ednc

enum ReferenceState {Ref_5, Ref_1p1};CI1ednc

ReferenceState  reference = Ref_5;CI1ednc

void setup() {CI1ednc

  // Initialize serial communication at 9600 bits per secondCI1ednc

  Serial.begin(9600);CI1ednc

  // Set the analog reference to 5V (default)CI1ednc

  analogReference(DEFAULT);CI1ednc

  reference = Ref_5; // Set reference stateCI1ednc

}CI1ednc

void loop() {CI1ednc

  int sensorValue = 0;CI1ednc

  int junk = 0;CI1ednc

  float voltage = 0; CI1ednc

  sensorValue = analogRead(analogPin); // Take a reading using the current referenceCI1ednc

  CI1ednc

  if (reference == Ref_5) {CI1ednc

    voltage = (sensorValue / 1023.0) * referenceVoltage5V; //Convert readingCI1ednc

      if (voltage < 1100) { // Check if the voltage is less than 1.1VCI1ednc

         // Change the ref voltage to 1.1v and take a new readingCI1ednc

         analogReference(INTERNAL); // Set the analog reference to 1.1V (internal)CI1ednc

         reference = Ref_1p1; // Set reference state       CI1ednc

         junk = analogRead(analogPin); // Take a throw-away read after ref changeCI1ednc

         sensorValue = analogRead(analogPin); // Take a new reading using 1.1v refCI1ednc

         voltage = (sensorValue / 1023.0) * referenceVoltage1p1V; //Convert reading CI1ednc

      }CI1ednc

  }CI1ednc

  else // Reference is currently set to 1.1vCI1ednc

    voltage = (sensorValue / 1023.0) * referenceVoltage1p1V; //Convert readingCI1ednc

    if (sensorValue == 1023) { // Check if the ADC is at maximum (>= 1.1v)CI1ednc

       // Voltage is 1.1 volts or greater, so change to 5v ref and rereadCI1ednc

       analogReference(DEFAULT); // Set the analog reference to 5V (default)CI1ednc

       reference = Ref_5; // Set reference stateCI1ednc

       junk = analogRead(analogPin); // Take a throw-away read after reference changeCI1ednc

       sensorValue = analogRead(analogPin); // Take a reading using the 5v referenceCI1ednc

       voltage = (sensorValue / 1023.0) * referenceVoltage5V; //Convert readingCI1ednc

  }CI1ednc

  // Print the analog value and voltage to the serial monitorCI1ednc

  if (reference == Ref_5) Serial.print("Analog value with 5V reference: ");CI1ednc

  else Serial.print("Analog value with 1.1V reference: ");CI1ednc

  Serial.print(sensorValue);CI1ednc

  Serial.print(", Voltage: ");CI1ednc

  Serial.println(voltage / 1000,4);CI1ednc

  // Delay for a moment before the next loopCI1ednc

  delay(1000);CI1ednc

}    CI1ednc

这段代码持续读取连接到模拟引脚A0的ADC电压。它首先使用Vcc(~5V)作为ADC的参考电压。如果读数小于1.1V,则ADC参考电压切换至1.1V内部参考电压。此参考电压将被持续使用,直到ADC返回其最大二进制值1023,这意味着A0电压必须为1.1V或更高,因此,在这种情况下,参考电压会再次切换至Vcc。在获取有效电压读数后,代码将输出与读数一同使用的参考电压值。 CI1ednc

为了获得准确的读数,5V和1.1V参考电压在使用前必须进行校准。校准应该使用一个性能良好的电压表(我使用了一个经过校准的5½位万用表),然后可以将这些测量到的电压输入到代码中。CI1ednc

请注意,在代码顶部,当A0上的输入大于1.1V时,5V参考电压变量(“referenceVoltage5V”)会被设置为在Arduino Nano的REF引脚上测得的实际电压。当A0电压小于1.1V时,也应通过测量REF引脚上的电压来设置1.1V参考电压变量(“referenceVoltage1p1V”)。下图3说明了这一概念。CI1ednc

CI1ednc

图3:此代码持续读取连接到模拟引脚A0的ADC电压。如果A0电压<1.1V,则ADC参考电压切换至1.1V。如果A0>1.1V,则ADC参考电压切换至Vcc。CI1ednc

1.1V和5V参考电压之间的相对误差

以下几项数据显示了此自适应分辨率带来的改进:在1.1V左右,参考5V的读数分辨率误差可能高达0.41%,而参考1.1V的读数误差可能只有0.10%。在100mV时,参考5V的读数误差可能高达4.6%,而参考1.1V的读数误差可能只有1.1%。当输入信号达到10mV时,参考5V的读数误差可能高达46%,而参考1.1V的读数误差只有10.7%或更低。CI1ednc

扩大参考

外部DAC方法

如果需要,可以扩展此概念以添加更多参考级,但由于收益递减,我不会在10位ADC上使用超过3或4个参考级,以下是一些如何实现此操作的示例。CI1ednc

第一种方案是使用一个DAC,将其自身参考电压源连接到Nano的REF引脚。然后,可以调整Nano控制的DAC,使其提供所需的参考电压值。例如,MAX5362 DAC支持I2C控制(尽管其内部基准电压源为0.9xVcc,因此最大读数约为4.5V)。在此设计中,Nano的REF引脚应设置为“EXTERNAL”。请参见下方图4以获得更清晰的说明。CI1ednc

CI1ednc

图4:使用Arduino Nano控制的外部DAC(MAX5362)提供更多参考级。CI1ednc

Nano的PWM输出方式

另一种创建多个参考电压的方法是使用Arduino Nano的PWM输出。这需要使用高频PWM和非常出色的滤波电路,以获得与5V参考电压成比例的良好平坦直流信号。您需要约1mV(-74dB)或更低的纹波电压才能获得干净、可用的输出。此外,还需要测量输出以便在代码中进行校准。这种方法所需的元件数量极少,但可以提供多种不同级别的参考电压。图5显示了此概念的框图。CI1ednc

CI1ednc

图5:使用Arduino Nano的PWM输出和低通滤波器获取所需的直流信号作为电压参考。CI1ednc

电阻梯形网络方法

另一种实现可调参考电压的方案是使用梯形电阻网络和一个模拟开关来选择梯形电阻网络中的不同节点。例如,TI TMUX1204可能就适合这种方案。您可以根据自己的参考电压需求选择梯形电阻网络的阻值。图6显示,Nano的两个数字输出也用于选择梯形电阻网络中的节点位置。CI1ednc

CI1ednc

图6:使用梯形电阻网络和模拟开关(例如TI TMUX1204)选择梯子上的不同节点来生成所需的电压参考值。CI1ednc

总结

或许还有其他方法可以构建参考电压,但您应该明白我想表达的意思了,这里的核心是使用多个参考电压来提高电压读数的分辨率。CI1ednc

(原文刊登于EDN美国版,参考链接:Adaptive resolution for ADCs,由Ricardo Xie编译)CI1ednc

责编:Ricardo
本文为电子技术设计原创文章,未经授权禁止转载。请尊重知识产权,违者本司保留追究责任的权利。
  • 微信扫一扫
    一键转发
  • 最前沿的电子设计资讯
    请关注“电子技术设计微信公众号”
广告
热门推荐
广告
广告
广告
EE直播间
在线研讨会
广告
面包芯语
广告
向右滑动:上一篇 向左滑动:下一篇 我知道了