Project tutorial

Indoor NeoPixel Thermometer 

An indoor thermometer with LCD and "analog" readouts.

  • 3,894 views
  • 2 comments
  • 7 respects

Components and supplies

A000066 iso both
Arduino UNO & Genuino UNO
×1
NeoPixel
×1
LCD readout
×1
TMP36 sensor
×1
Mfr 25frf52 1k sml
Resistor 1k ohm
×1
470 ohm resistor
×1
09939 01
Rotary potentiometer (generic)
×1
Simple momentary switch
×1
F to M jumper wires
for the LCD
×1
M to M Jumpers
for everything else
×1
12002 04
Breadboard (generic)
×1

About this project

Hello! This is a quick, intermediate Arduino project that takes a temperature reading from a TMP36 , reads it onto an LCD screen and gives an "Analog" readout on a Neopixel stick that changes color and number of lights lit every 10 degrees Fahrenheit. It's easily customizable as NeoPixels can be coded in many ways so the NeoPixel stick can change size and colors every which way a maker would want it to.

Step 1: Gather Components

For this build you will need an Arduino (any one will do, I used Uno), NeoPixels (can be found here) an LCD screen (I used this one) a TMP36 sensor (or comparable, I used this inexpensive one from Adafruit ) a 1k ohm resistor, a 470 ohm resistor, a potentiometer, a simple momentary switch, F to M jumper wires (for the LCD) and M to M Jumpers (for everything else) and a breadboard.


Step 2: Construct Circuit

Fritzing View of Circuit

From the fritzing diagram the circuit looks a little confusing but it's actually relatively simple. What is important to take note is you're going to want the TMP36 on a separate circuit from the rest of the project because some noise that's caused by the Pixels messes up the voltage readout from the TMP36 and in turn the temperature reading. When it comes to the Pixels a bit a soldering is going to have to happen. You're going to want to use 4 plain, everyday headers, and solder them directly onto the NeoPixel stick. It's absolutely imperative that you get the pin out correct on this otherwise you'll have to de and resolder the headers and trust me, the copper pads on the NeoPixels do not like being resoldered and while NeoPixels are not the most expensive component in the world, several sticks that are rendered unusable because the copper pads have been taken off add up very quickly. To solder you will want a good iron and a solder with a thin gauge. A pair of "third hands" are especially useful in this project as the headers can be tricky to solder onto the stick straight if the stick is lying on the table.

How I set up the pixels and header in the Third hand
NeoPixel PinOut

I included a photo with the proper pin order, the side with "DIN" goes to the breadboard/Arduino and the side "DOUT" goes to other pixels or just the air. You can use any number of NeoPixels, the one at the Studio has 4 sticks for an especially prominent read out that would be ideal if you were to enclose it in a laser cut acrylic display (possibly stay tuned). On the other hand, and as seen in one of the photos, I have a smaller one using only one stick that works just fine at home that you could then also turn into a wall mounted display with a very quick enclosure. That's one of the things with NeoPixels that make them great, it doesn't take much code to make them fit almost any size or form factor.

The pin out from the Arduino goes as follows:

  • A0 to Vout on TMP36
  • 3.3V to TMP36 PWR Rail
  • AREF to TMP36 PWR Rail //AREF takes a reference voltage and gives a more accurate reading than just taking //straight from the source, you'll see why this is important on the next page
  • GND to TMP36 GND rail
  • 5V to Primary PWR rail
  • other GND to Primary GND rail
  • 13 to pin 4 on LCD
  • 12 to momentary switch //while not necessary I included a momentary switch that, when pressed will switch //between Celsius and Fahrenheit readout on the LCD
  • 11 to pin 6 on LCD
  • 6 to 470 ohm resistor leading to DIN on NeoPixels //resistor prevents surges and damage to the pixel stick
  • 5 to pin 11 on LCD
  • 4 to pin 12 on LCD
  • 3 to pin 13 on LCD
  • 2 to pin 14 on LCD
  • Other pinouts on LCD Screen
  • LCD pin 1 to one leg of potentiometer leading to Primary GND rail
  • LCD pin 2 to one leg of potentiometer leading to Primary PWR rail
  • LCD pin 3 to middle leg or "wiper" of potentiometer //this controls contrast on the screen
  • LCD pin 5 to primary GND rail
  • LCD pin 15 to primary PWR rail
  • LCD pin 16 to primary GND rail

The rest of the circuit is pretty self explanatory and clear on the Fritzing Diagram, just remember to keep the TMP36 and Primary circuits separate.


Step 3: Writing the Code

Attached to this is a file with the Arduino code. It can be broken up into three parts.

First you have the main method that goes from line 1 to line 61 and includes the setup, loop, and any imports, variables, and function calls you may need. This is the skeleton that puts all the code together to make it function. You're going to want to download and import the NeoPixel library (found here) and the LiquidCrystal library that should be already included with the Arduino software.

https://github.com/adafruit/Adafruit_NeoPixel

Second you have the function double tempMeasure starting from line 64 and going until 79. This is the code that takes the voltage that the TMP36 is reading and translates it, using some quick math, into a temperature readout and then returns that readout to the main method. This is where it's important to note why we have the TMP36 attached to the 3.3V and AREF pins. How the TMP36 works is it takes a voltage reading between two points that, because of a change in resistance from temperature, can then take very very very accurate temperature readings. In the code we have it to 2 decimal points but if you wanted to you could get the full 64 bit Decimal that would go into the thousandths, ten thousandths, hundred thousandths, what have you. That readout would be interesting but also a bit unwieldy for the purposes of this project. That voltage reading is then fed through a conversion that divides by 1024 (10 bits, the mapping Arduino uses) and then converts that using 10 mV per degree with a 500 mV offset. What is returned is an incredibly accurate temperature reading in Celsius which is then converted to Fahrenheit in the main method.

Third you have the function void pixelCasef that runs from line 81 to 158. This is the code that controls the NeoPixel readout with a series of If Else statements and for loops that work in ~10 (for noise tolerance) degree Fahrenheit increments that change color and height of pixels lit. This is where you change the code to behave differently with different number of sticks. To customize you just go to each of these for loops and switch out numbers. The number in the loop statement (i.e for(int i = 0; i <= 16; i++)) is the number you change for the number of pixels lit and the number in the body of the for loop (i.e. strip.setPixelColor(i,strip.Color(0,0,255));) changes color of the pixels lit.

Remember to take a really good look at the code to fully understand what's going on before compiling it.

neoTemp.ino
Untitled file

Warning: Embedding code files within the project story has been deprecated. To edit this file or add more files, go to the "Software" tab. To remove this file from the story, click on it to trigger the context menu, then click the trash can button (this won't delete it from the "Software" tab).

#include <LiquidCrystal.h>
#include <Adafruit_NeoPixel.h>

// Create a variable that will store the temperature value
int TMPin = 0;
const int button = 12;
int lastColor = -1;


#define aref_voltage 3.3
#define PIN 6


/*
Param 1 == number of pixels
Param 2 == Arduino pin attached to din
Param 3 == pixel type flags, add together as needed
  NE0_KHZ800 800 KHZ bitstream (avg neopix)
  NE0_GRB wired for GRB bitstream
*/
Adafruit_NeoPixel strip = Adafruit_NeoPixel(32, PIN, NEO_GRB + NEO_KHZ800); //call Neopixels, 32 pixels in all, on pin 6, RGB system and 800 KHZ
LiquidCrystal lcd(13, 11, 5, 4, 3, 2); //call LCD display

void setup() 
{
  lcd.begin(16,2); //initialize LCD screen 16 by 2  
  strip.begin(); //begin neo pixel strip
  strip.show(); //initialize strip
  Serial.begin(9600);// serial monitor access
  pinMode(button, INPUT); //button for celsius
  analogReference(EXTERNAL); //analog reference for use with TMP36
}

void loop() 
{
  double temperature;
  double temp;
  double tempF;


  temp = tempMeasure(temperature); //call tempMeasure function
  tempF = (temp * 9.0/5.0 + 32);  //take reading from tempMeasure and convert to faharenheit
  
  
  while(digitalRead(button) == false) //button is depressed readout is in Celsius
  {
    Serial.println(temp); //prints in serial monitor
    lcd.print(temp); //prints on LCD screen
    lcd.setCursor(0,1); //sets cursor
    delay(2000); //2 seconds between readings
    lcd.clear(); //clear LCD after 2 seconds   
}
 
 pixelCaseF(tempF); //call pixelCase function that controls lights
 Serial.println(tempF); //print in serial
 lcd.print(tempF); //print temp in F on LCD
 lcd.setCursor(0,1); //set cursor
 delay(2000); //take reading every 2 seconds
 lcd.clear(); //clear LCD
 
}//end loop


double tempMeasure(double temperature)
{
 // -----------------
// Read temperature
// -----------------

  int reading = analogRead(TMPin); //voltage reading
  double voltage = reading * aref_voltage; //take initial reading and multiply by 3.3 ref voltage for arduino
  
  voltage /= 1024.0; //divide reading by 1024 to map
   
  temperature = (voltage - 0.5) * 100; //converts 10mv per degree with 500 mV offset to (voltage - 500mV) * 100)
   
  return temperature; //return temperature to top level method

}//end tempMeasure

void pixelCaseF(double tempF)
/*
This method controls the neo-pixel for the "analog" readout on the thermometer. With every temperature group, the number of pixels lit changes along with the color
*/

{
 int i;
 strip.setBrightness(64);
 strip.show();
  
  if (tempF >= 90.05)//if above 90 degrees, strip is red and entire strip is lit
 {
   strip.clear();
   for(int i=0;i <= 32;i++)
   {
   strip.setPixelColor(i, strip.Color(255,0,0));
   }
 }
 else if (tempF < 90.2 && tempF >= 80.05) //if 90 > tempF >= 80 orange and strip is partially lit up to 29th pixel
 { 
   strip.clear();
   for(int i=0;i <= 28;i++)
  {
  strip.setPixelColor(i, strip.Color(255,128,0)); 
  }
 }
 else if (tempF < 80.02 && tempF >= 70.5)// if 80 > tempF >= 70 yellow-green and strip is lit up to 25th pixel
 {
   strip.clear();
   for(int i = 0; i <= 24; i++)
   {
    strip.setPixelColor(i,strip.Color(204,255,0)); 
   }
 }  
 else if (tempF < 70 && tempF >= 60.5)// if 70 > tempF >= 60 green and strip is lit up to 21st pixel
{
  strip.clear();
  for(int i = 0; i<= 20; i++)
  {
   strip.setPixelColor(i,strip.Color(0,255,0));
  }
}
 else if (tempF < 60.02 && tempF >= 50.5) //if 60 > tempF >= 50 blue and strip is lit up to 17th pixel
{
  strip.clear();
  for(int i = 0; i <= 16; i++)
  {
    strip.setPixelColor(i,strip.Color(0,0,255));
  }
} 
 else if (tempF < 50.02 && tempF >= 40.5) //if 50 > tempF >= 40 aqua and strip is lit to 13th pixel
 {
   strip.clear();
   for(int i = 0; i <= 12; i++)
  {
   strip.setPixelColor(i, strip.Color(0,255,255));
  }
 }
 else if (tempF < 40.02 && tempF >= 32.5) //if 40 > tempF >= 32 fuschia and strip is lit to 9th pixel
 {
   strip.clear();
   for(int i = 0; i <= 8; i++)
  {
   strip.setPixelColor(i, strip.Color(153, 51,255)); 
  }
 }
 else if (tempF < 32.5) //temp < freezing white and strip is lit to 5th pixel
 {
   strip.clear();
   for(i = 0;i <= 4; i++)
 { 
   strip.setPixelColor(i, strip.Color(255,255,255)); 
 }//end for
 }
 
strip.show(); //update color change

}//end pixelCase

Step 4: Plug it in and Light it Up


With the circuit and the code in place you should have a working thermometer. It's especially handy to have around the house in the winter and summer when you're trying to save energy, and it's a fun project and great introduction to NeoPixels. The versatility with the pixels alone should provide plenty of ideas and since it uses the same libraries this will work with almost any other NeoPixel type such as ring, matrix, strips, etc. The best part is it takes very little power and can easily be plugged in with a USB phone charger (with proper USB cord) or even batteries (a 9V battery will do nicely and two coin cells at 6V is even better).

If you're ever in the Philadelphia area don't forget to look us up and visit the shop. We provide tours Monday through Friday from 2 to 6 without appointment and with appointment at any other time of the week. Hope you enjoyed the Instructable and happy making, cheers!



Code

file_9790.txtC/C++
neoTemp.ino
#include <LiquidCrystal.h>
#include <Adafruit_NeoPixel.h>

// Create a variable that will store the temperature value
int TMPin = 0;
const int button = 12;
int lastColor = -1;


#define aref_voltage 3.3
#define PIN 6


/*
Param 1 == number of pixels
Param 2 == Arduino pin attached to din
Param 3 == pixel type flags, add together as needed
  NE0_KHZ800 800 KHZ bitstream (avg neopix)
  NE0_GRB wired for GRB bitstream
*/
Adafruit_NeoPixel strip = Adafruit_NeoPixel(32, PIN, NEO_GRB + NEO_KHZ800); //call Neopixels, 32 pixels in all, on pin 6, RGB system and 800 KHZ
LiquidCrystal lcd(13, 11, 5, 4, 3, 2); //call LCD display

void setup() 
{
  lcd.begin(16,2); //initialize LCD screen 16 by 2  
  strip.begin(); //begin neo pixel strip
  strip.show(); //initialize strip
  Serial.begin(9600);// serial monitor access
  pinMode(button, INPUT); //button for celsius
  analogReference(EXTERNAL); //analog reference for use with TMP36
}

void loop() 
{
  double temperature;
  double temp;
  double tempF;


  temp = tempMeasure(temperature); //call tempMeasure function
  tempF = (temp * 9.0/5.0 + 32);  //take reading from tempMeasure and convert to faharenheit
  
  
  while(digitalRead(button) == false) //button is depressed readout is in Celsius
  {
    Serial.println(temp); //prints in serial monitor
    lcd.print(temp); //prints on LCD screen
    lcd.setCursor(0,1); //sets cursor
    delay(2000); //2 seconds between readings
    lcd.clear(); //clear LCD after 2 seconds   
}
 
 pixelCaseF(tempF); //call pixelCase function that controls lights
 Serial.println(tempF); //print in serial
 lcd.print(tempF); //print temp in F on LCD
 lcd.setCursor(0,1); //set cursor
 delay(2000); //take reading every 2 seconds
 lcd.clear(); //clear LCD
 
}//end loop


double tempMeasure(double temperature)
{
 // -----------------
// Read temperature
// -----------------

  int reading = analogRead(TMPin); //voltage reading
  double voltage = reading * aref_voltage; //take initial reading and multiply by 3.3 ref voltage for arduino
  
  voltage /= 1024.0; //divide reading by 1024 to map
   
  temperature = (voltage - 0.5) * 100; //converts 10mv per degree with 500 mV offset to (voltage - 500mV) * 100)
   
  return temperature; //return temperature to top level method

}//end tempMeasure

void pixelCaseF(double tempF)
/*
This method controls the neo-pixel for the "analog" readout on the thermometer. With every temperature group, the number of pixels lit changes along with the color
*/

{
 int i;
 strip.setBrightness(64);
 strip.show();
  
  if (tempF >= 90.05)//if above 90 degrees, strip is red and entire strip is lit
 {
   strip.clear();
   for(int i=0;i <= 32;i++)
   {
   strip.setPixelColor(i, strip.Color(255,0,0));
   }
 }
 else if (tempF < 90.2 && tempF >= 80.05) //if 90 > tempF >= 80 orange and strip is partially lit up to 29th pixel
 { 
   strip.clear();
   for(int i=0;i <= 28;i++)
  {
  strip.setPixelColor(i, strip.Color(255,128,0)); 
  }
 }
 else if (tempF < 80.02 && tempF >= 70.5)// if 80 > tempF >= 70 yellow-green and strip is lit up to 25th pixel
 {
   strip.clear();
   for(int i = 0; i <= 24; i++)
   {
    strip.setPixelColor(i,strip.Color(204,255,0)); 
   }
 }  
 else if (tempF < 70 && tempF >= 60.5)// if 70 > tempF >= 60 green and strip is lit up to 21st pixel
{
  strip.clear();
  for(int i = 0; i<= 20; i++)
  {
   strip.setPixelColor(i,strip.Color(0,255,0));
  }
}
 else if (tempF < 60.02 && tempF >= 50.5) //if 60 > tempF >= 50 blue and strip is lit up to 17th pixel
{
  strip.clear();
  for(int i = 0; i <= 16; i++)
  {
    strip.setPixelColor(i,strip.Color(0,0,255));
  }
} 
 else if (tempF < 50.02 && tempF >= 40.5) //if 50 > tempF >= 40 aqua and strip is lit to 13th pixel
 {
   strip.clear();
   for(int i = 0; i <= 12; i++)
  {
   strip.setPixelColor(i, strip.Color(0,255,255));
  }
 }
 else if (tempF < 40.02 && tempF >= 32.5) //if 40 > tempF >= 32 fuschia and strip is lit to 9th pixel
 {
   strip.clear();
   for(int i = 0; i <= 8; i++)
  {
   strip.setPixelColor(i, strip.Color(153, 51,255)); 
  }
 }
 else if (tempF < 32.5) //temp < freezing white and strip is lit to 5th pixel
 {
   strip.clear();
   for(i = 0;i <= 4; i++)
 { 
   strip.setPixelColor(i, strip.Color(255,255,255)); 
 }//end for
 }
 
strip.show(); //update color change

}//end pixelCase
Github
https://github.com/adafruit/Adafruit_NeoPixel

Comments

Similar projects you might like

Lightpipe 7-Segment Display

Project tutorial by Brian Lough

  • 2,712 views
  • 3 comments
  • 8 respects

ElBanquos 1D Pong

Project showcase by ElBanquo

  • 157 views
  • 2 comments
  • 2 respects

Arduino - Control Arm Robot via Web

Project tutorial by phpoc_man

  • 60 views
  • 0 comments
  • 7 respects

Arduino Spider Robot (Quadruped)

Project tutorial by MEGA DAS

  • 2,102 views
  • 1 comment
  • 14 respects

PENXZYL: Arduino 3-Axis Brush Plotter

Project showcase by Guiye Perez Bongiovanni

  • 4,483 views
  • 4 comments
  • 20 respects

Google Chrome Dinosaur Game on 16x2 LCD Shield

Project showcase by brzi

  • 388 views
  • 1 comment
  • 7 respects
Add projectSign up / Login