MCP23017 IO Expansion Board

From CQRobot-Wiki
Revision as of 16:35, 30 July 2020 by Chenqi (talk | contribs) (Demo for Raspberry Pi)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
MCP23017 IO Expansion Board

Introduction

The MCP23017 IO Expansion Board expands 2 signal pins as 16 I/O pins based on the I2C bus, up to 8 MCP23017 IO Expansion Board can be used at the same time, providing up to 128 I/O pins, it is compatible with both 3.3V and 5V levels.


Features

  • I2C controlled, expands 2 signal pins as 16 I/O pins
  • I2C address configurable by shorting the A0/A1/A2 jumpers
  • Up to 8 MCP23017 IO Expansion Board can be used at the same time, providing up to 128 I/O pins.
  • Onboard voltage translator, compatible with 3.3V/5V level
  • Comes with development resources and manual (examples for Raspberry Pi / micro:bit / Arduino / STM32)

Product Size

MCP23017 IO Expansion Board-72.jpg
MCP23017 IO Expansion Board-73.jpg

Pin Description

MCP23017 IO Expansion Board-71.jpg

Connection Diagram

Connect to Arduino:

  • Note: Do not connect the DuPont female single-head wire directly to the UNO R3 control board. You need to stack the sensor expansion board on the UNO R3 control board or connect the male-to-male Dupont wire on the Dupont female single-head wiring(bread wire).
  • We connected the 4Pin interface of the sensor to the UNO R3 control board in the experiment.
MCP23017 IO Expansion Board-74.jpg

Connect to Raspberry Pi:

  • We connected the 4pin interface of the sensor to the Raspberry Pi 4B control board in the experiment.
MCP23017 IO Expansion Board-75.jpg

Specifications

Sensor Specifications

  • Operating Voltage: 5V/3.3V
  • Interface: I2C (JST PA SMT 6-Pin interface to 2.54mm pitch pin header interface)
  • Interrupt Pins: INTA, INTB
  • Expansion I/Os: 16
  • Dimension: 45.24mm * 31.79mm
  • Mounting Hole Size: 3.0mm

Ocean Wire Specifications

  • Cable specifications: 22AWG
  • Material: Silicone
  • Withstand Voltage: Less Than 50V
  • Withstand Current: Less Than 1000MA
  • Length: 21cm
  • Line Sequence: Black-negative power supply, Red-positive power supply, Green-SDA, Blue-SDA, Yellow-INTA, Orange-INTB.

Demo for Arduino

//Note: Before uploading the code, the corresponding library file must be placed in the library file folder where the Arduino IDE is installed.
#include <Wire.h>
#include "MCP23017.h"
// Connect pin SCL of the expander to SCL
// Connect pin SDA of the expander to SDA
// don't solder A0,A1,A2 (default)
// Connect PA0 to a led
MCP23017 mcp;
byte arduinoIntPin1 = 2;
byte arduinoIntPin2 = 3;
byte arduinoInterrupt1 = 0;
byte arduinoInterrupt2 = 1;
volatile boolean awakenByInterrupt1 = false;
volatile boolean awakenByInterrupt2 = false;
byte mcpPinA = 7;
byte mcpPinB = 15;
void setup() {
	/*the param can be 0 to 7,the default param is 7.means the dafault device address 0x27.
    Addr(BIN)  Addr(hex)   param
    010 0111    0x27        7
    010 0110    0x26        6
    010 0101    0x25        5
    010 0100    0x24        4
    010 0011    0x23        3
    010 0010    0x22        2
    010 0001    0x21        1
    010 0000    0x20        0
    */
	Serial.begin(9600);
	Serial.println("Interrupt Test Start");
	pinMode(arduinoIntPin1,INPUT);
	pinMode(arduinoIntPin2,INPUT);
	mcp.begin(7);
	mcp.setupInterrupts(true,false,LOW);
	mcp.pinMode(mcpPinA, INPUT);
	mcp.pullUp(mcpPinA, HIGH);
	// turn on a 100K pullup internally
	mcp.setupInterruptPin(mcpPinA,FALLING);
	mcp.pinMode(mcpPinB, INPUT);
	mcp.pullUp(mcpPinB, HIGH);
	// turn on a 100K pullup internall
	mcp.setupInterruptPin(mcpPinB,FALLING);
	for (int i = 0; i < 7; i++) {
		mcp.pinMode(i, INPUT);
	}
	for (int i = 0; i < 7; i++) {
		mcp.pullUp(i, HIGH);
	}
	for (int i = 8; i < 15; i++) {
		mcp.pinMode(i, OUTPUT);
	}
}
// The int handler will just signal that the int has happen
// we will do the work from the main loop.
void intCallBack1() {
	awakenByInterrupt1 = true;
}
void intCallBack2() {
	awakenByInterrupt2 = true;
}
void handleInterrupt1() {
	// Get more information from the MCP from the INT
	uint8_t pin = mcp.getLastInterruptPin();
	uint8_t val = mcp.getLastInterruptPinValue();
	Serial.println("_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-");
	Serial.println("the key has been pressed!!!");
	Serial.print("the last interrupt Pin is:");
	Serial.println(pin);
	Serial.print("the last interrupt value is:");
	Serial.println(val);
	Serial.println("_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-");
	// we have to wait for the interrupt condition to finish
	// otherwise we might go to sleep with an ongoing condition and never wake up again.
	// as, an action is required to clear the INT flag, and allow it to trigger again.
	// see datasheet for datails.
	//while( ! (mcp.digitalRead(mcpPinB) && mcp.digitalRead(mcpPinA) ));
	while( ! (mcp.digitalRead(mcpPinA) ));
	// and clean queued INT signal
	cleanInterrupts1();
}
void handleInterrupt2() {
	// Get more information from the MCP from the INT
	uint8_t pin = mcp.getLastInterruptPin();
	uint8_t val = mcp.getLastInterruptPinValue();
	Serial.println("_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-");
	Serial.println("the key has been pressed!!!");
	Serial.print("the last interrupt Pin is:");
	Serial.println(pin);
	Serial.print("the last interrupt value is:");
	Serial.println(val);
	Serial.println("_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-");
	// we have to wait for the interrupt condition to finish
	// otherwise we might go to sleep with an ongoing condition and never wake up again.
	// as, an action is required to clear the INT flag, and allow it to trigger again.
	// see datasheet for datails.
	//while( ! (mcp.digitalRead(mcpPinB) && mcp.digitalRead(mcpPinA) ));
	while( ! (mcp.digitalRead(mcpPinB) ));
	// and clean queued INT signal
	cleanInterrupts2();
}
// handy for interrupts triggered by buttons
// normally signal a few due to bouncing issues
void cleanInterrupts1() {
	EIFR = 0x01;
	awakenByInterrupt1 = false;
}
void cleanInterrupts2() {
	EIFR = 0x02;
	awakenByInterrupt2 = false;
}
// int this loop will flip the PA0 up and down
void loop() {
	//PA0-PA6 input low level, PB0-PB6 output low level.
	for (int i = 0; i < 7; i++) {
		mcp.digitalWrite(i + 8, mcp.digitalRead(i));
	}
	//PA7, PB7 low level trigger interrupt, print the value of the corresponding IO port as 0.
	attachInterrupt(arduinoInterrupt1,intCallBack1,FALLING);
	attachInterrupt(arduinoInterrupt2,intCallBack2,FALLING);
	//while(!awakenByInterrupt);
	// disable interrupts while handling them.
	detachInterrupt(arduinoInterrupt1);
	detachInterrupt(arduinoInterrupt2);
	if(awakenByInterrupt1) {
		handleInterrupt1();
	}
	if(awakenByInterrupt2) {
		handleInterrupt2();
	}
}

Test Methods and Results

First, upload the test code on the UNO R3 control board with Arduino IDE software. Then, connect the cable according to the wiring method and power on by USB cable. PA0-PA6 input low level, PB0-PB6 output low level; PA0-PA6 input high level, PB0-PB6 output high level.

Next, turn on the serial monitor, and set the baud rate to 9600. When the interrupt signal is detected by D2, D3, the serial monitor will display the corresponding images.


Demo for Raspberry Pi

import smbus
import time

MCP23017_IODIRA = 0x00
MCP23017_IPOLA  = 0x02
MCP23017_GPINTENA = 0x04
MCP23017_DEFVALA = 0x06
MCP23017_INTCONA = 0x08
MCP23017_IOCONA = 0x0A
MCP23017_GPPUA = 0x0C
MCP23017_INTFA = 0x0E
MCP23017_INTCAPA = 0x10
MCP23017_GPIOA = 0x12
MCP23017_OLATA = 0x14

MCP23017_IODIRB = 0x01
MCP23017_IPOLB = 0x03
MCP23017_GPINTENB = 0x05
MCP23017_DEFVALB = 0x07
MCP23017_INTCONB = 0x09
MCP23017_IOCONB = 0x0B
MCP23017_GPPUB = 0x0D
MCP23017_INTFB = 0x0F
MCP23017_INTCAPB = 0x11
MCP23017_GPIOB = 0x13
MCP23017_OLATB = 0x15


bus = smbus.SMBus(1)

#   Addr(BIN)      Addr(hex)
#XXX X  A2 A1 A0
#010 0  1  1  1      0x27 
#010 0  1  1  0      0x26 
#010 0  1  0  1      0x25 
#010 0  1  0  0      0x24 
#010 0  0  1  1      0x23 
#010 0  0  1  0      0x22
#010 0  0  0  1      0x21
#010 0  0  0  0      0x20

MCP23017_ADDRESS = 0x27

#Configue the register to default value
for addr in range(22):
	if (addr == 0) or (addr == 1):
		bus.write_byte_data(MCP23017_ADDRESS, addr, 0xFF)
	else:
		bus.write_byte_data(MCP23017_ADDRESS, addr, 0x00)
		
		
		#configue all PinA output
		bus.write_byte_data(MCP23017_ADDRESS,MCP23017_IODIRA,0x00)
		
		#configue all PinB input
		bus.write_byte_data(MCP23017_ADDRESS,MCP23017_IODIRB,0xFF)
		#configue all PinB pullUP
		bus.write_byte_data(MCP23017_ADDRESS,MCP23017_GPPUB,0xFF)   
		
		
		#only for debug       
		for addr in range(22):
			print(bus.read_byte_data(MCP23017_ADDRESS,addr))
			
			
			print("----------------Start to toggle all PinA, all PinB will read it----------------")
			
			while True:
				#configue all PinA output low level
				bus.write_byte_data(MCP23017_ADDRESS,MCP23017_GPIOA,0x00)
				#then PinB read the level from PinA, print 0 means all PinA are in low level
				print(bus.read_byte_data(MCP23017_ADDRESS,MCP23017_GPIOB))
				time.sleep(0.5)
				
				#configue all PinA output high level
				bus.write_byte_data(MCP23017_ADDRESS,MCP23017_GPIOA,0xFF)
				#then PinB read the level from PinA, print 255 means all PinA are in high level
				print(bus.read_byte_data(MCP23017_ADDRESS,MCP23017_GPIOB))
				time.sleep(0.5)

Test Methods and Results

1. Save the test code as a folder in the Raspberry Pi system.

2. The I2C communication function is used in the code. Since the Raspberry Pi does not enable the I2C function by default, you need to enable that before running the code.

A. Enter “sudo raspi-config” in the terminal to start the Raspberry Pi configuration interface.

B. Turn on the I2C function of Raspberry Pi according to the steps below.

Long long.jpg

Execute the following commands in the terminal to run the program. The 16 IO ports (PA0-PA7 PB0-PB7) on the expansion board cycle between low and high levels with an interval of 0.5 seconds. The output data on the terminal is shown in the picture below.


cd TS1698
ls
sudo python TS1698.py