Utiliser les PIC 16F et 18F/Exercices/Les sous-programmes en assembleur
Exercice 1
modifierModifier le premier exemple du « suivant le cas faire ... » pour que ce que l’on doive faire se trouve dans des sous-programmes. On rappelle ce programme donné dans la partie cours :
CBLOCK 0x00 ; début de la zone variables en ACCESS RAM
w_temp :1 ; Zone de 1 byte
status_temp : 1 ; zone de 1 byte
Choix : 1 ; je déclare ma variable
ENDC ; Fin de la zone
...
;si Choix=0 faire le sous programme spgm0 si Choix=1 faire spgm1
; Choix contient ici une valeur <=N
movlw 0x0
subwf Choix,w ;Choix - W -> W
btfsc STATUS,Z ;Z=1 si = 0 et on saute
goto spgm0
movlw 0x1
subwf Choix,w ;Choix - W -> W
btfsc STATUS,Z ;Z=1 si = 0 et on saute
goto spgm1
...
movlw 0xN
subwf Choix,w ;Choix - W -> W
btfsc STATUS,Z ;Z=1 si = 0 et on saute
goto spgmN
; erreur ici !!!
suite
....
spgm0 ;code ici
goto suite
....
Le fait que les choix se font sur une instruction complique un peu la situation.
Modifier le programme en utilisant une technique similaire aux tableaux en mémoire programme.
processor 16f84
STATUS EQU 0x03
Z EQU 2
C EQU 0
W EQU 0
f EQU 1
choix EQU 0x0C
ORG 0
debut
;si Choix=0 faire le sous programme spgm0 si Choix=1 faire spgm1
; Choix contient ici une valeur <=N
movlw 0x0
subwf Choix,w ;Choix - W -> W
btfsC STATUS,Z ;Z=1 si = 0 et on saute
CALL spgm0
;GOTO suite
movlw 0x1
subwf Choix,w ;Choix - W -> W
btfsC STATUS,Z ;Z=1 si = 0 et on saute
CALL spgm1
;GOTO suite
movlw 0x2
subwF Choix,w ;Choix - W -> W
btfsC STATUS,Z ;Z=1 si = 0 et on saute
CALL spgm2
GOTO suite
; erreur ici !!!
suite GOTO debut
spgm0 ;code ici
RETURN
spgm1 ;code ici
RETURN
spgm2 ;code ici
RETURN
END
On peut donc procéder comme ceci :
ORG 0
debut
;si Choix=0 faire le sous programme spgm0 si Choix=1 faire spgm1
; Choix contient ici une valeur <=N
movlw 0x0
subwf Choix,w ;Choix - W -> W
btfsC STATUS,Z ;Z=1 si = 0 et on saute
GOTO CALL_spgm0
movlw 0x1
subwf Choix,w ;Choix - W -> W
btfsC STATUS,Z ;Z=1 si = 0 et on saute
GOTO CALL_spgm1
;GOTO suite
movlw 0x2
subwF Choix,w ;Choix - W -> W
btfsC STATUS,Z ;Z=1 si = 0 et on saute
GOTO CALL_spgm2
; si on est ici c’est pas normal : erreur !!!
suite GOTO debut
; debut des appels
CALL_spgm0
CALL spgm0
GOTO suite
CALL_spgm1
CALL spgm1
GOTO suite
CALL_spgm2
CALL spgm2
GOTO suite
; code des sous-programmes
spgm0 ;code ici
RETURN
spgm1 ;code ici
RETURN
spgm2 ;code ici
RETURN
END
L'amélioration demandée peut être faite en remarquant dans le code ci-dessus quelque chose qui ressemble à la déclaration de tableau :
CALL_spgm0
CALL spgm0
GOTO suite
CALL_spgm1
CALL spgm1
GOTO suite
CALL_spgm2
CALL spgm2
GOTO suite
On va le transformer en
tableau_Appels
BCF STATUS,C ;C<-0
RLF choix,f ; choix=choix x 2
MOV choix,w
addwf PCL , f ; ajouter w à PCL
CALL spgm0
GOTO suite
CALL spgm1
GOTO suite
CALL spgm2
GOTO suite
soit :
processor 16f84
STATUS EQU 0x03
PCL EQU 0x02
Z EQU 2
C EQU 0
W EQU 0
f EQU 1
choix EQU 0x0C
ORG 0
debut
;si Choix=0 faire le sous programme spgm0 si Choix=1 faire spgm1
; Choix contient ici une valeur <=N
GOTO tableau_Appels
suite GOTO debut
; tableau en mémoire programme des appels
tableau_Appels
BCF STATUS,C ;C<-0
RLF choix,f ; choix=choix x 2
; les tests de dépassement ne sont pas faits
movf choix,w
addwf PCL , f ; ajouter w à PCL
CALL spgm0
GOTO suite
CALL spgm1
GOTO suite
CALL spgm2
GOTO suite
; code des sous-programmes
spgm0 ;code ici
RETURN
spgm1 ;code ici
RETURN
spgm2 ;code ici
RETURN
END
Exercice 2
modifierÉcrire un programme qui lit sans arrêt le PORTB pour le mettre dans Choix et qui suivant la valeur décimale (1, 2, 4, 8, 16, 32, 64, 128) appelle un des sous programme do, re, mi, fa, sol, la, si et do2. On ne vous demande pas de détailler les sous-programmes .
Cette solution n'a pas été rédigée. Vous pouvez le faire en modifiant le paramètre « contenu
» du modèle. Comment faire ?
Exercice 3
modifierÉcrire un programme qui, suivant la valeur présente en PORTB soit fait la somme des cases d'un tableau de 4 cases, soit calcule la moyenne de ces cases, soit cherche le maximum du tableau.
Cette solution n'a pas été rédigée. Vous pouvez le faire en modifiant le paramètre « contenu
» du modèle. Comment faire ?
Exercice 4 (18F)
modifierOn suppose qu'en PORTB se trouvent des valeurs positives (octets) provenant de l'extérieur du PIC (18FXXXX). Les détails sur la façon dont cela peut marcher ne nous intéressent pas ici. Faire un programme qui fait sans arrêt l'acquisition de 4 de ces valeurs, fait la somme et divise par 4 le résultat pour le ranger dans une variable moyenne.
CBLOCK 0x00 ; début de la zone variables en ACCESS RAM
somme_pdsfort :1 ; Zone de 1 byte
somme_pdsfaible : 1 ; zone de 1 bytes
compteur :1 ; zone de 1 byte
moyenne :1 ; le resultat sera ici
ENDC ; Fin de la zone
...
debut
movlw 0x0
movwf somme_pdsfort
movwf somme_pdsfaible
movlw 0x4
movwf compteur ; initialiser compteur
boucle
movf PORTB,W ; PORTB -> W
addwf somme_pdsfaible,f ;somme_pdsfaible + W ->somme_pdsfaible
btfsc STATUS,C ; test si pas retenue
incf somme_pdsfort,f ; sinon incremente somme_pdsfort
decfsz compteur , f ; décrémenter compteur et tester sa valeur
goto boucle
; il faut diviser par 4
bcf STATUS,C ;C<-0
rrf somme_pdsfort,f ;division par 2
rrf somme_pdsfaible,f ;division par 2
bcf STATUS,C ;C<-0
rrf somme_pdsfort,f ;division par 2
rrf somme_pdsfaible,f ;division par 2
; on a la moyenne dans somme_pdsfaible
movf somme_pdsfaible , w ; on charge la valeur obtenue dans w
movwf moyenne,f ;on range en 14 comme demandé
goto debut
END
Exercice 5
modifier1) On suppose qu'en PORTB se trouvent des valeurs (octets) provenant de l'extérieur du PIC (16F84). Les détails sur la façon dont cela peut marcher ne nous intéressent pas ici. Faire un programme qui fait l'acquisition de 4 de ces valeurs et les stocke dans un tableau. Ensuite on calculera la somme de ces 4 cases divisée par 4 et le résultat sera rangé à l'adresse $14.
CBLOCK 0x00 ; début de la zone variables en ACCESS RAM
somme_pdsfort :1 ; Zone de 1 byte
somme_pdsfaible : 1 ; zone de 1 byte
compteur :1 ; zone de 1 byte
tab:4 ;zone 4 bytes
ENDC ; Fin de la zone
...
debut
movlw 0x0
movwf somme_pdsfort
movwf somme_pdsfaible
movlw 0x4
movwf compteur ; initialiser compteur
movlw tab
movwf FSR ; W -> FSR
; mettre aussi STATUS,RP1=0 et STATUS,IRP=0 pour compatibilité
boucle
movf PORTB,w ; PORTB -> W
movwf INDF ;(FSR)<-W
incf FSR,f
decfsz compteur , f ; décrémenter compteur et tester sa valeur
goto boucle
; initialisation boucle 2
movlw 0x4
movwf compteur ; initialiser compteur
movlw tab
movwf FSR
boucle2
movf INDF,w ; W <-(FSR)
incf FSR,f
addwf somme_pdsfaible,f ;somme_pdsfaible + W ->somme_pdsfaible
btfsc STATUS,C ; test si pas retenue
incf somme_pdsfort,f ; sinon incremente somme_pdsfort
decfsz compteur , f ; décrémenter compteur et tester sa valeur
goto boucle2
; il faut diviser par 4
bcf STATUS,C ;C<-0
rrf somme_pdsfort,f ;division par 2
rrf somme_pdsfaible,f ;division par 2
bcf STATUS,C ;C<-0
rrf somme_pdsfort,f ;division par 2
rrf somme_pdsfaible,f ;division par 2
; on a la moyenne dans somme_pdsfaible
movf somme_pdsfaible , w ; on charge la valeur obtenue dans w
movwf 0x14 ;on range en 14 comme demandé
goto debut
END
2) Modifier ce programme pour qu’il calcule le maximum des 4 valeurs du tableau et le range en mémoire à la suite du tableau.
CBLOCK 0x00 ; début de la zone variables en ACCESS RAM
somme_pdsfort :1 ; Zone de {{Unité|1|octets}}
somme_pdsfaible : 1 ; zone de {{Unité|1|octets}}
compteur :1 ; zone de {{Unité|1|octets}}
tab:4 ;zone {{Unité|4|octets}}
Max:1 ;;;;;;;;zone {{Unité|1|octets}}
ENDC ; Fin de la zone
...
debut
movlw 0x0
movwf somme_pdsfort
movwf somme_pdsfaible
movwf Max ;;;;;;;; initialisation de Max
movlw 0x4
movwf compteur ; initialiser compteur
movlw tab
movwf FSR ; W -> FSR
; mettre aussi STATUS,RP1=0 et STATUS,IRP=0 pour compatibilité
boucle
movf PORTB,w ; PORTB -> W
movWf INDF ;(FSR)<-W
subwf Max,w ;;;;;;;;;;Max - W -> W
btfsS STATUS,C ;;;;;;;;;;c=1 si >0 et on saute
GOTO suite
GOTO suite2
suite movf INDF,w ;;;; W <-(FSR) on recherche dernière valeur
movwf Max ;;;;;;;;;;pour mettre dans Max
suite2 incf FSR,f
decfsz compteur , f ; décrémenter compteur et tester sa valeur
goto boucle
; initialisation boucle 2
movlw 0x4
movwf compteur ; initialiser compteur
movlw tab
movwf FSR
boucle2
movf INDF,w ; W <-(FSR)
incf FSR,f
addwf somme_pdsfaible,f ;somme_pdsfaible + W ->somme_pdsfaible
btfsc STATUS,C ; test si pas retenue
incf somme_pdsfort,f ; sinon incremente somme_pdsfort
decfsz compteur , f ; décrémenter compteur et tester sa valeur
goto boucle2
; il faut diviser par 4
bcf STATUS,C ;C<-0
rrf somme_pdsfort,f ;division par 2
rrf somme_pdsfaible,f ;division par 2
bcf STATUS,C ;C<-0
rrf somme_pdsfort,f ;division par 2
rrf somme_pdsfaible,f ;division par 2
; on a la moyenne dans somme_pdsfaible
movf somme_pdsfaible , w ; on charge la valeur obtenue dans w
movwf 0x14 ;on range en 14 comme demandé
goto debut
END
3) Modifier ce programme pour que le passage d'un tableau de 4 cases à un tableau de 10 (ou autre) cases se fasse seulement par la changement d'une seule valeur dans votre programme.