Arduino Thermometer with... TV Output

Analog video is getting replaced by digital signals which provide better resolution and picture without noise or interference. Although receivers for digital signals are cheap and popular, devices for generating such signals are expensive and intended for professional use only. On the other hand, analog video is easy to generate with simple hardware. You can even broadcast it over RF (on wire, not on air) with common modulators (standalone devices or modules from video game consoles, set top boxes, VCRs etc.).

An easy way to generate video signal is by using a microcontroller and some resistors. I'll use for this purpose an Arduino board (ATmega 328p) with the TVout library. The video signal is of low resolution and black&white. But it can be used to display data on a TV screen. If you no longer own a TV with analog video input, an USB capture card can be used. TVout library is interrupt based, therefore will interfere with some of other interrupt dependent microcontroller features.

 Thermometer with TV Output
For example, using TVout, the temperature readout from a sensor can be displayed. But not all kind of sensors. Because TVout is interrupt based, you can't use OneWire or I2C sensors. OneWire communication interferes with video sync, therefore every time the sensor is read, picture get distorted for a short time. I2C however ic completely incompatible with TVout (you get no picture at all once you use Wire library).

All that's left is to use an analog sensor (thermistor). These are good too, but require calibration. Here is the schematic of the device.

 Thermometer with TVout schematic
The schematic is very simple. I built it on a breadboard. If you don't have the KY-013 module, you can build the voltage divider with a thermistor and 100 ohms resistor.

I used an audio jack on the breadboard (one channel is for video, the other for audio). A jack to RCA cable is plugged into this.

The thermometer displays the actual temperature, the minimum and the maximum and a small graph of temperature variation over 116 seconds. When a new minimum or maximum value is recorded, a short beep of 1kHz is generated.

TVout library is required. To install it, use the Library Manager of Arduino IDE. However, compilation will fail unless you find the library folder (where your projects are, there is a libraries folder; find TVout, enter it) where you must delete TVout subfolder and rename TVOutfonts to utility. The issue has been reported on GitHub.

Here is the code:
#include <TVout.h>
#include <utility/fontALL.h>

TVout TV;
float minTemp = 100, maxTemp = 0;
byte graph[117] = { 0 };

// Read thermistor and convert to Celsius degrees
// https://tkkrlab.nl/wiki/Arduino_KY-013_Temperature_sensor_module
double Temp;
Temp = log(10000.0 * ((1024.0 / RawADC - 1)));
Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp )) * Temp );
Temp = Temp - 273.15;            // Convert Kelvin to Celcius
//Temp = (Temp * 9.0)/ 5.0 + 32.0; // Convert Celcius to Fahrenheit
return Temp;
}

void draw_initial_screen() {
TV.clear_screen();

TV.set_cursor(19, 3);
TV.select_font(font8x8);
TV.print("Thermometer");

TV.draw_rect(0, 0, 125, 14, 1, 2);

TV.select_font(font6x8);
TV.set_cursor(0, 20);
TV.print("MIN");

TV.set_cursor(43, 20);
TV.print("Current");

TV.set_cursor(109, 20);
TV.print("MAX");

TV.select_font(font4x6);
TV.set_cursor(4, 86);
TV.print("0");
TV.set_cursor(0, 76);
TV.print("10");
TV.set_cursor(0, 66);
TV.print("20");
TV.set_cursor(0, 56);
TV.print("30");
TV.set_cursor(0, 46);
TV.print("40");

TV.draw_line(10, 46, 10, 88, 1);
TV.draw_line(10, 88, 126, 88, 1);
TV.set_pixel(9, 48, 1);
TV.set_pixel(11, 48, 1);
TV.set_pixel(9, 58, 1);
TV.set_pixel(11, 58, 1);
TV.set_pixel(9, 68, 1);
TV.set_pixel(11, 68, 1);
TV.set_pixel(9, 78, 1);
TV.set_pixel(11, 78, 1);

TV.set_cursor(67, 90);
TV.select_font(font4x6);
TV.print("2 min evolution");
}

void display_min(float mt) {
TV.set_cursor(0, 33);
TV.select_font(font6x8);
if (mt < 10) TV.print(" ");
TV.print(mt, 1);
}

void display_max(float mt) {
TV.set_cursor(103, 33);
TV.select_font(font6x8);
if (mt < 10) TV.print(" ");
TV.print(mt, 1);
}

void display_current(float t) {
TV.set_cursor(42, 32);
TV.select_font(font8x8);
TV.print(t, 2);
TV.draw_rect(40, 30, 44, 12, 1, -1);
}

void setup()  {
TV.begin(PAL, 128, 96);
draw_initial_screen();
delay(1000);
}

void display_graph(float ct) {
for (int i = 0; i < 116; i++) {
graph[i] = graph[i + 1];
TV.set_pixel(i + 10, 88 - graph[i], 1);
if (graph[i + 1] > 0)
TV.set_pixel(i + 11, 88 - graph[i + 1], 0);
}
graph[116] = (byte)ct;
if (graph[116] > 40) graph[116] = 40;
}

void loop() {

display_current(currTemp);
display_graph(currTemp);

if (currTemp < minTemp) {
minTemp = currTemp;
display_min(minTemp);
TV.tone(1000, 200);
}

if (currTemp > maxTemp) {
maxTemp = currTemp;
display_max(maxTemp);
TV.tone(1000, 200);
}

delay(1000);
}

Analog video signal generation with an Arduino takes up a lot of the microcontroller resources. However digitalRead and digitalWrite, as well as analogRead and probably analogWrite do work. This lets you interface the microcontroller with various analog sensors and to trigger relays or other devices.

Going further from here, you can connect AV outputs to a RF modulator. Remember you can't use an I2C controlled modulator because the Arduino used for video generation can't communicate via I2C too. You can use a fixed output channel modulator from a game console. And do not output RF signal into an antenna. Although analog TV broadcasts have been shut off, it may be illegal to broadcast on that frequency bands. Use a cable to send the signal over a long distance.

1 comment :

1. Helpful info. Lucky me I discovered your website unintentionally, and I'm
surprised why this twist of fate didn't happened earlier!
I bookmarked it.