Bienvenue dans l'univers 68hc11

Utilisation de la maquette 68hc11 du Service Électronique
Document rédigé par J. Weiss, septembre 95

1 Introduction

2 Organisation de la maquette

2.1 Implantation de la carte mère
2.2 Schéma électrique de la carte mère
2.3 espace d'adressage
2.3.1 Ressources internes
2.3.2 Mode Étendu
2.4 Vecteurs d'interruption
2.4.1 Mode bootstrap
2.4.2 Mode Normal
2.4.3 Mode Étendu
2.5 Schéma électrique de la carte Clavier-Affichage
2.6 Transfert SPI
2.7 Registres internes du microcontrôleur
2.8 Constantes de la carte

3 Programmes assembleur

3.1 Initialisation
3.1.1 Index, Pile et Vecteurs
3.1.1.1 Mode Bootstrap
3.1.1.2 Mode Normal
3.1.1.3 Mode Étendu
3.1.2 SPI
3.1.3 Afficheur LCD
3.2 Affichage
3.2.1 Procédure d'appel d'affichage LCD
3.2.2 Préambule d'affichage LCD
3.2.3 Affichage d'une chaîne de caractères sur LCD
3.2.4 exemple : affichage de l'heure sur l'afficheur LCD
3.2.5 Affichage de 2 digits LED 7 segments
3.2.6 Affichage sur les 3 diodes LED
3.3 Transfert SPI
3.4 Saisie du clavier
3.5 Gestion des interruptions temps réel (RTI)
3.5.1 Initialisation et préparation RTI
3.5.2 Gestion de l'interruption RTI : exemple de calcul de l'heure

4 Annexes

4.1 Annexe 1 : Boot ROM en $BF40 (mode bootstrap)
4.2 Annexe 2 : Boot ROM en $E000 (mode normal)
4.3 Annexe 3 : Talker PC Bug11 (talkJW.asc)
4.4 Annexe 4 : Programmes exemples
4.4.1 LCD_Time.asc : utilisation d'un 68hc811E2 en mode normal
4.4.2 LCD_A1.asc : utilisation d'un 68hc11A1 en mode bootstrap ou normal
4.5 Annexe 5 : Documentation sur l'afficheur LCD

1 Introduction

Ce document présente des programmes et des sous-programmes permettant l'exploitation des diverses fonctionnalités de la maquette 68hc11 (origine : ERP562 et 565), telles que :
        Affichage : LCD de caractères ASCII (afficheur de 4 lignes de 20 caractères)

                    LED 7 segments de  2 digits

                    LED 3 mm (LED 1, LED 2 et LED3)

        Saisie :    clavier 16 touches

                    boutons poussoirs (2)

        Gestion d'interruptions temps réel (horloge)

2 Organisation de la maquette

2.1 Implantation de la carte mère

La carte mère comprend le microcontrôleur, un décodeur, un tampon d'adresse ainsi qu'un emplacement pour une mémoire EEPROM de type 27C256.

En mode bootstrap et en mode normal, les connecteurs de la carte permettent de disposer de tous les ports de sortie du microcontrôleur; en mode Étendu le connecteur central de la carte permet la connexion d'une carte comprenant une extension mémoire et un module d'E/S parallèles (2*8 bits); le mode de fonctionnement du microcontrôleur est déterminé par la position des cavaliers ModA et ModB au moment du Reset :

        Mode BootStrap : les 2 cavaliers doivent être en place

        Mode Normal :    seul le cavalier ModB doit être en place

        Mode Étendu :    aucun des cavaliers ne doit être installé

L'implantation de la carte avec les différents brochages est donnée par la figure suivante :

Le schéma d'implantation de la carte mère est disponible en 2 versions :
complète : image de 1330*939 pixels (26 ko)
écran : image de 800*600 pixels (17 ko)

2.2 Schéma électrique de la carte mère

Le schéma électrique de la carte mère est disponible en 2 versions :
complète : image de 2300*2100 pixels (116 ko)
écran : image de 800*600 pixels (21 ko)

2.3 espace d'adressage

Le microcontrôleur est capable d'adresser 64 kOctets (adresse sur 16 bits) en mémoire, il peut s'agir de RAM, de ROM (masquée, EPROM ou EEPROM) ou de registres de configuration; les ressources peuvent être internes ou externes, en cas de conflit (plusieurs entités à la même adresse), les ressources internes sont prioritaires. En mode Bootstrap, et en mode Normal, il n'est possible d'exploiter que les ressources internes.

2.3.1 Ressources internes

Type 68hc11A1 68hc811E2 Taille
Registres  $1000-$103F  64 registres 
RAM  $0000-$00FF  256 Octets 
ROM Boot  $BF40-$BFFF  192 Octets 
ROM Interne  $E000-$FFFF  8kOctets/- 
EEPROM  $B600-$B7FF  $F800-$FFFF  512 Octets/ 2kOctets 

2.3.2 Mode Étendu

En mode Étendu (uniquement pour 68hc11A1), la table de l'espace adressable définie par la carte est donnée par le tableau ci-après :

Adresse Hexa A15 .................A0 CONTENU
$0000-$00FF  %0000 0000 0000 0000  256 OCTETS RAM
$0100-$0FFF  %0000 0001 0000 0000 
$1000-$103F  %0001 0000 0000 0000  64 REGISTRES
$1040-$1FFF  %0001 0000 0100 0000 
$2000-$3FFF  %0010 0000 0000 0000  RAM Externe: 8ko.
$4000-$B5FF  %0100 0000 0000 0000 
$B600-$B7FF  %1011 0000 0000 0000  512 OCTETS EEPROM
$B800-$BFFF  %1011 1000 0000 0000 
$C000-$FFBF  %1100 0000 0000 0000  EPROM PROGRAMME
$FFC0  %1111 1111 1100 0000  VECTEURS IT & RESET

2.4 Vecteurs d'interruption

Les adresses et la gestion des vecteurs d'interruption dépendent du type de processeur et du mode de fonctionnement :

2.4.1 Mode bootstrap

En mode Bootstrap, le vecteur d'initialisation (Reset) pointe vers la ROM boot (adresse $BF40), ce qui lance une routine (Bootloader) de téléchargement d'un programme de 256 Octets (exactement !) en RAM; l'exécution de ce programme démarre après le chargement du 256ème octet, il peut s'agir, par exemple, du "Talker" utilisé par le moniteur (PCBug11).

Il est ensuite possible d'exécuter un programme à partir de l'EEPROM (adresse $B600 ou $F800); la gestion des vecteurs d'interruption est alors effectuée par des appels de sous-programmes placés en haut de la RAM ( adresses $C4 à $FF). À titre d'exemple, le gestion d'une interruption RTI se fait en écrivant, à partir de l'adresse $EB le mnémonique du saut vers le sous-programme sur 3 Octets :

Gestion RTI : $EB : $7E (Code JMP) $EC-$EE : @ SP (2 octets).

Pour exécuter un programme en mode Bootstrap sous le contrôle de PCBug11, il faut placer les variables de programme et la pile dans plage d'adresses $B0-$C3, soit 20 octets; il est également possible d'exploiter l'espace des interruptions qui ne sont pas validées (plage $C4-$FF). Le tableau suivant donne la carte de la mémoire RAM en mode Bootstrap :

Adresses  Taille Type Source d'interruption Masque
(Octets) Global Local
$0000-$00AF 175 Prog. (PCBug11)  -
$00B0-$00C3 20 Dispo.  -
$00C4-$00C6 3 Int. (PCBug11)  SCI : Liaison série asynchrone I
$00C7-$00C9 3 Int.  SPI : Liaison série synchrone  I SPIE 
$00CA-$00CC 3 Int.  Entrée du compteur  I PAII 
$00CD-$00CF 3 Int.  Débordement du compteur  I PAOVI 
$00D0-$00D2 3 Int.  Débordement du timer  I TOI 
$00D3-$00D5 3 Int.  OC5 : Comparateur 5  I OC5I 
$00D6-$00D8 3 Int.  OC4 : Comparateur 4  I OC4I 
$00D9-$00DB 3 Int.  OC3 : Comparateur 3  I OC3I 
$00DC-$00DE 3 Int.  OC2 : Comparateur 2  I OC2I 
$00DF-$00E1 3 Int.  OC1 : Comparateur 1  I OC1I 
$00E2-$00E4 3 Int.  IC3 : Entrée de capture 3  I IC3I 
$00E5-$00E7 3 Int.  IC2 : Entrée de capture 2  I IC2I 
$00E8-$00EA 3 Int.  IC1 : Entrée de capture 1  I IC1I 
$00EB-$00ED 3 Int.  RTI : Interruption temps réel  I RTII 
$00EE-$00F0 3 Int.  IRQ ou STRA  I non/STAII
$00F1-$00F3 3 Int.(PCBug11)  XIRQ  X
$00F4-$00F6 3 Int.(PCBug11)  SWI : interruption logicielle  -
$00F7-$00F9 3 Int.  Code illégal  -
$00FA-$00FC 3 Int.  COP : Chien de garde  - NOCOP 
$00FD-$00FF 3 Int.  Défaut d'horloge  -
Adresses Source d'interruption Masque
Global Local
$FFD6-$FFD7 SCI : Liaison série asynchrone I -
$FFD8-$FFD9 SPI : Liaison série synchrone  I SPIE
$FFDA-$FFDB Entrée du compteur  I PAII
$FFDC-$FFDD Débordement du compteur  I PAOVI
$FFDE-$FFDF Débordement du timer  I TOI
$FFE0-$FFE1 OC5 : Comparateur 5  I OC5I
$FFE2-$FFE3 OC4 : Comparateur 4  I OC4I
$FFE4-$FFE5 OC3 : Comparateur 3  I OC3I
$FFE6-$FFE7 OC2 : Comparateur 2  I OC2I
$FFE8-$FFE9 OC1 : Comparateur 1  I OC1I
$FFEA-$FFEB IC3 : Entrée de capture 3  I IC3I
$FFEC-$FFED IC2 : Entrée de capture 2  I IC2I
$FFEE-$FFEF IC1 : Entrée de capture 1  I IC1I
$FFF0-$FFF1 RTI : Interruption temps réel  I RTII
$FFF2-$FFF3 IRQ ou STRA  I non/STAII
$FFF4-$FFF5 XIRQ  X -
$FFF6-$FFF7 SWI : interruption logicielle  - -
$FFF8-$FFF9 Code illegal  - -
$FFFA-$FFFB COP : Chien de garde  - NOCOP
$FFFC-$FFFD Défaut d'horloge  - CME
$FFFE-$FFFF RESET  - -

2.5 Schéma électrique de la carte Clavier-Affichage

Cette carte sert d'interface homme-machine avec la carte mère, elle dispose d'un afficheur LCD de 4 lignes de 20 caractères, de 2 digits LED et de 3 LED 3 mm; la saisie peut se faire par un clavier de 16 touches et par 2 boutons poussoirs.

Le schéma électrique de la carte clavier-affichage est disponible en 2 versions :
complète : image de 2500*2000 pixels (113 ko)
écran : image de 800*600 pixels (20 ko)

2.6 Transfert SPI

La particularité des maquettes est d'utiliser l'interface série synchrone (SPI) pour dialoguer entre la carte processeur et la carte clavier-affichage; les transferts sont organisés sous forme de 2 envois vers la carte Clavier- afficheur et d'une lecture.
*
* Premier mot envoyé :            Q7   Q6   Q5   Q4   Q3   Q2   Q1   Q0 
*                               | R  | B  | D  | U  | L  | NC | RS | E  |
*                      Relais ____|    |    |    |    |          |   |
*                      Buzzer _________|    |    |    |          |   |
*                                           |    |    |          |   |    
*   Afficheur 7 Seg.   Dizaines ____________|    |    |          |   |
*                      Unités ___________________|    |          |   |
*                                                     |          |   |
*                      LED ___________________________|          |   |   
*                                                                |   |  
*   Afficheur LCD      Register Select __________________________|   | 
*                      Enable _______________________________________|
*
* Le deuxième mot envoyé correspond aux données
*
*      Afficheur 7 Seg. :         Q7   Q6   Q5   Q4   Q3   Q2   Q1   Q0 
*                               | d  | e  | c  | dp  | b | a  | f  | g  |
*
*      Afficheur LCD :            Q7   Q6   Q5   Q4   Q3   Q2   Q1   Q0 
*                               | q7 | q6 | q5 | q4 | q3 | q2 | q1 | q0 |
*
*
*                                 Q7   Q6   Q5   Q4   Q3   Q2   Q1   Q0 
*           LED      :          |    | k3 |    |    | k2 |    |    | k1 |
*         Clavier    :          |    |    |    |    | r4 | r3 | r2 | r1 |
*      Interrupteurs :          |    |    |    |  S |    |    |    |    |
*
*
*    Commandes Afficheur LCD     RS (Register Select) : 0 -> Instr. Reg. 
*                                                       1 -> Data Reg.
Le protocole SPI est indiqué par la figure suivante (N.B. : le signal SS doit être géré par logiciel) :

2.7 Registres internes du microcontrôleur

La liste de la plupart des registres de contrôle internes avec leur adresse (relativement à $1000) est donnée ci-après :
porta            equ 0          ; Port A (3 in, 5 out)
pioc             equ 2          ; Parallel I/O C Control Reg.
portc            equ 3          ; Port C
portb            equ 4          ; Port B (output only)
portcl           equ 5          ; Port C Control 
ddrc             equ 7          ; Data Direction Reg Port C
portd            equ 8          ; Port D
ddrd             equ 9          ; Data Direction Reg Port D
porte            equ $A         ; Port E

cforc            equ $B         ; Compare Force Register
oc1m             equ $C         ; OC1 Action Mask Register
oc1d             equ $D         ; OC1 Action Data Register
tcnt             equ $E    ; (16 bits) : Timer Counter Register
tic1             equ $10   ; (16 bits) : Input Capture 1 Register
tic2             equ $12   ; (16 bits) : Input Capture 2 Register
tic3             equ $14   ; (16 bits) : Input Capture 3 Register
toc1             equ $16   ; (16 bits) : Output Compare 1 register
toc2             equ $18   ; (16 bits) : Output Compare 2 register
toc3             equ $1A   ; (16 bits) : Output Compare 3 register
toc4             equ $1C   ; (16 bits) : Output Compare 4 register
toc5             equ $1E   ; (16 bits) : Output Compare 5 register
tctl1            equ $20        ; Timer Control Register 1
tctl2            equ $21        ; Timer Control Register 2
tmsk1            equ $22        ; Timer Mask Register 1
tflg1            equ $23        ; Timer Flag Register 1
tmsk2            equ $24        ; Timer Mask Register 2
tflg2            equ $25        ; Timer Flag Register 2
pactl            equ $26        ; Pulse Accumulator Control Reg.

spcr             equ $28        ; SPI Control Register
spsr             equ $29        ; SPI Status Register
spdr             equ $2A        ; SPI Data Register
baud             equ $2B        ; SCI Baud Rate Control
sccr1            equ $2C        ; SCI Control Register 1
sccr2            equ $2D        ; SCI Control Register 2
scsr             equ $2E        ; SCI Status Register
scdr             equ $2F        ; SCI Data Register

adctl            equ $30        ; A/D Control/Status Register
adr1             equ $31        ; A/D Result Register 1
adr2             equ $32        ; A/D Result Register 2
adr3             equ $33        ; A/D Result Register 3
adr4             equ $34        ; A/D Result Register 4

bprot            equ $35        ; Block Protection
option           equ $39        ; System Configuration Options
coprst           equ $3A        ; Arm/Reset COP Timer circuitry
pprog            equ $3B        ; EEPROM Programming Register   
hprio            equ $3C        ; Highest Priority Int. Reg.
config           equ $3f        ; COP, ROM & EEPROM enables

2.8 Constantes de la carte

************************************************************
*               Constantes du programme                    *
************************************************************

base_reg         equ $1000

** mots de commande (premier mot envoyé sur SPI)
RIEN             equ $FC  ; aucun affichage
LCD_on           equ $FF  ; affichage LCD
LCD_config       equ $FD  ; configuration de l'afficheur LCD
LED_on           equ $F6  ; sélection des LED
unites           equ $DE  ; sélection de l'afficheur des unités
dizaines         equ $EE  ; sélection de l'afficheur des dizaines
buzzer           equ $BE  ; sélection du buzzer 
relais           equ $7E  ; sélection du relais
switches         equ $10  ; interrupteurs

** mots de donnée (deuxième mot envoyé sur SPI)
LED_k1           equ $1   ; cathode de la LED 1 
LED_k2           equ $8   ; cathode de la LED 2 
LED_k3           equ $40  ; cathode de la LED 3

3 Programmes assembleur

Les programmes et sous-programmes présentés ci-dessous ont pour but de fournir des utilitaires de développement pour les maquettes 68hc11; ces programmes sont présentés comme des modules élémentaires, les variables exploitées sont rapellées en début de listing (en commentaire); sauf mention contraire, l'utilisation des sous- programmes n'entraine de modification du contexte (accus, registres, ...). En plus des procédures d'initialisation, sont présentés les modules suivants :
Aff_msg(Y)               : affiche la chaîne de caractères pointée par Y sur l'afficheur LCD)
                           variable modifiée : data_in
Aff_7seg(digit1,digit10) : affiche digit1 et digit10 sur les afficheurs 7 segments LED
                           variable modifiée : data_in
Aff_LED(A)               : allume la diode LED définie par l'accumulateur A (LED_k#)
Lect_clavier()           : effectue une lecture des touches du clavier et des interrupteurs
                           Valeur retournée :        retour : touche : valeur du clavier (4 bits) ou $FF si rien
                           inter : état des interrupteurs (0 : S1, 1 : S2 et $FF : rien)
En annexe de ce document, sont fournis 2 programmes qui ont servi à bâtir ces modules utilitaires, ils ont exactement la même fonctionnalité (affichage d'un message et de l'heure) mais ils sont utilisés sur 2 processeurs différents :

LCD_Time.ASC : microcontrôleur 68hc811E2 en mode Normal
LCD_A1.asc : microcontrôleur 68hc11A1 en mode Bootstrap (PCBug11) et en mode Normal

3.1 Initialisation

3.1.1 Index, Pile et Vecteurs

3.1.1.1 Mode Bootstrap

************************************************************
*                variables du programme                    *
************************************************************
        ORG $00B0
variable1        RMB 1   
...
************************************************************
*                constantes du programme                    *
************************************************************
JUMPEXT          equ $7E             ; mnémonique de l'instruction JMP
JRTI             equ $00EB           ; adresse du vecteur RTI
...
                 ORG  $F800          ; cas d'un 68hc811e2 ($B600 pour 68hc11a1)
Debut            SEI                 ; set interrupt mask
                 LDAA #JUMPEXT       ; mnémonique de l'instruction JMP
                 LDX  #Rti           ; adresse du sous-programme d'IT (ici : RTI)
                 STAA JRTI           ; ecriture de JMP Rti à partir de l'adresse $EB
                 STX  JRTI+1         ;

.... autres définitions de vecteurs

                 LDX  #base_reg      ; X <--- $1000 : base des registres
                 LDS  #$E7           ; initialisation de la pile à $E7

.... autres initialisation

                 CLI
.... départ du programme

3.1.1.2 Mode Normal
     68hc11A1 : même procédure qu'en mode Boostrap mais les variables peuvent être placées à partir de $0.
     68hc811E2 : même procédure qu'en mode Étendu
3.1.1.3 Mode Étendu
************************************************************
*                variables du programme                    *
************************************************************
        ORG $0000                ; cas de la RAM interne ($2000 pour la RAM externe)
variable1        RMB 1   
...

                 ORG  $FFF0          ; vecteur RTI (exemple)
                 FDB  Rti            ; adresse du sous-programme d'IT (ici : RTI)
                 ORG  $FFFE          ; vecteur RESET
                 FDB  Debut          ; début du programme
                 ORG  $F800          ; cas d'un 68hc811e2 
                                     ;($B600 pour 68hc11a1 ou $C000 pour EPROM externe)

Debut            SEI                 ; set interrupt mask

.... autres initialisation

                 CLI

.... départ du programme
3.1.2 SPI
************************************************************
*                 initialisation SPI                       *
************************************************************
Init_SPI         BSET ddrd,x,#$38    ; SS, SCK, MOSI en sortie
                 LDAA #$51           ; Enable SPI avec SCK=125kHz, wired_or mode
                 STAA spcr,x 
                 LDAA #$3F           ; on met les bits du port D à 1
                 STAA portd,x
3.1.3 Afficheur LCD
************************************************************
*                 initialisation LCD                       *
************************************************************
*Commande_LCD    RMB 1    ; mot de commande du LCD (0: commande; 2 : affichage)
*LCD_config      equ $FD  ; configuration de l'afficheur LCD

Init_LCD         LDAA #LCD_config     ; mode config LCD
                 STAA Commande_LCD
                 LDAA #$1             ; clear Display
                 JSR  Aff_LCD

** l'afficheur a besoin d'une tempo
Tempo            LDY #$1000           ; IY <- durée
T1               DEY                  ; IY <- IY-1
                 BNE T1

                 LDAA #$E             ; display =on 
                 JSR  Aff_LCD
                 LDAA #$3C            ; N =2 lignes; F =  1 
                 JSR  Aff_LCD

3.2 Affichage

3.2.1 Procédure d'appel d'affichage LCD
                 LDY  #introduction
                 JSR  Aff_msg
...
introduction     FCC ' On affiche ce texte\'

3.2.2 Préambule d'affichage LCD
******************************************************************
* SP *           préparation de l'affichage LCD                  *
******************************************************************
*Commande_LCD    RMB 1    ; mot de commande du LCD (0: commande; 2 : affichage)
Aff_LCD          PSHB
                 LDAB Commande_LCD
                 JSR  OUTSPI            ; on envoie la commande (E=1)
                 ANDB #$FE              ; Disable       
                 JSR  OUTSPI            ; on renvoie la commande (E=0)
                 PULB
                 RTS

3.2.3 Affichage d'une chaîne de caractères sur LCD
*******************************************************************
* SP * envoi d'une chaine de caractères pointée par y finie par \ *
*******************************************************************
Aff_msg          PSHA
                 PSHY
                 LDAA #LCD_config       ; mode config LCD 
                 STAA Commande_LCD
                 LDAA #$80              ; DD Ram =$00
                 JSR  Aff_LCD
                 LDAA #LCD_on           ; mode Affichage LCD
                 STAA Commande_LCD               
Envmot           LDAA 0,y
                 CMPA #'\'
                 BEQ  Envmot_fin        ; si \ alors retour
                 JSR  Aff_LCD           ; si non envoi du caractère (0,y)
                 INY                    ; IY <- IY + 1
                 BRA  Envmot            ; on boucle
Envmot_fin       PULY
                 PULA
                 RTS
3.2.4 exemple : affichage de l'heure sur l'afficheur LCD
*************************************************************************
* SP *        Affichage de l'heure sur l'afficheur LCD                  *
*************************************************************************
*seconde          RMB 1    ; nbre de secondes de 0 à 256 pour ajustement
*secondes         RMB 1    ; secondes de 0 à  59
*minutes          RMB 1    ; minutes de 0 à 59
*heures           RMB 1    ; heures de 0 à 23

Affhm           LDAA  #LCD_config        ; mode config LCD 
                STAA  Commande_LCD
                LDAA  #$C7               ; DD Ram =$47
                JSR   Aff_LCD
                LDAA  #LCD_on            ; RS  = 1 
                STAA  Commande_LCD
                LDAA  heures   
                JSR   Aff_ascii
                LDAA  #':'
                JSR   Aff_LCD
                LDAA  minutes   
                JSR   Aff_ascii
                LDAA  #':'
                JSR   Aff_LCD
                LDAA  secondes   
                JSR   Aff_ascii
                RTS

** envoi en DECIMAL ASCII du nombre contenu dans A
           
Aff_ascii       PSHB                   ; sauvegarde de B  
                JSR  Div_10            ; division par 10 de A
                STAA digit10
                STAB digit1
                ADDA #$30              ; A <- A + $30
                JSR  Aff_LCD           ; envoi du digit Quotient (dizaines)
                TBA                    ; A <- B
                ADDA #$30              ; B <- B + $30
                JSR  Aff_LCD           ; envoi du digit Reste (unités)
                PULB pulb              ; restauration de B
                RTS   

** DIVISION PAR 10  ----------------------------
** donnee dans A -> A/10 ds A et reste ds B

Div_10          TAB                 ; B <-- A
                CLRA                ; A <- 0  : variable dans AccD
                LDX  #10            ; ix <- 10
                IDIV                ; Q:IX ; R:AccD <- AccD/IX
                PSHB                ; push B : Pile <- MSB du reste
                XGDX                ; Accd <-> IX
                TBA                 ; A <-- B
                PULB                ; pull B : B <- MSB du reste
                LDX  #base_reg      ; réinitialisation de IX ($1000)
                RTS                 ; return

3.2.5 Affichage de 2 digits LED 7 segments
*************************************************************************
* SP *        Affichage sur les afficheurs 7 segments LED               *
*                   digit1 correspond aux unités                        *
*                  digit10 correspond aux dizaines                      *
*************************************************************************
*digit1           RMB 1    ; digit des unités de l'afficheur LED
*digit10          RMB 1    ; digit des dizaines de l'afficheur LED

Aff_7seg        PSHY
            PSHB
                PSHA
            LDY  #Tab_7seg    ; on pointe sur la table de conversion
            LDAA c244       ; chargement du compteur d'horloge c244
                ASRA                ; on propage le LSB dans C
                BCC  Aff2           ; c244 est pair (C=0), on affiche les unités
            LDAB #dizaines    ; adresse du digit à afficher
            PSHB
            LDAB digit10            ; chargement du digit à afficher
                    BRA  Fin_7seg

Aff2            LDAB #unites      ; adresse du digit à afficher
            PSHB
            LDAB digit1       ; chargement du digit à afficher
                
Fin_7seg        ABY               ;  Y <-- Y + B ( B :offset dans la table) 
                LDAA 0,y          ; pointage sur la table
                PULB              ; on récupère l'adresse du digit
            JSR  OUTSPI       ; envoi du digit 
                PULA
                PULB
                PULY
            RTS

*     segment :       dec.bafg                       
Tab_7seg        FCB #%11101110          ; chiffre 0
                FCB #%00101000          ; chiffre 1
                FCB #%11001101          ; chiffre 2
                FCB #%10101101          ; chiffre 3
                FCB #%00101011          ; chiffre 4
                FCB #%10100111          ; chiffre 5
                FCB #%11100111          ; chiffre 6
                FCB #%00101100          ; chiffre 7
                FCB #%11101111          ; chiffre 8
                FCB #%10101111          ; chiffre 9
                FCB #%01101111          ; chiffre A
                FCB #%11100011          ; chiffre b
                FCB #%11000001          ; chiffre c
                FCB #%11101001          ; chiffre d
                FCB #%11000111          ; chiffre E
                FCB #%01100111          ; chiffre F



3.2.6 Affichage sur les 3 diodes LED
*************************************************************************
* SP *                    Affichage  diodes LED                         *
*     Le numéro de la LED (LED_k#) se trouve dans l'accumulateur A      *
*************************************************************************
Aff_LED         PSHB
                LDAB #LED_on              ; mot de commande pour les diodes LED
                JSR OUTSPI
                PULB
                RTS

3.3 Transfert SPI

************************************************************************
* SP *     Envoi de 2 octets par SPI et réception d'un octet           *
*            - Le mot de commande est dans l'accumulateur B            *
*            - Les données en émission  sont dans l'accumulateur A     * 
*            - la donnée en réception est dans data_in                 *
************************************************************************
*data_in        RMB 1    ; lecture sur SPI

OUTSPI          PSHA                    ; on empile la donnée
                PSHB                    ; on empile le mot de commande
                PSHY
                BCLR portd,x,#$20       ; met SS à 0 latche entrée et sortie registres
                STAB spdr,x             ; envoi du mot de commande

                LDY #08                 ; 8 bits à faire tourner
RBBMIR          ROLA                    ; les bits sortent à gauche par la retenue
                RORB                    ; et rentrent à droite par la carry
                DEY
                BNE RBBMIR
ATE20           BRCLR spsr,x,#$80 ATE20  ; attend fin transmission prec.
                LDAA  spdr,x             ; on récupère la donnée sur le SPI
                STAA  data_in              ; enregistre            
                STAB  spdr,x             ; on envoie la donnée sur le SPI
ATEF2O          BRCLR spsr,x,#$80 ATEF2O ; attend fin transmission pour reset SS        
                BSET  portd,x,#$20       ; met SS à 1 (delatche sorties registres)
                PULY
                PULB                     ; on restaure le mot de commande dans B
                PULA                     ; on restaure la donnée dans A
                RTS

3.4 Saisie du clavier

******************************************************************************
* SP *             Lecture du clavier et des interrupteurs                   *
*            touche : lecture du clavier (4 bits ou $FF si rien)             *
*        inter : état des interrupteurs (0 : S1, 1 : S2 et $FF : rien)       *
******************************************************************************
*touche           RMB 1    ; touche frappée sur le clavier (4 bits ou $FF si rien)
*inter            RMB 1    ; interrupteurs (0 : S1, 1 : S2 et $FF : rien)

Lect_clavier    PSHA
                PSHB
                PSHY
Init_lect       LDAA #$FF
                STAA inter
                STAA touche
                LDAA #1                   ; on pointe sur la 1ère rangée
                LDAB #RIEN                ; mot de commande nul
                BRA Lect_2
Lect_1          ASLA                      ; rangée suivante
                BEQ Fin_lect              ; fin du balayage des rangées
Lect_2          JSR OUTSPI                ; on stimule
                JSR OUTSPI                ; on réceptionne la donnée (4 bits LSB)
                BRSET data_in,#$0F,Lect_1 ; réponse vierge ?, si oui on boucle
                COM data_in               ; complémentation de la donnée
                CMPA #switches            ; adressage des interrupteurs ?
                BEQ Lect_int              ; il 'agit d'un interrupteur !
                JSR Lin_bin               ; conversion en binaire (résultat dans B)
                PSHB                      ; sauvegarde du résultat "rangée"
                LDAA data_in              ; réponse "colonne"
                JSR Lin_bin               ; conversion en binaire (résultat dans B)
                ASLB
                ASLB
                PULA                      ; récupération du résultat "rangée"
                ABA                       ; mise en forme de la réponse clavier
                TAB
                LDY #Tab_clavier
                ABY
                LDAA 0,Y
                STAA touche             
Fin_lect        PULY
                PULB
                PULA 
                RTS

Lect_int        LDAA data_in
                RORA
                STAA inter
                BRA Fin_lect

Lin_bin         LDAB #0         ; compteur à zéro
Lin_1           RORA            ; on décale
                BCS Fin_lin     ; fin si on a propagé un 1 dans C
                CMPB #3         ; fin des 4 bits ?
                BEQ Fin_lin     ; si oui alors fin
                INCB            ; incrémentation du compteur
                BRA Lin_1       ; on boucle
Fin_lin         RTS

* on lit : 147A2580369BFEDC
Tab_clavier     FCB #$1
                FCB #$4
                FCB #$7
                FCB #$A
                FCB #$2
                FCB #$5
                FCB #$8
                FCB #$0
                FCB #$3
                FCB #$6
                FCB #$9
                FCB #$B
                FCB #$F
                FCB #$E
                FCB #$D
                FCB #$C

3.5 Gestion des interruptions temps réel (RTI)

3.5.1 Initialisation et préparation RTI
************************************************************
*                  Début du programme                      *
************************************************************
Debut           SEI                     ; set interrupt mask
                LDX  #base_reg          ; X <--- $1000
                LDS  #$FF               ; initialisation de la pile à FF

                BSET pactl,x,#0         ; rti rate : 4,10 ms
                BSET tmsk2,x,#$40       ; rti Interrupt Enable                   
...
***************************************************************
*   Départ du programme  *
***************************************************************
                LDY  #introduction
                JSR  Aff_msg
...
B1              SEI
...
                JSR Lect_clavier
                JSR Aff_7seg
                CLI                     ; Clear interrupt Mask                 
                WAI                     ; Attente d'une interruption
                JMP  B1
3.5.2 Gestion de l'interruption RTI : exemple de calcul de l'heure
******************************************************************
* INT *          Gestion de l'interruption périodique            *
* RTI *                  calcul de l'heure                       *
******************************************************************
*c244           RMB 1    ; compte 244 interuptions RTI avant d'obtenir 1s.
*bis            RMB 1    ; indique à ff que l'on a ajouté le reste
*seconde        RMB 1    ; nbre de secondes de 0 à 256 pour ajustement
*secondes       RMB 1    ; secondes de 0 à  59
*minutes        RMB 1    ; minutes de 0 à 59
*heures         RMB 1    ; heures de 0 à 23

** toutes les 256 s, on charge c244 avec le reste (16) pour ajuster l'horloge

Rti             DEC c244
                BEQ Rti_0
                JMP Fin_rti
Rti_0           BSET  c244,#244        ; recharge le compteur
                BRSET bis,#$ff,Rti_1   ; bis indique que l'on a déjà re-
                                        * chargé c244 avec le reste
                INC  seconde            ; inc sauf si bis = $ff
                                        * chaque fois que seconde passe à 0
                BNE  Rti_2              ; on charge bis à ff et c244 à 16 (reste)
                                        * on ne compte pas cette "seconde"
Rti_01          LDAA #16                ; on charge le reste
                STAA c244
                BSET bis,#$ff
                JMP  Fin_rti

Rti_1           CLR  bis
Rti_2           JSR  Affhm
                LDAA #60
                INC  secondes           ; secondes de 0 à 59
                CMPA secondes
                BNE  Fin_rti            
                CLR  secondes
                INC  minutes
                LDAA #60
                CMPA minutes
                BNE  Fin_rti            ; minutes
                CLR  minutes
                INC  heures
                LDAA heures
                CMPA #24
                BNE  Fin_rti            ; heures
                CLR  heures

Fin_rti         BCLR tflg2,x,#$BF       ; annule flag RTI
                RTI

... n'oubliez pas de consulter les annexes


Remarques à Jacques.Weiss@supelec.fr