L’integrato MCP23017 (
datasheet) è un I/O port expander per
bus i2c. Permette di controllare 16 ingressi/uscite singolarmente configurabili.
I terminali di I/O (PA0..PA7 e PB..PB7) sono suddivisi in due
porte a 8 bit (GPIOA e GPIOB).
Collegamento di prova
Il terminale di reset (/RST) per le prove è stato collegato direttamente a Vcc. Volendolo utilizzare basta tenerlo a 5V con una resistenza di pull-up, e portarlo a livello basso (GND) per almeno 1 microsecondo.
Parametri ingressi/uscite
- Ogni pin può gestire 25mA sia in source che in sink
- Totale complessivo 150mA su GND e 125mA su Vcc
- VIL = 0.2Vcc (1V a 5Vcc)
- VIH = 0.8Vcc (4V a 5Vcc)
- VOL = 0.6V
- VOH = Vcc-0.7V (4.3V a 5Vcc)
- Gli ingressi sono triggerati
- Clamp ±20mA
- Protezione ESD 4kV
Registri base
REGISTRO |
INDIRIZZO |
NOTA |
IODIRA |
0x00 |
direzione, bit 1=in 0=out |
IODIRB |
0x01 |
|
GPPUA |
0x0C |
pull-up, bit 1=pup 100kΩ |
GPPUB |
0x0D |
|
GPIOA |
0x12 |
bit porta A |
GPIOB |
0x13 |
bit porta B |
IPOLA |
0x02 |
polarità, bit 1=inversione livello |
IPOLB |
0x03 |
|
Programma Arduino di test:
Questo programma legge l’ingresso PB0, e a seconda del livello letto fa lampeggiare a frequenze diverse un LED collegato all’uscita PB7. I terminali SCK e SDA del bus i2c vanno collegati ai corrispondenti terminali di Arduino, che nel caso di Arduino2009/UNO sono rispettivamente A5 e A4.
//___________________________________________________________
//
// MCP23017 test - By C.Fin 2018
//___________________________________________________________
#include <Wire.h>
//___________________________________________________________
#define MC_IODIRA 0x00
#define MC_IODIRB 0x01
#define MC_GPIOA 0x12
#define MC_GPIOB 0x13
#define MC_GPPUA 0x0C
#define MC_GPPUB 0x0D
//___________________________________________________________
void mcWrite(uint8_t mcAddr, uint8_t dataAddr, uint8_t data)
{
Wire.beginTransmission(mcAddr);
Wire.write(dataAddr);
Wire.write(data);
Wire.endTransmission();
}
//___________________________________________________________
uint8_t mcRead(uint8_t mcAddr, uint8_t dataAddr)
{
Wire.beginTransmission(mcAddr);
Wire.write(dataAddr);
Wire.endTransmission();
Wire.requestFrom(mcAddr, 1);
return Wire.read();
}
//___________________________________________________________
void setup()
{
Wire.begin();
mcWrite(0x20, MC_IODIRA, 0b11111111); // PA tutti ingressi
mcWrite(0x20, MC_GPPUA, 0b11111111); // tutti pull-up
mcWrite(0x20, MC_IODIRB, 0b01111111); // PB7 uscita
mcWrite(0x20, MC_GPPUB, 0b01111111);
}
//___________________________________________________________
void loop()
{
static byte n = 0b10000000;
mcWrite(0x20, MC_GPIOB, n ^= 0b10000000);
if(mcRead(0x20, MC_GPIOB) & 1)
delay(50);
else
delay(500);
}
//___________________________________________________________
L’uso di periferiche i2c è molto comodo, bastano due fili per
connettere diverse periferiche (sensori, memorie, expander ecc),
ma è piuttosto lento (più di mezzo millisecondo per ogni
operazione). Se servono ingressi/uscite aggiuntivi più veloci
si possono usare degli
shift register.