Notes About Working with Various Arduino & Netduino Microcontroller Boards

Thursday, January 24, 2013

I2C Version of Using the 4x4 Universal 16 Key Keypad for Arduino

A while back I posted about using the 4x4 Universal 16 Key Keypad for Arduino. One drawback to the parallel connection is that it requires 8 digital pins for the connections. There is an alternative approach that uses an PCF8574(P) I/O expander (datasheet) that connects to the Arduino Uno via I2C using just 2 data lines.

This example uses Joe Young's Keypad_I2C library (which, in turn, requires the Keypad library from the Arduino Playground).  

Pins A0 - A2 on the I/O expander determine the I2C address. This example uses 0x20. See this post for information on using other addresses. 

Connections:


The pin to the left of the "dot" on the PCF8574P is pin 1 (assuming the dot is in the 12 o'clock position). The other pins are numbered down the left side and up the right (counterclockwise). The lines on the keypad are numbered left to right with the keypad face up with the wires pointing downward.

PCF8574P  Pin 1 (A0)  -->  GND  
          Pin 2 (A1)       GND
          Pin 3 (A2)       GND
          Pin 4 (P0)       Keypad line 1
          Pin 5 (P1)       Keypad line 2
          Pin 6 (P2)       Keypad line 3
          Pin 7 (P3)       Keypad line 4
          Pin 8 (VSS)      GND
          Pin 9 (P4)       Keypad line 5
          Pin 10 (P5)      Keypad line 6
          Pin 11 (P6)      Keypad line 7
          Pin 12 (P7)      Keypad line 8
          Pin 13 (/INT)    --Not Used--
          Pin 14 (SCL)     Arduino SCL
          Pin 15 (SDA)     Arduino SDA
          Pin 16 (VDD)     5V
          

Code:



#include <Wire.h>
#include <Keypad_I2C.h>
#include <Keypad.h>

const byte ROWS = 4; 
const byte COLS = 4; 

char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};

byte rowPins[ROWS] = {0,1,2,3}; 
byte colPins[COLS] = {4,5,6,7};

int i2caddress = 0x20;

Keypad_I2C kpd = Keypad_I2C( makeKeymap(keys), rowPins, colPins, ROWS, COLS, i2caddress );

void setup(){
  Serial.begin(9600);
  kpd.begin();
}

void loop(){
  char key = kpd.getKey();
  if (key){
    Serial.println(key);
  }
}


Note: This code does not work with the Arduino Due.   


Tuesday, January 22, 2013

Parallax RFID Reader & the Arduino Due

Using the serial version of the Parallax RFID reader (125 kHz) with an Arduino Uno is straight forward. The RFID reader also works with an Arduino Due, too. Because the Parallax RFID reader is 5V, though, a logic level converter is needed to protect the lower voltage pins on the Arduino Due.

Connections:

RFID --> Log Lvl Conv --> Arduino Due
GND  --> GND (HV)     --> GND
SOUT --> RXI / RXO    --> D19 (RX1)
/ENABLE  ---------------> D2
VCC  --> HV           --> 5V
         LV           --> 3V3
         GND (LV)     --> GND

D19 (RX1) on the Arduino Due connects to Serial1. Serial2 (D17 - RX2) or Serial3 (D15 - RX3) could also be used with change to code.
        
Code:

// RFID reader for Arduino 
// Wiring version by BARRAGAN <http://people.interaction-ivrea.it/h.barragan> 
// Modified for Arudino by djmatic
// Slight modification by Brad Berkland

int const ENABLE_PIN = 2;

int  val = 0; 
char code[10]; 
int bytesread = 0; 

void setup() { 
  Serial.begin(19200);
  Serial1.begin(2400);            // RFID reader SOUT pin connected to D19 on Due (RX1) 
  pinMode(ENABLE_PIN, OUTPUT);    // Set D2 as OUTPUT to connect it to the RFID /ENABLE pin 
  digitalWrite(ENABLE_PIN, LOW);  // Activate the RFID reader
}  

void loop() { 
  if(Serial1.available() > 0) {          // if data available from reader 
    if((val = Serial1.read()) == 10) {   // check for header 
      bytesread = 0; 
      while(bytesread < 10) {            // read 10 digit code 
        if( Serial1.available() > 0) { 
          val = Serial1.read(); 
          if((val == 10)||(val == 13)) { // if header/stop bytes before 10 digit reading 
            break;                       // stop reading 
          } 
          code[bytesread] = val;         // add the digit           
          bytesread++;                   // ready to read next digit  
        } 
      } 
      if(bytesread == 10) {              // if 10 digit read is complete 
        Serial.print("TAG code is: ");   // possibly a good TAG 
        Serial.println(code);            // print the TAG code 
      } 
      bytesread = 0; 
      digitalWrite(ENABLE_PIN, HIGH);    // Stop reader for a moment to avoid flooding
      delay(1500);                       // wait for a bit 
      digitalWrite(ENABLE_PIN, LOW);     // Activate the RFID reader
    } 
  } 


Monday, January 21, 2013

Multiple OneWire (1-Wire) Devices with a Netduino Plus 2

Previously, I posted a quick example of using the Netduino Plus 2's 1-Wire support with a single device. Here is an example with multiple devices (DS18B20 temperature sensors). You can find the DS18B20 datasheet here.

This example assumes that you have Netduino firmware version 4.2. As in the one device example, I have use I used godfroi's  OneWireBus and DS18B20 classes (posted at TinyCLR). Just add the code for these classes to your project. Be sure to add the reference to Microsoft.SPOT.Hardware.OneWire in your project's references section.

Important note: I have gotten multiple 1-Wire devices to work with the Netduino in normal or "non-parasitic" power mode. This means that each device has its own connection to ground and voltage. The data line is shared among the devices, so only one pin is needed for data on the Netduino.  When I have tried parasitic power mode, all sensors report the same invalid temperature. For more information on 1-wire power modes, see the OneWire page at the Arduino Playground.

Note (March 29, 2013): When working with temperatures below freezing, see this post.

Connections:

1. Looking at the flat side of the sensor, the left pin is connected to GND.
2. The right pin on the sensor is connected to 5V.
3. The center (data) pin of each connects to the center pin of the previous sensor.
4. There is a pull-up resistor (4k7) at the head of the data line where it connects to the Netduino (to pin D0). 

This code queries the 1-wire bus to get a list of devices and then cycles through the devices to get the temperature and convert it to Fahrenheit. The results are printed to the debug console in Visual Studio.

Code:

using ThreelnDotOrg.NETMF.Hardware;
using Microsoft.SPOT.Hardware;
using Microsoft.SPOT;
using System.Threading;
using SecretLabs.NETMF.Hardware.Netduino;
using System;


namespace OneWireMultDev
{
    public class Program
    {
        private static OneWireBus.Device[] devs;

        public static void Main()
        {
            // Data line connected to D0 - but couldn be any digital pin
            OutputPort pin = new OutputPort(Pins.GPIO_PIN_D0, false);
            OneWire bus = new OneWire(pin);
            // Get list of devices (just in DS18B20 family)
            devs = OneWireBus.Scan(bus, OneWireBus.Family.DS18B20);
            // Create array to hold DS18B20 references
            DS18B20[] ds = new DS18B20[devs.Length];
            // Instantiate DS18B20 objects
            for (int i = 0; i < devs.Length; i++)
            {
                ds[i] = new DS18B20(bus, devs[i]);
            }
            while (true)
            {
                for (int i = 0; i < devs.Length; i++)
                {
                    float temp = ds[i].ConvertAndReadTemperature();
                    temp = temp / 5 * 9 + 32;
                    Debug.Print(i.ToString() + ": " + temp.ToString());
                }
                Thread.Sleep(1000);
                Debug.Print(" ");
            } 
        }
    }


Note (March 29, 2013): When working with temperatures below freezing, see this post.

Wednesday, January 16, 2013

Controlling an LCD Backlight with an IR Remote

Yesterday I posted an example of how to use and Arduino Uno, an IR remote, and digital potentiometer to control the contrast of a parallel LCD. This post builds (slightly) on that one by adding a transistor to control the LCD's backlight (LCD pins 15 (A) and 16 (K)). 

The transistor (P2N2222A) is inline between pin 18 (K) of the LCD and GND. Looking at the flat side of the transistor body, the LCD pin is connected to the left side, the transistor's center wire is connected to Arduino digital pin 2, and the right-side wire goes to GND (with a small resistor).

In the section of the code before the setup() method, add the following constant to declare the IR code for the EQ key that turns the backlight off and on:

  // IR code for EQ key
  const long ON_OFF = 0x40BF20DF;

Add the following variable declaration to track the state of the backlight:

  int backlight = HIGH;

Then, add the following to the loop() method body:

if(results.value == ON_OFF) {
  backlight = !backlight;
  digitalWrite(2, backlight);
}

The volume buttons on the remote control the contrast and the EQ button now controls the backlight.    

Tuesday, January 15, 2013

Using a Digital Pot & IR Remote to Control Contrast of an LCD with an Arduino Uno

This post shows how to use a digital potentiometer and an infra-red remote to control the contrast of an LCD display. In this case, the LCD is a 16 x 2 LCD with a parallel interface driven by the Arduino LiquidCrystal library
The digital potentiometer allows control via the code rather than by way of a physical control. This example uses an MCP4131 10k pot from Sparkfun. The Arduino and digital MCP4131 communicate via SPI. (This means you have to avoid using Uno's digital pins 11, 12,  & 13 for other purposes, even you run the SPI connections to the SPI header on the Arduino.) 

The IR remote is from the CuteDigi Infrared Remote Control Kit for Arduino. I posted the IR codes for this remote control here. The IR receiver is the Sparkfun IR receiver (TSOP85) used with the IRremote library for Arduino. Pressing the VOL+ key increases the LCD's contrast, while pressing the VOL- key decreases it. 

LCD Connections:
LCD Disp.  Arduino Uno 
1  (VSS)   GND
2  (VDD)   5V
3  (V0)    [Dig. Pot Pin 6 (P0W)]
4  (RS)    D7
5  (RW)    GND
6  (E)     D8
11 (D4)    D9
12 (D5)    D10
13 (D6)    D3
14 (D7)    D6
15 (A)     5V  (backlight)
16 (K)     GND (w/ 330 Ohm resistor)

MCP4131 Digital Pot. Connections:

Dot marks pin 1. Pins counted counterclockwise from pin 1.

MCP4131      Arduino Uno
1 (CS)       D4
2 (SCK)      D13
3 (SDI/SDO)  D11
4 (VSS)      GND
5 (P0A)      GND
6 (P0W)      [LCD Pin 3 (V0)]
7 (P0B)      5V
8 (VDD)      5V

TSOP85 IR Receiver Connections:
TSOP85     Arduino Uno 
VCC        5V
OUT        D5
GND        GND

Code:

#include <LiquidCrystal.h>
#include <SPI.h>
#include <IRremote.h>

LiquidCrystal lcd(7, 8, 9, 10, 3, 6);

// Set digital pin 4 as slave select for digital pot:
const int POT_PIN = 4;
// Set digital pin 5 for IR data:
const int RECV_PIN = 5;

// IR codes for VOL- & VOL+ keys
const long VOL_DOWN = 0x40BFA05F;
const long VOL_UP = 0x40BF609F;

IRrecv irrecv(RECV_PIN);
decode_results results;

// Starting level for digital pot
int level = 80;

void setup()
{
  lcd.begin(16, 2);
  // The usual msg. for demo
  lcd.print("Hello, world!");
  // set the POT_PIN as an output:
  pinMode(POT_PIN, OUTPUT);
  // initialize SPI:
  SPI.begin(); 
  Serial.begin(9600);
  irrecv.enableIRIn(); 
}
void loop()
{
  lcd.setCursor(0, 1);
  // Print the number of seconds since reset as part of demo:
  lcd.print(millis()/1000);
  // Check if IR data received 
  if(irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    // 80 defined as minimum contrast
    if((results.value == VOL_DOWN) && level > 80) {
      level--;
    }
    // 127 is maximum contrast
    if((results.value == VOL_UP) && level < 127) {
      level++;
    }
    digitalPotWrite(level);
    irrecv.resume();
  }
}
int digitalPotWrite(int value)
{
  // Take the SS/CS pin low to select the chip:
  digitalWrite(POT_PIN, LOW);
  // Send in the address and value via SPI:
  SPI.transfer(0);
  SPI.transfer(value);
  // Take the SS/CS pin high to de-select the chip:
  digitalWrite(POT_PIN, HIGH); 

Sunday, January 13, 2013

Innovations ID12 RFID Reader, Sparkfun RFID USB Reader Board, and a Netduino Plus 2

I posted yesterday about using an Innovations ID12 plus a Sparkfun RFID USB Reader board with a serial connection to an Arduino Uno to read RFID tags.  Here is a similar simple example of using an ID12 and a Sparkfun RFID USB Reader board with a Netduino Plus 2. This setup also uses a serial connection between the pins on the board (not the USB connection) and the Netduino.

The digital pins on the Netduino are 5 volt tolerant, but for best results, use a logic level converter on the serial RX line between the breakout board and the Netduino. Without the logic level converter, the output sometimes shows some garbage characters after a card's code.

This sample C# program reads the card when it is brought near the the ID12 and prints the card's code to the debug console. 

In the References section of the project in Visual Studio 2010, add the references for Microsoft.SPOT.Hardware.SerialPort and SecretLabs.NETMF.Hardware.NetduinoPlus.

Connections:


Reader Board   Netduino Plus 2 
  VCC            5V
  GND            GND
  TX             Digital 0 (via logic level converter)

Connect the serial RX line via the logic level converter. CC and GND on the level converter need to be connected - 3v3 side to Netduino and 5v side to the board. 

Logic Level Converter Connections:
  RXI  -->  Board's TX
  HV        Board's VCC
  GND       Board's GND
  RXO       Netduino's Digital 0
  LV        Netduino's 3V3
  GND       Netduino's GND
  

Code:


using System;
using System.Threading;
using Microsoft.SPOT;
using SecretLabs.NETMF.Hardware.NetduinoPlus;
using System.IO.Ports;


namespace ID12
{
    public class Program
    {
        public static void Main()
        {
            SerialPort serial = new SerialPort(SerialPorts.COM1, 
                9600, Parity.None, 8, StopBits.One);
            serial.Open();
            while (true)
            {
                String code = "";
                while (serial.BytesToRead > 0)
                {
                    byte[] buf = new byte[1];
                    serial.Read(buf, 0, 1);
                    code += (char)buf[0];
                }
                if (code.Length > 0)
                {
                    Debug.Print(code);
                }
                // Slight delay - otherwise data is garbled
                Thread.Sleep(100);
            }
        }
    }
}



Saturday, January 12, 2013

Innovations ID12 RFID Reader, Sparkfun RFID USB Reader Board, and an Arduino Uno

I've had an Innovations ID12 around for a while that I wasn't using because the pins on the ID12 didn't work on a breadboard or connect to anything I have on hand. Sparkfun has a breakout board and special 2mm headers that are supposed to get it to work on a breadboard, but I never got that far with it.  

I recently got the Sparkfun RFID USB Reader board to use the ID12 with a computer. It works fine as such. The board also has connections broken out so that it can be used on a breadboard and connected to an Arduino via a serial connection. Here is a brief example using the Arduino SoftwareSerial library. It reads a 125 kHz card and prints the card's number to the serial console when a suitable card is brought near.

Connections:

Reader Board   Arduino Uno 
  VCC            5V
  GND            GND
  TX             Digital 10
  
Sketch:

#include <SoftwareSerial.h>

SoftwareSerial rfidSerial(10, 11); // RX, TX (TX not used)
void setup()  
{
  Serial.begin(9600);
  rfidSerial.begin(9600);
}

void loop() 
{
  if (rfidSerial.available())
    Serial.write(rfidSerial.read());
}

Note that the board, which Sparkfun unhelpfully calls an "RFID USB Reader," does not actually include the RFID reader chip. In terms of cost, it's certainly cheaper to get the breakout board and solder the chip correctly, if you only need to use it with an Arduino, but the RFID USB reader board offer the flexibility of using the ID12 RFID reader with either a computer (via USB) or an Arduino (via TTL serial). 

Saturday, January 5, 2013

Synchronizing a DeadOn Real Time Clock to an NTP Server with a Netduino Plus 2

A few days ago I shared an example of how to read the current date and time from a Sparkfun DeadOnRTC using a Netduino Plus 2. Today's example shows how to synchronize the DeadOnRTC with a public NTP server. I have not found a solution to the seconds problem in the previous post. You can set the seconds (apparently), but the Netduino only reads zeros when getting the value from the seconds register.

The code below uses an Ntp class by JayPM (based on work by Michael Schwarz). You will need to include Jay's Ntp class in your project.  You may wish to update the address of the NTP server and offset from GMT as appropriate for your location.

As noted in the previous post, the Sparkfun DeadOnRTC module uses a DS3234 chip and connects via SPI. Here are the connections for the Netduino: 

Connections:

DeadOn RTC  Netduino Plus 2
GND         GND
VCC         3V3
CLK         D13
MISO        D12
MOSI        D11
SS          D10

This example assumes that you have the Netduino Plus 2's ethernet connection up and running. 

Code:

using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace DeadOnNTP
{
    public class Program
    {
        public static void Main()
        {
            byte[] WriteBuffer = new byte[8];
            SPI.Configuration Device1 = new SPI.Configuration(
                Pins.GPIO_PIN_D10, // SS-pin
                false,             // SS-pin active state - false = low
                0,                 // setup time for SS port
                0,                 // hold time for SS port
                true,              // idle state of clock
                true,              // sampling clock edge
                2000,              // SPI clock rate in KHz
                SPI_Devices.SPI1   // SPI bus used 
            );
            SPI SPIBus = new SPI(Device1);

            Ntp.UpdateTimeFromNtpServer("216.171.120.36", -6);
            Debug.Print(DateTime.Now.ToString());
            int month = DateTime.Now.Month;
            int date = DateTime.Now.Day;
            int year = DateTime.Now.Year - 2000;
            int hour = DateTime.Now.Hour;
            int min = DateTime.Now.Minute;
            int sec = DateTime.Now.Second;
            WriteBuffer[0] = 0x80;
            WriteBuffer[1] = decToBcd(sec);
            WriteBuffer[2] = decToBcd(min);
            WriteBuffer[3] = decToBcd(hour);
            // Day of week not used in this example
            WriteBuffer[4] = decToBcd(0);
            WriteBuffer[5] = decToBcd(date);
            WriteBuffer[6] = decToBcd(month);
            WriteBuffer[7] = decToBcd(year);
            SPIBus.Write(WriteBuffer);
            Debug.Print("Done");
        }

        static byte decToBcd(int val)
        {
            return Convert.ToByte(((val / 10 * 16) + (val % 10)).ToString());
        }
    }
}