Introduction: BjTerm. Arduino Thermometer With Analog Sensor and Bargraph
Recently I got Arduino starter kit as a gift. It caused me to have fun like a child with building blocks ;)
In this Instructable, I'll show You one of the circuit that I built - digital thermometer with simple analog sensor based on single BJT transistor.
Parts needed:
- BJT transistor or diode (I used BC547, every npn transistor or diode will be good, but other transistor may have different temperature coefficient)
- resistor 1k2Ω
- Arduino Board
- LED bargraph or 9...10 LED diodes and current limiting resistors - 220Ω
- some wires and breadboard will be helpfull
Warning: Educational Content! ;)
Step 1: Proof of Concept
Ok, start to play;) After some test of every elements i decided to build digital thermometer.
Digital but ...analog, with very basic analog sensor build from bipolar transistor.
As we know the voltage drop on p-n junction is temperature-related. Forward bias is changing about 2 mV per 1°C. This is not always positive phenomenon. We have to fight with this effect in some circuits using various methods for temperature compensation. But this effect may be also useful, for example when we want to build electronic thermometer.
The First Step is test of conceptions. Let's see if it works!
Connect transistor or diode as in picture to analog input of Arduino and run the following code (step1_test).
//pin connected to sensor const int analogPin = A0; void setup() { Serial.begin(9600); //internal reference 1.1V //we are measuring very low signal and have only 10bit ADC analogReference(INTERNAL); } void loop() { unsigned int sensorRead = analogRead(analogPin); //map ADC value to voltage drop on transistor/diode int voltageDrop = map(sensorRead, 0, 1023, 0, 1100); Serial.print("ADC:"); Serial.print(sensorRead); Serial.print(" voltageDrop:"); Serial.print(voltageDrop); Serial.println(" mV"); Serial.println("-----------------------------"); delay(300); }
Resistor determines the current flowing through the transistor or the diode. This current can not be too large because it will heat up the transistor causing measurement error. With 1200 Ohm resistor the current has a value of ~4...5 mA for VCC = 5 V. Analog input AO measure the voltage drop (forward bias) on junction. We can read in serial monitor. Touch the sensor and try to notice the change of the measured value...
Ok, it's working. ;)
So, the next step is to calculate the temperature. If You can do this in the "hard way", You can solve Shockley equation:
https://en.wikipedia.org/wiki/Shockley_diode_equat...
There is also a "easy way" for lazy people;) After short google search I found some links:
The last source described the practical demo circuit with multimeter, as it's written for temperature range 0...100
°C the voltage is changing from 0.7 V to 0.4 V (remember that the coefficient is negative).
In the second program (step1a_test) we try to calculate temperature using this information using fmap() function, similar to map() from Arduino library, but working with floats.
//pin connected to sensor const int analogPin = A0; void setup() { Serial.begin(9600); //internal reference 1.1V //we are measuring very low signal and have only 8bit ADC analogReference(INTERNAL); } void loop() { unsigned int sensorRead = analogRead(analogPin); //map ADC value to voltage drop on transistor/diode int voltageDrop = map(sensorRead, 0, 1023, 0, 1100); //map voltage drop to temperature float temperature = fmap(voltageDrop, 700, 400, 0, 100); Serial.print("ADC:"); Serial.print(sensorRead); Serial.print(" voltageDrop:"); Serial.print(voltageDrop); Serial.println(" mV"); Serial.print("temperature:"); Serial.print(temperature); Serial.print("deg. C"); Serial.println("-----------------------------"); delay(300); } //implementation of map() function for float float fmap(float x, float in_min, float in_max, float out_min, float out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; }
That is working, but the temperature may not be correct. In next step we try to calibrate our thermometer.
Step 2: Calibration
The forward voltage on is dependent on the temperature and the flowing current. The temperature coefficient also depends on the collector current, also may be different for other types of transistors.
The voltage drop range of the previous step needs to be improved.
float temperature = fmap(voltageDrop, 700, 400, 0, 100);
For BC547 I found, based on datasheets and comparison with the other electronic thermometer:
- the voltage is between 495 mV and 715 mV for temperature range -10...100°C.
So in code we have:
float temperature = fmap((float)voltageDrop, 715*8, 495*8, -10, 100);
Magic number "8" is needed for use wider range of int and minimize rounding error during casting to floats.
After this improvements thermometer indicating the good value! ;)
//pin connected to sensor const int analogPin = A0; void setup() { Serial.begin(9600); //internal reference 1.1V //we are measuring very low signal and have only 8bit ADC analogReference(INTERNAL); } void loop() { unsigned int sensorRead = analogRead(analogPin); //map ADC value to voltage drop on transistor/diode // //MAGIC NUMBER 8 - using full range of int, minimize rounding errors int voltageDrop = map(sensorRead, 0, 1023, 0, 1100*8); //map voltage drop to temperature //MAGIC NUMBER 8 - using full range of int, minimize rounding erros //range for voltage drop for BC547 transistor float temperature = fmap((float)voltageDrop, 715*8, 495*8, -10, 100); Serial.print("ADC:"); Serial.print(sensorRead); Serial.print(" voltageDrop:"); Serial.print(voltageDrop); Serial.println(" mV"); Serial.print("temperature:"); Serial.print(temperature); Serial.println("deg. C"); Serial.println("-----------------------------"); delay(1000); } //implementation of map() function for float float fmap(float x, float in_min, float in_max, float out_min, float out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; }
Attachments
Step 3: Add More Channels...
Every Arduino board has a multiple analog inputs. Transistor and diodes are very cheap so You can add more channels to our thermometer. I added three channels.
With arrays the code will be more readable and clear:
int sensor[sensorCount]; int sensorRead[sensorCount]; int voltageDrop[sensorCount]; float temperature[sensorCount];
The sensor[] stores pin number, sensorRead[] stores raw data from ADC, voltageDrop[] stores ADC reading converted to voltage drop. The final value - measured temperature is stored in float's array temperature[]. All computations, regardless of the number of connected sensors are made in one loop:
for (int i = 0; i < sensorCount; i++) { sensorRead[i] = analogRead(sensor[i]); voltageDrop[i] = map(sensorRead[i], 0, 1023, 0, 1100 * 8); temperature[i] = fmap((float)voltageDrop[i], 715 * 8, 495 * 8, -10, 100); }
We can also compute average temperature from all connected sensors, again using loop:
float meanTemperature = 0.0f; for (int i = 0; i < sensorCount; i++) { meanTemperature += temperature[i]; } meanTemperature /= sensorCount;
Step 4: Final
In last step I made analog-like display, namely a LED bargraph.
In Arduino Examples->07.Display->barGraph is a piece of code which I modified.
The barGraph was made from single LEDs on breadbord. You can also use integrated 10 segment LED bargraph.
I reversed polarity of LEDs, Arduino outputs working as open collector, with 220 Ω resistor. Diodes are connected to Arduino pins 2...10. I used nine LEDs which indicate temperature between 16...24 °C. As You can see in picture, at the end I also connected a buzzer to the last LED, which is a simple thermal alarm.
The movie present a hairdryer test;)
You can download final version of code. Enjoy!
________________________________________________________
At the end I would remind You that this is a very simple way to measure temperature and it's not very accurate.
This circuit was built mostly for fun and educational purposes. If you want to achieve more accurate temperature measurement with Arduino you can use popular DS18B20 sensor. Another way is to use industrial sensor (like Pt-100, Pt-1000 or thermocouple) with some analog front-end.