Today I bring you something you have never seen before: a ruler with an embedded electronic functioning thermometer in it. It is a common 20 cm (twenty centimeters) ruler made out of PCB (printed circuit board), but it has a fully functioning degress Celsius thermometer in it.
How? so, I am using an Attiny85 microcontroller running Arduino code, a CR2032 button battery, one SMD (0805) 10k NTC thermistor and two LEDs; also four more SMD (0805) resistors, besides the 6-pin programming connector.
The idea of making a ruler came from the JuliaLabs store, but hers is not a thermometer, just a normal ruler. I then wanted to add some electronics to it, thought of implementing a LED blink circuit with 7414 (or even a PIC16F675 or Attiny85). Then ended up deciding to do a thermometer, a useful and interesting way of using some available space on the ruler.
The “display”
A thermometer needs some way for us to check the temperature, right? Could be a TFT, an OLED, a LED display or even LCD. But I decided to make things simpler (at least in terms of coding) and implement a two LED display, as seen here. This is the way it works:
- Each LED will blink the number of times the number is has to represent, for example:
- If we want to represent 23 degress Celsius, LED1 will blink twice and LED2 three times
- If we want to represent 08 degress Celsius, LED1 will not blink and LED2 will blink eight times
Did you get the idea? I don’t know whether this scheme has a name or not, but I have implemented it and it works.
Hardware
As stated above, the heart and brain of this thermometer ruler is an Attiny85 being supplied by a single CR2032 battery. There is a 10k NTC thermistor being read for temperature and two LEDs used as display. See the schematic below, in Kicad. It is also in my Github.
You can see also R3 and R4 in series, these were intended to read the battery voltage. But as we have no referece (no fixed supply voltage) there is no way to read it. This is also a problem for the NTC reading, since the battery voltage decreases with time. I then had to input a fixed value of supply voltage in my code, meaning that this value will be correct only once and never again (ultil you replace the battery).
This means that this thermometer ruler will never be super precise, but just enought to be usable.
Code/software
As stated above I have programmed this thermometer ruler in Arduino, using the Arduino IDE. Code has two big IF’s, one that is entered every 100ms (one hundred milisseconds) to convert temperature values into which LED will light. The other IF is entered every 400ms to toggle (blink) each LED in the correct way.
Code below attributes integers for the tens and the units (meaning, for each LED). For example if the temperature is between 10 and 20 degrees Celsius the tens will be 1. To obtain the unit (the least significant part) one just subtracts the respective tens, the rest of the subtraction is the unit.
if(temperature < 10){
tens= 0;
unit= temperature;
}else if(temperature >= 10 && temperature < 20){
tens= 1;
unit= temperature - 10;
}else if(temperature >= 20 && temperature < 30){
tens= 2;
unit= temperature - 20;
}else if(temperature >= 30 && temperature < 40){
tens= 3;
unit= temperature - 30;
}else if(temperature >= 40 && temperature < 50){
tens= 4;
unit= temperature - 40;
}else{
tens= 0;
unit= 0;
}
Complete code is seen below, also available in my Github:
// Conexão do termistor
const int pinTermistor = A1;
const int referencia = A2;
// Parâmetros do termistor
const double beta = 4000.0;
const double r0 = 10000.0;
const double t0 = 273.0 + 25.0;
const double rx = r0 * exp(-beta/t0);
// Parâmetros do circuito
double vcc = 3.2;
const double R = 10000.0;
// Numero de amostras na leitura
const int nAmostras = 5;
int bitsresultados[6];
int passagem= 0;
// Variables used on this code
unsigned long time1;
unsigned long previousTime;
boolean enterFunction = true;
unsigned long time2;
unsigned long previousTime2;
boolean enterFunction2 = true;
//-----------------------
bool blinkingtens= false;
bool enteredtens= false;
int doubletens= 0;
bool blinkingunits = false;
bool enteredunit = false;
int doubleunit = 0;
int unit = 0;
int tens = 0;
bool waittime = true;
bool startedwait = false;
long elapsedtime;
int temperature;
int digitoaentrar = 1;
void setup() {
//Serial.begin(9600);
pinMode(0, OUTPUT);
pinMode(1, OUTPUT);
}
void loop() {
time1 = micros();
time2 = micros();
if (enterFunction == true) {
previousTime = time1;
passagem++;
// Start your code below
//-----------------------
if(blinkingtens == true && blinkingunits == false){
if(enteredtens == false){
enteredtens = true;
doubletens = 2 * tens;
if(doubletens == 0){
doubletens= 1;
}
}
doubletens --;
if(doubletens != 0){
digitalWrite(0, !digitalRead(0));
}else{
blinkingunits = true;
blinkingtens = false;
}
}else if(blinkingunits == true && blinkingtens == false){
blinkingtens= false;
if(enteredunit == false){
enteredunit = true;
doubleunit = 2 * unit;
if(doubleunit == 0){
doubleunit= 1;
}
}
doubleunit --;
if(doubleunit != 0){
digitalWrite(1, !digitalRead(1));
}else{
waittime = true;
blinkingunits = false;
startedwait = true;
}
}else if(waittime == true){
if(startedwait == true){
digitalWrite(1, LOW);
digitalWrite(0, LOW);
startedwait = false;
elapsedtime = millis();
}
if(millis() - elapsedtime > 998){
waittime = false;
}
}else{
blinkingtens= true;
enteredtens = false;
enteredunit = false;
}
//-----------------------
// End of your code
}
if (enterFunction2 == true && waittime == true) { //Enter this function every xx milisseconds and IF LEDs are not blinking
previousTime2 = time2;
// Le o sensor algumas vezes
int soma = 0;
for (int i = 0; i < nAmostras; i++) {
soma += analogRead(pinTermistor);
delay (100);
}
vcc= 2 * analogRead(referencia) * 5 / 1023;
// Determina a resistência do termistor
double v = (vcc*soma)/(nAmostras*1024.0);
double rt = (vcc*R)/v - R;
// Calcula a temperature
double t = beta / log(rt/rx);
t= t - 273;
temperature = int(t);
//Serial.println (t-273.0);
if(temperature < 10){
tens= 0;
unit= temperature;
}else if(temperature >= 10 && temperature < 20){
tens= 1;
unit= temperature - 10;
}else if(temperature >= 20 && temperature < 30){
tens= 2;
unit= temperature - 20;
}else if(temperature >= 30 && temperature < 40){
tens= 3;
unit= temperature - 30;
}else if(temperature >= 40 && temperature < 50){
tens= 4;
unit= temperature - 40;
}else{
tens= 0;
unit= 0;
}
}
// The DELAY time is adjusted in the constant below >>
if (time1 - previousTime < 399990) { // 1 million microsencods= 1 second delay
/* I have actually used 0.999990 seconds, in a trial to compensate the time that
this IF function takes to be executed. this is really a point that
need improvement in my code */
enterFunction = false;
}
else {
enterFunction = true;
}
if (time2 - previousTime2 < 99990) { // 1 million microsencods= 1 second delay
/* I have actually used 0.999990 seconds, in a trial to compensate the time that
this IF function takes to be executed. this is really a point that
need improvement in my code */
enterFunction2 = false;
}
else {
enterFunction2 = true;
}
}
To blink the LEDs in the correct way I use the below code for the tens. It toggles the LED while doubletens is not 0, when it reaches zero I do blinkingunits= true and go to blink the units.
if(doubletens != 0){
digitalWrite(0, !digitalRead(0));
}else{
blinkingunits = true;
blinkingtens = false;
}
End result
I made a quick video explaining how this thermometer ruler works, see below: