Arduino with Bluetooth and a TFT Screen
ABSTRACT
In this project, my intentions are to get data from the sensors, show
them in a TFT screen and send them via Bluetooth to other device like as an
Android phone. Like others exercises that I’ve done before, I’ve also used
temperature and humidity sensors. The TFT screen is a 2.8" TFT Touch Shield
bought in “Adafruit.com”, it costs 59$.
The Bluetooth was bought in “dealextreme.com”, this device is very
economic and can be acquired for around 6$, depends on the web offers, in
addition, the shipping is free.
The goals of this exercise are to learn how to use the TFT screen and
the Bluetooth with Arduino. The Bluetooth works with AT commands sent by the
serial ports. With Arduino Mega is very straightforward because has four serial
ports and as a consequence, you don’t need to use other libraries like
“SoftwareSerial.h” to simulate another serial port. Moreover, this Bluetooth
basically uses just four AT command for setup the configuration that are: AT,
AT+NAME, AT+BAUD and AT+PIN [2].
In the case of the TFT SCREEN, everything you need for this shield is
described in [1].
Figure 1: Arduino Mega with the TFT screen, the Bluetooth and the sockets for the sensors. |
MATERIALS
1 x Arduino Mega board [3]
1 x USB cable
1 x Humidity sensor
1 x Temperature sensor
1 x 2.8" TFT Touch Shield for Arduino
1 x Arduino Bluetooth Wireless Serial Port Module (from DealExtreme.com)
2 x 3 pins socket
1 x proto-board shield
Wires, pins, solder lead, etc…
Figure 2: Components |
DEVELOPMENT
For making this I used a small proto shield in which I’ve soldered pins
for the connection with the Arduino Mega, two sockets of three pins for the
sensors, pins for the Bluetooth and finally, two wires that are connected to
GND and VCC of the ICSP pins for distributing the signals for the rest
components on the board. You can see how in the Figure 2. Each socket has a pin
for VCC, GND and the analog input.
The temperature sensor uses the analog pin 14 and the humidity sensor
uses the analog pin 15.
The Bluetooth need four pins: TXD, RXD, VCC and
GND. TXD is attached to the RX2 (digital pin 16) and RXD is connected to the
TX2 (digital pin 17).
After the assembling, I wrapped all in a box and plugged
to the electricity. For seeing the data transmitted by the Bluetooth it is necessary
a device for visualizing it. I used an application for Android called Blueterm [4].
The Arduino codes are in the appendix 1, 2 and 3.
Figure 3: The circuit inside the box. |
Figure 4: Blueterm App receives the data transmitted by the bluetooth. |
In the Figure 4, you can also see the temperature sensor ( looks like a transistor) and the humidity sensor ( plated color) .
RESULTS
The results can be watched in the next video:
The temperature measures are not very accurate because the voltage levels measured are not constant.
PROPOSALS OF
IMPROVEMENT
Develop my own Android app for communicate with the
Bluetooth.
Improve the graphics of the TFT screen.
REFERENCE
[2] http://www.extremadura-web.es/Blog/2012/10/29/comunicacion-bluetooth-serie-arduino-y- basic4android/
APPENDIX 1
Arduino main code:
#include
<Arduino.h>
#include
<Adafruit_GFX.h> // Core
graphics library
#include
<Adafruit_TFTLCD.h> // Hardware-specific library
#include
<SD.h>
#include
"Bluetooth.h"
#include
"Sensors.h"
#define
SD_CS 5 // The chip select pin for the SD card on
the shield
//
Assign human-readable names to some common 16-bit color values:
#define BLACK
0x0000
#define BLUE
0x001F
#define RED
0xF800
#define GREEN
0x07E0
#define
CYAN 0x07FF
#define
MAGENTA 0xF81F
#define
YELLOW 0xFFE0
#define
WHITE 0xFFFF
Adafruit_TFTLCD
tft;
uint8_t spi_save;
int
humidity=0,temperature=0;
void
setup()
{
Serial.begin(9600);
tft.reset();
uint16_t identifier = tft.readID();
if(identifier == 0x9325) progmemPrintln(PSTR("Found ILI9325
LCD driver"));
else if(identifier == 0x9328)
progmemPrintln(PSTR("Found ILI9328 LCD driver"));
else if(identifier == 0x7575)
progmemPrintln(PSTR("Found HX8347G LCD driver"));
else
{
progmemPrint(PSTR("Unknown LCD driver
chip: "));
Serial.println(identifier, HEX);
progmemPrintln(PSTR("If using the
Adafruit 2.8\" TFT Arduino shield, the line:"));
progmemPrintln(PSTR(" #define USE_ADAFRUIT_SHIELD_PINOUT"));
progmemPrintln(PSTR("should appear in
the library header (Adafruit_TFT.h)."));
progmemPrintln(PSTR("If using the
breakout board, it should NOT be #defined!"));
progmemPrintln(PSTR("Also if using the
breakout, double-check that all wiring"));
progmemPrintln(PSTR("matches the
tutorial."));
return;
}
tft.begin(identifier);
progmemPrint(PSTR("Initializing SD
card..."));
if (!SD.begin(SD_CS))
{
progmemPrintln(PSTR("failed!"));
return;
}
progmemPrintln(PSTR("OK!"));
spi_save = SPCR;
tft.setRotation(3);
bmpDraw("Arduino.bmp", 0, 0);
setupBlueToothConnection();
progmemPrint(PSTR("Screen fill:"));
Serial.println(FillScreen(RED));
delay(500);
}
void
loop()
{
//if (Serial.available() > 0 )
Serial2.write((char)Serial.read());
//if (Serial2.available() > 0 )
Serial.write((char)Serial3.read());
temperature=Temperatura();
humidity=Humedad();
Serial2.println();
Serial.println();
Text();
delay(2000);
}
//
This function opens a Windows Bitmap (BMP) file and
//
displays it at the given coordinates.
It's sped up
//
by reading many pixels worth of data at a time
//
(rather than pixel by pixel). Increasing
the buffer
//
size takes more of the Arduino's precious RAM but
//
makes loading a little faster. 20 pixels
seems a
//
good balance.
#define
BUFFPIXEL 20
void
bmpDraw(char *filename, int x, int y)
{
File
bmpFile;
int
bmpWidth, bmpHeight; // W+H in
pixels
uint8_t
bmpDepth; // Bit
depth (currently must be 24)
uint32_t bmpImageoffset; // Start of image data in file
uint32_t rowSize; // Not always = bmpWidth; may
have padding
uint8_t
sdbuffer[3*BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
uint16_t lcdbuffer[BUFFPIXEL]; // pixel out buffer (16-bit per pixel)
uint8_t
buffidx = sizeof(sdbuffer); // Current position in sdbuffer
boolean
goodBmp = false; // Set to
true on valid header parse
boolean
flip = true; // BMP is stored bottom-to-top
int
w, h, row, col;
uint8_t
r, g, b;
uint32_t pos = 0, startTime = millis();
uint8_t
lcdidx = 0;
boolean
first = true;
if((x >= tft.width()) || (y >=
tft.height())) return;
Serial.println();
Serial.print("Loading image '");
Serial.print(filename);
Serial.println('\'');
// Open requested file on SD card
SPCR = spi_save;
if ((bmpFile = SD.open(filename)) == NULL) {
Serial.print("File not found");
return;
}
//The bitmap Header use to be 54 Bytes
// Read BMP header(14 Bytes)
if(read16(bmpFile) == 0x4D42) { //
"BM" Magic number (unsigned 66,77),2 Bytes
progmemPrint(PSTR("File size:
")); Serial.println(read32(bmpFile));//Size of the BMP file 4 Bytes
(void)read32(bmpFile); // Read & ignore
creator 4 Bytes
bmpImageoffset = read32(bmpFile); // Offset
where the pixel array (bitmap data) can be found.
progmemPrint(PSTR("Image Offset:
"));
Serial.println(bmpImageoffset, DEC);
//Normally 36h, the byte number
54. 4 Bytes
// Read DIB header (40 Bytes).(Device
Independent Bitmap)
progmemPrint(PSTR("Header size:
")); Serial.println(read32(bmpFile));
//Number of bytes in the DIB
header(from this point).4 Bytes
bmpWidth
= read32(bmpFile);//Width of the bitmap in pixels.4 Bytes
bmpHeight = read32(bmpFile);//Height of the
bitmap in pixels.4 Bytes
if(read16(bmpFile) == 1) { // # planes --
must be '1'. 2 Bytes
bmpDepth = read16(bmpFile); //Number of
bits per pixel. It must be: 0x18 0x00 = 24 bits. 2 Bytes
progmemPrint(PSTR("Bit Depth:
")); Serial.println(bmpDepth);
if((bmpDepth == 24) &&
(read32(bmpFile) == 0)) { // 0 = uncompressed. 4 Bytes
goodBmp = true; // Supported BMP format
-- proceed!
progmemPrint(PSTR("Image size:
"));
Serial.print(bmpWidth);
Serial.print('x');
Serial.println(bmpHeight);
// BMP rows are padded (if needed) to
4-byte boundary. 4 Bytes
rowSize = (bmpWidth * 3 + 3) & ~3;
// If bmpHeight is negative, image is
in top-down order.
// This is not canon but has been
observed in the wild.
if(bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}
// Crop area to be loaded
w = bmpWidth;
h = bmpHeight;
if((x+w-1) >= tft.width()) w = tft.width() - x;
if((y+h-1) >= tft.height()) h =
tft.height() - y;
// Set TFT address window to clipped
image bounds
SPCR = 0;
tft.setAddrWindow(x, y, x+w-1, y+h-1);
for (row=0; row<h; row++) { // For
each scanline...
// Seek to start of scan line. It might seem labor-
// intensive to be doing this on
every line, but this
// method covers a lot of gritty
details like cropping
// and scanline padding. Also, the seek only takes
// place if the file position
actually needs to change
// (avoids a lot of cluster math in
SD library).
if(flip) // Bitmap is stored bottom-to-top
order (normal BMP)
pos = bmpImageoffset + (bmpHeight -
1 - row) * rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + row *
rowSize;
SPCR = spi_save;
if(bmpFile.position() != pos) { //
Need seek?
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); //
Force buffer reload
}
for (col=0; col<w; col++) { // For
each column...
// Time to read more pixel data?
if (buffidx >= sizeof(sdbuffer))
{ // Indeed
// Push LCD buffer to the display
first
if(lcdidx > 0) {
SPCR = 0;
tft.pushColors(lcdbuffer,
lcdidx, first);
lcdidx = 0;
first = false;
}
SPCR = spi_save;
bmpFile.read(sdbuffer,
sizeof(sdbuffer));
buffidx = 0; // Set index to
beginning
}
// Convert pixel from BMP to TFT
format
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
lcdbuffer[lcdidx++] =
tft.color565(r,g,b);
} // end pixel
} // end scanline
// Write any remaining data to LCD
if(lcdidx > 0) {
SPCR = 0;
tft.pushColors(lcdbuffer, lcdidx,
first);
}
progmemPrint(PSTR("Loaded in
"));
Serial.print(millis() - startTime);
Serial.println(" ms");
} // end goodBmp
}
}
bmpFile.close();
if(!goodBmp) Serial.println("BMP format
not recognized.");
Serial.println();
}
//
These read 16- and 32-bit types from the SD card file.
//
BMP data is stored little-endian, Arduino is little-endian too.
//
May need to reverse subscript order if porting elsewhere.
uint16_t
read16(File f)
{
uint16_t result;
((uint8_t *)&result)[0] = f.read(); //
LSB
((uint8_t *)&result)[1] = f.read(); //
MSB
return result;
}
uint32_t
read32(File f)
{
uint32_t result;
((uint8_t *)&result)[0] = f.read(); //
LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); //
MSB
return result;
}
//
Copy string from flash to serial port
//
Source string MUST be inside a PSTR() declaration!
void
progmemPrint(const char *str)
{
char c;
while(c = pgm_read_byte(str++))
Serial.print(c);
}
//
Same as above, with trailing newline
void
progmemPrintln(const char *str)
{
progmemPrint(str);
Serial.println();
}
unsigned
long FillScreen(int color)
{
unsigned long start = micros();
tft.fillScreen(color);
return micros() - start;
}
unsigned
long Text()
{
tft.fillScreen(BLUE);
unsigned long start = micros();
tft.setCursor(0, 0);
tft.setTextColor(YELLOW); tft.setTextSize(3);
tft.println("\n\n");
tft.print("TEMPERATURA:
");tft.print(temperature,DEC);tft.println("\11C");
tft.println();
tft.print("HUMEDAD:
");tft.print(humidity,DEC);tft.println("%");
return micros() - start;
}
APPENDIX 2
Sensors.h code:
static int
temperaturePin = 14;//Analog input 0
static int
humidityPin=15;//Analog input 1static int moisturePin=2;//Analog input 2
int
Temperatura(void)
{
//the analog pin the TMP36's Vout (sense) pin
is connected to the resolution is 10 mV / degree centigrade.
//(500 mV offset) to make negative
temperatures an option
float temperature=analogRead(temperaturePin) *
.004882814;//converting from a 0 to 1023 digital range
// to 0 to 5 volts (each 1 reading equals ~ 5
millivolts.Example: 5:1024=0.004882814
temperature = (temperature - .5) * 100;//0
degree begins in 500mV
Serial.print("Temperatura: ");
Serial.print(temperature,0);
Serial.println("\260C");
delay(100);
Serial2.print("Temperatura: ");
Serial2.print(temperature,0);
Serial2.println(" C");
return(int(temperature));
}
int Humedad (void)
{
//5V=1024;5000mV/1024=4.882814mv por unidad
float humidity=analogRead(humidityPin)*
4.882814;
humidity=(humidity-800)/31;//Conversion of
milivolts to humidity
Serial.print("Air humidity: ");
Serial.print(humidity,0);
Serial.println("%");
delay(100);
Serial2.print("Humedad del aire: ");
Serial2.print(humidity,0);
Serial2.println("%");
delay(100);
return(int(humidity));
}
APPENDIX 3
Bluetooth.h code:
void
setupBlueToothConnection()
{
Serial2.begin(9600);
Serial.print("Initializing
bluetooth->");
delay(5000);
Serial2.print("AT");
delay(1000);//Wait 1 second according to the
datasheet of AT commands
while(Serial2.available() > 0 )
Serial.write((char)Serial2.read());
Serial.println();//Write the response of the
bluetooth for debugging
Serial2.print("AT+NAMETFTBlue");
Serial.print("Name: TFTBlue->");
delay(1000);//Wait 1 second according to the
datasheet of AT commands
while (Serial2.available() > 0 )
Serial.write((char)Serial2.read());
Serial.println();//Write the response of the
bluetooth for debugging
/*Cambio de la
velocidad del modulo en baudios
Se
envia AT+BAUD y seguido el numero correspondiente:
1 -- 1200 bauds
2 -- 2400 bauds
3 -- 4800 bauds
4 -- 9600 bauds (by defect)
5 -- 19200 bauds
6 -- 38400 bauds
7 -- 57600 bauds
8 -- 115200 bauds
*/
Serial2.print("AT+BAUD4");Serial.print("9600
bauds->");
delay(1000);//Wait 1 second according to the
datasheet of AT commands
while (Serial2.available() > 0 )
Serial.write((char)Serial2.read());
Serial.println();//Write the response of the
bluetooth for debugging
//Configuracion
Password, se envia AT+PIN y seguido password que queremos
Serial2.print("AT+PIN1234");
Serial.print("Pin: 1234->");
delay(1000);//Wait 1 second according to the
datasheet of AT commands
while (Serial2.available() > 0 )
Serial.write((char)Serial2.read());
Serial.println();//Write the response of the
bluetooth for debugging
Serial.println("Bluetooth Setup
complete");
Serial.println();//Write the response of the
bluetooth for debugging
}