Arduino USB Host
Shield & Sensors
ABSTRACT
ABSTRACT
In this activity I’ve
used the Arduino USB Host Shield to send sensor data from Arduino to an Android
Device. The communication is full duplex, Arduino send data to Android and
Android send data to Arduino.
The USB Host Shield
is a board that uses the USB host controlled chip MAX3421E. I’ve used the
SparkFun board [1]. This version takes its power from the 'Vin' pin on your
Arduino. Power from that pin is regulated to both 5V and 3.3V on the shield.
For this reason, it is necessary an extra charger.
There are several
libraries for USB Host Shield, I know two: “Adb.h” and “AndroidAccessory.h”. In
[2], there are explained a lot of examples with the Abd library but the
drawback of use it is that you need Android programming knowledge for
developing your application. In this case I’ve used the AndroidAccessory
library because I wanted to program the Android App with Processing. In [3],
you can download a tool for Processing to compile code for the latest Android
OS and upload it to phones and tablets.
Figure 1: Usb host
connected to the phone
|
MATERIALS
1 x Arduino board
1 x USB cable
1 x Humidity sensor 808H5V5
1 x Temperature sensor MCP9700A
1 x Pot 10KΩ
1 x Pot 4K7Ω
1 x Res. 1KΩ
1 x Res. 330Ω
2 x Res. 10KΩ
1 x Res. 330Ω
2 x Res. 10KΩ
1 x Photoresistor
1 x Temperature and humidity sensor: DHT03
1 x Green led
1 x Small buttons
1 x proto-board
1 x Charger
1 x Android Phone
Wires, pins, solder lead, etc…
Figure 2: Arduino host
shield and the others components
|
DEVELOPMENT
In the next figure you can see the schematic of how I’ve connected to
Arduino the sensors and the other things.
Figure 3: Schematic |
The Arduino code is in the Appendix 1. From [1] you
can download all the libraries that you need for the USB Host Shield. If you
are using the SparkFun board you must assure that in the file
Max3421e_constans.h has the correct definition of some pins. In my case, I had
to modify this pins:
#define MAX_INT
9
#define MAX_GPX
8
#define MAX_RESET 7
The library for the digital humidity and temperature
sensor DHT03 is in [4]. The Processing code is in the Appendix 3.
RESULTS
The best way to see the results is to watch it in a video. In this video you are going to see how Arduino send data to the phone.
Sometimes, when you push the button “OUT”, Arduino detects two pulsations because the Processing code don’t have any kind of anti debounce method.
PROPOSALS OF IMPROVEMENT
Send the data obtained by the USB Host Shield via 3G
or via Wi-Fi to another device.
[1] https://www.sparkfun.com/products/9628
[2] http://labs.arduino.cc/ADK/Index
[3] http://mitchtech.net/
[4] http://playground.arduino.cc/Main/DHTLib
APPENDIX 1
Arduino main code:
#include
<Arduino.h>
#include
<Max3421e.h>
#include
<Usb.h>
#include
<AndroidAccessory.h>
#include
<dht.h>
#include
<Bounce.h>
#include
"floatToString.h"
dht
DHT;
float
data[6];
int
boton=3,led=5,dhtpin=6,temp=0,luz=0,humedad=0,temperatura=0,moisture=0,pot1=0,pot2=0;
char cadena[80];
char tempC[10];
char luzC[10];
byte
pulsacion[2];
byte
msg[2];
AndroidAccessory
acc("pruebaUSB3",
"pruebaUSB3",
"pruebaUSB3",
"1.0",
"http://www.android.com",
"0000000012345678");
//
Instantiate a Bounce object with a 5 millisecond debounce time
Bounce
bouncer = Bounce( boton,5 );
void
setup()
{
Serial.begin(9600);
pinMode(led, OUTPUT);
pinMode(boton, INPUT);
digitalWrite(led, LOW);
digitalWrite(boton, HIGH); // enable the
internal pullups
attachInterrupt(1, sendBoton, FALLING);
delay(100);
acc.powerOn();
delay(5000);
}
void loop()
{
//Lectura de entradas analógicas y digitales
pot1=analogRead(A0);
delay(10);
pot2=analogRead(A1);
delay(20);
data[2] = analogRead(A4) * .004882814;
data[2] = (data[2] - 0.5) * 100;//0 degree
begins in 500mV
//temp=(int)data[2];
floatToString(tempC,data[2],0);
delay(20);
data[3] = analogRead(A5);
//luz = (int)data[3];
floatToString(luzC,data[3],0);
delay(10);
data[6]=analogRead(A3)* 4.882814;
data[6]=(data[6]-800)/31;
moisture = (int) data[6];
delay(10);
int chk = DHT.read22(dhtpin);
data[4] = DHT.humidity;
humedad=(int)data[4];
delay(10);
data[5] = DHT.temperature;
temperatura=(int)data[5];
delay(10);
bouncer.update();
//Enviar datos al dispositivo android
if (acc.isConnected())
{
acc.read(msg, sizeof(msg), 1);
Serial.println((char)msg[0]);
if((char)msg[0]=='a')
{
//Encender y apagar el led
if(digitalRead(led)) digitalWrite(led, LOW);
else digitalWrite(led,
HIGH);
msg[0]='b';
}
delay(10);
sprintf(cadena,"%d,%d,%sC,%s,%uH,%dH
%dC,",pot1,pot2,tempC,luzC,moisture,humedad,temperatura);
Serial.println(cadena);
acc.write(cadena,sizeof(cadena));
delay(1000);
}
else
{
Serial.println("No conectado");
delay(2000);
}
}
void
sendBoton(void)
{
pulsacion[0]=1;
if (acc.isConnected())
acc.write(pulsacion,1);
else
Serial.println("Incapaz de conectar");
delay(10);
pulsacion[0]=0;
}
/*
AndroidAccessory(const char *manufacturer,
const char *model,
const char *description,
const char *version,
const char *uri,
const char *serial);
void powerOn(void);
bool isConnected(void);
int
read(void *buff, int len, unsigned int nakLimit = USB_NAK_LIMIT);
//NAK
means no communication error
int write(void *buff, int len);
*/
digitalWrite(ledPin, HIGH); // Toggle status LED
delay(1000);
digitalWrite(ledPin, LOW); // Toggle status
LED
}
}
APPENDIX 2
FloatToString.h code:
//
floatToString.h
//
//
Tim Hirzel
//
tim@growdown.com
//
March 2008
//
float to string
//
//
If you don't save this as a .h, you will want to remove the default arguments
// uncomment this first line, and swap it for
the next. I don't think keyword
arguments compile
// in .pde files
// in .pde files
//char
* floatToString(char * outstr, float value, int places, int minwidth=, bool
rightjustify) {
char
* floatToString(char * outstr, float value, int places, int minwidth=0, bool
rightjustify=false) {
// this is used to write a float value to
string, outstr. oustr is also the return
value.
int digit;
float tens = 0.1;
int tenscount = 0;
int i;
float tempfloat = value;
int c = 0;
int charcount = 1;
int extra = 0;
// make sure we round properly. this could
use pow from <math.h>, but doesn't seem worth the import
// if this rounding step isn't here, the
value 54.321 prints as 54.3209
// calculate rounding term d: 0.5/pow(10,places)
float d = 0.5;
if (value < 0)
d *= -1.0;
// divide by ten for each decimal place
for (i = 0; i < places; i++)
d/= 10.0;
// this small addition, combined with
truncation will round our values properly
tempfloat += d;
// first get value tens to be the large
power of ten less than value
if (value < 0)
tempfloat *= -1.0;
while ((tens * 10.0) <= tempfloat) {
tens *= 10.0;
tenscount += 1;
}
if (tenscount > 0)
charcount += tenscount;
else
charcount += 1;
if (value < 0)
charcount += 1;
charcount += 1 + places;
minwidth += 1; // both count the null final
character
if (minwidth > charcount){
extra = minwidth - charcount;
charcount = minwidth;
}
if (extra > 0 and rightjustify) {
for (int i = 0; i< extra; i++) {
outstr[c++] = ' ';
}
}
// write out the negative if needed
if (value < 0)
outstr[c++] = '-';
if (tenscount == 0)
outstr[c++] = '0';
for (i=0; i< tenscount; i++) {
digit = (int) (tempfloat/tens);
itoa(digit, &outstr[c++], 10);
tempfloat = tempfloat - ((float)digit *
tens);
tens /= 10.0;
}
// if no places after decimal, stop now and
return
// otherwise, write the point and continue
on
if (places > 0)
outstr[c++] = '.';
// now write out each decimal place by
shifting digits one by one into the ones place and writing
//the truncated value
//the truncated value
for (i = 0; i < places; i++) {
tempfloat *= 10.0;
digit = (int) tempfloat;
itoa(digit, &outstr[c++], 10);
// once written, subtract off that
digit
tempfloat = tempfloat - (float) digit;
}
if (extra > 0 and not rightjustify) {
for (int i = 0; i< extra; i++) {
outstr[c++] = ' ';
}
}
outstr[c++] = '\0';
return outstr;
}
APPENDIX 3
Processing code:
import
cc.arduino.*;
ArduinoAdkUsb
arduino;
String
inString;
byte
pulsador=0;
String
A="0",B="0",C="0",D="0",E="0",F="0";
int
index=0;
boolean
i=false;
char a='a',b='b';
boolean botonPulsado = false;
color
botonAmarillo= color(255,255,0);
color
botonGris=color(150);
int puntoX=380,puntoY=630,diametro=100;
void
setup()
{
arduino = new ArduinoAdkUsb( this );
if ( arduino.list() != null ) arduino.connect( arduino.list()[0] );
orientation( PORTRAIT );
textSize(40);
stroke(4);
strokeWeight(8);
}
void draw()
{
fill(0);
//RECIBIR EL MENSAJE DE ARDUINO
if ( arduino.isConnected())
{
int bytesDisponibles =
arduino.available();
if(bytesDisponibles> 3 )
{
inString="";
for(int
n=0;n<bytesDisponibles;n++)
inString=inString+arduino.readChar();
index = inString.indexOf(',');
A=inString.substring(0,index);
index =
inString.indexOf(',',index+1);
B=inString.substring(A.length()+1,index);
index =
inString.indexOf(',',index+1);
C=inString.substring(A.length()+B.length()+2,index);
index =
inString.indexOf(',',index+1);
D=inString.substring(A.length()+B.length()+C.length()+3,index);
index =
inString.indexOf(',',index+1);
E=inString.substring(A.length()+B.length()+C.length()+D.length()+4,index);
index =
inString.indexOf(',',index+1);
F=inString.substring(A.length()+B.length()+C.length()+D.length()+E.length()+5,index);
}
else if (0<bytesDisponibles & bytesDisponibles< 3)
{
pulsador = arduino.readByte();
//Encender y apagar el circulo
if(pulsador>0)
{
if(i)
i=false;
else
i=true;
}
}
background(255);//Color de fondo blanco
text("Si
conectado",20,750);
}
else
{
background(255);//Color de fondo blanco
text("No conectado",20,750);
A="0";B="0";C="0";D="0";E="0";F="0";
i=false;
}
text("POT10K: "+A,20,50);
text("POT4K7: "+B,20,150);
text("TEMPERATURA: "+C,20,250);
text("DHT03: "+F,20,350);
text("LUZ: "+D,20,450);
text("HUMEDAD: "+E,20,550);
if(i)
fill(0,250,0);
else
fill(150);
ellipse(80,630,100,100);
fill(botonGris);
update(mouseX, mouseY);
if(botonPulsado)
{
if(mousePressed)
{
fill(botonAmarillo);
arduino.write(a);
}
else
{
fill(botonGris);
arduino.write(b);
}
}
ellipse(puntoX,puntoY,diametro,diametro);
fill(0);
text("IN",60,645);
text("OUT",340,645);
pulsador=0;
}
void update(int x, int y)
{
if
( overCircle(puntoX, puntoY, diametro) )
botonPulsado = true;
else
botonPulsado = false;
}
boolean
overCircle(int x, int y, int diameter)
{
float disX = x - mouseX;
float disY = y - mouseY;
if (sqrt(sq(disX) + sq(disY)) < diameter/2
) return true;
else
return false;
}
//
clean up nicely after the app closes:
void
onStop()
{
finish();
super.onDestroy();
}