This repository has been archived on 2019-08-09. You can view files and clone it, but cannot push or open issues or pull requests.
s6-up-tp/TP2/TP2.md

8.7 KiB

Compte-rendu TP2 Microprocesseurs

DJERABA Taky PREUD'HOMME Geoffrey (IMA3 TP2)

Ce TP a pour but de nous familiariser avec la gestion des interruptions et du watchdog sur l'Atmega 2560.

Un bouton/une LED et un chien de garde (TP20)

!include(TP20.txt lang=avrasmplus)

Ce programme allume la LED lors de l'appui sur un bouton, et ce jusqu'à une seconde après l'avoir relâché. Si on rappuie sur le bouton pendant l'intervalle des 1s, le compteur est remis à zéro.

Chenillard par interruption (TP21)

On nous demande ici la même chose qu'au TP11, les différence étant :

  • Les changement doivent se faire sur une interruption et non plus dans une boucle
  • On peut tourner dans les deux sens et non plus dans un seul

On écrira alors notre code dans des parties d'interruption, et se contentera de duppliquer le code en "changeant le sens" pour gérer le sens inverse. La seule partie commune étant l'actualisation de la valeur des ports, on créera une fonction pour cette dernière.

On utilise le registre port comme un booléen. On considère qu'une valeur paire correspond à vrai, et une valeur impaire correspond à faux. On peut donc vérifier si le port est vrai ou faux en comparant son bit de point faible avec 0 ou 1. L'intérêt réside surtout dans le fait qu'on peut inverser l'état du booléen avec une simple incrémentation ou décrémentation.

La boucle principale du code reste sur l'instruction sleep, ce qui permet au microprocesseur de ne rien faire tant qu'il n'y a pas d'interruption, et ainsi économiser de l'énergie.

chen ← 0b00000001
port ← 0x00 ; pair : chenillard sur le port A, impair : port B

boucle:
    sleep ; On attend là si rien ne se passe
    jmp boucle 

horaire:
    Si (port & 0x01) == 0 alors DecalerGauche chen
    Si (port & 0x01) == 1 alors DecalerDroite chen
    Si chen != 0 saut boucle
    Si (port & 0x01) == 0 alors chen ← 0b00000001
    Si (port & 0x01) == 1 alors chen ← 0b10000000
    Incrementer port ; On change de port
    call afficher
    Retourner

antihoraire:
    Si (port & 0x01) == 0 alors DecalerDroite chen
    Si (port & 0x01) == 1 alors DecalerGauche chen
    Si chen != 0 saut boucle
    Si (port & 0x01) == 0 alors chen ← 0b10000000
    Si (port & 0x01) == 1 alors chen ← 0b00000001
    Incrementer port ; On change de port
    call afficher
    Retourner

afficher:
    Si (port & 0x01) == 0 alors PortB@IO ← 0x00
    Si (port & 0x01) == 1 alors PortA@IO ← 0x00
    Si (port & 0x01) == 0 alors PortA@IO ← chen
    Si (port & 0x01) == 1 alors PortB@IO ← chen
    Retourner

On a pu constater qu'éxecuter une instruction de décalage en tant qu'instruction conditionelle (j'entend par là ce qui est éxécuté lorsque la condition d'un si est vraie) n'est pas possible avec l'assembleur étendu (bien que tout à fait réalisable en assembleur standard). On a donc triché un peu et utilisé le fait que multiplier ou diviser un nombre par sa base (ici 2) permet de décaler ses chiffres vers la gauche ou vers la droite repectivement.

!include(TP21.txt lang=avrasmplus)

Compteur (TP22)

On nous demande de faire l'affichage d'un compteur qui s'incrémente toutes les secondes.

L'affichage sur un afficheur 7 segments avait déjà été réalisé au TP précédent, on peut reprendre le tableau de correspondances nombre ↔ représentation sur les 7 segments.

Pour les différentes étapes proposées, voici ce qu'il faut faire :

Comptage de 1 digit sur le simulateur

On considère un registre d0 stockant ce digit (et non sa représentation sur le 7 segment). On configure le Watchdog de façon à ce qu'il effectue une interruption toutes les secondes. L'interruption se chargera d'incrémenter ce registre et de le remettre à 0 au cas où il viendrait à dépasser 9, puis d'envoyer sa représentation sur le port A.

d0 ← 0

Configurer Watchdog: Interruption toutes les secondes sur wd

boucle:
    sleep
    jmp boucle

wd:
    ; Logique
    Incrementer d0
    Si d0 > 10 saut d0 ← 0:
    ; Affichage
    Sortir afficheur[d0] sur portA
    Retourner

Comptage de 1 digit sur la maquette

Le code ne doit à priori pas changer, il faut juste s'assurer qu'un bit parmi PC5 à PC7 soit à un afin que le digit soit bien affihé sur l'un des trois segments.

Cependant, on se rend compte que le Watchdog sur la carte se comporte bizarrement : en effet il compte approximativement 100 fois plus vite que sur le simulateur, pour exactement le même code. Nous n'avons pas réussi à résoudre ce problème, cependant nous aurions pu utiliser le timer (qui lui semble fonctionner) qui incrémente un registre, et éxecuter le code de l'interruption dès que ce registre dépasse une certaine valeur (\frac{1}{\text{periode du timer}}) correspondant à une seconde.

Comptage de 3 digits sur le simulateur

À d0 viennent s'ajouter d1 et d2, correspondant aux digit de poids plus élevés. Ici, dès qu'un digit dépasse 9, il se remet à 0 et incrémente le suivant. Il suffit ensuite d'afficher chaque digit sur son port correspondant.

d2 ← 0
d1 ← 0
d0 ← 0

Configurer Watchdog: Interruption toutes les secondes sur wd

boucle:
    sleep
    jmp boucle

wd: 
    Incrementer d0
    Si d0 < 10 Saut afficher
    d0 ← 0
    Incrementer d1
    Si d1 < 10 Saut afficher
    d1 ← 0
    Incrementer d2
    Si d2 < 10 Saut afficher
    d2 ← 0
    ; Comportement si >999 : on revient à 000

afficher:
    Sortir afficheur[d2] sur portC
    Sortir afficheur[d1] sur portB
    Sortir afficheur[d0] sur portA
    Retourner

Comptage de 3 digits sur la maquette

C'est ici un peu plus compliqué, en effet le port A est utilisé pour chacun des afficheurs 7 segments. On peut cependant sélectionner l'afficheur avec le port C (PC5 à PC7). L'astuce consiste à afficher un afficheur à la suite et ce suffisament rapidement (un affichage peut se faire entre 8 et 16 ms) pour que l'œil ait l'impression qu'ils soient tous affichés en même temps. On utilisera pour ça un timer, qui toutes les 4 ms (<\frac{16}{3}) changera le digit affiché.

On stockera le digit en cours d'affichage dans un registre select. Il contiendra en réalité la configuration du PortC à envoyer pour prendre l'afficheur voulu. Il suffit ensuite de le décaler vers la droite ou vers la gauche et de recommencer (tel un chenillard) à chauque interruption de timer.

d2 ← 0
d1 ← 0
d0 ← 0
select ← 0x80

Configurer Watchdog: Interruption toutes les secondes sur wd
Configurer timer0: Interruption toutes les 4 ms sur tm

boucle:
    sleep
    jmp boucle

wd: 
    Incrementer d0
    Si d0 < 10 Retourner
    d0 ← 0
    Incrementer d1
    Si d1 < 10 Retourner
    d1 ← 0
    Incrementer d2
    Si d2 < 10 Retourner
    d2 ← 0
    Retourner ; Comportement si >999 : on revient à 000

tm:
    PortC@IO ← select
    Si select = 0x80 alors PortA ← afficheur[d0]
    Si select = 0x40 alors PortA ← afficheur[d1]
    Si select = 0x20 alors PortA ← afficheur[d2]
    DecalerGauche select
    Si select = 0 alors select ← 0x80
    Retourner

En assembleur étendu, cela donne :

!include(TP23.txt lang=avrasmplus)

Minuteur d'un four (TP23)

Cet exercice nous propose de rassembler ce que l'on a appris dans ce TP dans un seul programme. L'algorithme étant plutôt simple, il sera décrit en commentaire du programme.

Quelques notes cependant :

  • On utilise le fait qu'une décrémentation d'un registre déjà à 0 provoque un dépassement et sa valeur repasse à 255, et le flag du dépassement est mis à 1. Pour savoir si un nombre était à 0 avant de faire une décrémentation, on vérifiera si le nombre n'est plus dans son intervalle de définition "normal" (0-9 pour un chiffre). Il aurait été plus "propre" de vérifier le drapeau, mais plus coûteux (utilise un masque et une comparaison).
  • Le watchdog est initialisé au début du programme et n'est plus réinitialisé après, son interruption associée a un effet en fonction de si le four est en route ou non. Cela a deux désavantages : le four compte entre 0 et 1 seconde de moins que nécessaire en fonction de quand a été appuyé le bouton marche par rapport à l'état du watchdog, et une interruption est effectuée chaque seconde même si le four est en mode veille (ce qui n'est pas une bonne idée d'un point de vue énergétique). Il aurait été plus judicieux d'activer le watchdog lorsque de l'appui sur le bouton marche et de l'arrêter lors de la fin de décompte.
  • Notre four affiche 0 pendant une seconde alors que la plupart des fours affichent 1 pendant une seconde et puis s'arrêtent. Ce comportement n'a pas été spécifié dans le cahier des charges, on en a donc profité pour simplifier notre logique.

!include (TP23.txt lang=avrasmplus)