Teclado y pantalla lcd con solo dos pines

Un problema habitual al trabajar con estos componentes es que requieren muchos puertos de nuestro microcontrolador; para el caso de ejemplo utilizaremos un ESP8266, un NodeMCU.

¿Cual es la trampa?

Necesitamos de otro chip que se ocupe de extender los puertos necesarios, para el caso del teclado utilizaremos un MCP23017, es lo que tengo a mano, pero estimo que puede ser cualquier chip de la familia. Requeriremos además tres resistencias de 10k, el diagrama de como conectarlo es el siguiente:

Requeriremos además instalar la librería keypad, si ya la tenemos instalada no será necesario. Para instalar desde el IDE de Arduino, debemos ir al menú Programa – Incluir Librería – Añadir desde ZIP.

Además también sera necesario arduino_keypads-master, simplemente debemos descomprimir dentro de la carpeta Libraries (en mi caso esta en C:\Users\Guillermo\Documents\Arduino\libraries ).

Luego que se hayan instalados estas librerías y construido el circuito anterior, es conveniente chequear cual es la dirección que tiene nuestro chip MCP23017 para poder comunicarnos adecuadamente con él; para ello cargaremos en el nodemcu un sketch para buscar las direcciones disponibles:

Si copia y pega el código verifique que no vayan caracteres incorrectos, tengo la mala experiencia que en oportunidades al pegar no llevar el carácter adecuado.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include  < Wire.h >
 
void setup() {
  Wire.begin();
 
  Serial.begin(9600);
  Serial.println("\nI2C Scanner");
}
 
 
void loop() {
  byte error, address;
  int nDevices;
 
  Serial.println("Scanning...");
 
  nDevices = 0;
  for(address = 1; address < 127; address++ )  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
 
    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");
 
      nDevices++;
    } else if (error==4) {
      Serial.print("Unknown error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
 
  delay(5000);           // wait 5 seconds for next scan
}

Si todo esta correctamente conectado, en el monitor serie deberíamos ver un mensaje como el siguiente:

Donde 0x20 es la dirección de MCP23017.

El paso siguiente seria cargar el ejemplo para poder interactuar con el teclado:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <Keypad_MC17.h>
#include <Keypad.h>
#include <Wire.h>

#define I2CADDR 0x20

const byte ROWS = 4; //four rows
const byte COLS = 4; //five columns

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

Keypad_MC17 customKeypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS, I2CADDR);

void setup(){
//  Wire.begin( );
  customKeypad.begin( );        // GDY120705
  Serial.begin(9600);
  Serial.println("Iniciando");
}
 
void loop(){
  char customKey = customKeypad.getKey();
 
  if (customKey != NO_KEY){
    Serial.println(customKey);
  }
}

De esta forma podemos conectar el teclado a una placa NodeMCU, también funciona con Arduino, utilizando solo dos pines.

Queda por ver si es posible utilizar los otros 8 pines restantes del MCP23017 para realizar otras operaciones y ampliar aún mas la cantidad de entradas y salidas.

NodeMCU y MicroPython: múltiples entradas analógicas

Una de las particularidades del NodeMCU con el chip ESP8266 es tener un solo puerto analógico, a diferencia del Arduino UNO o Nano que tienen varios, esta diferencia genera que al momento de querer trabajar con más de un sensor analógico tengamos una limitante y debamos buscar alternativas.

Podemos resolver este problema utilizando diferentes métodos, por ejemplo utilizar un Arduino conectado al NodeMCU para que sense los valores de los sensores analógicos y los comunique por serie; pero se incorpora cierta complejidad y no podríamos resolver todo con MicroPython en un solo programa.

Multiplexor Analógico de 16 canales

La solución que encontré es con un pequeño chip llamado 74HC4067 que nos permite tener hasta 16 entradas analógicas por medio de una multiplexación de 4 canales digitales.

La forma de conectarlo es la siguiente:

NodeMCU PinMultiplexor Analógico
D4S0
D3S1
D2S2
D1S3
VCC3v3
GNDGND
ENGND
SIGA0

En el diagrama anterior tenemos conectado la salida de cada potenciometro a un puerto analógico de 74HC4067, en nuestro ejemplo solo utilizaremos 3 entradas para mostrar su uso. Cada sensor analógico va conectado en alguno de los puerto C0-C15.

Para poder leer cada uno de los valores de los puertos C0-C15 tenemos que poner en HIGH o LOW los puertos S0-S3 siguiendo la tabla indicada por el fabricante, se puede encontrar en el siguiente link: http://www.ti.com/lit/ds/symlink/cd74hct4067.pdf.

De esta forma si queremos leer el puerto C0 debemos poner en en LOW D4,D3,D2 y D1. Para leer el puerto C1 seria HIGH D4 y LOW D3,D2 y D1. Extendiendo esto se entiende la idea.

Si solo deseamos leer los puerto C0, C1 y C3 para poder probar el ejemplo del diagrama se puede utilizar el siguiente código de ejemplo:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from machine import Pin, ADC
import time

s0 = Pin(2, Pin.OUT)
s1 = Pin(0, Pin.OUT)
s2 = Pin(4, Pin.OUT)
s3 = Pin(5, Pin.OUT)

adc = ADC(0)

while True:

    # Se lee C0
    # Todos los pins van a LOW
    s0.off()
    s1.off()
    s2.off()
    s3.off()

    c0 = adc.read()

    # Se lee C1
    # Ponemos en HIGH S0 y el resto en LOW
    s0.on()
    s1.off()
    s2.off()
    s3.off()

    c1 = adc.read()    

    # Se lee C2
    # Ponemos en HIGH S1 y el resto en LOW
    s0.off()
    s1.on()
    s2.off()
    s3.off()

    c2 = adc.read()  

    print(c0,c1,c2)

    time.sleep_ms(250)

Si en cambio deseamos tener una forma dinámica de acceder a cada uno de los pins, podemos crear una lista con los elementos de la tabla de verdad anterior y recorrerla según el nro. de pin analógico que deseamos leer, a continuación el programa completo:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
from machine import Pin, ADC
import time

s0 = Pin(2, Pin.OUT)
s1 = Pin(0, Pin.OUT)
s2 = Pin(4, Pin.OUT)
s3 = Pin(5, Pin.OUT)

adc = ADC(0)

multiplexor = [  
    [0,0,0,0], #0
    [1,0,0,0], #1
    [0,1,0,0], #2
    [1,1,0,0], #3
    [0,0,1,0], #4
    [1,0,1,0], #5
    [0,1,1,0], #6
    [1,1,1,0], #7
    [0,0,0,1], #8
    [1,0,0,1], #9
    [0,1,0,1], #10
    [1,1,0,1], #11
    [0,0,1,1], #12
    [1,0,1,1], #13
    [0,1,1,1], #14
    [1,1,1,1], #15
]

pinCx = list(range(0,15))

while True:

    # Si queremos leer los valores de todos los puertos Cx
    for pin in pinCx:
        s0.value(multiplexor[pin][0])
        s1.value(multiplexor[pin][1])
        s2.value(multiplexor[pin][2])
        s3.value(multiplexor[pin][3])

        cx = adc.read()  

        print(pin," = ",cx)

    # Se lee C2
    # Ponemos en HIGH S1 y el resto en LOW
    s0.value(multiplexor[2][0])
    s1.value(multiplexor[2][1])
    s2.value(multiplexor[2][2])
    s3.value(multiplexor[2][3])

    c2 = adc.read()  

    print("Valor de C2 = ",c2)

    time.sleep_ms(250)

Si utilizamos una función, podemos simplificar aún mas:


1
2
3
4
5
6
7
8
9
def valor_analogico(cx):
    s0.value(multiplexor[pin][0])
    s1.value(multiplexor[pin][1])
    s3.value(multiplexor[pin][3])
    s2.value(multiplexor[pin][2])

    lectura = adc.read()    

    return lectura

Para utilizar simplemente invocamos de la siguiente manera:


1
lectura = valor_analogico(2) #leemos C2

Se puede encontrar el ejemplo en github:
https://github.com/gsampallo/micropython_examples/blob/master/74HC4067/multiplexor.py