diff --git a/CR.md b/CR.md index 4d59ec7..b76df32 100644 --- a/CR.md +++ b/CR.md @@ -60,16 +60,23 @@ La température mesurée (et convertie via le convertisseur ADC), est comparée ## Stockage des données -Les accès à la RAM nécessitant plus d'instructions et donc étant plus gourmands en énergie, on stockera le maximum d'informations dans les registres, de préférences les données étant lues/écrites les plus fréquemment. On y stockera donc : +Les accès à la RAM nécessitant plus d'instructions et donc étant plus gourmands en énergie, on stockera le maximum d'informations dans les registres, de préférences les données étant lues/écrites les plus fréquemment. On y utilisera donc : -- **4 registres** : les 4 digits de l'afficheur 7 segments en cours d'affichage. Ces informations devant être récupérées 4 fois toutes les quelques millisecondes, on ne calculera leur représentation que lors de leur changement et on les stockera dans ces registres. -- **1 registre (dont 4 bits inutilisés)** : afficheur 7 segment actuellement en cours d'affichage. Cela permet d'alterner les 4 dans l'ordre. Pour économiser un registre d'utilisation générale, on utilisera le fait que le port C est considéré comme un registre et sauvegarde les états qui lui sont envoyés. -- **3 registres** : Stockage du temps. Le compteur de temps le plus grand mais à la fois diviseur de la période de changement de mode veille et d'une heure sur l'Atmega 2560 est deux secondes. On comptera le temps de la semaine avec cette période de deux secondes. Il y a alors $\frac{7 \times 24 \times 60 \times 60 }{ 2 }$ $=302400$ valeurs possibles pour ce compteur de temps. On a donc besoin de 3 registres $\left( 2^{8 \times 2} = 65536 < 302400 < 16777216 = 2^{8 \times 3} \right)$ pour stocker cette valeur. Afin de simplifier, sur le premier registre on utilisera 3 bits pour stocker le jour de la semaine, 5 bits pour l'heure du jour, on utilisera le deuxième registre pour stocker la minute de l'heure, et le troisième registre pour stocker le nombres de fois qu'il y a eu 2 secondes dans la minute actuelle. Cela permet de simplifier les calculs et d'éviter de faire des opérations sur des entiers de 24 bits *(on aurait pu utiliser un registre supplémentaire pour stocker le jour de la semaine et éviter des opérations, mais on voulait s'amuser avec des masques et des divisions)*. +- `d3`, `d2`, `d1` et `d0` : les 4 digits de l'afficheur 7 segments en cours d'affichage. Ces informations devant être récupérées 4 fois toutes les quelques millisecondes, on ne calculera leur représentation que lors de leur changement et on les stockera dans ces registres. +- `PORTC` : afficheur 7 segment actuellement en cours d'affichage. Cela permet d'alterner les 4 dans l'ordre. Pour économiser un registre d'utilisation générale, on utilisera le fait que le port C est considéré comme un registre et sauvegarde les états qui lui sont envoyés. +- `t2`, `t1` et `t0` : stockage du temps actuel. Il y a $7 \times 24 \times 60 \times 60$ $=604800$ valeurs possibles pour ce compteur de temps. On a donc besoin de 3 registres $\left( 2^{8 \times 2} = 65536 < 604800 < 16777216 = 2^{8 \times 3} \right)$ pour stocker cette valeur. Afin de simplifier, sur le premier registre on utilisera 3 bits pour stocker le jour de la semaine, 5 bits pour l'heure du jour, on utilisera le deuxième registre pour stocker la minute de l'heure, et le troisième pour stocker les secondes de la minute. Cela permet de simplifier les calculs et d'éviter de faire des opérations sur des entiers de 24 bits. +- `etat` et `compteur` : ils permettent de stocker l'état actuel du menu. +- `reference` : contient la température désirée actuelle (c'est à dire pour le mode de l'heure actuelle). Étant comparée toutes les 10 secondes avec la température réelle et le calcul de sa valeur nécessitant de connaître le temps actuel, le mode associé à ce temps et la température associée à ce mode, on a jugé avantageux de le stoceker dans un registre qui sera mis à jour au besoin. +- `temp` : registre dédié à certaines opérations temporaires. Il n'a pas de rapport (la plupart du temps) avec la température. -TODO Il manque des registres +Notes : +- Nous aurions pu utiliser un registre distinct pour stocker le jour de la semaine et éviter des opérations, mais on voulait s'amuser avec des masques et des divisions. +- Nous aurions pu utiliser une période Watchdog plus grande afin de minimiser les opérations. Mais on verra par la suite que nous n'avons pas pu utiliser le Watchdog du tout. Les associations de chaque heure de la semaine à son mode (jour/nuit) seront stockées dans la RAM. Bien qu'en théorie nous n'avons besoin que de $\frac{ \text{nb jours/semaine} \times \text{nb heures/jour} \times \text{nb bits pour stocker le mode} }{ \text{nb bits stockables sur une adresse} }$ $=\frac{7 \times 24 \times 1 }{ 8 }$ $=\frac{168}{8}$ $=21$ adresses pour stocker ces informations, on préfèrera utiliser une adresse par heure de la semaine, soit $168$ adresses. Bien que l'on perd en espace mémoire disponible, on garde en rapidité d'éxecution (et donc en énergie), en effet il n'est pas nécessaire d'utiliser des masques pour récupérer la valeur des bits individuels. Dans notre cas le microprocesseur n'abritera aucun autre programme avec qui il devra partager la RAM, et la consommation énergétique ne change pas selon le nombre d'adresses utilisées, il n'y a donc que des avantages à utiliser cette technique. +Enfin, on stockera les températures des deux modes dans la RAM également, car on y accède que toutes les heures (ou lors de leur modification), le registre `reference` agissant comme intermédiaire. + # Configuration des interfaces ## Interruptions externes @@ -198,19 +205,39 @@ On utilise le fait qu'une décrémentation depuis la valeur 0 effectue un dépas ## Fonction d'agissement -TODO +Ces fonctions permettent de prendre des actions en fonction du temps. + +- `agir1s` : déclenchée toutes les secondes, elle met à jour les registres de temps, et appelle les fonctions `agir10s` et `agirHeure` +- `agir10s` : déclenchée toutes les dix secondes, elle change l'état de veille si l'appareil est en veille. Dans tous les cas, elle déclenche une conversion analogique numérique pour lire le capteur de température. +- `agirHeure` : elle recharge depuis la RAM le mode actuel, et met à jour le registre `reference` contenant la température à utiliser. + +Voici à titre d'exemple une de ces fonctions (bien qu'elles soient toutes radicalement différentes) : ## Interruptions -TODO +Les fonctions que nous avons vues jusqu'à lors sont appelées uniquement par les interruptions, étant donné qu'il n'y a pas de programme principal. Voici les différentes interruptions qui sont déclenchées. -## Timer +### Timer -## Watchdog +Déclenchée toutes les ~4 ms, elle change le digit de l'afficheur 4 × 7 segments actuellement affiché en modifiant la configuration du port C, et cenvoie sur le port A les données du registre `dX` correspondant. + +### Watchdog + +Déclenché toutes les secondes, il se contente d'appeler la fonction `agir1s`. Cependant, on s'est rendu compte que la fréquence d'appel était ~100× plus élevé que ce qui devrait être. N'ayant pas réussi à corriger ce comportement (que l'on a pu aussi constater en TP), nous avons dû trouver un autre moyen de procéder. + +En effet, nous avons utilisé le timer, et un registre supplémentaire, `tt`, qui est incrémenté à chacune de ses interruptions. Le timer ayant une fréquence exacte de $\frac{16 MHz}{256^2}=244.140625 Hz$;, dès que `tt` a depassé `244` on appelle donc `agir1s`. + +D'un point de vue énergétique, cette approche est beacoup moins efficace car elle rajoute des instructions supplémentaires à l'interruption du timer, qui est la fonction « critique » du système car appelée 244 fois par secondes. + +### ADC + +Cette interruption est déclenchée à chaque fois qu'une conversion analogique→numérique est terminée. Elle est donc déclenchée à peu près toutes les 10 secondes car les conversions ne sont demandées que depuis la fonction `agir10s`. Elle s'occupe d'activer ou de désactiver la chaudière en fonction de la température récupérée lors de la conversion, en se basant sur le registre `reference`. Par exemple, la chaudière est éteinte si la température dépasse de plus de 0,5 degrés la température de référence. Dans le code, on vérifiera si `ADCH > reference + 5`, car 0,1°C correspond à une unité. On remarque que l'on peut obtenir un dépassement si jamais `reference > 250`, ce qui n'est pas censé arriver car on ne propose à l'utilisateur que de choisir une température entre 5,5 et 30,0°C, `reference` est donc compris entre 5 et 250. Si jamais la température est comprise dans l'intervalle, le port G conserve l'état de la chaudière actuel. + +*Note : Pour la présentation orale vous pourrez constater dans le code que cette interruption en déclenche une autre afin d'avoir un retour immédiat sur nos actions.* -## ADC +### Boutons -## Boutons +À chaque bouton est associé une interruption, et chacun d'entre elle appelle une fonction d'état selon la valeur actuelle de compteur. Par exemple, si l'état actuel est `veilleHeure` et que le bouton Valider est pressé, la fonction `etatMenuAssoc` est appelée. Pour les boutons Incrémenter et Décrémenter, le registre `compteur` est incrémenté ou décrémenté respectivement avant d'appeler la fonction d'état. # Conclusion diff --git a/principal.txt b/principal.txt index e33f461..8cadbf8 100644 --- a/principal.txt +++ b/principal.txt @@ -49,7 +49,7 @@ ; Nommage des adresses RAM utilisées -.equ assocs = 0x0200 ; Association des modes aux heures +.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 @@ -290,6 +290,8 @@ a10sVeilleTemp: 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 @@ -598,13 +600,18 @@ eteindreChaudiere: PORTG@IO <- 0x00 reti -; Interruption timer +; 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 - lsr temp + 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 -- libgit2 0.21.2