Le clavier PC et son interface
A partir de 1997 j'ai commencé à écrire des articles dans le magazine "Electronique Pratique" puis dans son Hors Série "Interfaces PC". Comme son nom l'indique (ou plutôt l'indiquait) ce hors série était dédié à l'expérimentation de montages autour des différentes interfaces disponibles sur un PC. A l'époque les deux interfaces massivement utilisées pour faire communiquer un PC avec de l'électronique externe étaient le port série (RS232) et le port parallèle (LPT). Arriva ensuite le port USB auquel j'ai consacré plusieurs montages puis un ouvrage "L'USB pour tous" (Editions DUNOD-ETSF)
Au cours de ces différents travaux je me suis intéressé à la communication entre un clavier et un PC, notemment dans le but de réutiliser le clavier PC comme interface d'entrée pour des montages microcontrôlés.
Quelques années plus tard j'ai repris ces travaux pour proposer un petit montage très facile à réaliser permettant de faire comprendre, à un public de lycée, ce qu'est une communication numérique et "voir", avec un oscilloscope numérique ou une interface Exao, ce qui se passe lorsque l'on frappe la touche d'un clavier. On aura alors la surprise de voir que la touche "A" d'un clavier Azerty ou la touche "Q" d'un clavier Qwerty génèrent le même signal électrique... expliquant par là même, pourquoi au tout début du démarrage de l'ordinateur le clavier Azerty répond comme un clavier Qwerty (il faut attendre la prise en charge par le système d'exploitation pour retrouver la bonne interprétation des touches frappées)
On trouvera ci-dessous l'ensemble de ces travaux :
- l'article originel
- les compléments (vidéos, programme de communication avec un microcontrôleur)
- L'activité de découverte des scancodes émis par le clavier
- le montage à réaliser pour cette activité
L'article
L'article ci-dessous a été rédigé pour le numéro 6 du magazine Electronique Pratique - Interfaces et développements PC, en mai 2000.
Cet article permet de découvrir une liaison série de type point à point entre un ordinateur et un clavier PC/AT. Cette communication synchrone (un signal d'horloge est véhiculé sur un fil à part des données) permet de s'initier à la communication entre deux objets numériques.
L'article décrit de plus l'interfaçage du clavier avec un microcontrôleur (un 68HC11).
Le code en assembleur (pour le 68HC11) est fourni et commenté dans l'onglet "Compléments".
Compléments
Ces deux vidéos montrent le montage en action :
Le clavier PC est relié au micrcontrôleur. Celui-ci est également relié à un afficheur LCD à deux lignes de caractères. Un programme en assembleur a été injecté dans le micrcontrôleur pour :
- envoyer des codes au clavier pour activer l'une ou l'autre des Leds du clavier (visible sur la deuxième vidéo)
- capturer les signaux électriques provenant du clavier (horloge et données)
- interpréter au moment voulu le niveau sur la ligne de données (0 ou 1)
- extraire l'octet
- l'afficher sur le LCD
1- Décodage de la succession de touches AZERT :
2- Envois de codes vers le clavier pour allumer les LEDs du clavier puis décodage de quelques touches :
Le code source en assembleur (pour 68HC11) :
* dec_cla2.a11
*
* Programme permettant d'afficher sur écran LCD deux lignes de
* 16 caractères les codes émis par le clavier PC ainsi que de lui
* envoyer des instructions : Reset du clavier puis allumage
* des Leds du clavier
* V.LE-MIEUX (Janvier 2000)
* LCD : Data sur PORTB (8 bits)
* LCD : E sur PA4
* LCD : RS sur PA5
*
* Clavier : Données sur PC7
* Clavier : horloge sur PC6
#include Mes_Def.A11 ;fichier de définitions des ports/
;ce fichier doit être dans le même répertoire
DON equ %10000000 ;Données du clavier = bit 7 (du portC)
HORL equ %01000000 ;Horloge clavier = bit 6 (du portC)
************************************************************
* *
* Réservations de mémoires de travail *
* *
************************************************************
org $02
NL rmb 1 ;Nø de ligne du LCD
NCAR rmb 1 ;Nbre de caractères affichés
POSIT rmb 1 ;position du caractère dans la ligne
DEL rmb 1 ;valeur de Delai
SCAN rmb 1 ;octet = scancode émis
CARAC rmb 2 ;les 2 caractères de l'octet décodé(en hexa)
POS rmb 1
BIT_P rmb 1 ;pour compter les bits à 1 envoyés
*****************************************************************
* *
* DEBUT DU PROGRAMME *
* *
*****************************************************************
org $F800
DEBUT cli
lds # $E8
bset PIOC,x %00100000 ;PortC en Drain ouvert
ldx # $E8
clra
BOUC dex ;efface la RAM disponible
staa 0,x
cpx # $02
bne BOUC
ldx # $1000
*****************************************************************
* CARACTERISTIQUES DE L'AFFICHEUR LCD *
* *
* On définit ici sur quels ports se trouvent les *
* données (DATA) et le contrôle (CONTR) à envoyer sur *
* l'afficheur, puis sur quelles lignes du port de contrôle*
* se trouvent E et RS *
* TYPE = 2 (afficheur 2 lignes de 16 caractères) * *
*****************************************************************
DATA EQU PORTB ;définit le port des données (ici PORTB)
CONTR EQU PORTA ; " " " de contrôle (ici PORTA)
RS EQU PA5 ;définit les lignes du port de contrôle...
E EQU PA4 ;...pour les signaux E et RS
TYPE EQU 2 ;définit le type d'afficheur
*****************************************************************
* *
* Assemblage conditionnel portant sur le choix de *
* branchement de l'afficheur LCD = *
* *
*****************************************************************
#IF DATA == PORTC
bset DDRC,x $FF
#ENDIF
#IF CONTR == PORTC
bset DDRC,x E
bset DDRC,x RS
#ENDIF
#IF CONTR == PORTD
bset DDRD,x E
bset DDRD,x RS
#ENDIF
#IF E == PA7
bset PACTL,x E
#ENDIF
#IF RS == PA7
bset PACTL,x RS
#ENDIF
* initialisation de l'afficheur =
INIT ldaa # %00111000 ;2lignes;8bits;matrice 5x10
jsr A_LCDIN
ldaa # %00001100 ;afficheur:on ; curseur:off et ne clignote pas
jsr A_LCDI
ldaa # %00000110 ;direction du curseur
jsr A_LCDI
ldaa # %00000001 ;effacement de l'écran
jsr A_LCDIN
ldaa # %00000010 ;curseur en position initiale
jsr A_LCDIN
ldy #ECRAN1 ;affichage d'un écran de présentation
jsr A_FLCD
ldaa #5
staa DEL
jsr A_TTEN
ldy #ECRAN2
jsr A_FLCD
jsr A_TTEN
ldaa # 1 ;effacement de l'écran
jsr A_LCDI
*****************************************************************
* Exemple d'envoi d'instructions *
* au clavier par le 68HC11 : instruction de Reset *
* *
*****************************************************************
RESET ldaa # $FF ;fait un reset du clavier
jsr INSTR
jsr RECEP
jsr CONV
LEDS ldaa # $ED ;Contrôle des leds
jsr INSTR
ldaa # $01 ;allume Scroll Lock seule
jsr INSTR
ldaa # $ED ;Contrôle des leds
jsr INSTR
ldaa # $02 ;allume Num Lock seule
jsr INSTR
ldaa # $ED ;Contrôle des leds
jsr INSTR
ldaa # $04 ;allume Caps Lock seule
jsr INSTR
ldaa # $ED ;Contrôle des leds
jsr INSTR
ldaa # $07 ;allume les 3 leds
jsr INSTR
ldaa # $ED ;Contrôle des leds
jsr INSTR
ldaa # $00 ;éteint les 3 Leds
jsr INSTR
BCL jsr RECEP ;recevoir les données du clavier
jsr CONV
bra BCL
*********************************************************
* Routine de conversion de SCAN en ASCII *
* pour afficheur LCD et affichage *
*********************************************************
CONV ldaa # %00001111 ;traitement du premier nibble
anda SCAN ;de l'octet SCAN reçu
cmpa #9 ; chiffre ou lettre ??
bhi LETTRE
adda # $30 ;ajouter $30 pour afficher le chiffre
staa CARAC+1
bra AUTRE
LETTRE adda # $37 ;sinon ajouter $37 pour une lettre
staa CARAC+1
AUTRE ROR SCAN ;traitement du 2ème nibble de l'octet reçu
ROR SCAN ;on décale 4 fois à droite
ROR SCAN
ROR SCAN
ldaa # %00001111
anda SCAN
cmpa #9 ;chiffre ou lettre ??
bhi LETTRE2
adda # $30 ;ajouter $30 pour afficher le chiffre
staa CARAC
bra A_SCAN
LETTRE2 adda # $37 ;sinon ajouter $37 pour une lettre
staa CARAC
A_SCAN ldaa CARAC ;affichage des deux caractères
jsr A_LCDCH
ldaa CARAC+1
jsr A_LCDCH
ldaa POS
inca
staa POS
cmpa # 8
blo REC ;si 1ère ligne incomplète,attendre autre octet
cmpa # 9
bhs DECAL
ldaa # $C0 ;passer à la ligne suivante
jsr A_LCDI
DECAL ldaa POS
cmpa # 16
bhi NOUV ;passer à l'écran suivant
bra REC
NOUV ldaa # 1 ;effacement de l'écran
jsr A_LCDI
staa DEL
jsr A_TTEN
clr CARAC
clr CARAC+1
clr POS
REC rts
*********************************************************
* *
* Routine de communication Vers le clavier *
* *
*********************************************************
INSTR jsr ENVOI
jsr RECEP
jsr CONV
ldy # $FFFF
jsr DELAI
rts
ENVOI bclr DDRC,x %11000000
clr BIT_P
bclr PORTC,x %11000000 ;prépare HORL et DON à 0
bset DDRC,x HORL ;HORLOGE en sortie et donc à 0
ldy # 20
jsr DELAI
bset DDRC,x DON ;Donnée en sortie et donc à 0
BR1 ldy # 30
jsr DELAI
bclr DDRC,x HORL ;ligne Horloge en entrée
brclr PORTC,x HORL * ; attendre ici que Horloge passe à 1
brset PORTC,x HORL * ; " ici que Horloge passe à 0
ldab # 8
OCTET brclr PORTC,x HORL * ; attendre ici que Horloge passe à 1
rora
bcs UN_EMI
bset DDRC,x DON ;ligne Donnée en sortie donc = 0
bra HORL_1
UN_EMI bclr DDRC,x DON ; " " " entrée donc = 1
inc BIT_P
HORL_1 brset PORTC,x HORL * ; " ici que Horloge passe à 0
decb
bne OCTET
brclr PORTC,x HORL * ; attendre ici que Horloge passe à 1
ror BIT_P ;récupère le LSB
bcs IMPAIR ;si =1 alors Nbre de bit impair
bclr DDRC,x DON ;sinon nbre de bit pair ->parité = 1
bra HORL_2
IMPAIR bset DDRC,x DON ; ->parité = 0
HORL_2 brset PORTC,x HORL * ; " ici que Horloge passe à 0
brclr PORTC,x HORL * ; " ici que Horloge passe à 1
bclr DDRC,x DON ;bit de stop
brset PORTC,x DON * ; " ici que DONNEE passe à 0(ACK)
brclr PORTC,x HORL * ; " ici que Horloge passe à 1
; (acquittement du clavier)
brclr PORTC,x DON * ; " ici que DONNEE passe à 1
bclr DDRC,x %11000000
rts
*********************************************************
* *
* Routine de réception des données *
* en provenance du clavier *
* *
*********************************************************
RECEP bclr DDRC,x %11000000 ;Horloge et Donnée en entrées
brset PORTC,x DON * ;attendre ici que Donnée passe à 0
brset PORTC,x HORL * ; " ici que Horloge passe à 0
* Le clavier va commencer à émettre des donnés
ldaa #8 ;8 bits à recevoir
ldab #0
clr SCAN
REC_D ror SCAN ;décalage de bit : rotation à droite
brclr PORTC,x HORL * ;attendre ici que Horloge passe à 1
brset PORTC,x HORL * ;attendre ici que Horloge passe à 0
brset PORTC,x DON UN ;si le bit lu vaut un
bclr SCAN %10000000 ;sinon il vaut zero
bra ENCORE
UN bset SCAN %10000000 ;le bit vaut 1
ENCORE deca
bne REC_D ;attendre le bit suivant si bit 8 non
;encore reçu
****************************
* Réception du bit de parité :
****************************
REC_P brclr PORTC,x HORL * ;attendre ici que Horloge passe à 1
brset PORTC,x HORL * ;attendre ici que Horloge passe à 0
*******************************
* Réception du bit de stop : *
*******************************
REC_S brclr PORTC,x HORL * ;attendre ici que Horloge passe à 1
brset PORTC,x HORL * ;attendre ici que Horloge passe à 0
brclr PORTC,x DON * ;attendre ici le bit de stop
rts
*********************************************************
* *
* Routines de gestion de l'afficheur LCD : *
* *
* - envoi de caractères A_LCDCH *
* - envoi d'instructions A_LCDI *
* - affichage d'une ligne complète A_FLIGN *
* - " de quelques caractères A_FPART *
* - délais : A_TTEN et DELAI *
*********************************************************
A_FLIGN ldaa # 0 ;affichage d'une ligne complète
staa POSIT
ldab #TYPE
cmpb # 2
beq A_TYPE2
ldab # 9
bra A_FS
A_TYPE2 ldab # 17
A_FS stab NCAR
bra A_FL
A_FPART ldab NCAR ;affichage de quelques caractères en position
incb ; quelconque sur une ligne
stab NCAR
A_FL ldaa NL
cmpa # 2
beq A_DL2
ldaa POSIT
adda # $80 ;ligne 1
bra A_ENVOI
A_DL2 ldaa POSIT
adda # $C0 ;ligne 2
A_ENVOI jsr A_LCDI
A_ENVOI1 ldaa 00,y
decb
bne A_FCHAR
rts
A_FCHAR jsr A_LCDCH
iny
bra A_ENVOI1
*sous programme d'affichage complet (1 ligne de 16 caractères)
A_FLCD ldaa # 1
staa NL
jsr A_FLIGN
ldaa # 2
staa NL
jsr A_FLIGN
rts
* sous programme d'envoi d'instructions
A_LCDIN pshy
bclr CONTR,x RS ; RS=0 ->instruction
staa DATA,x
bset CONTR,x E ; E=1 ->valide LCD
ldy # 100
jsr DELAI
bclr CONTR,x E ; E=0 ->invalide LCD
ldy # 100
jsr DELAI
puly
rts
* sous programme d'envoi d'instructions (délai court)
A_LCDI pshy
bclr CONTR,x RS ; RS=0 ->instruction
staa DATA,x
bset CONTR,x E ; E=1 ->valide LCD
ldy # 40
jsr DELAI
bclr CONTR,x E ; E=0 ->invalide LCD
ldy # 40
jsr DELAI
puly
rts
* sous programme d'envoi de caractères
A_LCDCH pshy
bset CONTR,x RS ; RS=1 ->instruction
staa DATA,x
bset CONTR,x E ; E=1 ->valide LCD
ldy # 40
jsr DELAI
bclr CONTR,x E ; E=0 ->invalide LCD
ldy # 40
jsr DELAI
puly
rts
* sous programmes de delai
A_TTEN ldaa DEL
pshy
A_BCL1 ldy # $FFFF
jsr DELAI
deca
bne A_BCL1
puly
rts
DELAI dey
bne DELAI
rts
; Programmation en EEPROM de quelques écrans
ECRAN1 fcb 'DECODAGE CLAVIER PC (VLM 2000) '
ECRAN2 fcb ' JEU DE CODES CLAVIER Num.2 '
Activité : décodage clavier
Etude d'une transmission numérique : le clavier PC
Un ancien clavier de PC est un moyen simple pour faire découvrir une transmission numérique à des étudiants.
En effet, c'est l'appui sur une touche qui déclenche l'envoi de la donnée. Cette donnée est codée sur un octet (encapsulé entre un bit de start et un bit de stop, avec de plus un bit de contrôle de parité). La vitesse de transmission relativement faible permet d'obtenir un relevé avec un oscilloscope numérique, mais aussi avec une console d'acquisition EXAO.
Le schéma du montage :
Un générateur délivrant une tension de 5 volts, est branché entre C4 et C2
Lors de l'appui sur une touche, le clavier émet :
- un signal d'horloge que l'on récupère entre C1 et C2
- un signal de donnée que l'on récupère entre C3 et C2.
Observé à l'oscilloscope numérique, l'appui sur la touche "A" d'un clavier AZERTY donne l'oscillogramme suivant :
Dans la partie inférieure de l'oscillogramme, on voit le signal d'horloge généré par le clavier. Il s'agit d'un signal carré d'amplitude 5 volts (égale à la tension d'alimentation) dont la fréquence est de l'ordre de 13 kHz. Ce signal d'horloge indique au récepteur (le PC) à quel moment il doit lire le niveau électrique sur la ligne de donnée : le bit de donnée est valide après la retombée à zéro du signal d'horloge. La durée d'un bit de donnée est donc égale à la période du signal d'horloge
Dans la partie supérieure c'est le signal de donnée dont voici les caractéristiques :
- cette ligne de donnée reste à 5 volts tout le temps qu'une touche n'a pas été pressée.
- l'appui sur une touche entraîne une retombée de cette ligne au niveau 0 : c'est le bit de Start
- ensuite arrivent les 8 bits de donnée, qui constituent alors l'octet de donnée. Cet octet a une valeur qui dépend de la touche pressée. Le bit de poids faible est émis après le bit de Start.
- juste après le bit de poids fort est émis un bit de contrôle de parité qui permet de vérifier l'intégrité de la donnée.
- puis la ligne de donnée reviens au niveau haut (5 volts)
Lecture de la donnée : Ici, l'octet de donnée est 000010101 soit 0x15 (hexadécimal)
Contrôle de parité : parité impaire : le bit de parité est positionné soit à 0 soit à 1 de telle sorte que le nombre de bits à 1 soit impair. Ici la donnée contient 3 bits à 1, donc le bit de parité est mis à 0. A la réception, le PC vérifie ce bit de parité. S'il n'est pas conforme, c'est qu'un des bits a été inversé eu cours de transmission. (Cela ne vérifie pas les grosses erreurs de transmission telles que l'inversion de deux bits de l'octet de données)
Ci-dessous deux acquisitions réalisées avec un oscilloscope numérique (Rigol). L'acquisition est très simple à réaliser :
- base de temps de 100 µs/div (car l'observation d'une trame nécessite une durée de l'ordre d'une milliseconde)
- mode monocoup ; trigger sur le signal d'horloge en sens desendant avec une valeur nférieure à 5 V
- sensibiliés verticales de 2V/div
Scancode de la touche CTRL droite :
Scancode de la touche CTRL gauche :
Rque : ces deux touches CTRL, émettent un code différent : le système d'exploitation pourra donc, si besoin, les distinguer l'une de l'autre.
Acquisition de trames clavier en Exao :
Le système utilisé ici est la console ESAO 4+ de Jeulin avec le logiciel Atelier Scientifique.
On peut en Exao faire un relevé similaire à ceux obtenus ci-dessus avec un oscilloscope numérique.
Pour obtenir le relevé ci-dessous, on a utilisé les réglages suivants :
- signal d'horloge et signal de donnée sur les entrées directes (acceptent jusqu'à 5 V ; le clavier étant alimenté avec une tension légèrement inférieure à 5 V)
- synchronisation sur le signal d'horloge en sens décroissant
- durée d'acquisition de 1 ms avec 500 points d'acquisition.
En travaillant sur une durée d'acquisition plus grande, on va pouvoir observer ce que transmet le clavier lorsque l'on relâche la touche. On a choisi ici une durée d'acquisition de 100 ms. Pour pouvoir ensuite zoomer, et voir des détails sur une durée de l'ordre de la milliseconde, il est nécessaire de prendre un grand nombre de points de mesure : ici 16000 points :
En zoomant dans la partie correspondant au relâchement de la touche, on constate que le clavier a envoyé deux octets de donnée :
- un premier pour signifier qu'un touche a été relâchée (code 11110000 en binaire soit 0xF0 en hexadécimal)
- le second pour indiquer quelle touche (ici le code de la touche A) :
L'appui sur le touche "A" donne donc :
- l'octet de donnée 000010101 soit 0x15 (hexadécimal)
- suivi lors du relâchement par :
- le code 11110000 en binaire soit 0xF0 en hexadécimal
- l'octet de donnée 000010101 soit 0x15 (hexadécimal)
Soit au final la séquence (en hexadécimal) : 15 F0 15 que l'on peut voir sur la vidéo dans l'onglet "Compléments" et dont voici une copie d'écran :
Le montage
Réalisation du montage :
La réalisation du montage sur circuit imprimé permet d'obtenir un montage plus fiable que lorsqu'il est réalisé de façon câblée, en particulier lorsque le montage est destiné à l'enseignement.
L'auteur utilise le logiciel KICAD, qui est un logiciel libre, pour réaliser ses circuits imprimés.
Le schéma théorique :
Un schéma pas difficile à comprende puisqu'il ne consiste qu'en du câblage.
Pour pouvoir utiliser différents types de claviers, on a câblé la connectique type DIN 5 broches, comme la connectique type mini-DIN 6 broches (utilisée sur des claviers plus récents ... ou plutôt moins anciens !)
Attention : ce montage utilise les anciens claviers qui équipaient les PC il y a plusieurs années (pas les claviers USB que l'on trouve aujourd'hui) : il faudra aller fouiller dans les caves ou les greniers pour en retrouver ...
Le clavier doit être alimenté par une tension de 5V maximum. Des essais avec une tension de 3V se sont révélés concluants. On peut envisager une alimentation par pile de 4,5 V. (Rque : le niveau haut du signal numérique délivré est lié à la tension d'alimentation : ainsi l'utilisation d'une alimentation de 4,5 V donne un niveau haut de 4,5V).
La montée en tension doit être franche pour assurer le reset du microcontrôleur qui se trouve intégré au clavier : le clavier démarre alors par un autotest qui se traduit par l'allumage de ses Leds. (Si on utilise un générateur de tension réglable, le prérégler à 5 V, l'éteindre, le connecter au montage puis le mettre en fonctionnement).
Le circuit imprimé :
Réalisé avec Kicad, deux versions sont proposées, différentes selon la connectique choisie pour les douilles bananes.
Version faible coût :
C'est celle que nous avons réalisée au lycée en une dizaine d'exemplaires :
Pour la réalisation de ce montage :
A gauche l'embâse de type DIN, à droite la mini-DIN
On pourra trouver ici le schéma du typon (au format Postscript qui respecte les dimensions) : clavier_pc4-Cuivre.ps
Ce schéma sera imprimé sur une feuille autocollante, puis collée sur le circuit imprimé. Pour la protéger, on pourra la recouvrir d'une feuille de transparent, tenue par les différents composants (Cf photo ci-dessus).
Remarques :
- le fichier du typon représente trois fois le circuit imprimé, ce qui permet l'insolation en une seule fois de trois montages sur une plaque de circuit imprimé de dimensions (100x160 mm) ; celui de la face avant présente cinq faces avant à tirer sur une feuille A4 de papier autocollant.
- le montage propose la possibilité de connectecter un clavier à fiche DIN ou un clavier à fiche mini DIN : on pourra ne monter que l'une ou l'autre de ces fiches selon le type de clavier que l'on aura récupérés le type mini-DIN étant le plus récent
Matériel :
- une plaque de circuit imprimé (100x160mm) (pour trois montages)
- une embâse DIN 5 broches 45° pour circuit imprimé :
- - une embâse miniDIN 6 broches pour circuit imprimé :
- - des douilles 4 mm pour fiches bananes :
(elles sont vendues par lot de 100 : une quarantaine seront nécéssaires pour la réalisation d'une dizaine de montages)
- la version "DeLuxe" :
Elle utilise des embâse pour fiche banane de la marque Deltron : . Ces embâses sont disponibles en différentes couleurs.
Le circuit imprimé :