Commit 7fe247413cb87bd12b4fa94244246d4c2a5114e1

Authored by Geoffrey PREUD'HOMME
1 parent 514fdb6d

Encore des modifications du CR

Est-ce vraiment nécessaire de faire des messages explicites ?
Showing 2 changed files with 57 additions and 14 deletions   Show diff stats
@@ -16,7 +16,7 @@ Enfin, afin de vérifier la validité de notre algorithme et de nos configuratio @@ -16,7 +16,7 @@ Enfin, afin de vérifier la validité de notre algorithme et de nos configuratio
16 16
17 ## Entrées 17 ## Entrées
18 18
19 -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. <!-- TODO Pourquoi résistances et capa --> 19 +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. <!-- TODO Pourquoi résistances et capa -->
20 20
21 Le capteur de température est connecté sur le convertisseur analogique-numérique numéro 0 (`ADC0`). 21 Le capteur de température est connecté sur le convertisseur analogique-numérique numéro 0 (`ADC0`).
22 Pour la simulation, nous avons utilisé un potentiomètre afin de régler la température d'entrée du thermostat. 22 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à @@ -31,7 +31,7 @@ Enfin, le signal de contrôle de la chaudière est branchée sur un port parallÃ
31 31
32 ## Menu 32 ## Menu
33 33
34 -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 : 34 +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 :
35 35
36 - Veille 36 - Veille
37 - Association mode ↔ heure de la semaine 37 - Association mode ↔ heure de la semaine
@@ -66,7 +66,7 @@ Les accès à la RAM nécessitant plus d&#39;instructions et donc étant plus gourma @@ -66,7 +66,7 @@ Les accès à la RAM nécessitant plus d&#39;instructions et donc étant plus gourma
66 - `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. 66 - `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.
67 - `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. 67 - `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.
68 - `etat` et `compteur` : ils permettent de stocker l'état actuel du menu. 68 - `etat` et `compteur` : ils permettent de stocker l'état actuel du menu.
69 -- `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. 69 +- `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.
70 - `temp` : registre dédié à certaines opérations temporaires. Il n'a pas de rapport (la plupart du temps) avec la température. 70 - `temp` : registre dédié à certaines opérations temporaires. Il n'a pas de rapport (la plupart du temps) avec la température.
71 71
72 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. 72 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&#39;activer sur demande, ici toutes les dix secondes. En e @@ -94,6 +94,7 @@ Il sera configuré pour s&#39;activer sur demande, ici toutes les dix secondes. En e
94 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) 94 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)
95 95
96 ↓↓ à réintégrer 96 ↓↓ à réintégrer
  97 +
97 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. 98 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.
98 99
99 100
@@ -113,11 +114,11 @@ boucle: @@ -113,11 +114,11 @@ boucle:
113 114
114 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. 115 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.
115 116
116 -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 : <https://archives.plil.fr/gbontoux/s6-mp-tutorat> (`Fies` > `principal.txt`). 117 +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 : <https://archives.plil.fr/gbontoux/s6-mp-tutorat> (`Files` > `principal.txt`).
117 118
118 -## Menu 119 +## Gestion des états
119 120
120 -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 : 121 +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 :
121 122
122 - 0→1 : Veille (Heure / Température) 123 - 0→1 : Veille (Heure / Température)
123 - 2 : Menu Association mode ↔ Heure de la semaine 124 - 2 : Menu Association mode ↔ Heure de la semaine
@@ -205,13 +206,13 @@ On utilise le fait qu&#39;une décrémentation depuis la valeur 0 effectue un dépas @@ -205,13 +206,13 @@ On utilise le fait qu&#39;une décrémentation depuis la valeur 0 effectue un dépas
205 206
206 ## Fonction d'agissement 207 ## Fonction d'agissement
207 208
208 -Ces fonctions permettent de prendre des actions en fonction du temps. 209 +Ces fonctions permettent de réaliser des actions en fonction du temps.
209 210
210 - `agir1s` : déclenchée toutes les secondes, elle met à jour les registres de temps, et appelle les fonctions `agir10s` et `agirHeure` 211 - `agir1s` : déclenchée toutes les secondes, elle met à jour les registres de temps, et appelle les fonctions `agir10s` et `agirHeure`
211 -- `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. 212 +- `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.
212 - `agirHeure` : elle recharge depuis la RAM le mode actuel, et met à jour le registre `reference` contenant la température à utiliser. 213 - `agirHeure` : elle recharge depuis la RAM le mode actuel, et met à jour le registre `reference` contenant la température à utiliser.
213 214
214 -Voici à titre d'exemple une de ces fonctions (bien qu'elles soient toutes radicalement différentes) : 215 +*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.*
215 216
216 ## Interruptions 217 ## Interruptions
217 218
@@ -221,24 +222,66 @@ Les fonctions que nous avons vues jusqu&#39;à lors sont appelées uniquement par le @@ -221,24 +222,66 @@ Les fonctions que nous avons vues jusqu&#39;à lors sont appelées uniquement par le
221 222
222 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. 223 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.
223 224
  225 +```avrasmplus
  226 +timer:
  227 + ; Notre composant requiert d'envoyer 0 sur PC7-4
  228 + ; afin d'activer le digit qui y est connecté
  229 +
  230 + ; Affiche le digit suivant sur l'afficheur 7seg
  231 + temp <- PORTC@IO ; On lis l'état précédent du port
  232 + lsr temp ; On change de digit
  233 + ; Il y a 4 digits et 8 bits, on doit donc boucler plus tôt
  234 + si temp < 0b00001111 alors temp <- 0b11110111
  235 + PORTC@IO <- temp
  236 + ; On envoie le registre correpspondant
  237 + si temp = 0b11110111 alors PORTA@IO <- d3
  238 + si temp = 0b01111011 alors PORTA@IO <- d2
  239 + si temp = 0b00111101 alors PORTA@IO <- d1
  240 + si temp = 0b00011110 alors PORTA@IO <- d0
  241 +```
  242 +
224 ### Watchdog 243 ### Watchdog
225 244
226 -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`. 245 +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`.
227 246
228 -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. 247 +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.
229 248
230 ### ADC 249 ### ADC
231 250
232 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. 251 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.
233 252
234 -*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.* 253 +*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.*
235 254
236 ### Boutons 255 ### Boutons
237 256
238 À 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. 257 À 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.
239 258
  259 +Voici par exemple la fonction appelée par le bouton Incrémenter :
  260 +
  261 +```avrasmplus
  262 +incrementer:
  263 + inc compteur
  264 + si etat = 0 saut etatVeilleTemp
  265 + si etat = 1 saut etatVeilleHeur
  266 + si etat = 2 saut etatMenuTJour
  267 + si etat <= 9 saut etatMenuJoursC
  268 + si etat <= 16 saut etatParaJoursC
  269 + si etat = 17 saut etatMenuTNuit
  270 + si etat = 18 saut etatParaTJourC
  271 + si etat = 19 saut etatMenuHorloge
  272 + si etat = 20 saut etatParaTNuitC
  273 + si etat = 21 saut etatMenuAssoc
  274 + si etat = 22 saut etatMenuHHeur
  275 + si etat = 23 saut etatMenuHMinu
  276 + si etat = 24 saut etatMenuHJour
  277 + si etat = 25 saut etatParaHJourC
  278 + si etat = 26 saut etatParaHHeurC
  279 + si etat = 27 saut etatParaHMinuC
  280 + reti ; Ne devrait pas arriver, mais permet d'éviter les dégâts
  281 +```
  282 +
240 # Conclusion 283 # Conclusion
241 284
242 -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 285 +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.
243 286
244 287
@@ -11,7 +11,7 @@ Pour générer un fichier PDF, assurez-vous d&#39;avoir lancé `./configure` une foi @@ -11,7 +11,7 @@ Pour générer un fichier PDF, assurez-vous d&#39;avoir lancé `./configure` une foi
11 11
12 ## Programme 12 ## Programme
13 13
14 -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`. 14 +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`.
15 15
16 *(ne fonctionne que sur un environnement Linux)* 16 *(ne fonctionne que sur un environnement Linux)*
17 17