CODING ★ GESTION DU CLAVIER SOUS INTERRUPTION ★

Keyboard - Gestion du Clavier Sous Interruption|SOS Programmeurs)

Les routines système du CPC  concernant  le clavier utilisent abondamment les cycles d'interruption . Pour cette raison :  Tout appel à #BB06 , #BB1E , Etc ... A l'intérieur d'une  interruption  programmée ne peut qu'entraîner un plantage spectaculaire !

Une solution consiste  à  réécrire  une  routine  de  lecture  directe du clavier et à convertir les codes lus en numéro de touche ( KEY(N) ) en Basic.

Commençons par le commencement : La lecture directe du clavier .

Seules des instructions IN/OUT peuvent réaliser  cette lecture . Comme on ne peut adresser que 8 bits à la  fois  , le clavier de 80 touches est divisé en 10 lignes de 8 touches chacune (Joystick compris) .

Le clavier est lu  par  un  circuit  d'interface  nommé  PPI . Ce circuit d'interface parallèle est composé de 3 ports de 8 bits : A , B & C .
Le PPI s'occupe de l'interface K7 , du générateur sonore , du signal busy de l'imprimante ,  des  cycles  d'interruption  et  pour  la  partie qui nous intéresse , du clavier .

Nous n'entrerons pas ici dans  le  détail  de l'électronique Amstrad . Onnotera toutefois que pour économiser de  la  mémoire , l'adressage de lecture clavier se fait par l'intermédiaire du  P.S.G. En fonction de cela, certaines erreurs de programmation ont  des  effets  curieux  sur l'instruction SOUND .
L'efficacité primant avant tout , le plus  simple est de reproduire en RAM la section 'SCAN KEYBOARD' de la ROM (En  #846  pour CPC 464) et de l'adapter à nos besoins .

STRUCTURE DU CLAVIER ET POSITION DES TOUCHES

Voici ci-dessous la répartition des touches sur les 10 lignes du clavier.

               ;  F.=Flèche - J.=Joystick - Pn.=Pavé numérique
 Colonnes=>!    0   !   1   !   2   !   3   !   4   !   5   !   6   !   7   !
           ;!        !       !       !       !       !       !       !       !
 Lignes    !        !       !       !       !       !       !       !       !
 0         ;!  F.Hau ! F.Dro ! F.Bas ! Pn. 9 ! Pn. 6 ! Pn. 3 ! Pn.En ! Pn. . !
 1         ;!  F.gau ! Copy  ! Pn. 7 ! Pn. 8 ! Pn. 5 ! Pn. 1 ! Pn. 2 ! Pn. 0 !
 2         ;!   CLR  !  "["  ! Enter !  "]"  ! Pn. 4 ! SHIFT !  "ç"  !  CTRL !
 3         ;!   ""   !  "="  !  "à"  !  "P"  !  "+"  !  "*"  !  "?"  !  ">"  !
 4         ;!   "0"  !  "9"  !  "O"  !  "I"  !  "L"  !  "K"  !  "M"  !  "<"  !
 5         ;!   "8"  !  "7"  !  "U"  !  "Y"  !  "H"  !  "J"  !  "N"  ! SPACE !
 6         ;!   "6"  !  "5"  !  "R"  !  "T"  !  "G"  !  "F"  !  "B"  !  "V"  !
 7         ;!   "4"  !  "3"  !  "E"  !  "W"  !  "S"  !  "D"  !  "C"  !  "X"  !
 8         ;!   "1"  !  "2"  !  ESC  !  "Q"  !  TAB  !  "A"  ! CAPSL !  "Z"  !
 9         ;!  J.hau ! J.bas ! J.gau ! J.dro ! J.fir ! ----- ! ----- !  DEL  !

Si ceci vous fait penser à une  matrice  du genre DIM touches (8,10) vous avez raison ! La touche située sur  la  ligne  0 colonne 0 est KEY(0) , celle située sur la ligne 2 colonne 8 est KEY (66) , Etc ... Pour trouver le numéro de touche exact : TOUCHE=LIGNE*8 + COLONNE .

La routine assembleur  lira  successivement  chaque  ligne  du clavier et récupèrera au passage un octet indiquant l'état de cette ligne . Si cet octet contient #FF (11111111) , aucune touche des 8 de la ligne n'est enfoncée . Si une touche est pressée , un des  bits  de  l'octet  transmis sera à zéro . La position de ce bit nous donnera la colonne ou se trouve la touche .

Exemples : 11110111 = 3 ème colonne . 10111111 = 7ème colonne . C'est une série de rotations à droite de  l'octet  qui  donnera  le numéro de colonne .(Noter que du point de vue binaire  ,  le tableau ci-dessus est a l'envers de gauche à droite) .

Chaque  octet  lu  sera  stocké  dans   un   buffer  de  10  octets  pour interprétation ultérieure . Le principe de base sera :

Lire les 10 lignes du clavier et stocker chaque octet . Ensuite :

;
         ;LD HL,BUFFER DE 10 OCTETS
         ;LD B,10    ;Pour 10 lignes .
         ;LD C,0     ;Contiendra le numéro de touche KEY(n) en sortie .
 ;
 BCL     LD A,#FF
         ;CP (HL)    ;Si contenu de HL <> #FF on a trouvé une touche pressée .
         ;JR NZ,TOUCHE
 ;
         ;INC HL     ;Aucune touche sur la ligne N .
         ;LD A,8     ;On ajoute 8 touches au compteur C .
         ;ADD A,C    ;et on continue .
         ;LD C,A
         ;DJNZ BCL
         ;RET        ;Si on sort ici , aucune des 80 touches n'était pressée .
 ;
 TOUCHE  LD A,(HL)  ;Une touche a été pressée , chercher son numéro .
 LOOK    RRC A      ;Chercher le bit a zéro .
         ;JR NC,TOUCHETROUVEE
         ;INC C      ;C contient déja le numéro de ligne , on avance de 1
         ;JR LOOK    ;dans la colonne .
 ;
 TOUCHETROUVEE : C'est fini .
 ;

Comme on le voit , le principe est des plus simples si l'on veut lire une seule touche . Mais il ne faut pas oublier les combinaisons suivantes !

Touche + CTRL  , Touche + SHIFT , Touche + SHIFT + CTRL .

Aie aie ... Lire 2 touches sur  2  lignes différentes ne constitue pas unvraiment un problème , on testera en priorité  la ligne 2 et mettrons un flag si on y trouve SHIFT ou CTRL , mais  SHIFT  + CTRL + ENTER = 3 touches sur la même ligne ! Ca ce n'est pas un cadeau  ... Dans ce cas le clavier renvoie un code btard qui équivaut à  :  La  touche  pressée  ,  AND le code des autres touches pressées . Donc :

ENTER + SHIFT = &FB AND &20  = &DB
ENTER + CTRL  = &FB AND & 80 = &7B
ENTER + CTRL + SHIFT = &FB AND &80 AND &20 = &5B

Ou encore &FB AND &A0 =&5B

Dans le cas  ou  toutes  les  touches  d'une  même  ligne serait pressées simultanément (Pas facile ça...) , le clavier renvérait donc un 0 . Si la les 80 touches étaient enfoncées (il  faut  être  trois  pour y-arriver) , les 10 octets transmis seraient tous à  0  .  On  peut donc tester simultanément des dizaines de touches à condition  de  savoir  décoder  le résultat . (10110101 signifie que les touches des colonnes  6,3  &  1  sont enfoncées sur une même ligne) .

Inutile d'aller aussi loin dans  nos  spéculations . La reconnaissance de CTRL -  SHIFT  suffira  .  J'ai  effectué  ce  décodage  de  manière  un  peu particulière . L'octet de ligne 3 est lu  en  premier  . Si il est à #FF nous n'avons ni CTRL ni SHIFT et tout va bien . Sinon  un OR &A0 restaure un octet sans SHIFT ni CTRL qui est remis  dans  le  buffer . Ceci est nécéssaire pour que la boucle de décodage ne soit pas perturbée par un octet parasite .

Ceci fait , l'état éventuel de  SHIFT  -  CTRL  est stocké et on relit la totalité du buffer pour trouver le numéro de touche .

Un dernier détail : Lorsque  SHIFT  &  CTRL  sont enfoncés ,  la dernière colonne passe de #7F à #5F . Ceci quelque soit la ligne clavier concernée .

La démonstration fournie (Décodage clavier) , vous montrera les résultats obtenus . Notez que si  l'état  de  CTRL  -  SHIFT  est  lu et affiché en bas d'écran , on ne le voit pas dans l'affichage du buffer puisque le programme à effacé ces codes du buffer après interprétation .  Le Basic est un peu lent . Attendez le BIP avant de  relacher  les  touches . Appuyer sur CTRL+SHIFT+ESC pour quitter ce programme (Le RESET est déconnecté) .

Ci-dessous le listing assembleur  de  "-KEY-ES" (Voir aussi NOTE après le listing ) .

;
 ;- LECTURE DU CLAVIER PAR PORTS E/S DU PPI -
 ;
         ;ORG  40000
  ;
  scankeyboard:
         ;DI      ;Toujours interdire les interruptions avant
         ;PUSH HL ;d'utiliser les ports ES
         ;PUSH BC
         ;PUSH AF
****************************** VOIR NOTE **********************************
  ;
  ;- Routine recopiée de puis les ROMS -
  ;
         ;LD   BC,#F40E ; Le registre R14 du PSG est connecte au port
         ;OUT  (C),C      ;A du PPI .
         ;LD   B,#F6      ;Envoyer #C0 (11000000) sur le port C du PPI pour
         ;IN   A,(C)      ;l'activer en mode adressage
         ;AND  #30
         ;LD   C,A
         ;OR   #C0
         ;OUT  (C),A      ;STROBE on puis OFF . On ne voit pas bien a quoi
         ;OUT  (C),C      ;ca sert ????
         ;INC  B          ;Passer sur le port #F7 et envoyer un octet
         ;LD   A,#92      ;10010010 qui active le PPI comme suit :
         ;OUT  (C),A      ;Port A = IN , port B = IN , port C = OUT
         ;LD   C,#40      ;01000000 envoyer le bit 6 sur le port C pour activer
         ;PUSH BC     ;le mode lecture PPI clavier . Les 4 bits de poids faible
                        ; ;donnent le numéro de ligne a lire .
  ;
  ;- Modifiée a partir d'ici -
  ;
         ;LD   HL,buf1    ;Départ du buffer pour les 10 lignes
  bcl  : LD   B,#F6      ;Envoyer l'ordre de lecture .
         ;OUT  (C),C
         ;LD   B,#F4      ;Lire le registre R14 sur le port A qui nous donne
         ;IN   A,(C)      ;l'octet transmis par le clavier . (#FF si aucune
         ;LD   (HL),A     ;touche enfoncée) .
         ;INC  HL         ;;Adresse stockage ligne suivante .
         ;INC  C          ;Incrémenter pour lire la ligne clavier suivante .
         ;LD   A,C
         ;AND  #F         ;;Tester si on atteint la 10eme ligne
         ;CP   10
         ;JR   NZ,bcl     ;Sinon recommencer
  ;
         ;POP  BC         ;;Restaurer l'état des ports E/S
         ;LD   A,#82      ;Sinon Gare !!
         ;OUT  (C),A      ;(Copie depuis ROMS)
         ;DEC  B
         ;OUT  (C),C
         ;POP  AF         ;;Si cette routine est utilisée sous interruption
         ;POP  BC         ;;Placer un RET après EI et n'appeler la routine de
         ;POP  HL         ;;décodage que quand c'est nécéssaire .
         ;EI
***************************************************************************
  ;
  ; - Routine de décodage .
  ;
  keydecod:
         ;XOR  A          ;RAZ de la case CTRL-SHIFT
         ;LD   (statkey),A
         ;DEC  A          ;Et mise a #FF du numéro de touche
         ;LD   (numkey),A
  ;
         ;LD   A,(buf1+2) ;Tester d'abord la ligne maudite (3)
         ;CP   #FF        ;Si #FF aucune touche de cette ligne
         ;JR   Z,nostats
  ;
         ;LD   HL,bitmap  ;Charger adresse table pour comparaison .
         ;LD   B,5        ;Voir les 5 1ers octets et éliminer les cases
  bclmap:
         ;CP   (HL)       ; <> SHIFT ou CTRL
         ;JR   Z,nostats
         ;INC  HL
         ;DJNZ bclmap
         ;INC  HL         ;;Sauter aussi la case 7
         ;CP   (HL)
         ;JR   Z,nostats
  ;
  ; - La présence de SHIFT ou CTRL ou les 2 a été détectée -
  ;
         ;LD   HL,buf1+2  ;Reprendre la case 3eme ligne
         ;PUSH AF
         ;OR   #A0        ;Or #A0 (10100000) A pour effet de mettre l'octet
         ;LD   (HL),A     ;a &FF si la case contenait CTRL ou SHIFT seuls.
         ;POP  AF         ;;Dans le cas ou SHIFT - CTRL sont combines avec
  ;                     ; ;une autre touche sur la me^me ligne , le code de
         ;AND  #A0        ;celle ci-se trouve restaurée .
         ;JR   Z,shiftctrl
         ;AND  #20        ;Ensuite ces 3 comparaisons permettent de
         ;JR   NZ,ctrl    ;déterminer SHIF & CTRL ou les 2
  shift: LD   A,#20
         ;JR   setstat
  ctrl : LD   A,#80
         ;JR   setstat
  shiftctrl:
         ;LD   A,#A0
  setstat:
         ;LD   (statkey),A
  ;
  ;- Traitement des touches sans CTRL ni SHIFT . 1 Chercher la ligne -
  ;
  nostats:
         ;LD   HL,buf1    ;On balaie les 10 octets du buffer .
         ;LD   C,0        ;Tant que #FF , aucune touche sur cette ligne
         ;LD   B,10       ;et on ajoute 8 au compteur pour prendre en
  findline:             ; ;compte la ligne suivante .
         ;LD   A,(HL)
         ;CP   #FF
         ;JR   NZ,trouve
&nb sp;        LD   A,8
         ;ADD  A,C
         ;LD   C,A
         ;INC  HL
         ;DJNZ findline
         ;RET
  ;
  ;- 2 Chercher la touche -
  ;
  trouve:
         ;LD   B,0        ;Or #20 pour passer #5F en #7F dans le cas ou
         ;CP   #5F        ;dernière touche +CTRL + SHIFT mais tester
         ;JR   NZ,findkey ;avant car #DF OR #20 = #FF et dans ce
         ;OR   #20        ;cas on reste coince dans la boucle !
  findkey:
         ;RRC  A          ;Rotation a droite
         ;JR   NC,keyfind ;Si bit a 0 : Touche trouvée
         ;INC  B
         ;JR   findkey
  ;
  keyfind:
         ;LD   A,C        ;Ajouter le numéro de ligne au numéro de colonne
         ;ADD  A,B
  nokey: LD   (numkey),A ;Et nous avons enfin notre numéro INKEY
         ;RET
  ;
  ;- Les valeurs des 8 touches dans 1 ligne pour comparaison -
  ;
  bitmap:
         ;DB   #FE,#FD,#FB,#F7,#EF,#DF,#BF,#7F
   *LIST     ON
  numkey:
         ;DB   0
  statkey:
         ;DB   0
  ;
  ;- Buffer de stockage des 10 lignes clavier -
  ;
  buf1 : DB   #FF,#FF,#FF,#FF,#FF,#FF,#FF,#FF,#FF,#FF
  ;

NOTE

On peut remplacer  la  section  de  programme  (tirée  des ROMS) située à entre  les 2 ligne d'astériques par :

         ;LD BC,#F792     ;Initialiser directement le PPI en lecture
         ;OUT (C),C       ;clavier
         ;LD B,#F6
         ;LD   C,#40
  ;
         ;LD   HL,buf1    ;Départ du buffer pour les 10 lignes
  bcl  : LD   B,#F6      ;Envoyer l'ordre de lecture .
         ;OUT  (C),C
         ;LD   B,#F4      ;Lire le registre R14 sur le port A qui nous donne
         ;IN   A,(C)      ;l'octet transmis par le clavier . (#FF si aucune
         ;LD   (HL),A     ;touche enfoncée) .
         ;INC  HL         ;;Adresse stockage ligne suivante .
         ;INC  C          ;Incrémenter pour lire la ligne clavier suivante .
         ;LD   A,C
         ;AND  #F         ;;Tester si on atteint la 10eme ligne
         ;CP   10
         ;JR   NZ,bcl     ;Sinon recommencer
  ;
         ;POP  AF         ;;Si cette routine est utilisée sous interruption
         ;POP  BC         ;;Placer un RET après EI et n'appeler la routine de
         ;POP  HL         ;;décodage que quand c'est nécéssaire .
         ;EI


Dans ce cas , en sortie de  routine  ,  les ports E/S systéme se trouvent plutot perturbés . Ce n'est  pas  bien  grave  car  tous  les 1/50S. , AMSDOS effectue une lecture clavier  et  restaure  l'ordre  normal  des  choses . En employant cette seconde  version  (Ne  figure  pas  en  code  binaire  sur la disquette) :

10 CALL 40000:GOTO 10 .

Ceci  plante  complètement car le système n'a pas le temps de repasser par sa routine lire clavier .

10 CALL 40000:FOR tp=1 TO 20:NEXT:GOTO 10

Tout va bien car on laisse au cycle d'interruption le temps de se produire .

D'autres détails dans l'article : Buffer clavier AMSDOS .

★ ANNÉE: ???
★ AUTEUR: MICHEL MAIGROT

★ AMSTRAD CPC ★ DOWNLOAD ★

Other platform tool:
» SOS3KEYBOARDDATE: 2011-06-05
DL: 98 fois
TYPE: ZIP
SIZE: 6Ko
NOTE: 40 Cyls
.HFE: NON

Je participe au site:
» Newfile(s) upload/Envoye de fichier(s)
★ AMSTRAD CPC ★ A voir aussi sur CPCrulez , les sujets suivants pourront vous intéresser...

Lien(s):
» Coding » Clefs1 15 Logiciel Interne Table Clavier
» Coding » System - Les Routines System - Exemple d'usage des Routines Clavier et Texte (SOS Programmeurs)
» Coding » Clefs1 64 - Table des Codes Clavier
» Applications » Emulateur Clavier Minitel (CPC Revue)
» Applications » Turbo - Clavier (CPC Revue)
» Applications » Vocaclavier

QUE DIT LA LOI FRANÇAISE:

L'alinéa 8 de l'article L122-5 du Code de la propriété intellectuelle explique que « Lorsque l'œuvre a été divulguée, l'auteur ne peut interdire la reproduction d'une œuvre et sa représentation effectuées à des fins de conservation ou destinées à préserver les conditions de sa consultation à des fins de recherche ou détudes privées par des particuliers, dans les locaux de l'établissement et sur des terminaux dédiés par des bibliothèques accessibles au public, par des musées ou par des services d'archives, sous réserve que ceux-ci ne recherchent aucun avantage économique ou commercial ». Pas de problème donc pour nous!

CPCrulez[Content Management System] v8.7-desktop/cache
Page créée en 056 millisecondes et consultée 1902 fois

L'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent  du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko.