USB Host Shield & Sensors




Arduino USB Host Shield & Sensors

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 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.
  
Figure 4: Android application

         
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.

REFERENCE

[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

//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
    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();
}