如何提高 arduino TMP36 温度读数?
How to improve an arduino TMP36 temperature reading?
Arduino love-o-meter 项目(存在于入门工具包中)使用 float
根据从 TMP36 读取的电压计算温度。
Arduino Uno 微控制器 (ATmega328P) 没有任何 FPU 并且计算性能不佳。
我们如何改进这个计算?
// Code for 5V at the input of the TMP36
int reading = analogRead(PIN);
float voltage = (reading * 500.0) / 1024.0;
float celciusTemperature = voltage - 50.0;
性能不佳的原因是浮点值的使用。
我将展示如何摆脱它。
首先我们来谈谈精度:
- TMP36 的温度范围为 500°C(从 -50°C 到 +450°C)。
- 模拟读取适用于从 0 到 1023(1024 个可能值)的 10 位。
所以精度是500/1024。大约 0.5 °C。
所以如果我们想在 int
上编码温度,这个 int
的低位需要编码为 0.5°C 而不是 1°C。
示例:
int celciusTemperatureByHalfDegree = +40; // +20.0°C
int celciusTemperatureByHalfDegree = +41; // +20.5°C
int celciusTemperatureByHalfDegree = -10; // -5.0°C
int celciusTemperatureByHalfDegree = -15; // -5.5°C
我们看到:
celciusTemperatureByHalfDegree = celciusTemperature * 2
大致会有:
int reading = analogRead(PIN);
int voltage = (reading * 500) / 1024;
int celciusTemperature = voltage - 50;
int celciusTemperatureByHalfDegree = celciusTemperature * 2;
此时溢出和舍入问题导致此代码无用。
让我们简化一下:
int reading = (analogRead(PIN) * 500) / 1024;
int celciusTemperatureByHalfDegree = (reading - 50) * 2;
再一次:
int reading = (analogRead(PIN) * 500) / 512;
int celciusTemperatureByHalfDegree = reading - 100;
再一次:
int reading = (analogRead(PIN) * 125) / 128;
int celciusTemperatureByHalfDegree = reading - 100;
此时没有更多的舍入问题。但是 analogRead()
给出了 0 到 1023 之间的输出。
并且1023 * 125
大于最大值int16
(32,767),所以可能会溢出。
在这里我们将使用 125 = 5*25 和 128 = 4*32。
int reading = (analogRead(PIN) * 5 * 25) / (4 * 32);
int celciusTemperatureByHalfDegree = reading - 100;
将成为:
int reading = analogRead(PIN); // 0 to 1023
reading *= 5; // 0 to 5115 (no overflow)
reading /= 4; // 0 to 1278 (no overflow)
reading *= 25; // 0 to 31950 (no overflow)
reading /= 32; // 0 to 998
int celciusTemperatureByHalfDegree = reading - 100;
最后要打印它,我们将使用此代码:
// print the integer value of the temperature
Serial.print(celciusTemperatureByHalfDegree/2);
Serial.print(".");
// less significant bit code for "__.0" of "__.5"
Serial.print(celciusTemperatureByHalfDegree % 2 ? '5' : '0');
Serial.print("°C");
Arduino love-o-meter 项目(存在于入门工具包中)使用 float
根据从 TMP36 读取的电压计算温度。
Arduino Uno 微控制器 (ATmega328P) 没有任何 FPU 并且计算性能不佳。
我们如何改进这个计算?
// Code for 5V at the input of the TMP36
int reading = analogRead(PIN);
float voltage = (reading * 500.0) / 1024.0;
float celciusTemperature = voltage - 50.0;
性能不佳的原因是浮点值的使用。
我将展示如何摆脱它。
首先我们来谈谈精度:
- TMP36 的温度范围为 500°C(从 -50°C 到 +450°C)。
- 模拟读取适用于从 0 到 1023(1024 个可能值)的 10 位。
所以精度是500/1024。大约 0.5 °C。
所以如果我们想在 int
上编码温度,这个 int
的低位需要编码为 0.5°C 而不是 1°C。
示例:
int celciusTemperatureByHalfDegree = +40; // +20.0°C
int celciusTemperatureByHalfDegree = +41; // +20.5°C
int celciusTemperatureByHalfDegree = -10; // -5.0°C
int celciusTemperatureByHalfDegree = -15; // -5.5°C
我们看到:
celciusTemperatureByHalfDegree = celciusTemperature * 2
大致会有:
int reading = analogRead(PIN);
int voltage = (reading * 500) / 1024;
int celciusTemperature = voltage - 50;
int celciusTemperatureByHalfDegree = celciusTemperature * 2;
此时溢出和舍入问题导致此代码无用。
让我们简化一下:
int reading = (analogRead(PIN) * 500) / 1024;
int celciusTemperatureByHalfDegree = (reading - 50) * 2;
再一次:
int reading = (analogRead(PIN) * 500) / 512;
int celciusTemperatureByHalfDegree = reading - 100;
再一次:
int reading = (analogRead(PIN) * 125) / 128;
int celciusTemperatureByHalfDegree = reading - 100;
此时没有更多的舍入问题。但是 analogRead()
给出了 0 到 1023 之间的输出。
并且1023 * 125
大于最大值int16
(32,767),所以可能会溢出。
在这里我们将使用 125 = 5*25 和 128 = 4*32。
int reading = (analogRead(PIN) * 5 * 25) / (4 * 32);
int celciusTemperatureByHalfDegree = reading - 100;
将成为:
int reading = analogRead(PIN); // 0 to 1023
reading *= 5; // 0 to 5115 (no overflow)
reading /= 4; // 0 to 1278 (no overflow)
reading *= 25; // 0 to 31950 (no overflow)
reading /= 32; // 0 to 998
int celciusTemperatureByHalfDegree = reading - 100;
最后要打印它,我们将使用此代码:
// print the integer value of the temperature
Serial.print(celciusTemperatureByHalfDegree/2);
Serial.print(".");
// less significant bit code for "__.0" of "__.5"
Serial.print(celciusTemperatureByHalfDegree % 2 ? '5' : '0');
Serial.print("°C");