; Équivalences .equ PINA = 0x00 .equ DDRA = 0x01 .equ PORTA = 0x02 .equ PINC = 0x06 .equ DDRC = 0x07 .equ PORTC = 0x08 .equ PING = 0x12 .equ DDRG = 0x13 .equ PORTG = 0x14 .equ WDTCSR = 0x60 .equ TTCR0A = 0x24 .equ TTCR0B = 0x25 .equ TMSK0 = 0x6e .equ EIMSK = 0x3D .equ EICRA = 0x69 .equ EICRB = 0x6A .equ ADMUX = 0x7C .equ ADCSRB = 0x7B .equ ADCSRA = 0x7A .equ ADCH = 0x79 .equ SPH = 0x3E .equ SPL = 0x3D ; Nommage des registres utilisés .def etat = r12 .def compteur = r6 ; Utilisé pour modifier des valeurs dans le menu .def reference = r13 ; Température de référence actuelle .def d3 = r2 ; Digit 3 (tout à gauche) .def d2 = r3 ; Digit 2 .def d1 = r4 ; Digit 1 .def d0 = r5 ; Digit 0 (tout à droite) .def t2 = r8 ; Jour (3 premiers bits) et Heure (5 derniers bits) .def t1 = r9 ; Minutes .def t0 = r10 ; Secondes / 2 .def tt = r11 ; Watchdog artificiel .def temp = r7 ; Utilisé pour différentes choses mais très brièvement ; Nommage des adresses RAM utilisées .equ assocs = 0x0200 ; Association des modes aux heures (tableau de taille 168 octets) .equ tempJour = 0x02a8 ; Température du mode jour .equ tempNuit = 0x02a9 ; Température du mode nuit ; Vecteurs d'interruptions .org 0x000 ; Vecteur RESET jmp debut .org 0x0002 ; INT0 jmp valider .org 0x0004 ; INT1 jmp retour .org 0x0006 ; INT2 jmp decrementer .org 0x0008 ; INT3 jmp incrementer .org 0x0018 ; Watchdog jmp watchdog .org 0x002E ; Timer jmp timer .org 0x003A ; ADC jmp adc .org 0x0080 ; Tableaux de la mémoire du programme afficheur: .DB 0x3F, 0x30, 0x6D, 0x79, 0x72, 0x5B, 0x5F, 0x31, 0x7F, 0x7B ; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ; Programme debut: ; Configuration des composants ; Ports parallèles DDRA@IO <- 0xFF DDRC@IO <- 0xFF DDRG@IO <- 0xFF ; Barres de chargement PORTA@IO <- 0x40 PORTC@IO <- 0x00 ; Watchdog ;WDTCSR <- 0b00010000 ;WDTCSR <- 0b01000111 ; Timer TTCR0A@IO <- 0b00000000 TTCR0B@IO <- 0b00000100 ; Timer toutes les 4ms TMSK0 <- 0b00000001 ; Interruptions externes EIMSK <- 0b00001111 EICRA <- 0b10101010 EICRB <- 0b00000000 ; ADC ADMUX <- 0b01100000 ADCSRB <- 0b00000010 ADCSRA <- 0b11011110 ; Initialisation des registre etat <- 0 ; compteur initialisé quand on en aura besoin ; reference initialisé avec agirHeure ; d3, d2, d1, d0 initialisés avec afficherHorloge ; Mardi 14h00'55 t2 <- 0b00101110 t1 <- 0 t0 <- 55 tt <- 0 ; temp initialisé quand on en aura besoin ; Initialisation de la RAM ; Valeurs de démonstration : 7° - 27° (on jouerait plus sur du 17° - 21° en réalité) tempNuit <- 20 tempJour <- 220 ; Initialisation des associations compteur <- 0 ; Jour initJour: temp <- 0 ; Heure initHeure: assocs[compteur * 24 + temp] <- 0 ; Par défaut le mode jour si temp <= 7 alors assocs[compteur * 24 + temp] <- 1 ; Entre minuit et 7h le mode nuit inc temp if temp < 24 saut initHeure inc compteur if compteur < 7 saut initJour ; Logique de démarrage call afficherHorloge call agirHeure ; On active les interruptions une fois que tout est prêt sei boucle: sleep jmp boucle ; Fonctions ; Affichages afficherHorloge: ; Affiche l'heure actuelle temp <- t2 & 0b00011111 d3 <- 0x00 si temp > 10 alors d3 <- afficheur@ROM[temp/10] d2 <- afficheur@ROM[temp%10] | 0b10000000 d1 <- afficheur@ROM[t1/10] d0 <- afficheur@ROM[t1%10] ret afficherTemperature: ; Considère le registre compteur comme une température et l'affiche d0 <- 0x63 ; Sigle degré d1 <- afficheur@ROM[compteur%10] ; Décimale temp <- compteur / 10 + 5 ; On stocke temporairement la partie entière pour simplifier d2 <- afficheur@ROM[temp%10] | 0b10000000 ; Chiffre des unités, auquel on ajoute le point d3 <- 0x00 ; On affiche le chiffre des dizaines si la température est > 10 si temp > 10 alors d3 <- afficheur@ROM[temp/10] ret afficherHeur: ; Considère le registre compteur comme une heure et l'affiche d3 <- afficheur@ROM[compteur/10] d2 <- afficheur@ROM[compteur%10] | 0b10000000 d1 <- 0x00 d0 <- 0x00 ret afficherMinu: ; Considère le registre compteur comme une minute et l'affiche d3 <- 0x00 d2 <- 0b10000000 d1 <- afficheur@ROM[compteur/10] d0 <- afficheur@ROM[compteur%10] ret afficherJour: ; Considère le registre compteur comme un jour et l'affiche d1 <- 0x00; d0 <- 0x00; si compteur = 0 saut afficherLu si compteur = 1 saut afficherMa si compteur = 2 saut afficherMe si compteur = 3 saut afficherJe si compteur = 4 saut afficherVe si compteur = 5 saut afficherSa si compteur = 6 saut afficherDi ret ; Ne devrait pas arriver, mais permet d'éviter les dégâts afficherLu: d3 <- 0x0E d2 <- 0x1c ret afficherMa: d3 <- 0x37 d2 <- 0x77 ret afficherMe: d3 <- 0x37 d2 <- 0xcf ret afficherJe: d3 <- 0x3c d2 <- 0xcf ret afficherVe: d3 <- 0x1c d2 <- 0xcf ret afficherSa: d3 <- 0x5b d2 <- 0x77 ret afficherDi: d3 <- 0xfc d2 <- 0x04 ret ; Logique agir1s: ; Met à jour les registres de temps, active agir10s ou agirHeure si nécessaire inc t0 si t0%10 != 0 saut ret ; Continue si on est sur un multiple de 10 secondes call agir10s si t0 < 60 saut ret ; Continue si on est sur un multiple de 60 secondes t0 <- 0 inc t1 si t1 < 60 saut ret ; Continue si on est sur un multiple de 60 minutes t1 <- 0 inc t2 si t2 & 0b00011111 >= 7 saut agir1sHeur ; Continue si il est minuit t2 <- t2 + 0b00100000 ; Jour suivant t2 <- t2 & 0b11100000 ; Heure à minuit si t2 >= 0b11100000 alors t2 <- 0b00000000 ; Si on est dimanche soir, on revient à lundi matin agir1sHeur: call agirHeure ret agir10s: ; Déclenche une conversion ADC ADCSRA <- 0b11011101 ; Switche l'état de veille si veille il y a si etat = 0 saut a10sVeilleTemp si etat = 1 saut a10sVeilleHeur ret a10sVeilleHeur: etat <- 0 call afficherHorloge ret a10sVeilleTemp: etat <- 1 compteur <- ADCH call afficherTemperature ret agirHeure: ; Recharge la température de référence temp <- (t2 / 0b00100000) * 24 + (t2 & 0b00011111) ; ↑ numéro du jour de la semaine ; ↑ heure actuelle if assocs[temp] = 0x00 alors reference <- tempJour if assocs[temp] = 0x01 alors reference <- tempNuit ret ; Recadrage boundHeur: si compteur = 255 alors compteur <- 23 si compteur >= 24 alors compteur <- 0 ret boundMinu: si compteur = 255 alors compteur <- 59 si compteur >= 60 alors compteur <- 0 ret boundJour: si compteur = 255 alors compteur <- 6 si compteur >= 7 alors compteur <- 0 ret boundTemperature: si compteur < 5 alors compteur <- 250 si compteur > 250 alors compteur <- 5 ret ; Puisque l'assembleur étendu ne supporte pas les retours conditionnels ret: ret reti: reti ; États ; × : Arrivée à l'état par un niveau supérieur ; R : Arrivée à l'état par un niveau inférieur ; U : Mise à jour de l'affichage ; C : Changement de l'état etatVeilleHeur: etat <- 0 call afficherHorloge reti etatVeilleTemp: etat <- 1 compteur <- ADCH call afficherTemperature reti etatMenuAssoc: etat <- 2 d3 <- 0x77 d2 <- 0x5b d1 <- 0x5b d0 <- 0x5c reti etatMenuJours: ; Par défaut on prend le jour actuel compteur <- t2 / 0b00100000 etatMenuJoursU: etat <- 3 + compteur call afficherJour reti etatMenuJoursR: compteur <- etat - 7 - 3 jmp etatMenuJoursU etatMenuJoursC: call boundJour jmp etatMenuJoursU etatParaJours: etat <- etat + 7 compteur <- t2 & 0b00011111 etatParaJoursU: d3 <- afficheur@ROM[compteur/10] d2 <- afficheur@ROM[compteur%10] d1 <- 0x00 temp <- (etat - 10) * 24 + compteur ; Si la RAM n'est pas initialisée à cet endroit, on préfère afficher un tiret d0 <- 0x40 si assocs[temp] = 0b00000000 alors d0 <- 0x3c si assocs[temp] = 0b00000001 alors d0 <- 0x54 reti etatParaJoursC: call boundHeur jmp etatParaJoursU etatParaJoursS: ; Switch temp <- (etat - 10) * 24 + compteur assocs[temp] <- (assocs[temp] + 1) & 0b00000001 call agirHeure ; Au cas où on change l'heure en cours jmp etatParaJoursU ; Appelé depuis l'état 2 après un appui sur le bouton Incrémenter ; 19 Décrémenter ; 18 Valider ; 18 Retour etatMenuTJour: etat <- 17 d3 <- 0x3c ; "JOUR" d2 <- 0x5c d1 <- 0x1c d0 <- 0x44 reti ; Appelé depuis l'état 17 après un appui sur Valider etatParaTJour: etat <- 18 compteur <- tempJour ; Lecture depuis la RAM etatParaTJourU: call afficherTemperature reti ; Appelé depuis l'état 18 après un appui sur Incrementer ou Decrementer etatParaTJourC: call boundTemperature ; Remet la température dans les bornes tempJour <- compteur ; Écriture vers la RAM call agirHeure ; Au cas où on change le mode de l'heure actuelle, on recharge la température de référence jmp etatParaTJourU etatMenuTNuit: etat <- 19 d3 <- 0x54 ; "NUIT" d2 <- 0x1c d1 <- 0x04 d0 <- 0x4e reti etatParaTNuit: etat <- 20 compteur <- tempNuit etatParaTNuitU: call afficherTemperature reti etatParaTNuitC: call boundTemperature tempNuit <- compteur call agirHeure ; Au cas où on change le mode en cours jmp etatParaTNuitU etatMenuHorloge: etat <- 21 d3 <- 0x76 ; "HORL" d2 <- 0x5c d1 <- 0x44 d0 <- 0x0E reti etatMenuHJour: etat <- 22 d3 <- 0x3c ; "JOUR" d2 <- 0x5c d1 <- 0x1c d0 <- 0x44 reti etatMenuHHeur: etat <- 23 d3 <- 0x76 ; "HEUR" d2 <- 0xcf d1 <- 0x1c d0 <- 0x44 reti etatMenuHMinu: etat <- 24 d3 <- 0x37 ; "MINU" d2 <- 0x04 d1 <- 0x54 d0 <- 0x1c reti etatParaHJour: etat <- 25 compteur <- t2 / 0b00100000 call afficherJour reti etatParaHJourC: call boundJour t2 <- (compteur * 0b00100000) + (t2 & 0b00011111) call agirHeure call afficherJour reti etatParaHHeur: etat <- 26 compteur <- t2 & 0b00011111 call afficherHeur reti etatParaHHeurC: call boundHeur t2 <- (t2 & 0b11100000) + compteur call agirHeure call afficherHeur reti etatParaHMinu: etat <- 27 compteur <- t1 call afficherMinu reti etatParaHMinuC: call boundMinu t1 <- compteur call afficherMinu reti ; Interruption boutons incrementer: inc compteur si etat = 0 saut etatVeilleTemp si etat = 1 saut etatVeilleHeur si etat = 2 saut etatMenuTJour si etat <= 9 saut etatMenuJoursC si etat <= 16 saut etatParaJoursC si etat = 17 saut etatMenuTNuit si etat = 18 saut etatParaTJourC si etat = 19 saut etatMenuHorloge si etat = 20 saut etatParaTNuitC si etat = 21 saut etatMenuAssoc si etat = 22 saut etatMenuHHeur si etat = 23 saut etatMenuHMinu si etat = 24 saut etatMenuHJour si etat = 25 saut etatParaHJourC si etat = 26 saut etatParaHHeurC si etat = 27 saut etatParaHMinuC reti ; Ne devrait pas arriver, mais permet d'éviter les dégâts decrementer: dec compteur si etat = 0 saut etatVeilleTemp si etat = 1 saut etatVeilleHeur si etat = 2 saut etatMenuHorloge si etat <= 9 saut etatMenuJoursC si etat <= 16 saut etatParaJoursC si etat = 17 saut etatMenuAssoc si etat = 18 saut etatParaTJourC si etat = 19 saut etatMenuTJour si etat = 20 saut etatParaTNuitC si etat = 21 saut etatMenuTNuit si etat = 22 saut etatMenuHMinu si etat = 23 saut etatMenuHJour si etat = 24 saut etatMenuHHeur si etat = 25 saut etatParaHJourC si etat = 26 saut etatParaHHeurC si etat = 27 saut etatParaHMinuC reti ; Ne devrait pas arriver, mais permet d'éviter les dégâts valider: si etat <= 1 saut etatMenuAssoc si etat = 2 saut etatMenuJours si etat <= 9 saut etatParaJours si etat <= 16 saut etatParaJoursS si etat = 17 saut etatParaTJour si etat = 18 saut etatMenuTJour si etat = 19 saut etatParaTNuit si etat = 20 saut etatMenuTNuit si etat = 21 saut etatMenuHJour si etat = 22 saut etatParaHJour si etat = 23 saut etatParaHHeur si etat = 24 saut etatParaHMinu si etat = 25 saut etatMenuHJour si etat = 26 saut etatMenuHHeur si etat = 27 saut etatMenuHMinu reti ; Ne devrait pas arriver, mais permet d'éviter les dégâts retour: si etat <= 1 saut reti si etat = 2 saut etatVeilleHeur si etat <= 9 saut etatMenuAssoc si etat <= 16 saut etatMenuJoursR si etat = 17 saut etatVeilleHeur si etat = 18 saut etatMenuTJour si etat = 19 saut etatVeilleHeur si etat = 20 saut etatMenuTNuit si etat = 21 saut etatVeilleHeur si etat <= 24 saut etatMenuHorloge si etat = 25 saut etatMenuHJour si etat = 26 saut etatMenuHHeur si etat = 27 saut etatMenuHMinu reti ; Ne devrait pas arriver, mais permet d'éviter les dégâts ; Interruption Watchdog watchdog: call agir1s reti ; Interruption ADC adc: ADCSRA <- 0b11011101 ; DEBUG Lire la température continuellement si ADCH > reference + 5 saut eteindreChaudiere si ADCH < reference - 5 saut allumerChaudiere reti allumerChaudiere: PORTG@IO <- 0xFF reti eteindreChaudiere: PORTG@IO <- 0x00 reti ; Interruption timer (~4 ms) timer: ; Notre composant requiert d'envoyer 0 sur PC7-4 ; afin d'activer le digit qui y est connecté ; Affiche le digit suivant sur l'afficheur 7seg temp <- PORTC@IO ; On lis l'état précédent du port lsr temp ; On change de digit ; Il y a 4 digits et 8 bits, on doit donc boucler plus tôt si temp < 0b00001111 alors temp <- 0b11110111 PORTC@IO <- temp ; On envoie le registre correpspondant si temp = 0b11110111 alors PORTA@IO <- d3 si temp = 0b01111011 alors PORTA@IO <- d2 si temp = 0b00111101 alors PORTA@IO <- d1 si temp = 0b00011110 alors PORTA@IO <- d0 ; Watchdog artificiel inc tt if tt < 244 saut reti ;if tt < 10 saut reti ; DEBUG Avancer le temps tt <- 0 call agir1s reti