Wednesday, 20 November 2013

SPI Communication - What, Where & How? - Working with the W5100 Ethernet Shield

SPI Communication

SPI stands for Serial Peripheral Interface. Its a type of Serial communication that uses Synchronization. Here's a nice tutorial on this from Sparkfun(its better to share good content than rewrite!) ->  https://learn.sparkfun.com/tutorials/serial-peripheral-interface-spi/all

Read the above tutorial before proceeding.

The W5100 Ethernet Shield

The W5100 Ethernet Shield is based on the W5100 chip from Wiznet. There are 2 versions of this available from the Simple Labs website
  1. The Official Arduino Ethernet Shield R3 - This is the Rev3 Version of the Ethernet Shield
  2. The Low Cost W5100 Ethernet Shield - This is a cheap chinese version of the Ethernet Shield. This shield is not a Rev3 shield however will work with all boards including the Rev3 ones.
The shields come with a slot for microSD, which shares the SPI bus along with the Ethernet Controller. The Chip Select Pin for the microSD is Pin 4 and the Chip Select Pin for the  Ethernet Controller is Pin 10. Both of these can be used at the same time. Lets see how to work with both of these one at a time

Working with the MicroSD
Working with the MicroSD is easier as Arduino comes with a SD Library for working with these. The SD Library provides with a number of functions required for us to work with an SD card. You can read more about the library here -> http://arduino.cc/en/Reference/SD (Read Before you Proceed!)

Load and try the following examples from the Arduino IDE -> Examples -> SD
Cardinfo.ino
Datalogger.ino
ReadWrite.ino

Now lets modify the Datalogger example to include a date / time stamp from our RTC, This way the datalogger becomes more meaningful.

Here's the Program
/*  Induino R3 User Guide - Program 18.0 - A SD Datalogger with Time Stamp 
  SD card datalogger
 
 This example shows how to log data from three analog sensors 
 to an SD card using the SD library.
  
 The circuit:
 * analog sensors on analog ins 0, 1, and 2
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4
 
 created  24 Nov 2010
 modified 9 Apr 2012
 by Tom Igoe
 
 This example code is in the public domain.
   
 */

#include <SD.h>
#include <Wire.h> // I2C Library

// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.
const int chipSelect = 4;

#define myrtc 0x68 // I2C Address of DS1307

char *dow[]={
  " ","MON","TUE","WED","THU","FRI","SAT","SUN"}; // An Array to store the DAY text to match with the DAY parameter of the RTC

char *mode[]={
  "HR","AM","PM"}; // An Array to store the time mode 

char *month[]={
  "","JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"};

int dd,mm,yy,day,hh,mins,ss,mde; // Variables to store the retrieved time value


void setup()
{
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
  
  Wire.begin(); // Initialise Wire Communication - Join the I2C Bus
  delay(100);
  set_time(15,11,13,5,11,10,55,2);
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
  
}

void loop()
{
  // make a string for assembling the data to log:
  String dataString = "";
  String dateString ="";
  get_time();// get Date / time value into a String Variable
  dateString +=dow[day];
  dateString +="  ";
  dateString +=String(dd);
  dateString +="-";
  dateString +=month[mm];
  dateString +="-";
  dateString +=String(yy);
  dateString +=" : ";
  dateString +=String(hh);
  dateString +=":";
  dateString +=String(mm);
  dateString +=":";
  dateString +=String(ss);
  dateString +=" ";
  dateString +=mode[mde];
  dateString +=" ";
  
  dataString += dateString; // Append the Date String to the Data String
  // read three sensors and append to the string:
  for (int analogPin = 0; analogPin < 3; analogPin++) {
    int sensor = analogRead(analogPin);
    dataString += String(sensor);
    if (analogPin < 2) {
      dataString += ","; 
    }
  }

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    Serial.println(dataString);
  }  
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  } 
}

// The set_time function takes parameters in the order of date, month, year, day of week, hours, minutes, seconds & mode
// the mode can have 3 possible values  (0=>24HR, 1=> AM, 2 => PM)

void set_time(int sdd, int smm, int syy, int sday, int shr, int smin, int ssec, int smode)
{
  Wire.beginTransmission(myrtc); // Initialise transmission to the myrtc I2C address
  Wire.write(0x00); // Write the value of the register to start with, 0 in this case represented in BCD format
  Wire.write(dec_to_bcd(ssec));  // convert the seconds value from decimal to bcd and write it to the seconds register
  // after the write operation the register pointer will be at the next register, so we do not have to set the value of the register again
  Wire.write(dec_to_bcd(smin));  // convert the minutes value from decimal to bcd and write it to the minutes register
  if(smode == 0) // Check if the mode is 24hrs mode
  {
    Wire.write(dec_to_bcd(shr));  // if 24 hours mode is on then convert the hours value from decimal to bcd and write it to the hours register
  }
  else // if the mode is 12 hr mode
  {
    // If 12 hour mode is selected then the 12 Hour mode bit (the 6th bit) has to be set to 1
    // convert the hour value to bcd first and then adding 64(2^6) to the converted hrs value will set the 6th bit HIGH

    shr = dec_to_bcd(shr)+64; 

    if(smode == 1) // check if it is AM
      Wire.write(shr); // if it is AM we can directly write the value of the above modified hours values to the hours register
    if(smode == 2) // check if it is PM
      Wire.write(shr+32); // If it is PM, then adding 32 (2^5) sets the 5th bit (the PM indication bit) HIGH, the calculated value is written to the hours register
  }
  Wire.write(dec_to_bcd(sday));  // convert the day value from decimal to bcd and write it to the day register
  Wire.write(dec_to_bcd(sdd));  // convert the date value from decimal to bcd and write it to the date register
  Wire.write(dec_to_bcd(smm));  // convert the month value from decimal to bcd and write it to the month register
  Wire.write(dec_to_bcd(syy));// convert the year value from decimal to bcd and write it to the year register
  Wire.endTransmission();  // end the transmission with the I2C device

}

// the get_time() function will retrieve the current time from the RTC and store it in the Global Variables declared

void get_time()
{
  Wire.beginTransmission(myrtc); // Initialise transmission to the myrtc I2C address
  Wire.write(0x00); // Write the value of the register to start with, 0 in this case represented in BCD format
  Wire.endTransmission(); // end the transmission with the I2C device
  Wire.requestFrom(myrtc, 7);  // Now ask the I2C device for 7 Bytes of Data // This corresponds to the values of the 7 registers starting with the 0th register 

  ss = bcd_to_dec(Wire.read()); // The first read will retrieve the value from the register address 0x00 or the seconds register, this is in the BCD format, convert this back to decimal
  mins = bcd_to_dec(Wire.read());// The second read will retrieve the value from the register address 0x01 or the minutes register, this is in the BCD format, convert this back to decimal
  hh = Wire.read();// The third read will retrieve the value from the hours register, this value needs to be processed for the 24/12 hr mode

  // Check of if the BCD hours value retrieved is greater than 35 (this indicates that the hours is in 12 hour mode
  // 35 is the maximum BCD value possible in the 24hr mode
  if(hh > 35) 
  {
    hh = hh - 64; // in the 12 Hours Mode the 12 hour mode bit (6th bit) is set to high, so we need to subtract 2^6 from our hours value
    if(hh > 32)// Now check if the hour value is greater than 32 (2^5 = 32) (this indicates that PM bit (5th bit) is high)
    {
      mde = 2; // Set the mde variable to indicate PM
      hh = hh-32; // subtract 32 from the hours value 
    }
    else // if the hour value is less than 32 it means that its in the AM mode
    {
      mde = 1; // Set the mde variable to indicate AM
    }   
  }
  else // if the 12 hour mode bit was not set, then the hour is in the 24 hour mode
  {
    mde = 0; // Set the mde variable to indicate 24 Hours
  }

  hh = bcd_to_dec(hh); // Convert the final hour value from BCD to decimal and store it back into the same variable
  day = bcd_to_dec(Wire.read());// The fourth read will retrieve the value from the register address 0x03 or the day register, this is in the BCD format, convert this back to decimal
  dd = bcd_to_dec(Wire.read());// The fifthread will retrieve the value from the register address 0x04 or the date register, this is in the BCD format, convert this back to decimal
  mm = bcd_to_dec(Wire.read());// The sixth read will retrieve the value from the register address 0x05 or the month register, this is in the BCD format, convert this back to decimal
  yy = bcd_to_dec(Wire.read());// The seventh read will retrieve the value from the register address 0x06 or the year register, this is in the BCD format, convert this back to decimal

}

// The dec_to_bcd() function converts a given decimal number to BCD format

int dec_to_bcd(int dec)
{
  return dec/10*16 + (dec%10); // convert and return the number from decimal to bcd format
}

// The dec_to_bcd() function converts a given BCD number to decimal format

int bcd_to_dec(int bcd)
{
  return bcd/16*10 + (bcd%16); // convert and return the number from bcd to decimal format
}      


Next we will see how to work with the Ethernet Part of the shield.

Ethernet
The Ethernet Shield uses Wiznet W5100 Module for providing ethernet. The Ethernet Capability works out of the box with the Arduino Ethernet Library. To work with the ethernet shield you need to have a clear understanding of networks & HTML. The scope of this tutorial will be limited to getting the ethernet up and running and not venturing into these.  Get yourselves familiar with HTML & the Ethernet Library before proceeding

So lets try an example, Make the following connections

  1. Place the shield on top of your Induino R3 / Arduino Board
  2. Connect a Ethernet Cable Between the Shield and your modem / router - you cannot connect it your computer directly, it will not work!
  3. Upload the example from under Examples -> Ethernet-> WebServer
  4. Open your Browser (Chrome might have issues, try Firefox) and type in 192.168.1.177 in the address bar
  5. You should now see the Values from Analog Pins being displayed in the browser. 

What the example does is, it waits for a client(a browser) to connect to our ethernet shield and then it reads the GET request from the Client. At the end of the Get Request, it responsds with a HTML page which includes the Analog Pin Values

Next, Try the following modified version of the above example. We will build on top of this.

Here's the Program
/* Induino R3 User Guide - Program 18.1 - A Simple Webserver that responds with Analog Values
Modified original Webserver Example
  Web Server
 
 A simple web server that shows the value of the analog input pins.
 using an Arduino Wiznet Ethernet shield. 
 
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 * Analog inputs attached to pins A0 through A5 (optional)
 
 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe
 
 */

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1,177);

// Initialize the Ethernet server library
// with the IP address and port you want to use 
// (port 80 is default for HTTP):
EthernetServer server(80);

String req;                       // a variable to store the GET request

void setup() {
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}


void loop() {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {                          // Check if there is a client available
    Serial.println("new client");

    while (client.connected()) {        // check if the client is connected
      if (client.available()) {         // Check if there is a request from the client
        
        Serial.print("$$$$");
        req="";                         // reset the request variable
        while(client.available())      // Read data from the client 1 byte at a time as long as there is data
        {
        char c=client.read();          // Read 1 byte of data from the client
        req += c;                      // append the read data to the existing value 
        delay(1);
        }
        Serial.println(req);            
        Serial.println("XXX");
      }
          Serial.println("Sending Data to Client");
          client.println("HTTP/1.1 200 OK");   // start responding with the DATA to the client & Send out the response header
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the responsedelay(1);
  // client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          // output the value of each analog input pin
                    
          for (int analogChannel = 0; analogChannel < 6; analogChannel++) 
          {
            int sensorReading = analogRead(analogChannel);
            client.print("<a href=\"/");
            client.print(analogChannel);
            client.print(".html\">");
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(sensorReading);
            client.print("</a>");
            client.println("<br />");       
          }          
          client.println("</html>");
          break;
     }
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disonnected");
  
  }
}

Now open the Serial Monitor and Open your Browser. Try the address 192.168.1.177 from your browser and see the results in the Serial monitor (like in the image below).

The contents of the GET request are printed between the $$$ and the XXX markings. The content of the GET request will vary depending upon the address you type in the browser, for example if you try
192.168.1.177/echo_me you would get a response similar to this in the serial monitor


We need to process the content in the first line between the GET and the HTTP/1.1 to identify the address requested, we can then respond accordingly.  in addition, we would need to use additional string processing functions to extract string information.

Let's try a Simple Example to control a LED. We will try to On / OFF the RED of the RGB LED (we cannot use the LEDS on Pin 11, 12 & 13 as these pins are used for SPI communication with the Ethernet Shield). For this, we will generate a simple html page with a link to ON / OFF (the link keeps toggling based on the current status of the LED)

Here's the HTML code for generating a link
<a href="/?ON">Click Here to Switch ON</a>
<a href="/?OFF">Click Here to Switch OFF</a>

So when the user clicks the link, we will get /?ON or /?OFF as part of the GET request. We need to process the get request, identify this and control accordingly.
Here's the Program
/*Induino R3 User Guide - Program 18.2 - A Simple Webserver that Controls using Links
Modified original Webserver Example
 
 A simple web server that shows the value of the analog input pins.
 using an Arduino Wiznet Ethernet shield. 
 
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 * Analog inputs attached to pins A0 through A5 (optional)
 
 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe
 
 */

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1,177);

// Initialize the Ethernet server library
// with the IP address and port you want to use 
// (port 80 is default for HTTP):
EthernetServer server(80); 
String req; // a variable to store the GET request

boolean state = 0; // a variable to store the state of the LED 
String state_val[]={"OFF","ON"}; // A Variable to store the State of the LED as String


void setup() {
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
  pinMode(6,OUTPUT); // RGB LED RED is on Pin 6
}


void loop() {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) { // Check if there is a client available
    Serial.println("new client");
    while (client.connected()) {                    // check if the client is connected
      if (client.available()) {                    // Check if there is a request from the client
        
        Serial.print("$$$$");
        req="";                                    // reset the request variable
        while(client.available())                 // Read data from the client 1 byte at a time as long as there is data
        {  
        char c=client.read();                    // Read 1 byte of data from the client
        if(c==13) // Check if the data read is a Carriage Return a.ka. Enter, This means end of first line - the line starting with GET and ending with HTTP/1.1
          break; // Since we have read the first line, we need not read the remaining data for storage, so exit the while loop
        req += c; // append the read data to the existing value
        delayMicroseconds(1000);
        }
        // if the while loop above exited from the break statement, then there is data in the client buffer, which needs to be read to be removed
        // we need to read this data to empty the buffer
        while(client.available())                 // While loop to read the data to empty buffer
        {
          client.read();
          delayMicroseconds(1000);
        }
        Serial.println(req);                     // print the value of the request to the Serial Monitor for debugging
        Serial.println("XXX");
      }
          if(find_string(req,"GET /?ON"))       // Check if the received Request containts the String ON
          {
            state = 1;                          // Set the State Variable
            digitalWrite(6,state);              // Set the state to the RED LED
          }
          if(find_string(req,"GET /?OFF"))      // Check if the received Request containts the String ON
          {
            state = 0;                          // Set the State Variable
            digitalWrite(6,state);            
          }
        
          Serial.println("here 1");             // for debugging
          client.println("HTTP/1.1 200 OK");    // start responding with the DATA to the client & Send out the response header
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the responsedelay(1);
 
          client.println();
          client.println("<!DOCTYPE HTML>");    // Start of the HTML Page
          client.println("<html>");          
         
          client.println("<br />"); 
          if(state)                             // Check the State and print the LINK on the Page accordingly
          {
            client.println("<a href= \"/?"+state_val[0]+" \">");
          }
          else
          {
            client.println("<a href= \"/?"+state_val[1]+" \">");
          }
          client.println("Click Here to Switch "+state_val[!state]+" -RED of RGB LED");
          client.println("</a>");
          
          client.println("</html>");
          break;
     }
    client.stop();
    Serial.println("client disonnected");
  
  }
}



// A Function to locate a given search string in a given base string
boolean find_string(String base, String search)
{
  int len = search.length(); // find the length of the base string
  for(int m = 0; m<((base.length()-len)+1);m++)// Iterate from the beginning of the base string till the end minus length of the substring
  { 
     
    if(base.substring(m,(m+len))==search) // Check if the extracted Substring Matches the Search String
    {
      return true;        // if it matches exit the function with a true value
    }
    
  }
  return false; // if the above loop did not find any matches, control would come here and return a false value
}

Now open your browser, try the address 192.168.1.177, you should see the text with the link and clicking the text should toggle the state of the LED

Now lets see how to handle numeric values received through a get request, For the HTML Page We'll design 3 sliders that will let the user set values from 0-255. The slider will be set inside a form and when the user clicks the button to submit the form, it will be sent to a preset page along with the slider data as part of the get request, By processing the GET request for this page, we can read the data of the sliders that was submitted and use the values to control the RGB LED.

Here's the Program
/*Induino R3 User Guide - Program 18.2 - A Simple Webserver that Let you set the Intensity of the RGB LED on the Induino R3 Board using a Slider
Modified original Webserver Example

  Web Server
 
 A simple web server that shows the value of the analog input pins.
 using an Arduino Wiznet Ethernet shield. 
 
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 * Analog inputs attached to pins A0 through A5 (optional)
 
 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe
 
 */

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1,177);

// Initialize the Ethernet server library
// with the IP address and port you want to use 
// (port 80 is default for HTTP):
EthernetServer server(80);
String req;                // a variable to store the GET request

int RGB[]={0,0,0};        // a variable to store the Intensity Value, RGB[0] => RED, RGB[1] => Green, RGB[2]=>Blue

String tmp_rgb ="";       // a temporary variable

void setup() {
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}


void loop() {
  // listen for incoming clients
   EthernetClient client = server.available();
  if (client) { // Check if there is a client available
    Serial.println("new client");
    while (client.connected()) {                    // check if the client is connected
      if (client.available()) {                    // Check if there is a request from the client
        
        Serial.print("$$$$");
        req="";                                    // reset the request variable
        while(client.available())                 // Read data from the client 1 byte at a time as long as there is data
        {  
        char c=client.read();                    // Read 1 byte of data from the client
        if(c==13) // Check if the data read is a Carriage Return a.ka. Enter, This means end of first line - the line starting with GET and ending with HTTP/1.1
          break; // Since we have read the first line, we need not read the remaining data for storage, so exit the while loop
        req += c; // append the read data to the existing value
        delayMicroseconds(1000);
        }
        // if the while loop above exited from the break statement, then there is data in the client buffer, which needs to be read to be removed
        // we need to read this data to empty the buffer
        while(client.available())                 // While loop to read the data to empty buffer
        {
          client.read();
          delayMicroseconds(1000);
        }
        Serial.println(req);                     // print the value of the request to the Serial Monitor for debugging
        Serial.println("XXX");
      }
      // Check if the GET request contains the text setrgb? 
      // If it contains the text, then we need to extract the values for RED, GREEN & Blue
        if(find_string(req,"GET /setrgb?"))     
          {
            
            int start_loc= find_string_loc(req,"RED=")+4; // Find the starting location of the Value for RED
            int end_loc = find_string_loc(req, "&GREEN"); // Find the ending location of the Value for RED
            RGB[0] = string_to_int(req.substring(start_loc,end_loc)); // Extract the Value and Store it

            start_loc= find_string_loc(req,"GREEN=")+6;   // Find the starting location of the Value for GREEN
            end_loc = find_string_loc(req, "&BLUE");     // Find the ending location of the Value for GREEN
            RGB[1] = string_to_int(req.substring(start_loc,end_loc)); // Extract the Value and Store it
            
            start_loc= find_string_loc(req,"BLUE=")+5;   // Find the starting location of the Value for BLUE
            end_loc = find_string_loc(req, "HTTP/1.1")-1;// Find the ending location of the Value for BLUE
            RGB[2] = string_to_int(req.substring(start_loc,end_loc));// Extract the Value and Store it
            
            analogWrite(3,RGB[1]);analogWrite(5,RGB[2]);analogWrite(6,RGB[0]); // Set the RGB Intensities from the Variable
            
          }
          
          Serial.println("here 1");             // for debugging
          client.println("HTTP/1.1 200 OK");    // start responding with the DATA to the client & Send out the response header
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the responsedelay(1);
 
          client.println();
          client.println("<!DOCTYPE HTML>");    // Start of the HTML Page
          client.println("<html>");          
         
          client.println("<br />"); 
          // Code for Printing Slider
          client.println("<form action=\"/setrgb\" method=\"get\">");
          tmp_rgb = (String) RGB[0];
          // The Sliders are set to have the current RGB[] values as the default values
          client.println("RED  Value: <input type=\"range\" name=\"RED\" min=\"0\" max=\"255\" value=\""+tmp_rgb+"\">");
          tmp_rgb = (String) RGB[1];
          client.println("<br/>GREEN Value: <input type=\"range\" name=\"GREEN\" min=\"0\" max=\"255\" value=\""+tmp_rgb+"\">");
          tmp_rgb = (String) RGB[2];
          client.println("<br/>BLUE   Value: <input type=\"range\" name=\"BLUE\" min=\"0\" max=\"255\" value=\""+tmp_rgb+"\">");
          client.println("<br/><br/><input type=\"submit\" value=\"SET\" />");
          client.println("</form>");
          client.println("</html>");
          break;
     }
    //delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disonnected");
  
  }
}

// A Function to locate a given search string in a given base string
boolean find_string(String base, String search)
{
  int len = search.length(); // find the length of the base string
  for(int m = 0; m<((base.length()-len)+1);m++)// Iterate from the beginning of the base string till the end minus length of the substring
  { 
     
    if(base.substring(m,(m+len))==search) // Check if the extracted Substring Matches the Search String
    {
      return true;        // if it matches exit the function with a true value
    }
    
  }
  return false; // if the above loop did not find any matches, control would come here and return a false value
}


// This function is similar to the String Search function except it returns the starting location of the Search String in the Base String
int find_string_loc(String base, String search)
{
  int len = search.length(); // find the length of the base string
  int m, val=0; // val is used to store the return value and m is a counter
  for(m = 0; m<((base.length()-len)+1);m++)// Iterate from the beginning of the base string till the end minus length of the substring
  {     
    if(base.substring(m,(m+len))==search) // Check if the extracted Substring Matches the Search String
    {
      val= m;        // if it matches set the return value to the current value of m
    }
    if(val!=0) // if the return value is non-zero, exit the for loop
     break;
  }
  return val; // return the retun value
}

//A Function to convert a given String with numerical content to its integer equivalent
int string_to_int(String base)
{
  int len = base.length(); // get the length of the string
  int ret_val=0;
  for(int m=0;m<len;m++) // iterate through each character in the string
  {
    ret_val = (ret_val*10)+ (base[m]-48); // subtract 48 from the ascii value to get the numeric value and add it to the existing value
    // if the string was 225, then when m=0, ret_val would be 2, when m=1, ret_val would be 20+2, when m=2, ret_val would be 220+5,
  }
  return ret_val;
}
  

Now open your browser, try the address 192.168.1.177, you should see 3 Sliders that let you control the RGB Led on the Induino R3.

Thats It For This Part! Enjoy... and feel free to drop us an email with questions you might have -> info@simplelabs.co.in

 Visit www.simplelabs.co.in for more interesting products

Tuesday, 12 November 2013

Interfacing Serial Devices - Part 3 - Working with a Serial GSM Modem

GSM Modems

GSM modems are GSM devices that help you add GSM functionality to your projects. You can almost build a complete phone using a GSM modem however that would be a waste of time and energy as a phone would work out to be much more cost-efficient. While DTMF can help us control remotely, DTMF is limited when it comes to Monitoring. This is where GSM modems can help us. GSM modems could play a key role in projects requiring Remote monitoring and Control - Say an alarm system at a power plant that sends you an sms when something goes wrong and lets us access it and control it by calling from a specific number or by sending a specific SMS. In this tutorial, we will see how to interface with the popular Sim900A GSM modem

GSM Modems can be controlled Serially by sending out pre-defined commands to them. These commands are called AT commands.  Click To Download the Sim900A AT Command List. Working with GSM Modems would be a complete subject by itself and We shall limit the scope of this tutorial to focus on Calling & Messaging alone

Lets Look at some Basic Commands required to perform basic telephony operations

Calling
  • To Make a Call - ATD+91XXXXXXXXXX; Refer to Page 17 / Sec 2.2.3
  • To Hang up the Call Being Dialed - ATH Refer to Page 24 / Sec 2.2.6


Messaging
  • Set Message Type as Text - AT+CMGF=1 Refer to Page 100 / Sec 4.2.2
  • Set Message Destination Number & Type Message - AT+CMGS="+91XXXXXXXXXX" Refer to Page 107 / Sec 4.2.5  - On entering this command, the GSM modem would respond with its own terminal prompt where we need to type in the message to be sent. Once we are finished typing the message, we need to press Ctrl+Z to exit this terminal prompt. Once we exit, the modem will send the message to the user.

In addition to the above commands, the GSM modem will give us a set of Serial Messages when it receives a Call or SMS. Here are some of the messages (they will not be identical all the times!)

Incoming Calls
incoming calls return a message similar to this
RING

+CLIP: "+91XXXXXXXXXX",phonebook entry position,"",,"phonebook entry",0

Incoming SMS
incoming sms return a message similar
+CMTI: "SM",23


Read SMS
To Read the Incoming SMS, we can use the command AT+CMGR=X where X is the number returned at the last of the +CMTI output above. In our above example it is 23

This command would retrieve the SMS in the following format
+CMGR: "REC UNREAD","+91XXXXXXXXXX","phonebook entry","Date,Time"
Message Text

The above set of information is sufficient for us to work with the GSM modem. Now if you noticed, there is a lot of Text Data to be processed. Let's first get to processing Text Data (STRING) before proceeding with programming the GSM Modem.


Processing Text Data - Strings

Processing of Strings has become easier with recent versions of Arudino IDE. The datatype is now part of the core. You can read more about String Here - > http://arduino.cc/en/Reference/StringObject

Declaring a String Variable
You can declare a String Variable like any other Variable. Here are some example declarations

String  input;
String input = "";
String input = "Hello";

String Operations
Interestingly you can perform 3 Operations on the String Variable type

  1. [] (element access) => Access the element of a String
    • E.g.: input[0], this will be 'H' based on the above example
  2. + (concatenation) => Append characters to an Existing String
    • E.g.: input += 'W';  this will add 'W' towards the end of the String and now input will be "HelloW"
  3. == (comparison) => Compare a String Variable with a String
    • E.g.: if(input=="Hello") this will return true or false depending upon the value of input

String Functions
There are a number of String Functions that let you process Strings in different ways. Refer to the above String Object Reference Page for a complete list. We shall look at some of the functions we would need for our program

  1. length() => Returns the length of the given String. 
    • E.g.: int i = input.length(); this will get the length of the String input and store it in the variable i. in our case ("Hello") length will be returned as 5
  2. substring() => Extracts a substring from the given string
    • E.g.:  input.substring(1,3)  will return "el" the starting index '1' is included and the ending index '3' is excluded when extracting the substring
    • E.g.: input.sunstring(2) will return "llo". in this case only the starting index is provided. 
  3. toUpperCase() => Converts the given String to Upper Case
    • E.g.: input.toUpperCase(); will change the value of input from "Hello" to "HELLO". This makes it easier to build programs that are not case sensitive
  4. toLowerCase() => Converts the given String to Lower Case
    • E.g.: input.toLowerCase(); will change the value of input from "Hello" to "hello". This makes it easier to build programs that are not case sensitive
  5. trim() => Trims any leading / trailing white spaces in the string
    • E.g.:  Say we have a variable String input1 = "  Hello  "; with 2 leading and 2 trailing white spaces, input1.trim() will have the value "Hello" with the leading / trailing white spaces trimmed off
Now try the following program to understand the usage of all the above functions. The program receives a String Serially, Trims it, Extracts a substring and prints both the lower and upper case versions of it along with the length before and after trimming.

Here's the Program
/*  Induino R3 User Guide - Program 17.0 - Working with Strings - Basic String Operations
The program receives a String Serially, Trims it, Extracts a substring and prints both the lower and upper case versions of it
It also prints the length of the string before and after trimming
use the following string input as text (key it in from the Serial monitor)
"   This is a Test String   " // there are 3 leading and 3 trailing spaces
 */


String input=""; // Declare an Empty String Variable
String input_trimmed="";// a variable to store the trimmed string
String substring=""; // a variable to store the substring 
int length_before_trim = 0, length_after_trim = 0, length_substring=0; // 3 variables for storing the string lengths

void setup()
{
  Serial.begin(9600); // Initialise Serial Communication
}

void loop()
{
  if(Serial.available()) // Check if there is incoming data in the Serial Buffer
  {
    input = ""; // reset the input variable
    while(Serial.available()) // Process incoming data till the buffer becomes empty
    {     
      input += (char)Serial.read();// Read a byte of data, convert it to character and append it to the string variable
      delay(1);
    }
    Serial.println();
    input_trimmed = input; // assign the trimmed variable with the input value
    input_trimmed.trim();
    substring = input_trimmed.substring(10,14);
    length_before_trim = input.length();
    length_after_trim = input_trimmed.length();
    length_substring = substring.length();
    Serial.println("Your Original Input : " +input);
    Serial.print("Length of Your Original Input : ");
    Serial.println(length_before_trim);
    Serial.println("The Trimmed Input : " +input_trimmed);
    Serial.print("Length of Trimmed Input : ");
    Serial.println(length_after_trim);
    Serial.println("Substring : " +substring);
    Serial.print("Length of Substring : ");
    Serial.println(length_substring);
  }
}
      

Now open the Serial Monitor and paste the following text "   This is a Test String   " and press enter. you should see the output. Depending upon your settings for the serial monitor, the length of the input text will vary (carriage return, newline character, etc are treated as characters and counted)

Interfacing the GSM Modem

Now that we have seen how to work with Strings, lets proceed to see how we can interface the GSM modem.

Hardware Connections
  1. Insert your Sim Card into the GSM modem
  2. Connect the Tx pin of the GSM modem to Digital pin 3 of the Induino R3 / Arduino
  3. Connect the Rx pin of the GSM modem to Digital pin 4 of the Induino R3 / Arduino
  4. Connect the Gnd pin of the GSM modem to the Gnd pin of the Induino R3 / Arduino
  5. Power the GSM modem using an external 12V DC Adaptor (The +5V from the Induino R3 / Arduino is not sufficient!)
  6. Ensure the Network LED blinks with a 2 second delay and not 1 second delay. 2 second delay = connected to network, 1 second delay = unable to connect to network
  7. Additionally, call the number of the simcard in the GSM modem and check if it rings - Ensure you are NOT getting a out of coverage area / switched off message.
Programming it!
Here's a simple program to make a call/ hangup / send an sms based on button presses. you can modify this to suit your application. This program sends the value of the on-board LDR as a sms message.

Here's the Program
/*  Induino R3 User Guide - Program 17.1 - A Simple program to make a call/ hangup / send an sms based on button presses */


#include <SoftwareSerial.h>

SoftwareSerial mySerial(3,4);    //RX and TX pins to communicate with GSM module

#define sms_key  7
#define call_key 9
#define end_key 8

String number ="XXXXXXXXXX"; // The Number to which message / call is to be made

void setup()
{
  Serial.begin(9600);
  mySerial.begin(9600);

  pinMode(sms_key,INPUT);
  pinMode(call_key,INPUT);
  pinMode(end_key,INPUT);
  digitalWrite(sms_key,HIGH);
  digitalWrite(call_key,HIGH);
  digitalWrite(end_key,HIGH);
}

void loop()
{
  
  
   //This part sends an sms everytime sms_key is pressed
  if (digitalRead(sms_key)==LOW) // Check if the sms key is being pressed
  {
    int ldr = analogRead(3); // read the on-board LDR value (only on the Induino R3 Board)
    String val = (String)ldr; // Convert the value to a String 
    
    mySerial.println("AT+CMGF=1"); // Set the Mode as Text Mode
    delay(150);
    mySerial.println("AT+CMGS=\"+91"+number+"\"");  // Specify the Destination number in international format
    delay(150);
    mySerial.print("Hello..! The Current LDR Value is.."+val); // Enter the message and append the ldr value
    delay(150);
    mySerial.write((byte)0x1A);                                // End of message character 0x1A : Equivalent to Ctrl+z
    delay(50);
    mySerial.println();
  }
   
   //This section generates a call when call_key is pressed
   
  else if (digitalRead(call_key)==LOW) // Check if the call key is being pressed
  {
    mySerial.println("ATD+91"+number+";");  //Specify the number to call
    while(digitalRead(call_key)==LOW);
    delay(50);
  }
  
  //This section is to hang the call

  else if (digitalRead(end_key)==LOW) // Check if the hang up key is being pressed
  {
    mySerial.println("ATH");
    while(digitalRead(end_key)==LOW);
    delay(50);
  }
}  

Now Lets see how to handle a incoming call. We will match the number of the incoming call and if it matches to a preset number, then we will hang up the incoming call and revert with the LDR Value. In addition, we will add a simple debug / command interface which will allow us to issue commands directly to the gsm modem using the Serial Monitor.

Here's the Program
/*  Induino R3 User Guide - Program 17.2 - A Simple program to Respond to an Incomign Call
 The Program sends a SMS with the on-board LDR Value if the Call originates from a specific Number*/


#include <SoftwareSerial.h>

SoftwareSerial mySerial(3,4);    //RX and TX pins to communicate with GSM module

String number ="xxxxxxxxxx"; // The Authorised Number to which message
String gsm_input = "";

void setup()
{
  Serial.begin(9600);
  mySerial.begin(9600);
  delay(100);
  // Enable Caller Identification to ensure we are able to get the Caller Number
  mySerial.print("AT+CLIP=1\r");
  delay(100);
}

void loop()
{
  // We use the regular Serial Port for Debugging and Testing Commands Directly using the Serial monitor
  // You can issue serial commands directly from the Serial monitor, ensure you have selected Carriage Return in the Serial monitor
  if(Serial.available()) // Check if there is data available
  {
    String input ="";
    while(Serial.available()) // read the data into a variable as long as the buffer is not empty
    {
      input += (char)Serial.read();
      delay(30);
    }
    // in order to enable the user to test sending messages, when the user enters the text 'ascii' at the end of the message in the Serial monitor 
    //the ascii value for CTRL Z is sent out to the gsm modem
    if(input =="ascii") 
    {
      mySerial.write((byte)0x1A); // The value for CTRL Z
      delay(50);
      mySerial.println();
    }
    else // if the ascii text is not found then we print the input received from the Serial monitor directly to the gsm modem
    {
      mySerial.println(input);
      Serial.println(input);
    }
  }

  // Check data ouput of the GSM modem to identify incoming calls / messagess.
  if(mySerial.available()) 
  {
    String gsm_input="";
    while(mySerial.available()) // read the data into a variable as long as the buffer is not empty
    {
      gsm_input += (char)mySerial.read();
      delay(5);// Playaround with this timing if you have missing serial data / garbled Serial data coming from the GSM modem
    }
    gsm_input.trim(); // Trim all the leading / trailing white spaces from the input
    Serial.print("Printing Trimmed GSM Response : "); // print the input to the serial monitor for debugging
    Serial.println(gsm_input);
    Serial.print("Printing Trimmed GSM Response Length : ");
    Serial.println(gsm_input.length()); 
    
    
    // Check if the Input received frm the GSM modem contains the work "+CLIP", If it contains, it means there is a incoming call
    if(find_string(gsm_input,"+CLIP") ) 
    {
      Serial.println("Incoming Call");
      if(find_string(gsm_input,number)) // Check if the Input received frm the GSM modem contains the Authenticated Number
      {
        Serial.println("Authenticated Call, Sending SMS");
        mySerial.println("ATH"); // Hang up on the incoming Call once We know its a authenticated call
        delay(1000); 
        String msg = "The Current LDR Value is : "; // Compose the outgoing message base
        int val = analogRead(3); // Get the LDR Value
        msg += (String)val; // Convert the LDR value to a String and append it to the message text    
        send_sms(number, msg); // Send sms to the authenticaed number with the ldr value
      }
    }
  }
}

// A Function to send SMS to a given Number 
void send_sms(String Number, String Message)
{
  mySerial.println("AT+CMGF=1"); // Set the Mode as Text Mode
  delay(150);
  mySerial.println("AT+CMGS=\"+91"+Number+"\"");  // Specify the Destination number in international format
  delay(150);
  mySerial.print(Message); // The Message
  delay(150);
  mySerial.write((byte)0x1A);  // End of message character 0x1A : ASCII Equivalent to Ctrl+z
  delay(50);
  mySerial.println();
}


// A Function to locate a given search string in a given base string
boolean find_string(String base, String search)
{
  int len = search.length(); // find the length of the base string

  for(int m = 0; m<(base.length()-len);m++)// Iterate from the beginning of the base string till the end minus length of the substring
  {    
    if(base.substring(m,(m+len))==search) // Check if the extracted Substring Matches the Search String
    {
      return true;        // if it matches exit the function with a true value
    }
  }
  return false; // if the above loop did not find any matches, control would come here and return a false value
}


With the Above program to type a command to the gsm modem, open serial monitor and type in the command and press enter. to send a message us the same instructions however at the end of the message type in 'ascii' this will automatically send a CtrlZ sequence to the gsm modem as per our program.

Next Lets see how to read a incoming SMS from an authorized number and process it. We will see how to look for a text "switch on" perform a controlling activity based on the current state and send a sms response to the authorized number.

Here's the Program
/*  Induino R3 User Guide - Program 17.3 - A Simple program to Respond to an Incomign SMS
 The Program Checks the SMS content for matching text, validates the action request and 
 sends a SMS response to a specific Number*/


#include <SoftwareSerial.h>

SoftwareSerial mySerial(3,4);    //RX and TX pins to communicate with GSM module

String response1 = "switch on";
String response2 = "switch off";

int state = 0;

String number ="xxxxxxxxxx"; // The Authorised Number to which message
String gsm_input = "";

String no ="";
String msg ="";

void setup()
{
  Serial.begin(9600);
  mySerial.begin(9600);
  delay(100);
  // Enable Caller Identification to ensure we are able to get the Caller Number
  mySerial.print("AT+CLIP=1\r");
  delay(100);
  pinMode(13,OUTPUT);
}

void loop()
{
  // We use the regular Serial Port for Debugging and Testing Commands Directly using the Serial monitor
  // You can issue serial commands directly from the Serial monitor, ensure you have selected Carriage Return in the Serial monitor
  if(Serial.available()) // Check if there is data available
  {
    String input ="";
    while(Serial.available()) // read the data into a variable as long as the buffer is not empty
    {
      input += (char)Serial.read();
      delay(30);
    }
    // in order to enable the user to test sending messages, when the user enters the text 'ascii' at the end of the message in the Serial monitor 
    //the ascii value for CTRL Z is sent out to the gsm modem
    if(input =="ascii") 
    {
      mySerial.write((byte)0x1A); // The value for CTRL Z
      delay(50);
      mySerial.println();
    }
    else // if the ascii text is not found then we print the input received from the Serial monitor directly to the gsm modem
    {
      mySerial.println(input);
      Serial.println(input);
    }
  }

  // Check data ouput of the GSM modem to identify incoming calls / messagess.
  if(mySerial.available()) 
  {
    String gsm_input="";
    while(mySerial.available()) // read the data into a variable as long as the buffer is not empty
    {
      gsm_input += (char)mySerial.read();
      delay(5);// Playaround with this timing if you have missing serial data / garbled Serial data coming from the GSM modem
    }
    gsm_input.trim(); // Trim all the leading / trailing white spaces from the input
    Serial.print("Printing Trimmed GSM Response : "); // print the input to the serial monitor for debugging
    Serial.println(gsm_input);
    Serial.print("Printing Trimmed GSM Response Length : ");
    Serial.println(gsm_input.length()); 


    // Check if the Input received frm the GSM modem contains the work "+CMTI", If it contains, it means there is a incoming sms
    // The CMTI response will also contain the message location number for the message recieved. this is the location from where the message
    // has to be retrieved. The message location number is preceeded by a ','
    if(find_string(gsm_input,"+CMTI") ) 
    {
      Serial.println("Incoming SMS");
      int loc = find_char_loc(gsm_input,','); // Find the starting location of the message location number. the message location number is preceeded by a ','
      no = gsm_input.substring(loc+1); // extract the message location number from the CMTI response
      mySerial.println("AT+CMGR="+no);     // send a AT command to the GSM modem to retrieve the message from the given location
    }

    //Check if the Input received frm the GSM modem contains the work "+CMGR", 
    //If it contains, it means this is the message data which we had requested    
    if(find_string(gsm_input,"+CMGR") && find_string(gsm_input,number)) // Check for the authenticated number
    {      
      Serial.println("Authenticated  SMS");   
      gsm_input.toLowerCase();   // convert the gsm input to lower case so that there is no case sensitivity
      if(find_string(gsm_input,response1)) // Check if the message contains the text stored in the response1 variable
      {
        if(state) // check the current state of the device and rewrite the reponse sms accordingly
        {
          msg = "Device is Already ON";
        }
        else
        {
          state =!state;
          digitalWrite(13,state);
          msg = "Device Switched ON";
        }
        delay(1000);
        send_sms(number,msg);// Send the Response SMS
      }
      if(find_string(gsm_input,response2))// Check if the message contains the text stored in the response1 variable
      {
        if(state==0)// check the current state of the device and rewrite the reponse sms accordingly
        {
          msg = "Device is Already OFF";
        }
        else
        {
          state =!state;
          digitalWrite(13,state);
          msg = "Device Switched OFF";
        }
        delay(1000);
        send_sms(number,msg); // Send the Response SMS
      } 

    }

  }
}

// A Function to send SMS to a given Number 
void send_sms(String Number, String Message)
{
  mySerial.println("AT+CMGF=1"); // Set the Mode as Text Mode
  delay(150);
  mySerial.println("AT+CMGS=\"+91"+Number+"\"");  // Specify the Destination number in international format
  delay(150);
  mySerial.print(Message); // The Message
  delay(150);
  mySerial.write((byte)0x1A);  // End of message character 0x1A : ASCII Equivalent to Ctrl+z
  delay(50);
  mySerial.println();
}


// A Function to locate a given search string in a given base string
boolean find_string(String base, String search)
{
  Serial.println("Function Find String!");
  int len = search.length(); // find the length of the base string
  for(int m = 0; m<((base.length()-len)+1);m++)// Iterate from the beginning of the base string till the end minus length of the substring
  { 
     
    if(base.substring(m,(m+len))==search) // Check if the extracted Substring Matches the Search String
    {
      return true;        // if it matches exit the function with a true value
    }
    
  }
  return false; // if the above loop did not find any matches, control would come here and return a false value
}


// A Function to locate a given search character in a given base string and return its position 
boolean find_char_loc(String base, char search)
{
  for(int m = 0; m < base.length();m++)// Iterate from the beginning of the base string till the end minus length of the substring
  {    
    if(base[m]==search) // Check if the character Matches the Search character
    {
      return m;        // if it matches exit the function with the current location value
    }
  }
  return 0; // if the above loop did not find any matches, control would come here and return a zero value
}


A Quick Troubleshooting Tip (If you are having troubles with incoming messages)
Courtesy:  Our Customer Joji Mundakel 
Locate the file SoftwareSerial.h, and in the file, modify the following variable 

 _SS_MAX_RX_BUFF to 128 instead of 64


Thats It For This Part! Enjoy... and feel free to drop us an email with questions you might have -> info@simplelabs.co.in

 Visit www.simplelabs.co.in for more interesting products


Friday, 8 November 2013

Interfacing Serial Devices - Part 2 - Working with a Serial RFID Reader

The RFID Basics

What is RFID?
RFID stands for Radio Frequency IDentification. RFID is a basic technology that allows  the identification of a device (read tag / sticker / label)  to be read wirelessly by a Reader(RFID reader) using Radio Frequnecy.

How does it work?
The Tag contains a small IC containing the Identity Information. The IC is attached to an antenna and transmits its identity to a Reader when it detects a Reader. It detects a Reader by detecting the electromagnetic energy produced by the Reader. The Identity information is transmitted as Radio Frequencies. The Reader then converts the received Radio Frequencies into the Identity Data.

Types of Tags
There are 2 major types of tags available - Active & Passive.

Active Tags
Active tags have an embedded power source and use it to transmit data. Owing to this reason they are expensive and are not viable for large scale deployments. 

Passive Tags
Passive Tags on the other hand get their power from the electromagnetic energy produced by the Reader (Electromagnetic Induction). These are cheap and are the most commonly used RFID tags (ID Cards, etc).


Interfacing an RFID reader with Induino R3 / Arduino

Most RFID readers provide with a Serial Interface for connecting to a microcontroller. Some of the readers also provide another interface called the Weigand Intreface. However for the scope of our tutorial we will stick to the Serial Interface. We shall also use the EM 18 RFID Reader Module available on our site as the reference. This is a 125Khz module and comes with both Serial and Weigand interfaces. 



Since there is only 1 way communication (Reader to Microcontroller) the reader has only a Tx Pin. Connect the Reader as follows
  1. Connect the +5V of the Reader to the +5V pin on the Induino R3
  2. Connect the GND of the Reader to the GND pin on the Induino R3
  3. Connect the Tx pin of the Reader to the Rx pin on the Induino R3 - Make this connection after uploading the program otherwise you will not be able to upload to the Induino R3 / Arduino board as the Rx / Tx pins are used for Programming the Induino R3 / Arduino. Remember to take this connection out every time you re-program your Induino R3 / Arduino
  4. Leave alone the DET pin for now, we will connect this later

Reading a TAG

Lets first write a Simple Program that would read the value of a Tag and display it on the Serial monitor. Make a note of the value as we would use this in our next program.

Here's the Program
/*  Induino R3 User Guide - Program 16.0 - Reading a TAG Value using the RFID reader
 This sketch Reads the Value of a RFID Tag and displays it on the Serial Monitor   
 */

int count = 0; // A variable to count the length of the Tag DATA

void setup()
{
  Serial.begin(9600); // Initialize Serial Communication - Both with the RFID reader & the Serial Monitor

}

void loop()
{
  
  if(Serial.available()) // Check if there is Incoming Data in the Serial Buffer. This is data coming from the RFID reader
  {
    count = 0; // Reset count to zero
    while(Serial.available()) // Keep reading Byte by Byte from the Buffer till the Buffer is empty
    {
      char input = Serial.read(); // Read 1 Byte of data and store it in a character variable
      Serial.print(input); // Print the Byte
      count++; // Increment the Byte count after every Byte Read
      delay(5); // A small delay - Removing this might make the Program run faster and not respond properly as data from the reader could be slow
    }
    // Print Tag Length
    Serial.println();
    Serial.print("Tag Length : ");
    Serial.print(count);
    Serial.println(" Bytes");
  }
}

Now open the Serial Monitor and Show the TAG onto the RFID reader (You have to hold it very close to the Central part of the Reader) and you will get the value of the TAG displayed. Note this value down. Later, We shall do some additional programs to identify a Tag and do specific tasks. 


Software Serial
Its pretty annoying to remove the connection every time you have to upload a new program. This is required as the same pins are used both by our computer (for programming) and the RFID reader. We can overcome this by using Software Serial - The ability to use any 2 pins on an Arduino for Serial communication. This is made possible by the SoftwareSerial library in Arduino which programatically simulates Serial Communication. Now Lets change our connections and experiment with this.
  1. Connect the Tx pin of the Reader to the digital pin 7 on the Induino R3 - We will use this as our Rx Pin for Software Serial. We can use Pin 1 for Tx as we are not going to connect anything 

Here's the modified Program
/*  Induino R3 User Guide - Program 16.1 - Reading a TAG Value using the RFID reader using Software Serial
 This sketch Reads the Value of a RFID Tag and displays it on the Serial Monitor   
 */
 
#include <SoftwareSerial.h> // include the Software Serial Library

SoftwareSerial rfid_reader(7,1); // Creat a Software Serial Object Mapping it to 7th pin as Rx and 1st Pin as Tx

int count = 0; // A variable to count the length of the Tag DATA


void setup()
{
  rfid_reader.begin(9600); // Initialise Serial Communication with the RFID reader
  Serial.begin(9600); // Initialise Serial Communication with the Serial Monitor
}

void loop()
{
  
  if(rfid_reader.available()) // Check if there is Incoming Data in the RFID Reader Serial Buffer. 
  {
    count = 0; // Reset count to zero
    while(rfid_reader.available()) // Keep reading Byte by Byte from the Buffer till the RFID Reader Buffer is empty
    {
      char input = rfid_reader.read(); // Read 1 Byte of data and store it in a character variable
      Serial.print(input); // Print the Byte
      count++; // Increment the Byte count after every Byte Read
      delay(5); // A small delay - Removing this might make the Program run faster and not respond properly as data from the reader could be slow
    }
    // Print Tag Length
    Serial.println();
    Serial.print("Tag Length : ");
    Serial.print(count);
    Serial.println(" Bytes");
  }
}

Now open the Serial Monitor and Show the TAG onto the RFID reader (You have to hold it very close to the Central part of the Reader) and you will get the value of the TAG displayed.  

Read More on Software Serial Here -> http://arduino.cc/en/Reference/SoftwareSerial


Matching Tags

To Match a Tag with a specific action, we need to get the Tag ID using the above program (16.0 / 16.1) Once we have the ID, we can use it in our program and compare it to the ID of any tag being presented.  So, Lets try to toggle the state of a LED using a specific Tag ID.

Here's the Program
/*  Induino R3 User Guide - Program 16.2 - Toggling a LED based on a RFID Tag
 This sketch toggles the state of a led everytime the correct tag is presented.
 */

#include <SoftwareSerial.h> // include the Software Serial Library
SoftwareSerial rfid_reader(7,1); // Creat a Software Serial Object Mapping it to 7th pin as Rx and 1st Pin as Tx

char tag[] ="4F006DD86A90"; // The Tag ID which we got from Program 16.0
char input[12]; // A Variable to store the ID of the Tag being presented
int count = 0; // A counter variable to navigate through the input[] character array
boolean flag = 0; // A variable to store the Tag match status
boolean state = 0; // A variable to store the state of the Led to be toggled
void setup()
{
  rfid_reader.begin(9600); // Initialise Serial Communication with the RFID reader
  Serial.begin(9600); // Initialise Serial Communication with the Serial Monitor
  pinMode(13,OUTPUT); // LED output
}

void loop()
{
  
  if(rfid_reader.available())// Check if there is Incoming Data in the RFID Reader Serial Buffer. 
  {
    count = 0; // Reset the counter to zero
    while(rfid_reader.available() && count < 12) // Keep reading Byte by Byte from the Buffer till the RFID Reader Buffer is empty or till 12 Bytes (the ID size of our Tag) is read
    {
      input[count] = rfid_reader.read(); // Read 1 Byte of data and store it in the input[] variable
      count++; // increment counter
      delay(5);
    }
    if(count == 12) // When the counter reaches 12 (the size of the ID) we stop and compare each value of the input[] to the corresponding stored value
    {
      count =0; // reset counter varibale to 0
      flag = 1;
      while(count<12 && flag !=0) // Iterate through each value and compare till either the 12 values are all matching or till the first mistmatch occurs
      {
        if(input[count]==tag[count])
        flag = 1; // everytime the values match, we set the flag variable to 1
        else
        flag=0; // if the ID values don't match, set flag variable to 0 and stop comparing by exiting the while loop
        count++; // increment i
      }
    }
    if(flag == 1) // If flag variable is 1, then it means the tags match
    {
      Serial.println("Matched!");
      state = !state; // Toggle state
      digitalWrite(13,state); // Apply the new state to the LED
    }
    else
    {
      Serial.println("Wrong Tag"); // Incorrect Tag Message
    }
   
    for(count=0; count<12; count++) // Fill the input variable array with a fixed value 'F' to overwrite all values getting it empty for the next read cycle
      {
        input[count]= 'F';
      }
     count = 0; // Reset counter variable  
  }
}

Now this should control the state of the 13th pin LED on the Induino R3 everytime you show the correct tag to it.

Using Interrupts
Now we have managed to identify a tag and control accordingly. However, our program has a small drawback. We keep checking for the tag all the time. If we can optimize this to check only when a tag is being present, we should be done. The DET pin on the RFID Reader outputs a constant high signal and gives a short LOW pulse when a Tag is presented. We can use this signal as an interrupt trigger and check the RFID readers serial line only when an interrupt is triggered. To make it more interesting, we will let a simple blink program run and get interrupted by the RFID reader.

Make the following additional connection
  1. Connect the DET line of the RFID reader to the digital pin 2 (Interrupt 0)

Here's the Program
/*  Induino R3 User Guide - Program 16.3 - Toggling a LED based on a RFID Tag using Interrupts
 This sketch is a simple blink that uses interrupts to toggle the state of a led everytime the correct tag is presented 
 */
 
#include <SoftwareSerial.h> // include the Software Serial Library
SoftwareSerial rfid_reader(7,1); // Creat a Software Serial Object Mapping it to 7th pin as Rx and 1st Pin as Tx

char tag[] ="4F006DD86A90"; // The Tag ID which we got from Program 16.0
char input[12]; // A Variable to store the ID of the Tag being presented
int count = 0; // A counter variable to navigate through the input[] character array
boolean flag = 0; // A variable to store the Tag match status
boolean state = 0; // A variable to store the state of the Led to be toggled
boolean tag_ready=0; // A variable that is set by the ISR when an interrupt occurs

void setup()
{
  rfid_reader.begin(9600); // Initialise Serial Communication with the RFID reader
  Serial.begin(9600); // Initialise Serial Communication with the Serial Monitor
  pinMode(13,OUTPUT); // LED output
  pinMode(12,OUTPUT); // A Normal LED output for LED Blink
  pinMode(2,INPUT); // Interrupt Pin defined as Input
  attachInterrupt(0, check, FALLING); // Enable the Interrupt to call the ISR check when a Falling Interrupt occurs
}

void check() // The Interrupt Service Routine
{
 
  tag_ready = 1; // Set the tag_ready variable
  
}

void loop()
{
  if(tag_ready) // Check if the variable is set 
  {
    process_tag(); // if the variable is set, call the process_tag() function
  }
  // Regular Blink Operation
  digitalWrite(12,HIGH); 
  delay(500);
  digitalWrite(12,LOW);
  delay(500);
  
}

/* Function to Process the TAG and Act */

void process_tag()
{
  if(rfid_reader.available())// Check if there is Incoming Data in the RFID Reader Serial Buffer. 
  {
    count = 0; // Reset the counter to zero
    while(rfid_reader.available() && count < 12) // Keep reading Byte by Byte from the Buffer till the RFID Reader Buffer is empty or till 12 Bytes (the ID size of our Tag) is read
    {
      input[count] = rfid_reader.read(); // Read 1 Byte of data and store it in the input[] variable
      count++; // increment counter
      delay(5);
    }
    if(count == 12) // When the counter reaches 12 (the size of the ID) we stop and compare each value of the input[] to the corresponding stored value
    {
      count =0; // reset counter varibale to 0
      flag = 1;
      while(count<12 && flag !=0) // Iterate through each value and compare till either the 12 values are all matching or till the first mistmatch occurs
      {
        if(input[count]==tag[count])
        flag = 1; // everytime the values match, we set the flag variable to 1
        else
        flag=0; // if the ID values don't match, set flag variable to 0 and stop comparing by exiting the while loop
        count++; // increment i
      }
    }
    if(flag == 1) // If flag variable is 1, then it means the tags match
    {
      Serial.println("Matched!");
      state = !state; // Toggle state
      digitalWrite(13,state); // Apply the new state to the LED
    }
    else
    {
      Serial.println("Wrong Tag"); // Incorrect Tag Message
    }
   
    for(count=0; count<12; count++) // Fill the input variable array with a fixed value 'F' to overwrite all values getting it empty for the next read cycle
      {
        input[count]= 'F';
      }
     count = 0; // Reset counter variable  
  }
  tag_ready=0;
}

Now this should control the state of the 13th pin LED on the Induino R3 everytime you show the correct tag to it. The LED on the 12th pin should be blinking all the while

Thats It For This Part! Enjoy... and feel free to drop us an email with questions you might have -> info@simplelabs.co.in

 Visit www.simplelabs.co.in for more interesting products

Wednesday, 6 November 2013

Interfacing Serial Devices - Part 1 - Working with the Xbee / BTBee PRO

Serial Devices

There are a lot of external modules that can add functionality to your project - RFID Readers, GSM Modems, GPS Modules, XBees, Bluetooth Modules. Such modules often have their own processing capabilities and provide a controlling serial communication interface. In our lesson on Serial Communicaiton (http://www.induino.com/2013/07/serial-communication-what-where-how.html  - Read this before proceeding!), we saw how to work with serial communication. Now we shall try and extend this to use Serial communication with various devices. Communicating with other devices is not much different from communicating with your computer over serial port.

Xbee - Overview

Xbee is a popular wireless module based on the 802.15.4 Protocol (now Xbee offers a variety of protocol support).  It operates on the 2.4GHz Frequenecy. Xbees provide a easy wireless serial interface and offer a number of functionalities (some of them listed below). Xbee modules can be configured by connecting them to a computer and using the XCTU application.
  • Basic Wireless Serial Interface - In this configuration, the Xbee module act as a wireless serial port. One module is connected to your computer as a serial port and another module is connected to your microcontroller's serial interface. Now any time you print anything from your microcontroller using the Serial.print() function, the same is transmitted across wirelessly to the xbee module connected to the computer and received as serial data by the computer
  • Remote Xbee Control Using Arduino - A pair of Xbees are configured in a mode called the API mode, that would let a remote xbee be controlled / monitored by issuing a command serially. One of the xbees is connected to the microcontroller and another one is configured to be a standalone device with outputs/inputs connected. Now the microcontroller can issue serial commands and control / read the I/O's of the standalone device
  • Standalone Xbee Networks - Xbees can be configured to form different types of networks. For eg. they a pair of xbees can be configured such that I/Os are paired. An input to one xbee's i/o would trigger a output on a corresponding i/o on a different Xbee

Considering the scope of this tutorial, we will stick to using the xbee for Basic Wireless Serial Interface. Xbee's(S1 / S2) by default come configured for the serial port mode, so all we need to do is basic connections. We can even use the same programs from our old Serial port tutorial

Connecting the Xbee to the Computer
You can use a USB Xbee board like the Simple Labs Induino Xbee Explorer to connect an Xbee Module to your computer. The board uses the same FTDI drivers that we used for our Induino R3 boards and the drivers will get installed automatically. A new COM port number will be generated for the board. Open the Arudino IDE, choose the new COM Port and open Serial Monitor. We can view our data here like we would for a normal serial port.


Connecting the Xbee to the Induino R3

You can use the Simple Labs Wireless Xbee/BTbee shield to connect the Xbee Module to the Induino R3.

Ensure that the Jumpers on the Shield are set like in the image below



Now Upload Program 3.1 from the Serial Communication Tutorial
Here's the Program
/*  Induino R3 User Guide - Program 3.1 - Serial Input / Button controlled Binary Counter with Serial Print
 This sketch increases a 3 bit number every time a button is pressed by the user and shows the output on 3 LEDs   
 */

int i = 0;  
char txt[]="The Current Value is : "; // A string stored in a character array
void setup()  
{  
  pinMode(11,OUTPUT);   // declare LED pins as output pins  
  pinMode(12,OUTPUT);  
  pinMode(13,OUTPUT);  
  pinMode(7,INPUT_PULLUP);// declare the Button as INPUT pin with internal Pull up enabled
  Serial.begin(9600); // initialize Serial Communication
  Serial.println("Starting the Program");// This will be printed only once
}  
void loop()  
{  
  if(digitalRead(7)==0 || Serial.available()>0)  // if the button is pressed  or Serial data is received
  {
    if(digitalRead(7)==0) // if the button is pressed
    {  
      if(i<7)        // if counter value is less than 7 or 3 bits  
        i++;        // increment counter value  
      else           
        i=0;        // reset counter to 0  
      while(digitalRead(7)==0);  // wait till button is released to avoid incrementing the counter again               
      delay(100);         // small delay to avoid debounce  
}
    if(Serial.available()>0) // if Serial data is received
    {
      int val = Serial.read(); // read 1 byte of data and store in the integer variable val. if the user sent 1, the ascii value for 1 is 49 so val will have the value 49
      val = val - 48; // 48 is the ascii value for 0. So if we did receive a 0 subtracting 48 would make the value of val as 0, same is true for the remaining numbers
      if(val>=0 && val <=7)// Check if Val is in the range of 0 to 7, we can display only values in this range and ignore all other values
      {
        i = val; // assign the counter to the value received from the Serial Port
      }

    }
    Serial.print(txt); // Print Descriptive test from the character array
    Serial.println(i); // print the current value
    int a=i%2;      // calculate LSB   
    int b=i/2 %2;     // calculate middle bit  
    int c=i/4 %2;     // calculate MSB   
    digitalWrite(11,a);  // write LSB 
    digitalWrite(12,b);  // write middle bit  
    digitalWrite(13,c);  // write MSB  
    
  }  
}

Now open the Serial Monitor with the COM port corresponding to the Xbee Explorer Board and key in Numerical Values as you would normally. You should see the same values being displayed on the LEDS on the microcontroller Board. If you have a 12V DC Power Adaptor, you can power your Induino Board using the adaptor and keep it away from your computer. Now you have a remote board that can be controlled from your computer using a serial interface!


There is a lot more you can do with your Xbees. Xbee's by themselves would require a dedicated tutorial. Perhaps we will do one later :)

BTBee Pro - Overview

The BTBee Pro is a Xbee Format Bluetooth Breakout Module based on the popular HC-05 Bluetooth Module. This module provides us with Serial Bluetooth Interface - Meaning which, we can transmit serial data over bluetooth.

Given that we are using Bluetooth and most Phones have Bluetooth, the number of project possibilities increases! Bluetooth control seems to be the In-Thing! hook up your Induino R3 with your Android phone over Bluetooth and zap you go... With a little bit of Android Expertise, you can double the potential of your Arduino Projects.

BTBee General Harware Overview
The BTBee Pro module has 2 Buttons, 3 LEDS(PWR, CON & STATUS) and 1 Slider switch. Ensure that the Slider switch is on the side marked 'upload'. When the Module is Powered on the PWR LED will glow.  When the device is powered and not paired, the Status LED will keep Blinking. When the Device is paired the CON LED will be ON and the Status LED will stop Blinking.

We can plug in the BTBee Pro module onto the Simple Labs Wireless Xbee/BTbee shield as we did with the Xbee and use the same program as above.

Controlling Using an Android Phone

  • Download the following App for your android phone BlueTerm
  • Switch On Your Bluetooth and Scan for Devices
  • The BTBee Pro will show up either as 'BTBee Pro' or as 'HC-05'
  • Use the Pairing Code '1234' to pair with the device (Pairing is not complete at this stage, Pairing will actually happen only when you establish communication with the device!)
  • Open Blueterm and use the Options Key on your Phone and Select the 'Connect' option
  • You will see a list of devices available, Choose the BTBee Pro / HC-05 device
  • The Device will now be paired, you can check the CON Led on the module to verify this
  • Now using the Bluterm's Terminal, send commands as you would from a Serial Monitor

You can use other apps as well... here are a few that we have developed (No source Code is not available for these Apps!)

Thats It For This Part! Enjoy... and feel free to drop us an email with questions you might have -> info@simplelabs.co.in

 Visit www.simplelabs.co.in for more interesting products