我正在读取ADC值以测量温度,然后将它们平均。但是从中得出的图显示的是“步长”,但不是从值的实际步长中得出的。有人知道为什么会这样吗?
#include "arduino.h"
#define AVG_COUNT 1300
#define AVG_MAX_COUNT (2147483647/1023)
#define AVG_DURATION_TIME (AVG_COUNT * 150)
#define LOOP_INTERVAL 250
#define LOOP_INTERVAL_X 100
#define E 2.7182818284
#define AREF 4945.0
#define VREF 4945.0 // 3004 at about 22°C and 3012 at about 0°C
//#define S1_R_REF 15000.0
#define S1_R_REF_DIV4 3750.0
#define S1_RM 6260
#define S1_A_1 0.003354016
#define S1_B_1 0.0002744030
#define S1_C_1 0.00000366694
#define S1_D_1 0.000000137549
byte last_ADMUX = 0;
#define ADC_BANDGAP ((1 << MUX3) | (1 << MUX2) | (1 << MUX1))
#define ADC_RAW_BANDGAP 1110
#define T_B 5.255
#define T_A_x100 0.65
int temperature;
#define SUM_COUNT 10
int getADCRaw(){
//Start conversion
ADCSRA |= (1 << ADSC);
//wait for Measurment to finish
while(ADCSRA & (1 << ADSC));
return (ADCL | (ADCH << 8));
}
int getTempX100(int RntcDiv4){
return (int) (100 / (S1_A_1 + S1_B_1*log(RntcDiv4/S1_R_REF_DIV4) + S1_C_1*pow(log(RntcDiv4/S1_R_REF_DIV4),2) + S1_D_1*pow(log(RntcDiv4/S1_R_REF_DIV4), 3) ));
}
int getTempAvg(int avgCount){
unsigned long rmSum = 0;
for(int i = 0; i < avgCount; i++){
rmSum += (unsigned long) getADCRaw();;
}
float rmAvg = mapFloat((float)rmSum / avgCount, 0, 1023, 0, AREF);
int rntcDiv4 = (int) ((VREF / rmAvg - 1) * S1_RM / 4);
int tempCelsiusX100 = getTempX100(rntcDiv4) - 27315;
delay(1);
return tempCelsiusX100;
}
unsigned long getXBase10(byte exponent){
unsigned long rValue = 1;
for(;exponent > 0; exponent--){
rValue *= 10;
}
return rValue;
}
void setup(){
Serial.begin(57600);
//Pin A0input
DDRC &= ~(1 << PC0);
ADMUX |= (1 << REFS0); // 5V AREF (ADC0 is 0 by default)
}
unsigned long printTime = 0;
unsigned long nowMillis = 0;
unsigned long measTime = 0;
unsigned long lastPrintTime = 0;
#define INTERVAL 250
void loop(){
nowMillis = millis();
int temp = getTempAvg(20);
measTime = millis() - nowMillis;
while(millis() - lastPrintTime < INTERVAL)
delayMicroseconds(333);
Serial.println(measTime);
Serial.flush();
lastPrintTime = millis();
}
通过平均,我想提高分辨率,这样我就不会再走那么大步了。以及更精确的读数。为什么世界上有这些步骤?
问题似乎是您的平均值是很短时间内的平均值。假设A2D需要1us完成,那么您要在20us的窗口中获取数据。从那里,例程执行简单的平均(rmSum / avgCount)和查找。从那里开始,您可能会执行一些可能过于复杂的计算以生成单个结果。最终值(tempCelsiusX100和temp)永远不会在下一个周期中用作平均值的一部分。温度变化相对缓慢;连续读取20个读数是可以的,但同样,这实际上是相同的读数。您需要创建一个使用先前值的加权滚动平均值,并在更长的时间内提供平均值。例如,在循环部分中,每隔250毫秒您将获得一个新值,您应将这些值中的10个取平均值,以给出2.5秒的总体平均值。我建议使用加权滚动平均值,其中最新值的加权平均值要高于前一个值。使用10个值的滚动缓冲区限制了过去读数过多的影响。
我没有验证所有整数数学以确保您没有舍入问题,但假设您没有,并且0.1度对应于ADC的分辨率,那么...
问题是输入电路中没有足够的噪声。
如果您没有足够的噪声,则ADC将提供最接近实际温度的值。这不会改变,因此,如果将一束平均在一起,则几乎可以获得相同的值。
另一方面,如果您要采样的模拟信号中有少量LSB噪声,则ADC将根据概率分布产生值,并且该分布的中心-平均值-会发生变化以反映实际温度的微小变化。
合适的术语是“抖动”。在图像量化中更常见,但也用于量化一维信号:https://en.wikipedia.org/wiki/Dither
当然,增加输入噪声会使输出的噪声更大,而最初的精度会降低,但是看起来您有很大的空间来增加平均过程的长度来弥补这一点。
最简单的将噪声引入电路的方法可能是自己产生。这里有一篇很好的文章介绍如何使用arduino:https://thecavepearlproject.org/2017/02/27/enhancing-arduinos-adc-resolution-by-dithering-oversampling/