|
Interfacing the ATMEGA168/Arduino to the MCP23016 I/O Expanderby Lewis Loflin The MCP23016 is a popular I/O expander integrated circuit manufactured by Microchip. It provides 16 individually programmable I/O pins that can can source/sink 25 milliamps per pin up to about 250 milliamps total. Here we will explore how to use the MCP23016 with the ATMEGA168/Arduino.Note that in this discussion I'll use hex numbers, a digital "1" is five volts and a digital "0" is zero volts. In binary a byte as individual bits (MSB) B00000000 (LSB). The "B' means this is a binary number to the compiler. All zeros is a decimal values of zero, all ones is a decimal value of 255. The MCP23016 can only handle bytes. (8 bits = 1 byte.) All the ports and registers in the MCP23016 use bytes. The programming examples will use the Wire.h library. For more examples of this see:
Basics of the MCP23016Two separate 8-bit I/O ports bit programmable.
Open-drain interrupt output pin (6) on input change and interrupt port capture register. (Doesn't work very well.)
0x00 Port0; can be directly written/read. 0x01 Port1; can be directly written/read. Defaults to input. 0x02 Output latch 0; write changes output Port0. 0x03 Output latch 1; write changes output Port1. Write won't work if bit/port set for input. 0x04 Invert input polarity Port0 bit addressable. 1 invert bit, 0 no invert. 0x05 Invert input polarity Port1 bit addressable. 1 invert bit, 0 no invert. All bits default to 0. 0x06 I/O direction register Port0 bit addressable. 1 = output, 0 = input. 0x07 I/O direction register Port1 bit addressable. 1 = output, 0 = input. Defaults to all 0 for inputs. 0x08 Interrupt capture register Port0. 0x09 Interrupt capture register Port1. These are read only, shows state of port during an interrupt. Connect an LED/resistor to VCC (+5 volts) and to pin 6 of MCP23016 and LED will blink. Can be used to signal IRQ on on the ATMEGA168. See Using Hardware Interrupts ATMEGA168/Arduino 0x0A I/O control register 1 0x0B I/O control register 1 (same thing as 0x0A) A one-bit register that controls the sampling frequency of the 2 I/O ports. A "0" results in a 32 millisecond sample rate. A "1" results in a 200 microsecond sample rate, but uses more power in standby.
Example 1. In the setup sections of the two sample programs the MCP23016 is setup as follows to make Port0 all output and Port1 all inputs by writing to the two I/O direction registers: Wire.begin(); // connect the Arduino as a master Wire.beginTransmission(0x20); // setup out direction registers Wire.send(0x06); // pointer Wire.send(0x00); // DDR Port0 all output Wire.send(0xFF); // DDR Port1 all input 0xFF = B11111111 Wire.endTransmission(); Example 2. What if I wanted both ports to be inputs, but invert the input polarity (a 1 becomes a 0) on Port1 where my switches are connected? Wire.begin(); // connect the Arduino as a master, setup data direction Wire.beginTransmission(0x20); // setup out direction registers Wire.send(0x04); // pointer Wire.send(0x00); // DDR Port0 no invert Port0 Wire.send(0xFF); // DDR invert input polarity port1 0xFF = B11111111 Wire.send(0xFF); // DDR Port0 all input 0xFF = B11111111 Wire.send(0xFF); // DDR Port1 all input 0xFF = B11111111 Wire.endTransmission(); When the eight switches are open (see schematic) the normal input to Port1 pins are all "0". In program two below all the LEDs on Port0 will be on, will go off when switch is closed. As it is below all LEDs on Port0 will come on only when corresponding switch on Port1 is closed. Download the schematic here. /* The address for the MCP23016 is 0x20. There are eight resistor/LED indicators on pins 21 - 28. This demo produces a binary count of 0 to 255 on Port0 on the MCP23016. */ #include <Wire.h> // specify use of Wire.h library. int i = 0; void setup() { Wire.begin(); Wire.beginTransmission(0x20); // setup out direction registers Wire.send(0x06); // pointer Wire.send(0x00); // DDR Port0 all output Wire.send(0xFF); // DDR Port1 all input Wire.endTransmission(); } void loop() { i++; Wire.beginTransmission(0x20); // set mcp23016 for all output Wire.send(0x00); // begin here Wire.send(i); Wire.endTransmission(); if (i > 255) i = 0; delay(1000); // } } // end loop /* The address for the MCP23016 is 0x20. This routine reads 8 port1 switches and transfers the value to port0 */ #include <Wire.h> // specify use of Wire.h library. int i; void setup() { Wire.begin(); Wire.beginTransmission(0x20); // set mcp23016 output Wire.send(0x06); Wire.send(0x00); // DDR Port0 all output Wire.send(0xFF); // DDR Port1 all input Wire.endTransmission(); // invert input polarity on port 1 Wire.beginTransmission(0x20); // set mcp23016 output Wire.send(0x05); Wire.send(0xFF); // DDR Port0 all output Wire.endTransmission(); } // end setup void loop() { // read port 1 Wire.beginTransmission(0x20); Wire.send(0x01); // must act as a position pointer? Wire.endTransmission(); Wire.requestFrom(0x20, 1); // request 1 byte i = Wire.receive(); // receive a byte // send value to port 0 Wire.beginTransmission(0x20); Wire.send(0x00); // begin here // only 2 switches connected Wire.send(i); // send to port 0 // Note: noise problem on floating pins. Tie to GND through a 2.2k resistor Wire.endTransmission(); delay(500); } // end loop
You Tube Arduino Microcontroller Video Series March 2012:
Arduino demos:
» About me » Bristol VA/TN » E-Mail » Hobby Electronics » Arduino Microcontroller
General Electronics
Added January 2012: PICAXE Micro-controller Projects!The PICAXE series of micro-controllers rank as the easiest and most cost effective way to use Microchip processors. I wanted an easier and less expensive way to introduce my students to the "PIC" micro-controller. Here I hope to get those starting out past poorly written literature and lack of simple working code examples.
|