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-$00AF175Prog. (PCBug11) - --
$00B0-$00C320Dispo. - --
$00C4-$00C63Int. (PCBug11) SCI : Liaison série asynchroneI-
$00C7-$00C93Int. SPI : Liaison série synchrone ISPIE
$00CA-$00CC3Int. Entrée du compteur IPAII
$00CD-$00CF3Int. Débordement du compteur IPAOVI
$00D0-$00D23Int. Débordement du timer ITOI
$00D3-$00D53Int. OC5 : Comparateur 5 IOC5I
$00D6-$00D83Int. OC4 : Comparateur 4 IOC4I
$00D9-$00DB3Int. OC3 : Comparateur 3 IOC3I
$00DC-$00DE3Int. OC2 : Comparateur 2 IOC2I
$00DF-$00E13Int. OC1 : Comparateur 1 IOC1I
$00E2-$00E43Int. IC3 : Entrée de capture 3 IIC3I
$00E5-$00E73Int. IC2 : Entrée de capture 2 IIC2I
$00E8-$00EA3Int. IC1 : Entrée de capture 1 IIC1I
$00EB-$00ED3Int. RTI : Interruption temps réel IRTII
$00EE-$00F03Int. IRQ ou STRA Inon/STAII
$00F1-$00F33Int.(PCBug11) XIRQ X-
$00F4-$00F63Int.(PCBug11) SWI : interruption logicielle --
$00F7-$00F93Int. Code illégal --
$00FA-$00FC3Int. COP : Chien de garde -NOCOP
$00FD-$00FF3Int. Défaut d'horloge -
AdressesSource d'interruption Masque
GlobalLocal
$FFD6-$FFD7SCI : Liaison série asynchroneI-
$FFD8-$FFD9SPI : Liaison série synchrone ISPIE
$FFDA-$FFDBEntrée du compteur IPAII
$FFDC-$FFDDDébordement du compteur IPAOVI
$FFDE-$FFDFDébordement du timer ITOI
$FFE0-$FFE1OC5 : Comparateur 5 IOC5I
$FFE2-$FFE3OC4 : Comparateur 4 IOC4I
$FFE4-$FFE5OC3 : Comparateur 3 IOC3I
$FFE6-$FFE7OC2 : Comparateur 2 IOC2I
$FFE8-$FFE9OC1 : Comparateur 1 IOC1I
$FFEA-$FFEBIC3 : Entrée de capture 3 IIC3I
$FFEC-$FFEDIC2 : Entrée de capture 2 IIC2I
$FFEE-$FFEFIC1 : Entrée de capture 1 IIC1I
$FFF0-$FFF1RTI : Interruption temps réel IRTII
$FFF2-$FFF3IRQ ou STRA Inon/STAII
$FFF4-$FFF5XIRQ X-
$FFF6-$FFF7SWI : interruption logicielle --
$FFF8-$FFF9Code illegal --
$FFFA-$FFFBCOP : Chien de garde -NOCOP
$FFFC-$FFFDDéfaut d'horloge -CME
$FFFE-$FFFFRESET --

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