Compare commits

...

2 commits

Author SHA1 Message Date
Geoffrey Frogeye 162d381904 Début TP4 2017-06-09 12:30:34 +02:00
Geoffrey Frogeye 6ca11e8fda Fin TP3 2017-06-09 12:09:23 +02:00
16 changed files with 806 additions and 92 deletions

View file

@ -3,6 +3,8 @@
Avec ce TP nous allons pouvoir nous familiariser avec le convertisseur analogique-numérique (ou ADC).
**Note :** Bien que le code des programmes réalisés soient inclus dans ce compte-rendu, ils ne servent qu'à donner une vue d'ensemble et à justifier le travail réalisé.
# Prise en main de l'interface ADC (TP30)
Les deux programmes permettent d'afficher en continu les valeurs entrées sur ADC0 sur l'afficheur 7-segments situé PortA. Les conversions sont déclenchées à la suite (free running mode). Le premier programme utilise cependant une scrutation et ne se préoccupe pas de savoir si la conversion est terminée. Le deuxième programme déclenche une interruption pour chaque conversion terminée, et l'afficheur n'est mis à jour qu'à ce moment là, ce qui évite de gaspiller des ressources inutilement et évite aussi de récupérer des valeurs fausses dûes à une conversion pas totalement terminée (ce qui dans ce cas ne change quelque chose que pour la première scrutation).
@ -13,7 +15,7 @@ Les deux programmes permettent d'afficher en continu les valeurs entrées sur AD
Il est ici question d'utiliser un convertisseur analogique-numérique pour récupérer les valeurs d'une sonde de température pour l'afficheur dans un résultat plus lisible.
On réutilisera la même configuration que pour le deuxième programme du TP30, cependant l'affichage va varier un peu. En effet, on veut transformer la valeur reçue de l'ADC sur [0, 255] en valeur sur [0, 32]. Pour cela, on divise d'abord la valeur par $\frac{255}{32}\approx 8$. Puis on affiche les dizaines sur le premier afficheur et les unités sur le deuxième.
On réutilisera la même configuration que pour le deuxième programme du TP30, cependant l'affichage va varier un peu. En effet, on veut transformer la valeur reçue de l'ADC sur [0, 255] en valeur sur [0, 32]. Pour cela, on divise d'abord la valeur par $\frac{255}{32}\approx 8$. Puis on affiche les dizaines sur le premier afficheur et les unités sur le deuxième. D'un point de vue mathématique, on aurait aussi pu multiplier par $32$ puis diviser par $255$ ou multiplier par $\frac{32}{255}=0,12$, cependant ce n'est pas possible sur ce micro-contrôleur (du moins simplement) car les entiers sont stockés sur 8 bits donc leur valeur ne peuvent dépasser $255$, et les nombres à virgule ne sont pas supportés.
!include(TP31.txt lang=avrasmplus)
@ -25,7 +27,7 @@ On réutilise donc le code du TP22 nous permettant d'afficher un nombre différe
!include(TP32.txt lang=avrasmplus)
![Visualisation du capteur de distance](capteur_distance.svg)
![Visualisation du capteur de distance](capteur_distance_vect.svg)
Le capteur semble décroitre exponentiellement au fur et à mesure qu'on éloigne un obstacle de devant lui. Cependant, on remarque que si l'obstacle se rapproche trop, le capteur considère qu'il s'éloigne. Il a donc un intervalle de fonctionnement assez faible.
@ -33,3 +35,14 @@ Le capteur semble décroitre exponentiellement au fur et à mesure qu'on éloign
Nous allons réaliser une application concrète de l'utilisation de l'ADC en construisant un régulateur pour chauffage central. La difficulté sera ici de lire deux entrées d'ADC en alternance : il n'est donc pas possible d'utiliser le free-running mode que nous avons utilisé jusqu'ici. Le micro-contrôleur nous propose nativement de pouvoir comparer électriquement deux entrées d'ADC pour n'avoir à traiter qu'un seul résultat, cependant nous ne pourrons pas l'utiliser dans ce cas là car les deux entrées analogiques ne sont pas sur la même échelle (la première est sur [10, 26]°C, la deuxième est sur [0, 32]°C).
On utilisera donc aucun mode particulier, ni d'interruption, et on activera le bit permettant de déclencher une conversion sur `ADCSRA` après avoir sélectionné l'entre ADC que l'on désire avec `ADCMUX`, puis on scrutera le bit de réception pour continuer la suite du programme quand la conversion a été faite et on peut récupérer la valeur. Pour réduire le temps d'éxecution du programme (sa réactivité ici, étant donné que le programme tourne en boucle), on pourrait lancer une conversion dès que la précédente est terminée et qu'on a récupéré la valeur d'`ACDH` et de réaliser le traitement de la valeur précédente en même temps que la suivante est en train d'être convertie, plutôt que de passer en mode scrutation directement après le lancement de la conversion.
Un problème que nous avons rencontré est que l'on donnait une valeur à `ADMUX` deux fois avant que la conversion soit terminée (une fois lors de l'initialisation du programme et une autre fois dans la boucle). Cela avait pour effet de provoquer un comportement instable au niveau des conversions sur toute la durée d'éxecution du programme (et non que pour les premières lectures). Comme quoi vouloir s'assurer qu'un composant est bien configuré peut entraîner l'effet inverse.
Le programme alterne entre la lecture de la consigne et la lecture de la température réelle, qu'il stocke dans les registres `consigne` et `temperature`, respectivement. Pour gérer le mode hors-gel, `consigne` est écrasé avec la température du mode hors-gel si l'entrée correspondante (`PA7`) est active. Il aurait été plus judicieux de vérifier à priori si le mode hors-gel est actif et ainsi éviter une conversion inutile. Une fois les deux valeurs récupérées, on détermine si il faut allumer le chauffage ou l'éteindre, sinon le laisser dans son état actuel.
!include(TP33.txt lang=avrasmplus)
On remarque que la régulation se fait assez rapidement, et le chauffage "clignote" assez vite malgré l'hystéresis voulue. Dans un modèle plus fidèle à la réalité, où la température ne varie pas aussi rapidement, on préfèrerait mettre la procédure de mise à jour de l'état du chauffage (et donc par extensiion de la lecture des valeurs de consigne et d'entrée) dans une interruption watchdog à intervalle de temps assez grand (de l'ordre de plusieurs secondes) pour éviter d'utiliser des ressources inutilement, et éviter d'allumer et éteindre le chauffage trop fréquement malgré le phénomène d'hystéresis.

View file

@ -1,4 +1,4 @@
.equ PINA = 0x00 ; définition des adresses des ports
.equ PINA = 0x00 ; définition des adresses des ports
.equ DDRA = 0x01
.equ PORTA = 0x02
@ -17,12 +17,12 @@
.org 0x000 ; Vecteur RESET
jmp debut
.org 0x003A ; Interruption conversion ADC terminée
.org 0x003A ; Interruption conversion ADC terminée
jmp irqadc
.org 0x0080
codeAff: ; Représentation des chiffres sur l'afficheur 7-segments
codeAff: ; Représentation des chiffres sur l'afficheur 7-segments
.db 0b1111110, 0b001100, 0b0110111, 0b0011111, 0b1001101, 0b1011011, 0b1111011, 0b0001110, 0b1111111, 0b1011111
debut:
@ -33,7 +33,7 @@ debut:
out SPH, r29
DDRA@IO <- 0xFF ; Port A (afficheur 7-segments) en sortie
ADMUX <- 0b01100000 ; Sélection de l'ADC0
ADMUX <- 0b01100000 ; Sélection de l'ADC0
ADCSRB <- 0b00000000 ; Free running mode
ADCSRA <- 0b11101111 ; Activation des interruptions
@ -43,8 +43,8 @@ boucle:
sleep
jmp boucle
irqadc: ; Dès qu'une lecture est terminée, l'afficher sur l'afficheur
PORTA@IO <- codeAff@ROM[ADCH/51] ; On passe d'une valeur sur [0, 255] à [0, 5]
irqadc: ; Dès qu'une lecture est terminée, l'afficher sur l'afficheur
PORTA@IO <- codeAff@ROM[ADCH/51] ; On passe d'une valeur sur [0, 255] à [0, 5]
reti

View file

@ -1,4 +1,4 @@
.equ PINA = 0x00 ; définition des adresses des ports
.equ PINA = 0x00 ; définition des adresses des ports
.equ DDRA = 0x01
.equ PORTA = 0x02
.equ PINB = 0x03
@ -28,7 +28,7 @@
.org 0x0080
codeAff: ; Représentation des chiffres sur l'afficheur 7-segments
codeAff: ; Représentation des chiffres sur l'afficheur 7-segments
.db 0b1111110, 0b001100, 0b0110111, 0b0011111, 0b1001101, 0b1011011, 0b1111011, 0b0001110, 0b1111111, 0b1011111
debut:
@ -40,7 +40,7 @@ debut:
DDRA@IO <- 0xFF ; Port A (afficheur 7-segments) en sortie
DDRB@IO <- 0xFF ; Port B (afficheur 7-segments) en sortie
ADMUX <- 0b01100000 ; Sélection de l'ADC0
ADMUX <- 0b01100000 ; Sélection de l'ADC0
ADCSRB <- 0b00000000 ; Free running mode
ADCSRA <- 0b11101111 ; Activation des interruptions

View file

@ -1,4 +1,4 @@
.equ PINA = 0x00 ; définition des adresses des ports
.equ PINA = 0x00 ; définition des adresses des ports
.equ DDRA = 0x01
.equ PORTA = 0x02
.equ PINC = 0x06
@ -40,7 +40,7 @@
.org 0x0080
codeAff: ; Représentation des chiffres sur l'afficheur 7-segments
codeAff: ; Représentation des chiffres sur l'afficheur 7-segments
.db 0b1111110, 0b001100, 0b0110111, 0b0011111, 0b1001101, 0b1011011, 0b1111011, 0b0001110, 0b1111111, 0b1011111
debut:
@ -54,7 +54,7 @@ debut:
DDRA@IO <- 0xFF
DDRC@IO <- 0xFF
ADMUX <- 0b01100001 ; Sélection de l'ADC1
ADMUX <- 0b01100001 ; Sélection de l'ADC1
ADCSRB <- 0b00000000 ; Free-running mode
ADCSRA <- 0b11101111 ; Activation des interruptions

View file

@ -49,8 +49,9 @@ debut:
LDI R16,0xFF
OUT DDRB,R16
; ADCSRB <- 0b00000000
LDI R16,0b00000000
; ADCSRB <- 0b01000010
LDI R16,0b01000010
STS ADCSRB,R16
@ -58,6 +59,8 @@ debut:
boucle:
; Déclenchement de le lecture de la consigne
; ADMUX <- 0b01100000
LDI R16,0b01100000
STS ADMUX,R16
@ -66,7 +69,7 @@ boucle:
LDI R16,0b11100111
STS ADCSRA,R16
;ADCSRB <- 0b01000010
attente1:
; si (ADCSRA & 0b00010000) = 0 saut attente1
LDS R16,ADCSRA
@ -86,13 +89,44 @@ eti1:
JMP attente1
eti2:
; r5 <- ADCH
LDS R16,ADCH
MOV R5,R16
;ADCSRA <- ADCSRA & 0b11101111
; Lecture de la consigne
; consigne <- ADCH / 8 + 20
;si (PORTA@IO & 0b10000000) = 0 alors consigne <- 12
LDS R16,ADCH
LDI R17,8
SER R18
eti3:
INC R18
SUB R16,R17
BRCC eti3
MOV R16,R18
LDI R17,20
ADD R16,R17
STS consigne,R16
; Mode hors-gel
; si (PINA@IO & 0b10000000) == 0 alors consigne <- 12
IN R16,PINA
ANDI R16,0b10000000
PUSH R16
LDI R16,0
POP R17
CP R17,R16
BREQ eti4
CLR R16
RJMP eti5
eti4:
LDI R16,0x01
eti5:
TST R16
BREQ eti6
LDI R16,12
STS consigne,R16
eti6:
; Déclenchement de le lecture de la température
; ADMUX <- 0b01100001
LDI R16,0b01100001
STS ADMUX,R16
@ -102,7 +136,6 @@ eti2:
STS ADCSRA,R16
;ADCSRB <- 0b01000010
attente2:
; si (ADCSRA & 0b00010000) = 0 saut attente2
LDS R16,ADCSRA
@ -111,40 +144,119 @@ attente2:
LDI R16,0
POP R17
CP R17,R16
BREQ eti3
BREQ eti7
CLR R16
RJMP eti4
eti3:
RJMP eti8
eti7:
LDI R16,0x01
eti4:
eti8:
TST R16
BREQ eti5
BREQ eti9
JMP attente2
eti5:
eti9:
; r6 <- ADCH
LDS R16,ADCH
MOV R6,R16
;ADCSRA <- ADCSRA & 0b11101111
; temp <- ADCH / 4
LDS R16,ADCH
LDI R17,4
SER R18
eti10:
INC R18
SUB R16,R17
BRCC eti10
MOV R16,R18
STS temp,R16
; Affichage
; PORTA@IO <- codeAff@ROM[temp/20]
LDS R16,temp
LDI R17,20
SER R18
eti11:
INC R18
SUB R16,R17
BRCC eti11
MOV R16,R18
LDI R30,low(codeAff<<1)
LDI R31,high(codeAff<<1)
CLR R17
ADD R30,R16
ADC R31,R17
LPM R16,Z
OUT PORTA,R16
; PORTB@IO <- codeAff@ROM[temp-(temp/20)*20]
LDS R16,temp
PUSH R16
LDS R16,temp
LDI R17,20
SER R18
eti12:
INC R18
SUB R16,R17
BRCC eti12
MOV R16,R18
LDI R17,20
MUL R16,R17
MOV R16,R0
MOV R17,R16
POP R16
SUB R16,R17
LDI R30,low(codeAff<<1)
LDI R31,high(codeAff<<1)
CLR R17
ADD R30,R16
ADC R31,R17
LPM R16,Z
OUT PORTB,R16
; Gestion du radiateur
; si consigne - 1 > temp alors PORTB@IO <- PORTB@IO | 0b10000000
LDS R16,consigne
LDI R17,1
SUB R16,R17
PUSH R16
LDS R16,temp
POP R17
CP R17,R16
BREQ eti13
BRLO eti13
LDI R16,0x01
RJMP eti14
eti13:
CLR R16
eti14:
TST R16
BREQ eti15
IN R16,PORTB
ORI R16,0b10000000
OUT PORTB,R16
eti15:
; si consigne + 1 < temp alors PORTB@IO <- PORTB@IO & 0b01111111
;PORTB@IO <- PORTB@IO | 0b10000000
LDS R16,consigne
LDI R17,1
ADD R16,R17
PUSH R16
LDS R16,temp
POP R17
CP R17,R16
BRLO eti16
CLR R16
RJMP eti17
eti16:
LDI R16,0x01
eti17:
TST R16
BREQ eti18
IN R16,PORTB
ANDI R16,0b01111111
OUT PORTB,R16
eti18:
jmp boucle

View file

@ -1,4 +1,4 @@
.equ PINA = 0x00 ; définition des adresses des ports
.equ PINA = 0x00 ; définition des adresses des ports
.equ DDRA = 0x01
.equ PORTA = 0x02
.equ PINB = 0x03
@ -26,15 +26,11 @@
.org 0x0080
codeAff:
.db 0b1111110, 0b001100
.db 0b0110111, 0b0011111
.db 0b1001101, 0b1011011
.db 0b1111011, 0b0001110
.db 0b1111111, 0b1011111
codeAff: ; Représentation des chiffres sur l'afficheur 7-segments
.db 0b1111110, 0b001100, 0b0110111, 0b0011111, 0b1001101, 0b1011011, 0b1111011, 0b0001110, 0b1111111, 0b1011111
debut:
; Initialisation de la pile
ldi r28, low(RAMEND)
ldi r29, high(RAMEND)
@ -43,46 +39,41 @@ debut:
DDRA@IO <- 0b01111111
DDRB@IO <- 0xFF
ADCSRB <- 0b00000000
ADCSRB <- 0b01000010
boucle:
; Déclenchement de le lecture de la consigne
ADMUX <- 0b01100000
ADCSRA <- 0b11100111
;ADCSRB <- 0b01000010
attente1:
si (ADCSRA & 0b00010000) = 0 saut attente1
r5 <- ADCH
;ADCSRA <- ADCSRA & 0b11101111
;consigne <- ADCH / 8 + 20
;si (PORTA@IO & 0b10000000) = 0 alors consigne <- 12
ADMUX <- 0b01100001
ADCSRA <- 0b11100111
;ADCSRB <- 0b01000010
; Lecture de la consigne
consigne <- ADCH / 8 + 20
; Mode hors-gel
si (PINA@IO & 0b10000000) == 0 alors consigne <- 12
; Déclenchement de la lecture de la température
ADMUX <- 0b01100001
attente2:
si (ADCSRA & 0b00010000) = 0 saut attente2
r6 <- ADCH
;ADCSRA <- ADCSRA & 0b11101111
;temp <- ADCH / 4
;PORTA@IO <- codeAff@ROM[temp/20]
;PORTB@IO <- codeAff@ROM[temp-(temp/20)*20]
;si consigne - 1 > temp alors PORTB@IO <- PORTB@IO | 0b10000000
;si consigne + 1 < temp alors PORTB@IO <- PORTB@IO & 0b01111111
;PORTB@IO <- PORTB@IO | 0b10000000
temp <- ADCH / 4
; Affichage
PORTA@IO <- codeAff@ROM[temp/20]
PORTB@IO <- codeAff@ROM[temp-(temp/20)*20]
; Gestion du radiateur
si consigne - 1 > temp alors PORTB@IO <- PORTB@IO | 0b10000000
si consigne + 1 < temp alors PORTB@IO <- PORTB@IO & 0b01111111
jmp boucle

View file

@ -57,7 +57,7 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="269.36956"
inkscape:cx="40.064932"
inkscape:cy="187.87975"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
@ -97,14 +97,14 @@
xml:space="preserve"
id="flowRoot4801"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
transform="matrix(0.26458333,0,0,0.26458333,21.258142,1.1339286)"><flowRegion
transform="matrix(0.26458333,0,0,0.26458333,4.0241861,1.1339286)"><flowRegion
id="flowRegion4803"><rect
id="rect4805"
width="67.857132"
height="22.857159"
width="197.15665"
height="22.857147"
x="190"
y="471.09113" /></flowRegion><flowPara
id="flowPara4807">Distance</flowPara></flowRoot> <flowRoot
id="flowPara4807">Distance (unité arbitraire)</flowPara></flowRoot> <flowRoot
xml:space="preserve"
id="flowRoot4801-9"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.51181102;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"

Before

Width:  |  Height:  |  Size: 7 KiB

After

Width:  |  Height:  |  Size: 7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

39
TP4/Makefile Normal file
View file

@ -0,0 +1,39 @@
.PHONY: default cleantmp clean
#default: CR.pdf
##default: $(subst md,pdf,$(wildcard *.md))
#
## COMPTE-RENDU
#
#SOURCES=$(wildcard *.txt)
#
#%.pdf: %.html
# scripts/html2pdf -i "$<" -o "$@" -t "Tutorat de microprocesseurs S6 - TD1 Sujet 8"
#
#%.html: %.tmp template.html
# scripts/md2html -i "$<" -o "$@" -t template.html
#
#%.tmp: %.md $(SOURCES)
# scripts/node_modules/markedpp/bin/markedpp.js "$<" > "$@"
# PROGRAMME
%.asm: %.txt
wine ~/S6/uP/tutorat/scripts/Compilateur.exe ~/S6/uP/tutorat/scripts/gram.txt "$<" "$@"
%.hex: %.asm
wine ~/S6/uP/tutorat/scripts/gavrasm.exe "$<"
%.upload: %.hex
avrdude -C ~/S6/uP/tutorat/scripts/avrdude.conf -v -p atmega2560 -c wiring -P /dev/ttyACM0 -b 115200 -D -U flash:w:"$<":i
%.up: %.upload
serial:
minicom -D /dev/ttyACM0 -b 2400
clean:
rm -rf $(subst md,html,$(wildcard *.md)) *.tmp
rm -rf $(subst md,pdf,$(wildcard *.md))
rm -rf *.hex *.lst *.err

118
TP4/TP40.asm Normal file
View file

@ -0,0 +1,118 @@
; lecture de la liaison série
.equ RAMEND = 0x21FF
.equ SPH = 0x3E
.equ SPL = 0x3D
.equ UBRR0H = 0x00C5
.equ UBRR0L = 0x00C4
.equ UCSR0A = 0x00C0
.equ UCSR0B = 0x00C1
.equ UCSR0C = 0x00C2
.equ UDR0 = 0x00C6
.org 0x0000
; Vecteur RESET
jmp debut
.org 0x0080
debut:
; initialisation du pointeur de pile
ldi r28,low(RAMEND)
ldi r29,high(RAMEND)
out SPL, r28
out SPH, r29
; UBRR0H <- 3
LDI R16,3
STS UBRR0H,R16
; UBRR0L <- 64
LDI R16,64
STS UBRR0L,R16
; UCSR0A <- 0b00000110
LDI R16,0b00000110
STS UCSR0A,R16
; UCSR0B <- 0b00011000
LDI R16,0b00011000
STS UCSR0B,R16
; UCSR0C <- 0b00000110
LDI R16,0b00000110
STS UCSR0C,R16
boucle:
; attend qu'un caractère arrive
; si (UCSR0a & 0x80) == 0 saut boucle
LDS R16,UCSR0a
ANDI R16,0x80
PUSH R16
LDI R16,0
POP R17
CP R17,R16
BREQ eti0
CLR R16
RJMP eti1
eti0:
LDI R16,0x01
eti1:
TST R16
BREQ eti2
JMP boucle
eti2:
; R20 <- UDR0
LDS R16,UDR0
MOV R20,R16
; si R20 == 'a' alors R20 <- 'A'
MOV R16,R20
PUSH R16
LDI R16,'a'
POP R17
CP R17,R16
BREQ eti3
CLR R16
RJMP eti4
eti3:
LDI R16,0x01
eti4:
TST R16
BREQ eti5
LDI R16,'A'
MOV R20,R16
eti5:
; si R20 == 'e' alors R20 <- 'E'
MOV R16,R20
PUSH R16
LDI R16,'e'
POP R17
CP R17,R16
BREQ eti6
CLR R16
RJMP eti7
eti6:
LDI R16,0x01
eti7:
TST R16
BREQ eti8
LDI R16,'E'
MOV R20,R16
eti8:
; UDR0 <- R20
STS UDR0,R20
; saut boucle
JMP boucle

44
TP4/TP40.txt Normal file
View file

@ -0,0 +1,44 @@
; lecture de la liaison série
.equ RAMEND = 0x21FF
.equ SPH = 0x3E
.equ SPL = 0x3D
.equ UBRR0H = 0x00C5
.equ UBRR0L = 0x00C4
.equ UCSR0A = 0x00C0
.equ UCSR0B = 0x00C1
.equ UCSR0C = 0x00C2
.equ UDR0 = 0x00C6
.org 0x0000
; Vecteur RESET
jmp debut
.org 0x0080
debut:
; initialisation du pointeur de pile
ldi r28,low(RAMEND)
ldi r29,high(RAMEND)
out SPL, r28
out SPH, r29
UBRR0H <- 3
UBRR0L <- 64
UCSR0A <- 0b00000110
UCSR0B <- 0b00011000
UCSR0C <- 0b00000110
boucle:
; attend qu'un caractère arrive
si (UCSR0a & 0x80) == 0 saut boucle
R20 <- UDR0
si R20 == 'a' alors R20 <- 'A'
si R20 == 'e' alors R20 <- 'E'
UDR0 <- R20
saut boucle

91
TP4/TP41a.txt Normal file
View file

@ -0,0 +1,91 @@
.equ PINA = 0x00 ; définition des adresses des ports
.equ DDRA = 0x01
.equ PORTA = 0x02
.equ PINC = 0x06
.equ DDRC = 0x07
.equ PORTC = 0x08
.equ RAMEND = 0x21FF
.equ SPH = 0x3E
.equ SPL = 0x3D
.equ UBRR0H = 0x00C5
.equ UBRR0L = 0x00C4
.equ UCSR0A = 0x00C0
.equ UCSR0B = 0x00C1
.equ UCSR0C = 0x00C2
.equ UDR0 = 0x00C6
.equ TCCR0A = 0x24
.equ TCCR0B = 0x25
.equ TIMSK0 = 0x6E
.equ TIFR0 = 0x35
.def d2 = r19
.def d1 = r20
.def d0 = r21
.def select = r22
.org 0x0000
; Vecteur RESET
jmp debut
.org 0x002E ; Interruption du timer
jmp tm
.org 0x0080
codeAff: ; Représentation des chiffres sur l'afficheur 7-segments
.db 0b1111110, 0b001100, 0b0110111, 0b0011111, 0b1001101, 0b1011011, 0b1111011, 0b0001110, 0b1111111, 0b1011111
debut:
; initialisation du pointeur de pile
ldi r28,low(RAMEND)
ldi r29,high(RAMEND)
out SPL, r28
out SPH, r29
; Ports pour l'afficheur
DDRA@IO <- 0xFF
DDRC@IO <- 0xFF
; Port série 16 MHz 2400 Baud
UBRR0H <- 3
UBRR0L <- 64
UCSR0A <- 0b00000110
UCSR0B <- 0b00011000
UCSR0C <- 0b00000110
; Timer toutes les 2 ms
TCCR0A@IO <- 0x00
TCCR0B@IO <- 0x04
TIMSK0 <- 0x01
TIFR0 <- 0x01
; Initialisation des valeurs à envoyer sur le port série
d2 <- 0
d1 <- 0
d0 <- 0
sei
boucle:
; attend qu'un caractère arrive
si (UCSR0a & 0x80) == 0 saut boucle
R20 <- UDR0
d2 <- UDR0 / 100
d1 <- (UDR0 / 10) % 10
d0 <- UDR0 % 10
saut boucle
tm:
PortC@IO <- select
si select = 0b10000000 alors PortA@IO <- codeAff@ROM[d2]
si select = 0b01000000 alors PortA@IO <- codeAff@ROM[d1]
si select = 0b00100000 alors PortA@IO <- codeAff@ROM[d0]
lsl select
si select = 0 alors select <- 0b00100000
reti

89
TP4/TP41b.txt Normal file
View file

@ -0,0 +1,89 @@
.equ PINC = 0x06 ; définition des adresses des ports
.equ DDRC = 0x07
.equ PORTC = 0x08
.equ RAMEND = 0x21FF
.equ SPH = 0x3E
.equ SPL = 0x3D
.equ UBRR0H = 0x00C5
.equ UBRR0L = 0x00C4
.equ UCSR0A = 0x00C0
.equ UCSR0B = 0x00C1
.equ UCSR0C = 0x00C2
.equ UDR0 = 0x00C6
.equ TCCR0A = 0x24
.equ TCCR0B = 0x25
.equ TIMSK0 = 0x6E
.equ TIFR0 = 0x35
.def test = r19
.def numero = r20
.def ancienNumero = r21
.org 0x0000
; Vecteur RESET
jmp debut
.org 0x002E ; Interruption du timer
jmp tm
.org 0x0080
touche:
.DB 0x41, 0x88, 0x48, 0x28, 0x84, 0x44, 0x24, 0x82, 0x42, 0x22, 0x81, 0x21
; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, *, #
debut:
; initialisation du pointeur de pile
ldi r28,low(RAMEND)
ldi r29,high(RAMEND)
out SPL, r28
out SPH, r29
; Ports pour la touche de clavier
DDRC@IO <- 0xFF
; Port série 16 MHz 2400 Baud
UBRR0H <- 3
UBRR0L <- 64
UCSR0A <- 0b00000110
UCSR0B <- 0b00011000
UCSR0C <- 0b00000110
; Timer toutes les 65 ms
TCCR0A@IO <- 0x00
TCCR0B@IO <- 0b00000101
TIMSK0 <- 0x01
TIFR0 <- 0x01
sei
test <- 0
numero <- 255
ancienNumero <- 255
boucle:
sleep
saut boucle
reti:
reti
tm:
; On teste la touche courante
PORTC@IO <- touche@ROM[test]
si PINC@IO = touche@ROM[test] alors numero <- test
; On prépare la touche suivante
inc test
; Si on est arrivé à la fin du test on recommence
si test > 11 alors test <- 0
; Si le numéro est différent du précédent (~ a changé) on l'envoie
si numero = test saut reti
si numero < 10 alors UDR0 <- 48 + numero
si numero = 10 alors UDR0 <- 42
si numero = 11 alors UDR0 <- 35
ancienNumero <- numero
reti

91
TP4/TP42a.txt Normal file
View file

@ -0,0 +1,91 @@
.equ RAMEND = 0x21FF
.equ SPH = 0x3E
.equ SPL = 0x3D
.equ ADMUX = 0x7C
.equ ADCSRB = 0x7B
.equ ADCSRA = 0x7A
.equ ADCH = 0x79
.equ UBRR0H = 0x00C5
.equ UBRR0L = 0x00C4
.equ UCSR0A = 0x00C0
.equ UCSR0B = 0x00C1
.equ UCSR0C = 0x00C2
.equ UDR0 = 0x00C6
.equ TCCR0A = 0x24
.equ TCCR0B = 0x25
.equ TIMSK0 = 0x6E
.equ TIFR0 = 0x35
.org 0x0000
; Vecteur RESET
jmp debut
.org 0x002E ; Interruption du timer
jmp tm
.def timer = r20
.org 0x0080
debut:
; initialisation du pointeur de pile
ldi r28,low(RAMEND)
ldi r29,high(RAMEND)
out SPL, r28
out SPH, r29
; Port série 16 MHz 2400 Baud
UBRR0H <- 3
UBRR0L <- 64
UCSR0A <- 0b00000110
UCSR0B <- 0b00011000
UCSR0C <- 0b00000110
; Timer toutes les 65 ms
TCCR0A@IO <- 0x00
TCCR0B@IO <- 0b00000101
TIMSK0 <- 0x01
TIFR0 <- 0x01
; ADC en déclenchement manuel
ADMUX <- 0b01100000
ADCSRB <- 0b00000010
ADCSRA <- 0b11010110
sei
timer <- 0
boucleTemps:
si timer < 122 saut boucleTemps ; 8 secondes ne sont pas encore passées
timer <- 0
; Lancement d'une conversion ADC
ADCSRA <- 0b11011101
; Tant que la conversion ADC n'est pas terminée
boucleAdc:
si (ADCSRA & 0x80) == 0 saut boucleAdc
UDR0 <- ADCH / 10
; Tant que le premier caractère n'est pas envoyé, attendre avant d'envoyer le prochain
boucleCar0:
si (UCSR0A & 0x4) == 0 saut boucleCar0
UDR0 <- ADCH % 10
; Tant que le deuxième caractère n'est pas envoyé, attendre avant d'envoyer le prochain
boucleCar1:
si (UCSR0A & 0x4) == 0 saut boucleCar1
UDR0 <- 67
; Tant que le troisième caractère n'est pas envoyé, attendre avant d'envoyer le prochain
boucleCar2:
si (UCSR0A & 0x4) == 0 saut boucleCar2
UDR0 <- 13
; Tant que le quatrième caractère n'est pas envoyé, attendre avant d'envoyer le prochain
boucleCar3:
si (UCSR0A & 0x4) == 0 saut boucleCar3
saut boucleTemps
tm:
inc timer
reti

117
TP4/TP42b.txt Normal file
View file

@ -0,0 +1,117 @@
.equ RAMEND = 0x21FF
.equ SPH = 0x3E
.equ SPL = 0x3D
.equ ADMUX = 0x7C
.equ ADCSRB = 0x7B
.equ ADCSRA = 0x7A
.equ ADCH = 0x79
.equ UBRR0H = 0x00C5
.equ UBRR0L = 0x00C4
.equ UCSR0A = 0x00C0
.equ UCSR0B = 0x00C1
.equ UCSR0C = 0x00C2
.equ UDR0 = 0x00C6
.org 0x0000
; Vecteur RESET
jmp debut
.org 0x002E ; Interruption du timer
jmp tm
.def timer = r20
.org 0x0080
debut:
; initialisation du pointeur de pile
ldi r28,low(RAMEND)
ldi r29,high(RAMEND)
out SPL, r28
out SPH, r29
; Port série 16 MHz 2400 Baud
UBRR0H <- 3
UBRR0L <- 64
UCSR0A <- 0b00000110
UCSR0B <- 0b00011000
UCSR0C <- 0b00000110
; ADC en déclenchement manuel
ADCSRB <- 0b00000010
ADCSRA <- 0b11010110
sei
timer <- 0
attendreConversionADC:
si (ADCSRA & 0b00010000) = 0 saut attendreConversionADC
ret
boucle:
; Lecture
ADMUX <- 0b01100000
call attendreConversionADC
; Comparaison avec la valeur correspondant à 10cm
si ADCH >
; Lecture de la consigne
consigne <- ADCH / 8 + 20
; Mode hors-gel
si (PINA@IO & 0b10000000) == 0 alors consigne <- 12
; Déclenchement de la lecture de la température
ADMUX <- 0b01100001
attente2:
si (ADCSRA & 0b00010000) = 0 saut attente2
temp <- ADCH / 4
; Affichage
PORTA@IO <- codeAff@ROM[temp/20]
PORTB@IO <- codeAff@ROM[temp-(temp/20)*20]
; Gestion du radiateur
si consigne - 1 > temp alors PORTB@IO <- PORTB@IO | 0b10000000
si consigne + 1 < temp alors PORTB@IO <- PORTB@IO & 0b01111111
jmp boucle
boucleTemps:
si timer < 122 saut boucleTemps ; 8 secondes ne sont pas encore passées
timer <- 0
; Lancement d'une conversion ADC
ADCSRA <- 0b11011101
; Tant que la conversion ADC n'est pas terminée
boucleAdc:
si (ADCSRA & 0x80) == 0 saut boucleAdc
UDR0 <- ADCH / 10
; Tant que le premier caractère n'est pas envoyé, attendre avant d'envoyer le prochain
boucleCar0:
si (UCSR0A & 0x4) == 0 saut boucleCar0
UDR0 <- ADCH % 10
; Tant que le deuxième caractère n'est pas envoyé, attendre avant d'envoyer le prochain
boucleCar1:
si (UCSR0A & 0x4) == 0 saut boucleCar1
UDR0 <- 67
; Tant que le troisième caractère n'est pas envoyé, attendre avant d'envoyer le prochain
boucleCar2:
si (UCSR0A & 0x4) == 0 saut boucleCar2
UDR0 <- 13
; Tant que le quatrième caractère n'est pas envoyé, attendre avant d'envoyer le prochain
boucleCar3:
si (UCSR0A & 0x4) == 0 saut boucleCar3
saut boucleTemps
tm:
inc timer
reti

View file

@ -14,6 +14,14 @@
}
code {
white-space: pre-wrap;
background: rgba(0, 0, 0, 0.1);
border-radius: 5px;
padding: 1px;
}
pre code {
border: solid 1px rgba(0, 0, 0, 0.5);
display: block;
padding: 2px;
}
h1, h2, h3 {
text-decoration: underline;