You are on page 1of 27

Project 22LCD Thermostat

Measuring Temperature Measuring temperature is a similar problem to measuring light intensity. Instead of an LDR, a device called a thermistor is used. As the temperature increases, so does the resistance of the thermistor. When you buy a thermistor, it will have a stated resistance. In this case, the thermistor chosen is 33 k. This will be the resistance of the device at 25C. The formula for calculating the resistance at a particular temperature is given by : R = Ro exp(-beta/(T + 273) - beta/(To + 273) You can do the math if you like, but a much simpler way to measure temperature is to use a special-purpose thermometer chip such as the TMP36. This three-pinned device has two pins for the power supply (5V) and a third output pin, whose temperature T in degrees C is related to the output voltage V by the equation : T = (V - 0.5) 100 So, if the voltage at its output is 1V, the temperature is 50C. The temperature in the Evil Genius lair must be regulated because the Evil Genius is particularly susceptible to chills. This project uses an LCD screen and a temperature sensor to display both the current temperature and the set temperature. It uses a rotary encoder to allow the set temperature to be changed. The rotary encoders button also acts as an override switch. When the measured temperature is less than the set temperature, a relay is activated. Relays are old-fashioned electromagnetic components that activate a mechanical switch when a current flows through a coil of wire. They have a number of advantages. First, they can switch high currents and voltages, making them suitable for controlling electrical service equipment. They also electrically isolate the control side (the coil) from the switching side so that the high and low voltages never meet, which is definitely a good thing. If the reader decides to use this project to switch electrical service electricity, he or she should do so only if he or she really knows what to do and exercises extreme caution. Electrical service electricity is very dangerous and kills about 500 people a year in the United States alone. Many more suffer painful and damaging burns. COMPONENTS AND EQUIPMENT

Hardware
The LCD module is connected up in exactly the same way as Project 17. The rotary encoder is also connected up in the same way as previous projects. The relay will require about 70 mA, which is a bit too much for an Arduino output to handle unaided, so we use an NPN transistor to increase the current. You will also notice that a diode is connected in parallel with the relay coil. This is to prevent something called back EMF (electromotive force), which occurs when the relay is turned off. The sudden collapse of the magnetic field in the coil generates a voltage that can be high enough to damage the electronics if the diode is not there to effectively short it out if it occurs. Figure 8-1 shows the schematic diagram for the project.

This project actually requires two half-sized breadboards or one single full-size breadboard. Even with two breadboards, the breadboard layout for the project is quite cramped because the LCD module uses a lot of the space.

Check your datasheet for the relay because the connection pins can be quite counterintuitive and there are several pin layouts, and your layout may not be the same as the relay that the author used. Figure 8-2 shows the breadboard layout for the project.

Figure 8-2 Breadboard layout for Project 22. You can also use a multimeter to find the coil connections by putting it on resistance mode. There will be only a pair of pins with a resistance of 40 to 100 .

Software
The software for this project borrows heavily from several of our previous projects: the LCD display, the temperature data logger, and the traffic signal project for use of the rotary encoder (see Listing Project 22). One thing that requires a bit of consideration when designing a thermostat like this is that you want to avoid what is called hunting. Hunting occurs when you have a simple on-off control system. When the temperature falls below the set point, the power is turned on, and the room heats until it is above the set point. Then the room cools until the temperature is below the set point again, at which point the heat is turned on again, and so on. This may take a little time to happen, but when the temperature is just balanced at the switchover temperature, this hunting can be frequent. High-frequency switching such as this is undesirable because turning things on and off tends to wear them out. This is true of relays as well. One way to minimize this effect is to introduce something called hysteresis, and you may have noticed a variable called hysteresis in the sketch that is set to a value of 0.25C.

LISTING PROJECT 22
// Project 22 - LCD Thermostat #include <LiquidCrystal.h> #define beta 4090 // from your thermistors datasheet #define resistance 33 // LiquidCrystal display with: // rs on pin 12 // rw on pin 11 // enable on pin 10 // d4-7 on pins 5-2 LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2); int int int int int int ledPin = 15; relayPin = 16; aPin = 8; bPin = 7; buttonPin = 6; analogPin = 0;

float setTemp = 20.0; float measuredTemp; char mode = 'C'; // can be changed to F boolean override = false; float hysteresis = 0.25; void setup() { lcd.begin(2, 20); pinMode(ledPin, OUTPUT); pinMode(relayPin, OUTPUT); pinMode(aPin, INPUT); pinMode(bPin, INPUT); pinMode(buttonPin, INPUT); lcd.clear(); } void loop() { static int count = 0; measuredTemp = readTemp(); if (digitalRead(buttonPin)) { override = ! override; updateDisplay(); delay(500); // debounce } int change = getEncoderTurn(); setTemp = setTemp + change * 0.1; if (count == 1000) { updateDisplay(); updateOutputs(); count = 0; } count ++; } int getEncoderTurn() { // return -1, 0, or +1

static int oldA = LOW; static int oldB = LOW; int result = 0; int newA = digitalRead(aPin); int newB = digitalRead(bPin); if (newA != oldA || newB != oldB) { // something has changed if (oldA == LOW && newA == HIGH) { result = -(oldB * 2 - 1); } } oldA = newA; oldB = newB; return result; } float readTemp() { long a = analogRead(analogPin); float temp = beta / (log(((1025.0 * resistance / a) - 33.0) / 33.0) + (beta / 298.0)) - 273.0; return temp; } void updateOutputs() { if (override || measuredTemp < setTemp - hysteresis) { digitalWrite(ledPin, HIGH); digitalWrite(relayPin, HIGH); } else if (!override && measuredTemp > setTemp + hysteresis) { digitalWrite(ledPin, LOW); digitalWrite(relayPin, LOW); } } void updateDisplay() { lcd.setCursor(0,0); lcd.print("Actual: "); lcd.print(adjustUnits(measuredTemp)); lcd.print(" o"); lcd.print(mode); lcd.print(" "); lcd.setCursor(0,1); if (override) { lcd.print(" OVERRIDE ON "); } else { lcd.print("Set: "); lcd.print(adjustUnits(setTemp)); lcd.print(" o"); lcd.print(mode); lcd.print(" "); } }

float adjustUnits(float temp) { if (mode == 'C') { return temp; } else { return (temp * 9) / 5 + 32; } }

Figure 8-3 Hysteresis in control systems. As the temperature rises with the power on, it approaches the set point. However, it does not turn off the power until it has exceeded the set point plus the hysteresis value. Similarly, as the temperature falls, the power is not reapplied the moment it falls below the set point but only when it falls below the set point minus the hysteresis value. We do not want to update the display continuously because any tiny changes in the reading would result in the display flickering wildly. So, instead of updating the display every time round the main loop, we just do it one time in 1000. This still means that it will update three or four times per second. To do this, we use the technique of having a counter variable that we increment each time round the loop. When it gets to 1000, we update the display and reset the counter to 0. Using lcd.clear() each time we change the display also would cause it to flicker. So we simply write the new temperatures on top of the old temperature. This is why we pad the OVERRIDE ON message with spaces so that any text that was previously displayed at the edges will be blanked out.

Putting It All Together


Load the completed sketch for Project 22 from your Arduino Sketchbook and download it to the board (see Chapter 1)

The completed project is shown in Figure 8-4. To test the project, turn the rotary encoder, setting the set temperature to slightly above the actual temperature. The relay should click on. Then put your finger onto the TMP36 to warm it up. If all is well, then when the set temperature is exceeded, the LED should turn off, and you will hear the relay click.

Figure 8-4 Project 22: LCD thermostat. You also can test the operation of the relay by connecting a multimeter in continuity test (beep) mode to the switched output leads. I cannot stress enough that if you intend to use your relay to switch electrical service electricity, first put this project onto a properly soldered Protoshield because breadboard is not suitable for high voltages. Second, be very careful, and check and double-check what you are doing. Electrical service electricity kills. You must only test the relay with low voltage unless you are going to make a proper soldered project from this design.

TMP36 - Temperature Sensor

Description: This is the same temperature sensor that is included in our SparkFun Inventor's Kit. The TMP36 is a low voltage, precision centigrade temperature sensor. It provides a voltage output that is linearly proportional to the Celsius temperature. It also doesn't require any external calibration to provide typical accuracies of 1C at +25C and 2C over the 40C to +125C temperature range. We like it be cause it's so easy to use: Just give the device a ground and 2.7 to 5.5 VDC and read the voltage on the Vout pin. The output voltage can be converted to temperature easily using the scale factor of 10 mV/C. Features:

Voltage Input: 2.7 V to 5.5 VDC 10 mV/C scale factor 2C accuracy over temperature 0.5C linearity Operating Range: 40C to +125C Output range: 0.1V (-40C) to 2.0V (150C) but accuracy decreases after 125C Power supply: 2.7V to 5.5V only, 0.05 mA current draw

I dont see the voltage => C equation at hand. So, to save others the trouble: The datasheet says 1C/10mV, and 750mV @ 25C. With V as our independant and C as our dependant variable, we can set up a point-slope form: C - 25C = 1C/10mV * (mV - 750mV). Solving and converting to V, I think this gives the formula: C = 100 * V - 50. This checks out with the graph on the datasheet, with 0.3v for -20C and 1.2v for 70C (158F). I havent tested it yet, but this looks great for working with an Xbee: they should run on the same supply voltage, and expec ted temperatures should fit within the Xbees ADC range (max. 1.2v). This is a nice sensor to learn about A/D manipulation with uCs. Dont know if anyone else has experienced this, but when use d remotely even less than 3ft, the noise susceptibility makes Vout will jump around by a few mV. I placed a 680 Ohm resistor in series with the output per the datasheet suggestions, and it helped somewhat but did not get rid of enough noise. Tried capacitors between Vin and Gnd, no change. Tried sampling 5 times then averaging the result - not good enough. Did not try shielded cable.. instead I got the DS18B20 and never looked back. (Not sure if the noisy signal of the TMP36 is a result solely of the Arduino or of the remote cable length. By noisy, I mean typically +/- 1 deg F bounce - too much for a temperature controller for a sensitive application.)

How to Measure Temperature


Using the TMP36 is easy, simply connect the left pin to power (2.7-5.5V) and the right pin to ground. Then the middle pin will have an analog voltage that is directly proportional (linear) to the temperature. The analog voltage is independant of the power supply.

To convert the voltage to temperature, simply use the basic formula:

Temp in C = [(Vout in mV) - 500] / 10


So for example, if the voltage out is 1V that means that the temperature is If you're using a LM35 or similar, use line 'a' in the image above and the formula: Temp

((1000 mV - 500) / 10) = 50 C in C = (Vout in mV) / 10

Problems you may encounter with multiple sensors:


If, when adding more sensors, you find that the temperature is inconsistant, this indicates that the sensors are interfering with each other when switching the analog reading circuit from one pin to the other. You can fix this by doing two delayed readings and tossing out the first one

Testing a Temp Sensor


Testing these sensors is pretty easy but you'll need a battery pack or power supply. Connect a 2.7-5.5V power supply (2-4 AA batteries work fantastic) so that ground is connected to pin 3 (right pin), and power is connected to pin 1 (left pin) Then connect your multimeter in DC voltage mode to ground and the remaining pin 2 (middle). If you've got a TMP36 and its about room temperature (25C), the voltage should be about 0.75V. Note that if you're using a LM35, the voltage will be 0.25V

The sensor is indicating that the temperature is 26.3C also known as 79.3F
You can change the voltage range by pressing the plastic case of the sensor with your fingers, you will see the temperature/voltage rise.

With my fingers on the sensor, heating it up a little, the temperature reading is now 29.7C / 85.5F
Or you can touch the sensor with an ice cube, perferrably in a plastic bag so it doesn't get water on your circuit, and see the temperature/voltage drop.

I pressed an ice-cube against the sensor, to bring the temperature down to 18.6C / 65.5F

Using a Temp Sensor


Connecting to a Temperature Sensor
These sensors have little chips in them and while they're not that delicate, they do need to be handled properly. Be careful of static electricity when handling them and make sure the power supply is connected up correctly and is between 2.7 and 5.5V DC - so don't try to use a 9V battery!

They come in a "TO-92" package which means the chip is housed in a plastic hemi-cylinder with three legs. The legs can be bent easily to allow the sensor to be plugged into a breadboard. You can also solder to the pins to connect long wires. If you need to waterproof the sensor, you can see below for an Instructable for how to make an excellent case.

Reading the Analog Temperature Data


Unlike the FSR or photocell sensors we have looked at, the TMP36 and friends doesn't act like a resistor. Because of that, there is really only one way to read the temperature value from the sensor, and that is plugging the output pin directly into an Analog (ADC) input. Remember that you can use anywhere between 2.7V and 5.5V as the power supply. For this example I'm showing it with a 5V supply but note that you can use this with a 3.3v supply just as easily. No matter what supply you use, the analog voltage reading will range from about 0V (ground) to about 1.75V. If you're using a 5V Arduino, and connecting the sensor directly into an Analog pin, you can use these formulas to turn the 10-bit analog reading into a temperature:

Voltage at pin in milliVolts = (reading from ADC) * (5000/1024)


This formula converts the number 0-1023 from the ADC into 0-5000mV (= 5V) If you're using a 3.3V Arduino, you'll want to use this:

Voltage at pin in milliVolts = (reading from ADC) * (3300/1024)


This formula converts the number 0-1023 from the ADC into 0-3300mV (= 3.3V) Then, to convert millivolts into temperature, use this formula:

Centigrade temperature = [(analog voltage in mV) - 500] / 10


Simple Thermometer
This example code for Arduino shows a quick way to create a temperature sensor, it simply prints to theserial port what the current temperature is in both Celsius and Fahrenheit.

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38.

//TMP36 Pin Variables int sensorPin = 0; //the analog pin the TMP36's Vout (sense) pin is connected to //the resolution is 10 mV / degree centigrade with a //500 mV offset to allow for negative temperatures /* * setup() - this function runs once when you turn your Arduino on * We initialize the serial connection with the computer */ void setup() { Serial.begin(9600); //Start the serial connection with the computer //to view the result open the serial monitor } void loop() // run over and over again { //getting the voltage reading from the temperature sensor int reading = analogRead(sensorPin); // converting that reading to voltage, for 3.3v arduino use 3.3 float voltage = reading * 5.0; voltage /= 1024.0; // print out the voltage Serial.print(voltage); Serial.println(" volts"); // now print out the temperature float temperatureC = (voltage - 0.5) * 100 ;

//converting from 10 mv per degree wit 500 mV offset //to degrees ((voltage - 500mV) times 100) Serial.print(temperatureC); Serial.println(" degrees C"); // now convert to Fahrenheit float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0; Serial.print(temperatureF); Serial.println(" degrees F"); delay(1000); } //waiting a second

Getting Better Precision


For better results, using the 3.3v reference voltage as ARef instead of the 5V will be more precise and less noisy

This example from the light&temp datalogging tutorial has a photocell but you can ignore it Note we've changed the TMP36 to A1

To use the 3.3v pin as your analog reference, don't forget to specify "analogReference(EXTERNAL)" in your setup as in the code below:
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. /* Sensor test sketch for more information see http://www.ladyada.net/make/logshield/lighttemp.html */ #define aref_voltage 3.3 // we tie 3.3V to ARef and measure it with a multimeter!

//TMP36 Pin Variables int tempPin = 1;

int tempReading;

//the analog pin the TMP36's Vout (sense) pin is connected to //the resolution is 10 mV / degree centigrade with a //500 mV offset to allow for negative temperatures // the analog reading from the sensor

void setup(void) { // We'll send debugging information via the Serial monitor Serial.begin(9600); // If you want to set the aref to something other than 5v analogReference(EXTERNAL); }

void loop(void) {

27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. }

tempReading = analogRead(tempPin); Serial.print("Temp reading = "); Serial.print(tempReading); // the raw analog reading // converting that reading to voltage, which is based off the reference voltage float voltage = tempReading * aref_voltage; voltage /= 1024.0; // print out the voltage Serial.print(" - "); Serial.print(voltage); Serial.println(" volts"); // now print out the temperature float temperatureC = (voltage - 0.5) * 100 ;

//converting from 10 mv per degree wit 500 mV offset //to degrees ((volatge - 500mV) times 100) Serial.print(temperatureC); Serial.println(" degrees C"); // now convert to Fahrenheight float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0; Serial.print(temperatureF); Serial.println(" degrees F"); delay(1000);

Please note, that generally you do not connect the 3.3V VCC to the Aref pin, but doing so makes the reading better. I also want to take your attention to the fact that I use 3.3V instead of the 5V as VCC, as the 3.3V please continue reading here.
// the reference voltage double REF_VOLTAGE = 3.3; // the pin where the temperature is to be mesured int tempPin = 5; void setup() { // open te serial output with 115200 baud Serial.begin(115200); // tell the Arduino that the reference voltage is // provided by an external source analogReference(EXTERNAL); // wait for the external source to be switched delay(100); } void loop() { // read the tempetarue int tempReading = analogRead(tempPin); // converting that reading to voltage float voltage = tempReading * REF_VOLTAGE / 1024.0; // convert the voltage to a temperature float celsius = (voltage - 0.5) * 100 ; // print it on the serial output Serial.println(celsius); // wait a second delay(1000); }

regulator has a better filtering . For more information about this,

Rudo do sinal enquanto TMP36


Na nossa instalao com diversos sensores aps os testes iniciais mostraram que um problema com o rudo na sada analgica do TMP36. O problema se manifesta medida que a temperatura calculada de vrios graus TMP36 foi obviamente muito baixo. Uma medio rpida com oDSO Nano revelou que o sinal foi medies reprodues vez distorcidas muito forte e na entrada analgica do Arduino as pontas inferiores do rudo como uma mdia. Aps a sada do TMP36 com um elemento RC sede parecia ser leituras plausveis novamente. Diagrama de blocos de suavizao do sinal para a sada TMP36

Com uma resistncia 10KOHM e um condensador de 100 nF resultados numa constante de 1 ms, ou seja, o tempo, o atraso das leituras 5ms. Podemos viver neste contexto. Se o TMP36 usado sozinho em uma placa de ensaio a de considerar este problema respectivamente menos. pode ser ignorado.

OUTRO PROJETO

/* Connect TMP36 sensor and output temperature on LCD screen TMP36 Middle pin to Analog A0 */ // include the library code #include <LiquidCrystal.h> // initialize the library with the numbers of the interface pins LiquidCrystal lcd(12,11,5,4,3,2); // initialize our variables int sensorPin = 0; int tempReading; float voltage; int tempC; void setup() { // set up the LCD's number of columns and rows: lcd.begin(16, 2); } void loop() { tempReading = analogRead(sensorPin); // convert the reading to a voltage voltage = tempReading * 5.0; voltage /= 1024.0; // convert the voltage to a temperature tempC = (voltage - 0.5) * 100; lcd.setCursor(0,0); lcd.print(tempC); lcd.print((char)223); lcd.print("C"); delay(200); } After you upload this code to the arduino, you should see a temperature in celsius displayed on the first line of your lcd screen.

Refactoring
Once you have code that's working, it's usually helpful to change it to make it easier to read. That's what we're going to do here. In this code, we're basically doing two things. First we're reading the temperature from a pin and secondly we're displaying the temperature on the lcd screen. For our first refactoring, let's move the reading of the temperature to a separate function. // include the library code #include <LiquidCrystal.h> // initialize the library with the numbers of the interface pins LiquidCrystal lcd(12,11,5,4,3,2); // initialize our variables int sensorPin = 0; int tempC; void setup() { // set up the LCD's number of columns and rows: lcd.begin(16, 2); } void loop() { tempC = get_temperature(sensorPin); lcd.setCursor(0,0); lcd.print(tempC); lcd.print(" "); lcd.print((char)223); lcd.print("C"); delay(200); } int get_temperature(int pin) { // We need to tell the function which pin the sensor is hooked up to. We're using // the variable pin for that above // Read the value on that pin int temperature = analogRead(pin); // Calculate the temperature based on the reading and send that value back float voltage = temperature * 5.0; voltage = voltage / 1024.0;

return ((voltage - 0.5) * 100); } Again, since this was just refactoring, you should see exactly the same thing on your lcd screen that you saw before, which is just a temperature in celsius.

Display Fahrenheit
On our ovens, we don't usually display temperatures in celsius, but instead use degrees fahrenheit. So, let's change our code so that instead of displaying celsius, we show fahrenheit. In order to calculate fahrenheit, you take the temperature in celsius and multiply it by 9, then divide by 5. Then add 32 to that value. Below is the equation to use: fahrenheit = (celsius * 9/5) + 32 We'll change the code by writing a function that performs this calculation. // include the library code #include <LiquidCrystal.h> // initialize the library with the numbers of the interface pins LiquidCrystal lcd(12,11,5,4,3,2); // initialize our variables int sensorPin = 0; int tempC, tempF; void setup() { // set up the LCD's number of columns and rows: lcd.begin(16, 2); } void loop() { tempC = get_temperature(sensorPin); tempF = celsius_to_fahrenheit(tempC); lcd.setCursor(0,0); lcd.print(tempF); lcd.print(" "); lcd.print((char)223); lcd.print("F"); delay(200); } int get_temperature(int pin) { // We need to tell the function which pin the sensor is hooked up to. We're using // the variable pin for that above // Read the value on that pin int temperature = analogRead(pin); // Calculate the temperature based on the reading and send that value back float voltage = temperature * 5.0; voltage = voltage / 1024.0; return ((voltage - 0.5) * 100); } int celsius_to_fahrenheit(int temp) { return (temp * 9 / 5) + 32; } You should now see the temperature in fahrenheit on your lcd screen.

Connect Light Sensor


Along with our temperature sensor, we can hook up other types of sensors to measure different things. Here, we're going to hook up a sensor that measures the amount of light hitting it. With the temperature sensor, we were reading degrees of celsius or fahrenheit. With a light sensor, we are going to read lux, which is a measurement of how much light is hitting an object. There's one really big difference between our temperature sensors and our light sensors and that has to do with accuracy. If everyone hooks up their temperature sensors and is working in the same room, they should all read just about the same value. This is not the case with our light sensor, where everyone could have very different values. That's ok becausethese light sensors are not designed for everyone to have the same reading. These sensors are

instead used to determine if a light is on or off, or is there something blocking the sensor. In these cases, we don't care about the exact reading, but the change in light levels. And for these types of events, our light sensor will work perfectly. For our solar oven, we're going to use the light sensor to determine when we need to reposition the oven to catch the maximum amount of light. So, we just want to know when the amount of light hitting the sensor changes by some amount. Note that you can bend the leads on the light sensor, but try not to bend them right by the sensor because you could break the leads right off.

// include the library code #include <LiquidCrystal.h> // initialize the library with the numbers of the interface pins LiquidCrystal lcd(12,11,5,4,3,2); // initialize our variables int sensorPin = 0; int photocellPin = 1; int tempC, tempF, lightReading; void setup() { // set up the LCD's number of columns and rows: lcd.begin(16, 2); } void loop() { tempC = get_temperature(sensorPin);

tempF = celsius_to_fahrenheit(tempC); lightReading = get_light_reading(photocellPin); lcd.setCursor(0,0); lcd.print(tempF); lcd.print(" "); lcd.print((char)223); lcd.print("F"); lcd.setCursor(0,1); lcd.print("Light: "); lcd.print(lightReading); lcd.print(" lux"); delay(200); } int get_light_reading(int pin) { int photocellReading = analogRead(pin); return photocellReading; } int get_temperature(int pin) { // We need to tell the function which pin the sensor is hooked up to. We're using // the variable pin for that above // Read the value on that pin int temperature = analogRead(pin); // Calculate the temperature based on the reading and send that value back float voltage = temperature * 5.0; voltage = voltage / 1024.0; return ((voltage - 0.5) * 100); } int celsius_to_fahrenheit(int temp) { return (temp * 9 / 5) + 32; }

COMPARAO de SENSORES de Temperatura

/*9-3-2013 This program makes use of two different types of temperature sensors to monitor the room temperature. The TMP36GZ will provide an voltage output of 10mV/degree C. However, its output will be 500mV at 0 degree C. The TM335AZ on other hand will provide an voltage output of 10mV/degree K. It has an output of 0mV when the temperature is 0 K. Note: 0 Kelvin = -273.15 degree C. Connection for TMP36: 1. L-pin: 5V 2. M-pin: A0; 3. R-pin: 0V; Connection for LM355: 1. L-pin: None; 2. M-pin: A1 & Wiper pin of 10K POT; one other pin of 10K POT to 5V; 3. R-pin: 0V; Use the temperature obtained from the TMP36 as a reference to calibrate the temperature output from the LM355. After the calibration is done, you may want to squeeze the sensor head to raise the temperature a little. You may squeeze the sensor head with your thumb and finger to raise the temperature a little. */ // declaration int Csensor = A0; // TMP36 sensor int Ksensor = A1; // LM355 sensor void setup () { Serial.begin (9600); } void loop () { float CsensorVoltage = 0; CsensorVoltage = (5.0 / 1023) * (analogRead (Csensor)); //convert to actual voltage float tempC = (CsensorVoltage - 0.5 ) * 100; //convert to degree Celsius Serial.print ("CsensorVoltage in Volt = "); Serial.print (CsensorVoltage); Serial.print (" Temperature in Celsius = "); Serial.println (tempC); float KsensorVoltage = 0; KsensorVoltage = (5.0 / 1023) * (analogRead (Ksensor)); // convert to actual voltage float tempK = (KsensorVoltage * 100); //convert to degree Kelvin Serial.print("KsensorVoltage in Volt = "); Serial.print (KsensorVoltage); Serial.print (" Temperature in Kelvin = "); Serial.println (tempK); Serial.print ("Temperature Conversion: Kelvin to Celsius = "); Serial.println (tempK - 273.15); //facilitates calibration Serial.println(); delay (5000); }

Measuring Temperature
Measuring temperature is a similar problem to measuring light intensity. Instead of an LDR, a device called a thermistor is used. As the temperature increases, so does the resistance of the thermistor. When you buy a thermistor, it will have a stated resistance. In this case, the thermistor chosen is 33 k . This will be the resistance of the device at 25C. The formula for calculating the resistance at a particular temperature is given by R = Ro exp(-beta/(T + 273) - beta/(To + 273) You can do the math if you like, but a much simpler way to measure temperature is to use a specialpurpose thermometer chip such as the TMP36. This three-pinned device has two pins for the power supply (5V) and a third output pin, whose temperature T in degrees C is related to the output voltage V by the equation T = (V - 0.5) 100 So, if the voltage at its output is 1V, the temperature is 50C.

Project 13USB Temperature Logger


This project is controlled by your computer, but once given its logging instructions, the device can be disconnected and run on batteries to do its logging. While logging, it stores its data, and then when the logger is reconnected, it will transfer its data back over the USB connection, where it can be imported into a spreadsheet. By default, the logger will record one sample every 5 minutes and can record up to 1000 samples. To instruct the temperature logger from your computer, we have to define some commands that can be issued from the computer. These are shown in Table 5-1. TABLE 5-1 Temperature Logger Commands

This project just requires a TMP36 that can fit directly into the sockets on the Arduino.

Figure 5-18 Schematic diagram for Project 13. This is so simple that we can simply fit the leads of the TMP36 into the Arduino board, as shown in Figure 5-19. Note that the curved side of the TMP36 should face outward from the Arduino. Putting a little kink in the leads with pliers will ensure a better contact.

Figure 5-19 Project 13: temperature logger. Two of the analog pins (A0 and A2) are going to be used for the GND and 5V power connections to the TMP36. The TMP36 uses very little current, so the pins can easily supply enough to power it if we set one pin HIGH and the other LOW.

Software
The software for this project is a little more complex than for some of our other projects (see Listing Project 13). All the variables that we have used in our sketches so far are forgotten as soon as the Arduino board is reset or disconnected from the power. Sometimes we want to be able to store data persistently so that it is there next time we start up the board. This can be done by using the special type of memory on the Arduino called EEPROM, which stands for electrically erasable programmable read-only memory. The Arduino Uno and Leonardo both have 1024 bytes of EEPROM. For the data logger to be useful, it needs to remember the readings that it has already taken, even when it is disconnected from the computer and powered from a battery. It also needs to remember the logging period. This is the first project where we have used the Arduinos EEPROM to store values so that they are not lost if the board is reset or disconnected from the power. This means that once we have set our data-logging recording, we can disconnect it from the USB lead and leave it running on batteries. Even if the batteries go dead, our data will still be there the next time we connect it. LISTING PROJECT 13
// Project 13 - Temperature Logger #include <EEPROM.h> #define ledPin 13

#define #define #define #define

analogPin 0 maxReadings 255 beta 4090 // from your thermistors datasheet resistance 33

float readings[maxReadings]; int lastReading = EEPROM.read(0); boolean loggingOn = false; long period = 300; long count = 0; char mode = 'C'; void setup() { pinMode(ledPin, OUTPUT); Serial.begin(9600); Serial.println("Ready"); } void loop() { if (Serial.available()) { char ch = Serial.read(); if (ch == 'r' || ch == 'R') { sendBackdata(); } else if (ch == 'x' || ch == 'X') { lastReading = 0; EEPROM.write(0, 0); Serial.println("Data cleared"); } else if (ch == 'g' || ch == 'G') { loggingOn = true; Serial.println("Logging started"); } else if (ch > '0' && ch <= '9') { setPeriod(ch); } else if (ch == 'c' or ch == 'C') { Serial.println("Mode set to deg C"); mode = 'C'; } else if (ch == 'f' or ch == 'F') { Serial.println("Mode set to deg F"); mode = 'F'; } else if (ch == '?') { reportStatus(); } } if (loggingOn && count > period) { logReading(); count = 0; } count++;

delay(1000); } void sendBackdata() { loggingOn = false; Serial.println("Logging stopped"); Serial.println("------ cut here ---------"); Serial.print("Time (min)\tTemp ("); Serial.print(mode); Serial.println(")"); for (int i = 0; i < lastReading; i++) { Serial.print((period * i) / 60); Serial.print("\t"); float temp = getReading(i); if (mode == 'F') { temp = (temp * 9) / 5 + 32; } Serial.println(temp); } Serial.println("------ cut here ---------"); } void setPeriod(char ch) { int periodMins = ch - '0'; Serial.print("Sample period set to: "); Serial.print(periodMins); Serial.println(" mins"); period = periodMins * 60; } void logReading() { if (lastReading < maxReadings) { long a = analogRead(analogPin); float temp = beta / (log(((1025.0 * resistance / a) - resistance) / resistance) + (beta / 298.0)) - 273.0; storeReading(temp, lastReading); lastReading++; } else { Serial.println("Full! logging stopped"); loggingOn = false; } } void storeReading(float reading, int index) { EEPROM.write(0, (byte)index); // store the number of samples in byte 0 byte compressedReading = (byte)((reading + 20.0) * 4); EEPROM.write(index + 1, compressedReading); } float getReading(int index) { lastReading = EEPROM.read(0); byte compressedReading = EEPROM.read(index + 1); float uncompressesReading = (compressedReading / 4.0) - 20.0; return uncompressesReading;

} void reportStatus() { Serial.println("----------------"); Serial.println("Status"); Serial.print("Sample period\t"); Serial.println(period / 60); Serial.print("Num readings\t"); Serial.println(lastReading); Serial.print("Mode degrees\t"); Serial.println(mode); Serial.println("----------------"); }

You will notice that at the top of this sketch we use the command #define for what in the past we would have used variables for. This is actually a more efficient way of defining constants that is, values that will not change during the running of the sketch. So it is actually ideal for pin settings and constants such as beta. The command #define is what is called a preprocessor directive, and what happens is that just before the sketch is compiled, all occurrences of its name anywhere in the sketch are replaced by its value. It is very much a matter of personal taste whether you use #define or a variable. Fortunately, reading and writing EEPROM happens just 1 byte at a time. So, if we want to write a variable that is a byte or a char, we can just use the functions EEPROM.write and EEPROM.read, as shown in the example here :

The 0 in the parameters for read and write is the address in the EEPROM to use. This can be any number between 0 and 1023, with each address being a location where 1 byte is stored. In this project we want to store both the position of the last reading taken (in the lastReading variable) and all the readings. So we will record lastReading in the first byte of EEPROM, the logging period as a character 1 to 9, and then the actual reading data in the bytes that follow. Each temperature reading is kept in a float, and if you remember from Chapter 2, a float occupies 4 bytes of data. Here we had a choice: We could either store all 4 bytes or find a way to encode the temperature into a single byte. We decided to take the latter route so that we can store as many readings as possible in the EEPROM. The way we encode the temperature into a single byte is to make some assumptions about our temperatures. First, we assume that any temperature in Centigrade will be between 20 and +40. Anything higher or lower would likely damage our Arduino board anyway. Second, we assume that we only need to know the temperature to the nearest quarter of a degree. With these two assumptions, we can take any temperature value we get from the analog input, add 20 to it, multiply it by 4, and still be sure that we always have a number between 0 and 240. Since a byte can hold a number between 0 and 255, that just fits nicely.

When we take our numbers out of EEPROM, we need to convert them back to a float, which we can do by reversing the process, dividing by 4, and then subtracting 20. Both encoding and decoding the values are wrapped up in the functions storeReading and getReading. So, if we decided to take a different approach to storing the data, we would only have to change these two functions. Putting It All Together Load the completed sketch for Project 13 from your Arduino Sketchbook and download it to the board (see Chapter 1). Now open the Serial Monitor (Figure 5-20), and for test purposes, we will set the temperature logger to log every minute by typing 1 in the Serial Monitor. The board should respond with the message Sample period set to: 1 min. If we wanted to, we could then change the mode to Fahrenheit by typing F into the Serial Monitor. Now we can check the status of the logger by typing? (Figure 5-21).

Figure 5-20 Issuing commands through the Serial Monitor.

Figure 5-21 Displaying the Temperature Logger Status.

In order to unplug the USB cable, we need to have an alternative source of power, such as the battery lead we made back in Project 6. You need to have this plugged in and powered up at the same time as the USB connector is connected if you want the logger to keep logging after you disconnect the USB lead. Finally, we can type the G command to start logging. We can then unplug the USB lead and leave our logger running on batteries. After waiting 10 or 15 minutes, we can plug it back in to see what data we have by opening the Serial Monitor and typing the R command, the results of which are shown in Figure 522. Select all the data, including the Time and Temp headings at the top .

Figure 5-22 Data to copy and paste into a spreadsheet. Copy the text to the clipboard (press CTRL-C on Windows and LINUX, ALT-C on Macs), open a spreadsheet in a program such as Microsoft Excel, and paste it into a new spreadsheet (Figure 5-23).

Once in the spreadsheet, we can even draw a chart using our data.

Summary
We now know how to handle various types of sensors and input devices to go with our knowledge of LEDs. In the next section we will look at a number of projects that use light in various ways and get our hands on some more advanced display technologies, such as LCD text panels and seven-segment LEDs.

You might also like