Teclado con Encoder

Al igual que en el proyecto anterior de teclado de membrana, en este caso he decidido hacer algo similar con Encoder rotatorio con lo que nos permite tener todos los caracteres que deseemos. En mi caso he programado los símbolos que hay en un teclado convencional y que requiere de la combinación de dos teclas presionadas a la vez.

En esta ocasión veréis que he utilizado un Arduino Leonardo. Para el fin de crear este teclado la condición indispensable es que la placa sea una Atmega32U4 ya que si lo probáis con cualquier otra no os funcionara.

Junto a este escrito os dejare un fichero comprimido con el código fuente de la aplicación y las dos librerías modificadas para que reconozca al teclado español, estos tres ficheros han de estar en la misma carpeta.

Cabe comentar que, si lo vais a usar en Mac, la primera tecla que habéis de presionar a la hora de que el sistema reconozca el teclado, es el símbolo “<”; de esta manera no perderéis la configuración del teclado principal.

Material

Arduino Leonardo
LCD 16×2
Enncoder
Resistencia 10K

Esquema de conexión

Código fuente

Código teclado Encoder
Keyboard.h
Keyboard.cpp
/*
  Teclado con un encoder
  De derecha a izquierda: CLK, DT, MS, 5V i GND
  El SW se conecta a 5V, con una resisténcia de 10K. El SW es el botón incorporada al encoder
  CLK = Gris        Pin 6
  DT  = Blanc/gris  Pin 5
  SW  = Marron      Pin 4
  5V  = Varmell
  GND = Negre
  Restabli teclat mac
  sudo rm /Library/Preferences/com.apple.keyboardtype.plist

*/

// Incluye la:
#include <LiquidCrystal_I2C.h>
//******************
#include "Keyboard.h"    // Esta es una biblioteca "incorporada" sin necesidad de instalar pero se tiene que modificar al castellano
#include <SoftwareSerial.h>
#include <Keypad.h>
#include <Wire.h>

#define RxD 0    // Usado para conexion rs232 virtual.
#define TxD 1    // Usado para conexion rs232 virtual.
SoftwareSerial comVirtual(RxD, TxD);

LiquidCrystal_I2C lcd (0x27, 16, 2);  // Inicia el LCD en la dirección 0x27, con 16 caracteres y 2 líneas

     // Array de caracteres 
char Tecles[22] = {'@','<','>','[',']','{','}','(',')','|','&',
                   '$','#','"','%','+','-','*','/','=','?','^'};

// Declaro Encoder
int pinEnt = 4;  // Conectado al SW 
int pinA = 6;    // Conectado al CLK 
int pinB = 5;    // Conectado al DT 
int Pos = -1;    // Es el que indica la posición del encoder

unsigned long time;
unsigned long t;
unsigned long tEnt;
bool C = true;
bool D = true;
bool E = false;
bool Ent = false;
int EncMenu = Pos;
String Cadena = "";

    // Representación binaria de las dos flechas que se mostraran en la LCD
byte derecha[8] = {B00000, B00010, B00110, B01110, B11111, B01110, B00110, B00010};
byte izquierda[8]   = {B00000, B01000, B01100, B01110, B11111, B01110, B01100, B01000};


void setup() {
  // Inicio puerto serie
  Serial.begin (9600);
  comVirtual.begin(9600);
  Wire.begin();
  

  //LCD
  // configure el número de columnas y filas de la pantalla LCD:
  lcd.begin(16, 2);
  //lcd.cursor();   // Muestra el cursor
  //lcd.blink();    // Parpadeo del cursor
  lcd.backlight();
  lcd.clear();
  lcd.createChar (1, izquierda);  // Creamos el primer caracter. Los valores atmitidos 0 a 7
  lcd.createChar (2, derecha);  // Creamos el segundo caracter. Los valores atmitidos 0 a 7

  //lcd.rightToLeft(); // Escribe hacia la izquerra.
  //lcd.leftToRight(); // Escribe hacia la derecha.
  //lcd.backlight();   // Enciende la luz de fondo de la LCD
    
  // Declaro pines Encoder
  pinMode (pinA,INPUT);   // Derecha
  pinMode (pinB,INPUT);   // Izquierda
  pinMode (pinEnt,INPUT); // Enter

  for(int i=0; i<22; i++){
    if (i<=10){
      lcd.setCursor(i, 0);
      lcd.write(Tecles[i]);
    } else {
      lcd.setCursor(i-11, 1);
      lcd.write(Tecles[i]);
    }  
  } 
  //***** Flechas
  lcd.setCursor(11, 0);
  lcd.print(" Car.");
  lcd.setCursor(11, 1);
  lcd.print("     ");
  lcd.setCursor(12, 1);
  lcd.write (1);
  lcd.setCursor(14, 1);
  lcd.write (2);
}

void loop() {
  time = millis(); // Registra el tiempo en todo el programa 
  //y lo usare en las distintas instancias.

  // -------------------------------------------------------
  // Codigo del encoder
  //*** Giro a la derecha ***
    if (digitalRead(pinA)==LOW){
      t = time;
      if(C == true){
        Pos ++;   
        if (Pos >=22){
            Pos = 0;
          }
        Serial.print("Encoder Position dreta: ");
        Serial.println(Pos);  //Posición en la matriz
        lcd.setCursor(13, 1);
        lcd.write(Tecles[Pos]);
        C = false;
        D = false;
      }
    }  
  //*** Giro a la izquierda ***
    if (digitalRead(pinB)==LOW){
      t = time;
      if(D == true){
        Pos --;   
        if (Pos<= -1){
            Pos = 21;
        }    
      Serial.print("Encoder Position esquerra: ");
      Serial.println(Pos);  //Posición en la matriz
      lcd.setCursor(13, 1);
      lcd.write(Tecles[Pos]);
      C = false;
      D = false;
      }  
    }
     if (time-t>8){ // Tengo que esperar 8 ms para registrar nuevamente
        C = true;
        D = true;
     }
  
//****** Tecla pulsada *******************
    // Enter
  if(E == false){
    if(digitalRead(pinEnt) == LOW){
      E = true;
    }
  }


  if(E == true){
    if(digitalRead(pinEnt) == HIGH){
      Serial.println(Tecles[Pos]);
      Keyboard.begin();
      Keyboard.write(Tecles[Pos]);
      delay(200);
      E = false;
    }
  } 
}
/*
  Keyboard.h
 
  Copyright (c) 2015, Arduino LLC
  Original code (pre-library): Copyright (c) 2011, Peter Barrett
 
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
 
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
 
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
 
#ifndef KEYBOARD_h
#define KEYBOARD_h
 
#include "HID.h"
 
#if !defined(_USING_HID)
 
#warning "Using legacy HID core (non pluggable)"
 
#else
 
//================================================================================
//================================================================================
//  Keyboard
 
#define KEY_LEFT_CTRL   0x80
#define KEY_LEFT_SHIFT    0x81
#define KEY_LEFT_ALT    0x82
#define KEY_LEFT_GUI    0x83
#define KEY_RIGHT_CTRL    0x84
#define KEY_RIGHT_SHIFT   0x85
#define KEY_RIGHT_ALT   0x86
#define KEY_RIGHT_GUI   0x87
 
#define KEY_UP_ARROW    0xDA
#define KEY_DOWN_ARROW    0xD9
#define KEY_LEFT_ARROW    0xD8
#define KEY_RIGHT_ARROW   0xD7
#define KEY_BACKSPACE   0xB2
#define KEY_TAB       0xB3
#define KEY_RETURN      0xB0
#define KEY_ESC       0xB1
#define KEY_INSERT      0xD1
#define KEY_DELETE      0xD4
#define KEY_PAGE_UP     0xD3
#define KEY_PAGE_DOWN   0xD6
#define KEY_HOME      0xD2
#define KEY_END       0xD5
#define KEY_CAPS_LOCK   0xC1
#define KEY_F1        0xC2
#define KEY_F2        0xC3
#define KEY_F3        0xC4
#define KEY_F4        0xC5
#define KEY_F5        0xC6
#define KEY_F6        0xC7
#define KEY_F7        0xC8
#define KEY_F8        0xC9
#define KEY_F9        0xCA
#define KEY_F10       0xCB
#define KEY_F11       0xCC
#define KEY_F12       0xCD
 
//  Low level key report: up to 6 keys and shift, ctrl etc at once
typedef struct
{
  uint8_t modifiers;
  uint8_t reserved;
  uint8_t keys[6];
} KeyReport;
 
class Keyboard_ : public Print
{
private:
  KeyReport _keyReport;
  void sendReport(KeyReport* keys);
public:
  Keyboard_(void);
  void begin(void);
  void end(void);
  size_t write(uint8_t k);
  size_t press(uint8_t k);
  size_t release(uint8_t k);
  void releaseAll(void);
};
extern Keyboard_ Keyboard;
 
#endif
#endif
/*
  Keyboard.cpp
 
  Copyright (c) 2015, Arduino LLC
  Original code (pre-library): Copyright (c) 2011, Peter Barrett
 
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
 
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
 
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
 
#include "Keyboard.h"
 
#if defined(_USING_HID)
 
//================================================================================
//================================================================================
//  Keyboard
 
static const uint8_t _hidReportDescriptor[] PROGMEM = {
 
  //  Keyboard
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)  // 47
    0x09, 0x06,                    // USAGE (Keyboard)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x85, 0x02,                    //   REPORT_ID (2)
    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
 
  0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
    0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
 
  0x95, 0x08,                    //   REPORT_COUNT (8)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)
 
  0x95, 0x06,                    //   REPORT_COUNT (6)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
 
  0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
    0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
    0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
    0xc0,                          // END_COLLECTION
};
 
Keyboard_::Keyboard_(void)
{
  static HIDSubDescriptor node(_hidReportDescriptor, sizeof(_hidReportDescriptor));
  HID().AppendDescriptor(&node);
}
 
void Keyboard_::begin(void)
{
}
 
void Keyboard_::end(void)
{
}
 
void Keyboard_::sendReport(KeyReport* keys)
{
  HID().SendReport(2,keys,sizeof(KeyReport));
}
 
extern
const uint8_t _asciimap[128] PROGMEM;
/*
 * _asciimap took from Keyboard.cpp,
 * need somebody to test with spansih layout.
 */
 
#define SHIFT 0x80
const uint8_t _asciimap[128] =
{
  0x00,             // NUL          0
  0x00,             // SOH
  0x00,             // STX
  0x00,             // ETX
  0x00,             // EOT
  0x00,             // ENQ
  0x00,             // ACK
  0x00,             // BEL
  0x2a,      // BS  Backspace
  0x2b,      // TAB  Tab
  0x28,      // LF  Enter           10
  0x00,             // VT
  0x00,             // FF
  0x00,             // CR
  0x00,             // SO
  0x00,             // SI
  0x00,             // DEL
  0x00,             // DC1
  0x00,             // DC2
  0x00,             // DC3
  0x00,             // DC4          20
  0x00,             // NAK
  0x00,             // SYN
  0x00,             // ETB
  0x00,             // CAN
  0x00,             // EM
  0x00,             // SUB
  0x00,             // ESC
  0x00,             // FS
  0x00,             // GS
  0x00,             // RS           30
  0x00,             // US
 
  0x2c,          //  ' '
  0x1e|SHIFT,    // !
  0x1f|SHIFT,    // "
    0x20,        // # 
  0x21|SHIFT,    // $
  0x22|SHIFT,    // %
  0x23|SHIFT,    // &
  0x2d,    // '
  0x25|SHIFT,    // (               40
  0x26|SHIFT,    // )
  0x30|SHIFT,    // *
  0x30,          // +
  0x36,          // ,
  0x38,          // -
  0x37,          // .    
  0x24|SHIFT,    // /
  0x27,          // 0
  0x1e,          // 1
  0x1f,          // 2               50
  0x20,          // 3
  0x21,          // 4
  0x22,          // 5
  0x23,          // 6
  0x24,          // 7
  0x25,          // 8
  0x26,          // 9
  0x37|SHIFT,      // :
  0x36|SHIFT,      // ;
    0x64,         // <             60
  0x27|SHIFT,      // =    
  0x64|SHIFT,      // > 0x64|SHIFT,
  0x2d|SHIFT,      // ?
    0x1f,            // @   
  0x04|SHIFT,      // A
  0x05|SHIFT,      // B
  0x06|SHIFT,      // C
  0x07|SHIFT,      // D
  0x08|SHIFT,      // E
  0x09|SHIFT,      // F             70
  0x0a|SHIFT,      // G
  0x0b|SHIFT,      // H
  0x0c|SHIFT,      // I
  0x0d|SHIFT,      // J
  0x0e|SHIFT,      // K
  0x0f|SHIFT,      // L
  0x10|SHIFT,      // M
  0x11|SHIFT,      // N
  0x12|SHIFT,      // O
  0x13|SHIFT,      // P             80
  0x14|SHIFT,      // Q
  0x15|SHIFT,      // R
  0x16|SHIFT,      // S
  0x17|SHIFT,      // T
  0x18|SHIFT,      // U
  0x19|SHIFT,      // V
  0x1a|SHIFT,      // W
  0x1b|SHIFT,      // X
  0x1c|SHIFT,      // Y
  0x1d|SHIFT,      // Z             90
  0x2f,          // [
  0x31,          // bslash 
  0x30,          // ]
    0x94|SHIFT,          // ^
  0x38|SHIFT,    // _
  0x2e|SHIFT,    // `    
  0x04,          // a
  0x05,          // b
  0x06,          // c
  0x07,          // d               100
  0x08,          // e
  0x09,          // f
  0x0a,          // g
  0x0b,          // h
  0x0c,          // i
  0x0d,          // j
  0x0e,          // k
  0x0f,          // l
  0x10,          // m
  0x11,          // n               110
  0x12,          // o
  0x13,          // p
  0x14,          // q
  0x15,          // r
  0x16,          // s
  0x17,          // t
  0x18,          // u
  0x19,          // v
  0x1a,          // w
  0x1b,          // x               120
  0x1c,          // y
  0x1d,          // z
  0x34,    // {
    0x38|SHIFT,   // |
  0x32,    // }
  0x21,    // ~
  0        // DEL                   127
};
 
// Init var         
bool _altGrMap[128];
bool _altFine = false;
 
// Individually define all needed char
void initAltGr() {
  _altFine = true;
 
  _altGrMap[126] = true; // ~
  _altGrMap[123] = true; // {
  _altGrMap[91] = true;  // [
  _altGrMap[93] = true;  // ]
  _altGrMap[125] = true; // }
  _altGrMap[92] = true;  // bslash
  _altGrMap[124] = true; // |
  _altGrMap[64] = true;  // @
  _altGrMap[35] = true; // #   35
  _altGrMap[94] = true; // ^
  _altGrMap[96] = true; // `
 }
 
uint8_t USBPutChar(uint8_t c);
 
// press() adds the specified key (printing, non-printing, or modifier)
// to the persistent key report and sends the report.  Because of the way
// USB HID works, the host acts like the key remains pressed until we
// call release(), releaseAll(), or otherwise clear the report and resend.
size_t Keyboard_::press(uint8_t k)
{
  uint8_t i;
  if (k >= 136) {      // it's a non-printing key (not a modifier)
    k = k - 136;
  } else if (k >= 128) {  // it's a modifier key
    _keyReport.modifiers |= (1<<(k-128));
    k = 0;
  } else {        // it's a printing key
    int oldKey = k;
    k = pgm_read_byte(_asciimap + k);
    if (!k) {
      setWriteError();
      return 0;
    }
    if (k & 0x80) {            // it's a capital letter or other character reached with shift
      _keyReport.modifiers |= 0x02;  // the left shift modifier
      k &= 0x7F;
    }
 
    if (!_altFine)
      initAltGr();
    if (_altGrMap[oldKey])
      _keyReport.modifiers |= 0x40;
  }
 
  // Add k to the key report only if it's not already present
  // and if there is an empty slot.
  if (_keyReport.keys[0] != k && _keyReport.keys[1] != k &&
    _keyReport.keys[2] != k && _keyReport.keys[3] != k &&
    _keyReport.keys[4] != k && _keyReport.keys[5] != k) {
 
    for (i=0; i<6; i++) {
      if (_keyReport.keys[i] == 0x00) {
        _keyReport.keys[i] = k;
        break;
      }
    }
    if (i == 6) {
      setWriteError();
      return 0;
    }
  }
  sendReport(&_keyReport);
  return 1;
}
 
// release() takes the specified key out of the persistent key report and
// sends the report.  This tells the OS the key is no longer pressed and that
// it shouldn't be repeated any more.
size_t Keyboard_::release(uint8_t k)
{
  uint8_t i;
  if (k >= 136) {      // it's a non-printing key (not a modifier)
    k = k - 136;
  } else if (k >= 128) {  // it's a modifier key
    _keyReport.modifiers &= ~(1<<(k-128));
    k = 0;
  } else {        // it's a printing key
    int oldKey = k;
    k = pgm_read_byte(_asciimap + k);
    if (!k) {
      return 0;
    }
    if (k & 0x80) {              // it's a capital letter or other character reached with shift
      _keyReport.modifiers &= ~(0x02);  // the left shift modifier
      k &= 0x7F;
    }
 
    if (_altGrMap[oldKey])
      _keyReport.modifiers &= ~(0x40);
  }
 
  // Test the key report to see if k is present.  Clear it if it exists.
  // Check all positions in case the key is present more than once (which it shouldn't be)
  for (i=0; i<6; i++) {
    if (0 != k && _keyReport.keys[i] == k) {
      _keyReport.keys[i] = 0x00;
    }
  }
 
  sendReport(&_keyReport);
  return 1;
}
 
void Keyboard_::releaseAll(void)
{
  _keyReport.keys[0] = 0;
  _keyReport.keys[1] = 0;
  _keyReport.keys[2] = 0;
  _keyReport.keys[3] = 0;
  _keyReport.keys[4] = 0;
  _keyReport.keys[5] = 0;
  _keyReport.modifiers = 0;
  sendReport(&_keyReport);
}
 
size_t Keyboard_::write(uint8_t c)
{
  uint8_t p = press(c);  // Keydown
  release(c);            // Keyup
  return p;              // just return the result of press() since release() almost always returns 1
}
 
Keyboard_ Keyboard;
 
#endif

Descarga de los ficheros

No debes olvidar de incluir los tres ficheros en la misma carpeta.