Saturday, November 24, 2012

More Ethernet - Read Analog, & Set Digital Pins

As a followup to our previous Ethernet web server example, I offer a enhanced version. Again, it displays what is coming in on the analog pins, but also allows you to control digital pins 0-7.

Get the CODE HERE!

You'll need:
Arduino UNO
Ethernet Shield

Plug shield into your home router with an ethernet cable. Change IP information to match your network, and MAC address to match your shield.

The html isn't pretty, but it's functional! I'm sure some of you can pretty it up, and even show the current status of the digital pins, like the status of the analog pins are displayed. Thanks to the What I did Was blog for inspiration!

Friday, November 23, 2012

Using a Keypad for Input

Keypads are handy for a variety of projects, from security access to telephone dialing. In this tutorial, we use a Adafruit membrane keypad, and output the button presses to the serial monitor. Nothing fancy, just a platform for future development. Expand the Library in your sketchbook/libraries/ folder. The next step will be to multiplex the lines so we don't use up 7 inputs with a SN74LS151 (reduces Arduino pins to 3, expands inputs up to 16).

You'll need:
Arduino Uno
Breadboard Kit
Membrane Keypad

#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
byte rowPins[ROWS] = {8, 7, 6, 5}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {4, 3, 2}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
void setup(){
  Serial.begin(9600);
}

void loop(){
  char key = keypad.getKey();

  if (key != NO_KEY){
    Serial.println(key);
  }
}



EtherShield SD Card Access

Since I was playing with my EtherShield SD, I figured I'd load up the example sketch "CardInfo" in the SD folder. I popped in the microSD card from my digital camera, and it started listing the files on my card (but did not recognize the full 16GB partition).


Initializing SD card...Wiring is correct and a card is present.

Card type: SDHC

Volume type is FAT32

Volume size (bytes): 3038248960
Volume size (Kbytes): 2967040
Volume size (Mbytes): 2897

Files found on the card (name, date and size in bytes):
DCIM/         2011-06-20 14:58:52
  100_PANA/     2011-06-20 19:07:48
    P1000812.JPG  2011-09-08 09:19:54 4158647
    P1000781.JPG  2011-08-20 21:02:02 4309863
    P1000813.JPG  2011-09-08 09:20:00 4258311
    P1000814.JPG  2011-09-08 09:20:06 4145655
    P1000954.JPG  2011-10-05 19:11:52 3605223
    ......



/*
  SD card test
 
 This example shows how use the utility libraries on which the'
 SD library is based in order to get info about your SD card.
 Very useful for testing a card when you're not sure whether its working or not.
 
 The circuit:
  * SD card attached to SPI bus as follows:
 ** MOSI - pin 11 on Arduino Uno/Duemilanove/Diecimila
 ** MISO - pin 12 on Arduino Uno/Duemilanove/Diecimila
 ** CLK - pin 13 on Arduino Uno/Duemilanove/Diecimila
 ** CS - depends on your SD card shield or module.
  Pin 4 used here for consistency with other Arduino examples


 created  28 Mar 2011
 by Limor Fried
 modified 9 Apr 2012
 by Tom Igoe
 */
 // include the SD library:
#include <SD.h>

// set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;

// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
const int chipSelect = 4;  

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
  }


  Serial.print("\nInitializing SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output
  // or the SD library functions will not work.
  pinMode(10, OUTPUT);     // change this to 53 on a mega


  // we'll use the initialization code from the utility libraries
  // since we're just testing if the card is working!
  if (!card.init(SPI_HALF_SPEED, chipSelect)) {
    Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card is inserted?");
    Serial.println("* Is your wiring correct?");
    Serial.println("* did you change the chipSelect pin to match your shield or module?");
    return;
  } else {
   Serial.println("Wiring is correct and a card is present.");
  }

  // print the type of card
  Serial.print("\nCard type: ");
  switch(card.type()) {
    case SD_CARD_TYPE_SD1:
      Serial.println("SD1");
      break;
    case SD_CARD_TYPE_SD2:
      Serial.println("SD2");
      break;
    case SD_CARD_TYPE_SDHC:
      Serial.println("SDHC");
      break;
    default:
      Serial.println("Unknown");
  }

  // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
  if (!volume.init(card)) {
    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
    return;
  }


  // print the type and size of the first FAT-type volume
  uint32_t volumesize;
  Serial.print("\nVolume type is FAT");
  Serial.println(volume.fatType(), DEC);
  Serial.println();
 
  volumesize = volume.blocksPerCluster();    // clusters are collections of blocks
  volumesize *= volume.clusterCount();       // we'll have a lot of clusters
  volumesize *= 512;                            // SD card blocks are always 512 bytes
  Serial.print("Volume size (bytes): ");
  Serial.println(volumesize);
  Serial.print("Volume size (Kbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);
  Serial.print("Volume size (Mbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);

 
  Serial.println("\nFiles found on the card (name, date and size in bytes): ");
  root.openRoot(volume);
 
  // list all files in the card with date and size
  root.ls(LS_R | LS_DATE | LS_SIZE);
}


void loop(void) {
 
}

Simple Ethernet

This is the first in a series of Ethernet projects. This first project will display the values coming from the analog ports in a web browser on a remote machine. Additional posts will cover controlling the Arduino from a web browser, and reading and writing to the SD card for logging purposes. Stay tuned!

I popped a Arduino EtherShield SD on to an older Duemilanove (328), and loaded the following sketch. I changed the MAC address to the one printed on the bottom of my EtherShield, and put in a applicable IP address from my network. When I pointed my browser to the new IP address, I got the following output:

analog input 0 is 1023
analog input 1 is 0
analog input 2 is 1023
analog input 3 is 771
analog input 4 is 551
analog input 5 is 437

This makes sense, because I have A0 and A2 connected to 5v, A1 connected to Gnd, and A3-A5 are left floating, and the values change every second or so.

Sketch from examples folder (Ethernet, Web Server)


/*
  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[] = {
  0x90, 0xA2, 0xDA, 0x00, 0x23, 0x36 };
IPAddress ip(192,168,254, 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);

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) {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connnection: close");
          client.println();
          client.println("");
          client.println("");
                    // add a meta refresh tag, so the browser pulls again every 5 seconds:
          client.println("");
          // output the value of each analog input pin
          for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
            int sensorReading = analogRead(analogChannel);
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(sensorReading);
            client.println("
");    
          }
          client.println("
");          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disonnected");
  }
}

Thursday, November 22, 2012

Producing DTMF Tones

I wanted to teach my Arduino to talk telephone, so I added a HT9000A DTMF chip to produce the familiar "touch tones" (upcoming projects will act upon "heard" DTMF tones, but with a different chip).

The output is really low volume, so you may want to plug in amplified speakers or use an input on your stereo. You could build an amplifier circuit with a LM386 as well.

I used an Ham Radio program that listens for touch tones and displays the number it hears to verify operation. http://downloads.fyxm.net/DTMF-Decoder-47129.html

The code I used (and modified) was built by Brohogan.(don't forget the include file)

/* HT9200A DTMF Generator Test                             BroHogan 7/17/09
 * SETUP FOR SERIAL MODE - Requires 3 pins - Data and Clock (100KHz) and CE
 * Wire per data sheet - 3.57MHz xtal (4.0MHz won't dial) S/P to GND = serial
 * modified by Steve Spence - http://arduinotronics.blogspot.com
 */

#include <HT9200.h>                     // defines for HT9200 DTMF chip
#define DATA_PIN   2                    // Data (serial)
#define CLOCK_PIN  3                    // Clock (serial)
#define CE_PIN     4                    // Chip Enable pin (must control)

#define PHONE_NMBR "2642262"         // phone # to dial
char PhoneNum[] = PHONE_NMBR;           // load phone # for dialer

void setup() {
  pinMode(DATA_PIN, OUTPUT);
  pinMode(CLOCK_PIN, OUTPUT);
  pinMode(CE_PIN, OUTPUT);
  Init_HT9200();                        // init the chip
}

void loop() {
  Dialer();                             // dials phone
  delay(3000);
}

void Init_HT9200 (){
  digitalWrite(CE_PIN, HIGH);           // start with chip disabled (else you go nuts)
  digitalWrite(CLOCK_PIN, HIGH);        // start with clock pin high
  digitalWrite(CE_PIN, LOW);            // now enable the chip
  delay(10);                            // delay 10ms to ramp up the ocillator
  DTMF_Out (DTMF_OFF,1,0);              // turn off any tone from previous run
}

void DTMF_Out (byte digit, long duration, long pause){  // FOR SERIAL COMM
  if (digit == 0) digit = 10;           // take care of 0 here
  for (byte i=0; i<5 br="br" i="i">    digitalWrite(CLOCK_PIN, HIGH);      // clock high while setting data
    digitalWrite(DATA_PIN, bitRead(digit,i)); // set data LSB->MSB
    delayMicroseconds(5);               // 1/2 of 100K Clock speed
    digitalWrite(CLOCK_PIN, LOW);       // clock low to latch data
    delayMicroseconds(5);               // 1/2 of 100K Clock speed
  }
  delay(duration);                      // how long tone will play
  if (pause != 0){                      // tone sounds continuously if zero
    for (byte i=0; i<5 above="above" as="as" br="br" i="i" nbsp="nbsp" same="same">      digitalWrite(CLOCK_PIN, HIGH);
      digitalWrite(DATA_PIN, bitRead(DTMF_OFF,i));
      delayMicroseconds(5);
      digitalWrite(CLOCK_PIN, LOW);
      delayMicroseconds(5);
    }
    delay(pause);                       // how long pause between tones
  }
}


void Dialer(){  // dials tones from number
  for (byte i=0; i<7 i="i" nbsp="nbsp" p="p"> //i<7 11="11" 7="7" br="br" digit="digit" for="for" i="i" number="number">    DTMF_Out(PhoneNum[i]-'0',500,100);  // 1/2 sec tone with 1/10 pause
  }
}




Tuesday, November 20, 2012

Using pull up / pull down resistors

Pull up and pull down resistors are used to eliminate floating inputs. Normally a input is either connected to a high (on), or a low (off). But if the input is not connected to anything, it's "floating" and can read either, or cycle back and forth due to stray currents, so it's not a reliable state. A resistor is used to pull an input to the opposite of what you are trying to read (ground if you are trying to read a high, +5V if you are trying to read a low). This resistor prevents a short circuit (you can't connect +5v to gnd), and makes sure the input is in a stable state when not connected, but is ignored when your input is connected to a high or a low.

Monday, November 19, 2012

Transistor and Resistor Sizing

When using a transistor to turn on a device, it's important to chose the right transistor, and to trigger it properly. NPN transistors get triggered with a high, PNP transistors get triggered with a low, and get connected differently in a circuit. You need to know how to size the base resistor properly, to make sure you drive the transistor hard enough, but not draw too much power from the Arduino. The typical hookup in the Arduino world is that a Arduino digital pin is driving the base of the transistor, through the resistor he talks about in the video, and that the voltage is typically (but not always) 5v. This video will make it very clear:



We are reading:

Electrical Engineering 101: Everything You Should Have Learned in School...but Probably Didn't (w/ CD)