From 7fe247413cb87bd12b4fa94244246d4c2a5114e1 Mon Sep 17 00:00:00 2001 From: Geoffrey Frogeye Date: Mon, 22 May 2017 18:35:05 +0200 Subject: [PATCH] Encore des modifications du CR --- CR.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------- README.md | 2 +- 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/CR.md b/CR.md index 054f3bf..27171f5 100644 --- a/CR.md +++ b/CR.md @@ -16,7 +16,7 @@ Enfin, afin de vérifier la validité de notre algorithme et de nos configuratio ## Entrées -On utilisera 4 boutons : pour valider, revenir en arrière, incrémenter et décrémenter. Ils sont branchés sur les ports d'interruption INT0 à INT3 respectivement pour éviter une scrutation afin d'économiser de l'énergie. +On utilisera 4 boutons pour pouvoir modifier les paramètres : pour valider, revenir en arrière, incrémenter et décrémenter. Ils sont branchés sur les ports d'interruption INT0 à INT3 respectivement pour éviter une scrutation afin d'économiser de l'énergie. Le capteur de température est connecté sur le convertisseur analogique-numérique numéro 0 (`ADC0`). Pour la simulation, nous avons utilisé un potentiomètre afin de régler la température d'entrée du thermostat. @@ -31,7 +31,7 @@ Enfin, le signal de contrôle de la chaudière est branchée sur un port parallà ## Menu -Pour pouvoir afficher et modifier les différentes valeurs dont l'utilisateur a accès, on a créé un menu, dont voici sa hiérarchie : +Pour pouvoir afficher et modifier les différentes valeurs dont l'utilisateur a accès, on a créé un menu, dont voici la hiérarchie : - Veille - Association mode ↔ heure de la semaine @@ -66,7 +66,7 @@ Les accès à la RAM nécessitant plus d'instructions et donc étant plus gourma - `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. +- `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 stocker 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. 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. @@ -94,6 +94,7 @@ Il sera configuré pour s'activer sur demande, ici toutes les dix secondes. En e TODO toutes les deux secondes, déclenche une interruption, nécessite d'être un multiple de 10 secondes, au final il marche pas parce qu'on sait pas du coup on utilise le timer (pas trop étaler là dessus, c'est expliqué plus en détails dans algorithme) ↓↓ à réintégrer + 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. @@ -113,11 +114,11 @@ boucle: En effet, nous avons dit précédemment que pour économiser l'énergie, toutes les actions seraient gérées par des interruptions, le reste du temps le micro-contrôleur ne fait que dormir. On peut se le permettre car les actions sont très courtes, et il n'y a donc peu de risque de conflit au cas où deux interruptions se déclenchent en même temps. -L'algorithme étant assez imposant (~620 lignes) et redondant, on ne présentera que les principes clefs et quelques exemples d'astuces utilisés. Le code complet (et les outils utilisés pour l'ensemble du projet) sont disponibles à l'adresse suivante : (`Fies` > `principal.txt`). +L'algorithme étant assez lourd et redondant, on ne présentera que les principes clefs et quelques exemples d'astuces utilisés. Le code complet (et les outils utilisés pour l'ensemble du projet) sont disponibles à l'adresse suivante : (`Files` > `principal.txt`). -## Menu +## Gestion des états -Ce fonctionnement peut être implémenté de deux manières différentes. La première, étant que à chaque élément du menu correspond un emplacement dans le code assembleur, et le programme passe le plus clair de son temps à scruter les boutons. La deuxième, étant que le programme reste sur une instruction sleep, et que les boutons provoquent des interruptions qui gèrent modifient l'affichage et les valeurs nécessaires en fonction du bouton qui a été appuyé et de l'état précédent du menu. D'un point de vue énergétique, la deuxième solution est clairement gagnante. Il faut alors stocker dans quel état est le menu en mémoire. On utilisera pour cela un registre d'état, qui prendra les valeurs suivantes : +Chacun des boutons provoque une interruption qui modifie l'affichage et les valeurs nécessaires en fonction de celui qui a été appuyé et de l'état précédent du menu. Il faut alors stocker dans quel état est le menu en mémoire. On utilisera pour cela un registre `etat`, qui prendra les valeurs suivantes : - 0→1 : Veille (Heure / Température) - 2 : Menu Association mode ↔ Heure de la semaine @@ -205,13 +206,13 @@ On utilise le fait qu'une décrémentation depuis la valeur 0 effectue un dépas ## Fonction d'agissement -Ces fonctions permettent de prendre des actions en fonction du temps. +Ces fonctions permettent de réaliser 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. +- `agir10s` : déclenchée toutes les dix secondes, elle change l'état de veille (affichage de l'heure ou température) 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) : +*Note : On a laissé la possibilité à l'utilisateur de changer de mode de veille avec les boutons Incrémenter / Décrémenter, mais `agir10s` ne prend pas en compte ce changement. Il est donc possible que l'utilisateur change d'état de veille et que le système revienne juste après à l'état précédent.* ## Interruptions @@ -221,24 +222,66 @@ Les fonctions que nous avons vues jusqu'à lors sont appelées uniquement par le 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. +```avrasmplus +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 -Le watchdog ne fonctionnant pas, 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`. +Le watchdog ne fonctionnant pas, 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. +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 seconde. ### 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.* +*Note : Vous pourrez constater dans le code que cette interruption en déclenche une autre afin d'avoir un retour immédiat sur nos actions. Cela n'a été fait que pour simplifier la présentation orale.* ### 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. +Voici par exemple la fonction appelée par le bouton Incrémenter : + +```avrasmplus +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 +``` + # Conclusion -Pour ce projet de thermostat, nous avons réalisé son architecture matérielle, son algorithme, et même réussi à en faire une simulation sur du matériel réel, ce qui a nécessite l'écriture de l'algorithme complet. Bien qu'un sujet similaire était proposé dans un des TP, on s'est rendu compte que l'ajout de certaines fonctions paraissant anodines (telles que la gestion du temps, ou un menu) nécessitent un gros travail pour tout coordonner. La réalisation de la simulation, bien que non nécessaire, a été utile pour se rendre compte que certains chemins envisagés au débuts n'étaient pas réalisables, et a permis de pouvoir tester notre algorithme. Au final +Pour ce projet de thermostat, nous avons réalisé son architecture matérielle, son algorithme, et même réussi à en faire une simulation sur du matériel réel, ce qui a nécessite l'écriture de l'algorithme complet. Bien qu'un sujet similaire était proposé dans un des TP, on s'est rendu compte que l'ajout de certaines fonctions paraissant anodines (telles que la gestion du temps, ou un menu) nécessitent un gros travail pour tout coordonner. La réalisation de la simulation, bien que non nécessaire, a été utile pour se rendre compte que certains chemins envisagés au débuts n'étaient pas réalisables, et a permis de pouvoir tester notre algorithme. Au final ce fut une experience très enrichissante. diff --git a/README.md b/README.md index c01070e..8686473 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Pour générer un fichier PDF, assurez-vous d'avoir lancé `./configure` une foi ## Programme -Pour envoyer un programme sur l'Arduino, assurez-vous d'avoir lancé `./configure` une fois sans erreur, puis lancez la commande `make programme.upload`, en supposant qu'il existe un fichier `programme.txt` ou `programme.hex`. Les fichiers intermédiaires nécessaires seront reconstruits si besoin. Si vous voulez juste vérifier que ça compile, `make programme.hex`. +Pour envoyer un programme sur l'Arduino, assurez-vous d'avoir lancé `./configure` une fois sans erreur, puis lancez la commande `make programme.upload`, en supposant qu'il existe un fichier `programme.txt` ou `programme.asm`. Les fichiers intermédiaires nécessaires seront reconstruits si besoin. Si vous voulez juste vérifier que ça compile, `make programme.hex`. *(ne fonctionne que sur un environnement Linux)* -- libgit2 0.21.2