Concevoir un clavier : logiciel embarqué

De Disposition de clavier bépo
Attention

En construction

Retour vers Concevoir un clavier

TMK

Pour programmer un microcontrolleur sans réinventer la roue, le mieux est de se reporter à un projet existant. TMK est relativement complet et flexible, il devrait pouvoir être adapté à la majorité des projet. La documentation est relativement claire, elle est à lire avant de se lancer dans un projet de développement.

C : pages et pointeurs de fonctions

Une technique simple est d'enregistrer le mappage des touches dans des «pages» représentées dans le code par des tableaux. Les majuscules et les minuscules ont chacune une page.

En utilisant des tableaux de pointeurs, il est possible qu'une touche donne accès à un caractère, une chaine ou une fonction.

TODO exemple d'utilisation des pointeurs de fonctions

Teensy

Les différentes «pages» de configuration de touches prennent pas mal de place en RAM. Lorsqu'il y en a trop, ça dépasse la capacité du processeur qui donne des résultats imprévus. Il faut alors stocker ces pages dans la mémoire de programmation (PROGMEM) et utiliser des fonctions spéciales pour y accéder. La Tensy 2++ ou 3 ont une mémoire vive plus importante qui peut éviter l'utilisation de PROGMEM.

TODO exemple d'utilisation PROGMEM

USB

  • type de périphérique (clavier, joystick, souris, stockage)
  • codage des caractères

Lecture PS2

La lecture des trames PS2 d'une puce de clavier peut être réalisée grâce à la bibliothèque PS2Keyborard http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html . S'il ne s'agit pas de transmettre directement un code via le port USB, certaines adaptations peuvent être nécessaire.

TODO relire le code pour vérifier

Commande IO expander

Le code suivant est destiné à piloter un MCP23017 mais peut être facilement adapté pour les autres composants de la même famille. Ce sont des extensions de port commandées par un bus I2C. Pour piloter ce bus à partir d'un microcontroleur (teensy, arduino) la bibliothèque I2C.h (https://github.com/rambo/I2C) est plus facile à utiliser que wire.h. C'est donc celle qui sera utilisée dans l'exemple ci après qui est donné à titre d'illustration, ce n'est pas un code fonctionnel.

Le schéma suivant est un exemple de montage destiné à illustrer le code qui suit (à confirmer avec un teensy 2.0, en fait seulement testé avec un teensy 2.0++)

Proposition cablage MCP23017.png.

Il faut d'abord définir les adresses spécifiques au MCP23017 (voir datasheet du composant )

#define IODIRA   0x00   // IO direction  (0 = output, 1 = input (Default))
#define IODIRB   0x01
#define IOPOLA   0x02   // IO polarity   (0 = normal, 1 = inverse)
#define IOPOLB   0x03
#define GPINTENA 0x04   // Interrupt on change (0 = disable, 1 = enable)
#define GPINTENB 0x05
#define DEFVALA  0x06   // Default comparison for interrupt on change (interrupts on opposite)
#define DEFVALB  0x07
#define INTCONA  0x08   // Interrupt control 
                        //(0 = interrupt on change from previous, 1 = interrupt on change from DEFVAL)
#define INTCONB  0x09
#define IOCON    0x0A   // IO Configuration: bank/mirror/seqop/disslw/haen/odr/intpol/notimp
//#define IOCON 0x0B  // same as 0x0A
#define GPPUA    0x0C   // Pull-up resistor (0 = disabled, 1 = enabled)
#define GPPUB    0x0D
#define INFTFA   0x0E   // Interrupt flag (read only) : (0 = no interrupt, 1 = pin caused interrupt)
#define INFTFB   0x0F
#define INTCAPA  0x10   // Interrupt capture (read only) : value of GPIO at time of last interrupt
#define INTCAPB  0x11
#define GPIOA    0x12   // Port value. Write to change, read to obtain value
#define GPIOB    0x13
#define OLLATA   0x14   // Output latch. Write to latch output.
#define OLLATB   0x15

On définit ensuite les adresses spécifiques au montage. Ici le clavier comporte 48 touches, c'est suffisant pour un clavier en deux parties.

#define MCP23017_ADDR 0x20 // En fonction du cablage de ses pattes d'adresse, 
                           //le composant peut prendre son adresse de  0.20 à 0x27
#define MCP23017_ROW 6
#define MCP23017_COL 8
#define MCP23017_NB  MCP23017_ROW * MCP23017_COL

Le composant est ensuite initialisé avant sa première utilisation :

void init_mcp23_kbd(){
  // direction 
  I2c.write(MCP23017_ADDR,IODIRA,0x00); // le port A est utilisé comme sortie
  I2c.write(MCP23017_ADDR,IODIRB,0xFF); // le port B est utilisé comme entrée
  // enable pull-up on switches
  I2c.write(MCP23017_ADDR,GPPUB,0xFF); // pour détecter quand une touche est relachée
  // invert polarity
  I2c.write(MCP23017_ADDR,IOPOLA, 0xFF); // pour avoir un 1 quand la touche est enfoncée
  I2c.write(MCP23017_ADDR,IOPOLB, 0xFF); 
  // enable interrupts
  // (GPINTENA, 0xFF); // enable interrupts - both ports  // pour l'instant, pas d'utilisation des interruptions
  // no interrupt yet
  // keyPressed = false
  // read from interrupt capture ports to clear them
  // Read (INTCAPA);
  // Read (INTCAPB);
}

Ensuite la boucle active les rangs alternativement et lit le résultat sur les colonnes :

void loop_mcp23_kbd(){
  int index = 0 ;
  for (int i = 0;i<MCP23017_ROW; i++) { 
    I2c.write(MCP23017_ADDR,GPIOA,~(1<<i));
    I2c.read(MCP23017_ADDR,GPIOB,2); // (pourquoi 2 ?)
    int tot= I2c.receive();
    for (int j = 0;j<MCP23017_COL; j++) { 
      //code de gestion des touches
      if (tot & (1<<j) ) {          
         index = j*MCP23017_ADRR_ROW+i ;
         Serial.print("touche : ");  Serial.print(index); Serial.println(" appuyée ");  
      } 
    }
  }  
}

Commande registre à décalage

Pilotage d'éléments annexes

  • I2C
  • série
  • parallèle



Concevoir un clavier :