Gestion afficheurs, 2013/2014, TD1 : Différence entre versions
(→Conclusion :) |
|||
(69 révisions intermédiaires par 2 utilisateurs non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
+ | <center> [[Fichier:Gestion_afficheurs_compressé.mp4|200px|thumb|right|vidéo]] </center> | ||
+ | <center> Vidéo : http://projets-imasc.plil.net/mediawiki/images/d/df/Gestion_afficheurs_compress%C3%A9.mp4 </center> | ||
+ | |||
== Projet SC : == | == Projet SC : == | ||
Ligne 20 : | Ligne 23 : | ||
source : http://rex.plil.fr/Enseignement/Systeme/Projet.IMA3/systeme018.html | source : http://rex.plil.fr/Enseignement/Systeme/Projet.IMA3/systeme018.html | ||
+ | |||
+ | [[File:seriel.JPG|800px|thumb|left]] | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
Il fallait rajouter une sécurité à cette initialisation pour éviter de perdre des données : | Il fallait rajouter une sécurité à cette initialisation pour éviter de perdre des données : | ||
Ligne 28 : | Ligne 72 : | ||
Ces données seront réutilisées lors du passage à la FoxBoard. | Ces données seront réutilisées lors du passage à la FoxBoard. | ||
− | Notre Port série est maintenant configuré, on peut envoyer notre code ! | + | Notre Port série est maintenant configuré, on peut envoyer notre code ! |
− | ==='''''2. | + | ==='''''2. Mise en place de l'application sur ordinateur ''''' === |
− | ===='''A. Un afficheur : un caractère !'''==== | + | ===='''A.Un afficheur : un caractère !'''==== |
− | + | Nous avons vite compris que l'afficheur 16 segments était codé sur 16 bits. | |
Nous avons dans un premier temps affiché un code 16 bits (le 0x0001 par exemple) sur les 8 segments pour comprendre comment on pouvait gérer les 8 afficheurs. | Nous avons dans un premier temps affiché un code 16 bits (le 0x0001 par exemple) sur les 8 segments pour comprendre comment on pouvait gérer les 8 afficheurs. | ||
Ligne 45 : | Ligne 89 : | ||
===='''B. L'alphabet latin, un bonheur !'''==== | ===='''B. L'alphabet latin, un bonheur !'''==== | ||
+ | Maintenant que nous savons afficher, il faut maîtriser le contenu de l'affichage. | ||
+ | |||
+ | Nous avons donc mis chaque bit à 1 séparément (ex : 0x0001 puis 0x0002 puis 0x0004 ..) et reportés sur papier quel segment s'allumait pour ce bit. | ||
+ | |||
+ | Nous avons ensuite nommé chaque segment pour pouvoir créer nos caractères ! | ||
+ | |||
+ | Cette technique nous permet de modéliser un afficheur : | ||
+ | |||
+ | |||
+ | [[File:Afficheur16seg.JPG|thumb|left|afficheur 16 segments]] | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | ===='''C. Lire un fichier, c'est la base !'''==== | ||
+ | |||
+ | Notre application doit permettre de modifier le message affiché. Pour ce faire, notre page html modifiera un fichier et notre code C lira ce | ||
+ | fichier pour créer le message. | ||
+ | On présente maintenant le code de l'action "creer_message": | ||
+ | |||
+ | void cree_message(FILE* fp) | ||
+ | { | ||
+ | int i=0,j=0; | ||
+ | char car; | ||
+ | while(j<8) { x[j]=0x0000; j++;} //Cette boule sert à initialiser les 8 afficheurs au caractère NULL (0x0000) | ||
+ | while (!feof(fp)) | ||
+ | { | ||
+ | fscanf(fp,"%c",&car); | ||
+ | while((car!=carac[i])){i++;} //Cette boucle stocke dans x le message du fichier en paramètre | ||
+ | x[j]=correspondance[i]; //lit le premier caractere, on le cherche dans le tableau carc[] | ||
+ | j++; //on stocke dans x le code 16bits correspondant puis on incrémente la case j du message x | ||
+ | i=0; //on met i à 0 pour la recherche du caractère suivant | ||
+ | } | ||
+ | x[j--]=0x0000; //Avec cette methode le dernier caractère est doublé car le fscanf n'est pas fait avant la boucle | ||
+ | while (j<MAX_SIZE) //Ainsi on remet le dernier caractère du message x à NULL puis on met 8 caractère NULL qui serviront | ||
+ | { //au défilement | ||
+ | x[j]=0x0000; | ||
+ | j++; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | ===='''D. Faut que ça bouge !'''==== | ||
+ | |||
+ | |||
+ | Dans un afficheur publicitaire, les messages défilent de droite à gauche. | ||
+ | |||
+ | Pour reproduire cet effet, nous procédons en 3 étapes! | ||
+ | |||
+ | '''Étape 1 :''' ''Créer le message et afficher les 8 premiers caractères'' | ||
+ | → Cette étape est décrite dans la partie précédente | ||
+ | '''Étape 2 :''' ''Afficher la suite du message pas à pas'' | ||
+ | → Pour ce faire, on utilise deux boucles, dont une qui commence quand les 8 premiers caractères du tableau ont été affichés | ||
+ | → On parcours le tableau au complet en incrémentant à chaque période le code que l'afficheur reçoit de 1 dans le tableau | ||
+ | |||
+ | '''Étape 3 :''' ''Une boucle infinie'' | ||
+ | → On utilise un « while 1 » sur tout le main pour pouvoir revenir au début de notre tableau contenant le message et ainsi afficher le message en continu ! | ||
+ | |||
+ | Cette action est l'action principale de notre application, c'est-à-dire que nous avons choisi de la mettre dans le main étant donné qu'elle boucle sur 1 | ||
+ | |||
+ | Voici donc la partie du main qui gère le défilement: | ||
+ | |||
+ | |||
+ | unsigned char low[MAX_SIZE]; // correspondance est codé sur 16 bits, mais on ne peut envoyer que 8bits à la fois | ||
+ | unsigned char high[MAX_SIZE]; // on découpe donc le tableau message en 2 tableaux low et high | ||
+ | int sd=serialOpen(SERIAL_DEVICE,SERIAL_BOTH); // ouverture du port série | ||
+ | int i=0,z=0,a=0,tot=0; | ||
+ | while(1) | ||
+ | { | ||
+ | FILE*fp=fopen(argv[1],"r"); | ||
+ | if(fp==NULL){ perror("fopen(message)"); exit(-1); } // vérification du bon déroulement de l'ouverture du fichier passé en argument | ||
+ | cree_message(fp); // on crée le message x | ||
+ | for(i=0;i<MAX_SIZE;i++) // i va servir à lire dans le message x | ||
+ | { | ||
+ | if (i>8) a++; // cette ligne permet d'initialiser rapidement sans devoir décaler les 8 premiers caractères | ||
+ | tot=i+a; //NULL, puis on stocke l'endroit où on va lire dans tot (i + le nombre de fois ou on a été | ||
+ | for(z=0;z<8;z++) // au dessus de i | ||
+ | { | ||
+ | low[z] = x[tot] & 0x00ff; // La correspondance est en 16 bits, or l'envoi sur z se fait en 8bits, ces fonctions nous | ||
+ | high[z]= x[tot]>>8; // permettent de stocker correctement sur z, z représentant le numéro de l'afficheur | ||
+ | if(write(sd,&high[z],sizeof(char))!=1){ perror("main.write"); exit(-1); } //Écriture sur l'afficheur | ||
+ | if(write(sd,&low[z],sizeof(char))!=1){ perror("main.write"); exit(-1); } | ||
+ | usleep(delai); | ||
+ | tot++; | ||
+ | } | ||
+ | if (tot>MAX_SIZE) i=MAX_SIZE; | ||
+ | } // Cette ligne nous permet de sortir un peu plus rapidement de la | ||
+ | tot=0; //boucle lorsque le message a été affiché | ||
+ | i=0; // on réinitialise les variables pour le message suivant, on ferme fp | ||
+ | a=0; | ||
+ | z=0; | ||
+ | fclose(fp); | ||
+ | } | ||
+ | |||
+ | [[File:Defilement1.jpg|800px|thumb|left]] | ||
+ | |||
+ | [[File:Defilement2.jpg|800px|thumb|left]] | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
− | |||
− | |||
− | |||
− | |||
Ligne 62 : | Ligne 267 : | ||
− | |||
− | |||
− | |||
Ligne 92 : | Ligne 294 : | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
Ligne 125 : | Ligne 316 : | ||
+ | On sait désormais lire notre message et le faire défiler, mais nous sommes loin d'avoir répondu au cahier des charges ! | ||
− | ====''' | + | ===='''E. Le cahier des charges'''==== |
Les deux grands axes du cahier des charges concernant la programmation sont les suivants : | Les deux grands axes du cahier des charges concernant la programmation sont les suivants : | ||
Ligne 139 : | Ligne 331 : | ||
======'''1) Le fichier texte !'''====== | ======'''1) Le fichier texte !'''====== | ||
− | + | La modification du fichier texte se fait dans une fonction écrire.php, voici son code : | |
− | + | ||
− | + | <?php | |
− | + | $message=$_REQUEST['message']; //on récupère le message de la page html | |
− | + | file_put_contents("note.txt",$message); //on écrit ce message dans note.txt | |
− | + | echo "message=$message"; | |
+ | ?> | ||
+ | |||
+ | La question que l'on se pose maintenant est "Comment faire appel à cette fonction?" | ||
+ | |||
+ | Grâce aux commande ajax, on peut récupérer une message sur la page html et appeler le fichier ercire.php | ||
+ | |||
+ | Voici les lignes du code html qui vont permettre de récupérer le message dans une case texte prévue à cet effet: | ||
+ | |||
+ | <input type="text" id="message" value="message"> | ||
+ | <input type="submit" value="Envoyer" onclick="javascript:envoyer();"> | ||
+ | |||
+ | |||
+ | Voici le code ajax qui va permettre d'appeler ecrire.php avec comme paramètre le message: | ||
+ | |||
+ | <script type="text/javascript" src="jquery.js"></script> | ||
+ | <script type="text/javascript"> | ||
+ | function envoyer(){ | ||
+ | var m=$('#message').val(); | ||
+ | $.ajax({url: 'ecrire.php', type: 'post', data: {message: m}}); | ||
+ | </script> | ||
====='''2) La vitesse de défilement'''===== | ====='''2) La vitesse de défilement'''===== | ||
− | <br> | + | La vitesse de défilement doit pouvoir se gérer grâce à deux boutons sur la page html. |
− | < | + | |
+ | Un bouton fast qui va appeler la fonction rapide.php et un bouton slow qui va appeler la fonction lent.php | ||
+ | |||
+ | En cliquant sur ces boutons, l'utilisateur va envoyer un signe (SIGUSR1 pour Fast et SIGUSR2 pour slow) | ||
+ | |||
+ | Grâce aux fonctionx lent.php et rapide.php ainsi qu'au pid, le code c (corresp.c) va récupérer le signal envoyé ou non par l'utilisateur | ||
+ | |||
+ | Voici le code des boutons Fast et Slow ainsi que le code ajax qui renvoie aux fonction lent.php et rapide.php : | ||
+ | |||
+ | <input type="submit" value="Fast" onclick="javascript:rapide();"> | ||
+ | <input type="submit" value="Slow" onclick="javascript:lent();"> | ||
+ | function rapide(){ | ||
+ | $.ajax({url: 'rapide.php', type:'post'}); | ||
+ | } | ||
+ | function lent(){ | ||
+ | $.ajax({url: 'lent.php', type:'post'}); | ||
+ | } | ||
+ | |||
+ | Passons maintenant à la fonction rapide.php : | ||
+ | |||
+ | define('SIGUSR1',10); // Ici les valeur des signaux SIGUSR1 et SIGUSR2 | ||
+ | define('SIGUSR2',12); | ||
+ | |||
+ | $pid=trim(file_get_contents("pid.txt")); // On récupère le pid (envoyé par le code c dans pid.txt) pour pouvoir communiquer avec le .c | ||
+ | if(is_numeric($pid)){ | ||
+ | posix_kill($pid,SIGUSR1); // On envoie SIGUSR1 au code c | ||
+ | $erreur=posix_get_last_error(); // Vérification que l'envoi s'est bien fait | ||
+ | if($erreur!=0) echo 'Erreur : '.posix_strerror($erreur)."<br>"; | ||
+ | |||
+ | Pour la fonction lent.php, il suffit de remplacer SIGUSR1 par SIGUSR2 ! | ||
+ | |||
+ | Comment le code exploite ces signaux? | ||
+ | |||
+ | Dans le code qui gère le défilement, nous avons vu qu'a chaque fois que les 8 afficheurs étaient remplis, une pause usleep(delai) était effectuée | ||
+ | |||
+ | Ce "delai" est en fait une variable globale. Lorsque le code va recevoir un signal SIGUSR1 ou SIGUSR2, il va appeler respectivement les fonction "rapide" | ||
+ | et "lent" et ainsi modifier la valeur de "delai" | ||
+ | |||
+ | Les fonction rapide et lent sont les suivant : | ||
+ | |||
+ | void rapide(int sig){ // le paramètre est un entier qui représente le signal reçu, c'est le 10 et 12 que nous avions défini dans les .php | ||
+ | delai=delai/2;} | ||
+ | |||
+ | void lent(int sig){ | ||
+ | delai=delai*2;} | ||
+ | |||
+ | Ces fonction sont simples, la complexité réside dans la réception et l'appel à ces fonctions. | ||
+ | |||
+ | Ceci se fait dans le main grâce au code suivant: | ||
+ | |||
+ | FILE*fd=fopen("pid.txt","w"); | ||
+ | if(fd==NULL){perror("open(pid)"); exit(-1);} //on écrit le pid dans le fichier pid.txt, pour pouvoir communiquer avec le php | ||
+ | fprintf(fd,"%d",getpid()); | ||
+ | fclose(fd); | ||
+ | |||
+ | memset(&action,'\0',sizeof(action)); //on ecrase l'adresse de action pour ne pas mélanger les fonctions rapide et lent | ||
+ | action.sa_handler=rapide; // on stocke la fonction rapide dans action | ||
+ | if(sigaction(SIGUSR1,&action,NULL)<0){perror("sigaction()"); exit(-1);} // on appelle action si on reçoit SIGUSR1 | ||
+ | memset(&action,'\0',sizeof(action)); | ||
+ | action.sa_handler=lent; // pareil pour SIGUSR2 et lent | ||
+ | if(sigaction(SIGUSR2,&action,NULL)<0){perror("sigaction()"); exit(-1);} | ||
+ | |||
+ | |||
+ | Tout notre code est prêt et fonctionne, il reste maintenant à tout embarquer sur la foxBoard ! | ||
+ | |||
+ | ==='''''3. Fox....Board to be alive ! ''''' === | ||
+ | |||
+ | ===='''A. Le produit fini'''==== | ||
+ | |||
+ | Le produit fini de notre projet est un système embarqué (la foxBoard) qui contiendra notre application et qui, dès que la foXboard sera branchée aux afficheurs, exécutera l'application. | ||
+ | |||
+ | Il fallait toutefois configurer la foxBoard avec minicom pour pouvoir ensuite accéder au ssh et ainsi finaliser ntore projet | ||
+ | |||
+ | [[File:Liaisonserie.JPG|800px|thumb|left]] | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | ===='''B. Les autorisations pour l'exécution'''==== | ||
+ | |||
+ | Sur la foxBoard, comme sur l'ordinateur, le code html ne peut pas modifier notre fichier "note.txt" si celui-ci n'est pas autorisé www-data | ||
+ | Par un raisonnement similaire, le code html ne peut pas récupérer la valeur dans "pid.txt" si ce fichier n'est pas autorisé sur www-data | ||
+ | |||
+ | |||
+ | Une fois que ces autorisations sont faites, que les fichiers sont placés au bon endroit (var/www/html) et que l'application est compilée, il faut créer un script permettant de l'exécuter au démarrage | ||
+ | |||
+ | |||
+ | ===='''C. Le script rc.local'''==== | ||
+ | |||
+ | La foxBoard contient (comme tout système unix) un fichier rc.local se lançant au démarrage. | ||
+ | Par défaut celui ci est vide mais si vous voulez lancer une application au démarrage, il faut entrer dans ce fichier les lignes de commandes que vous entreriez dans le terminal pour lancer l'application. | ||
+ | |||
+ | |||
+ | Voici notre scipt qui finalise donc le projet: | ||
+ | |||
+ | stty -F /dev/ttyACM0 9600 cs8 \ //initialisation du port série (vu au premier paragraphe) | ||
+ | -hupcl -icrnl -ixon -opost -onlcr -isig -icanon \ | ||
+ | -iexten -echo -echoe -echok -echoctl -echoke ignbrk | ||
+ | sleep 9999d 3</dev/ttyACM0 & //Cette tache est une tache de fond, elle met un certain temps à s'exécuter | ||
+ | sleep 5 //on ajoute donc une temporisation avant de passer à l'exécution de l'application | ||
+ | ( cd /var/www/html ; su www-data -c "./test note.txt" ) & //Exécution | ||
+ | exit 0 | ||
+ | |||
+ | ===='''''4. Les problèmes nous font avancer ! ''''' ==== | ||
+ | |||
+ | On a trouvé judicieux de recenser les problèmes rencontrés lors de ce projet, nous remercions également Mr Xavier REDON pour l'aide et les explications | ||
+ | apportées durant ce projet. | ||
+ | |||
+ | 1 --> trouver à quel bit correspond quel segment (difficulté faible, mais nous avons tout de même du réfléchir pour trouver une solution rapide) | ||
+ | |||
+ | 2 --> La gestion des signaux était quelque chose de nouveau et a engendré la difficulté 3. | ||
+ | |||
+ | 3 --> Comprendre et maîtriser les autorisations. | ||
+ | |||
+ | 4 --> Bloquage lors de la réception du signal. En effet notre code fonctionnait mais nous avions oubliés les sécurités, on créait donc une boucle infinie. | ||
+ | Suite à une intervention de M. REDON, les vérifications ont été codés et le programme fonctionnait parfaitement. | ||
+ | |||
+ | 5 --> le minicom pour configurer la foxBoard. | ||
+ | |||
+ | |||
+ | Sur ces difficultés, nous retiendrons particulièrement les sécurités sur les vérifications de la bon ouverture des fichiers | ||
+ | |||
+ | Le projet est terminé, le cahier des charges comblé, nous vous laissons avec une vidéo du travail final! | ||
==''Partie électronique :''== | ==''Partie électronique :''== | ||
Ligne 198 : | Ligne 572 : | ||
Voici l’idée globale retenue pour le circuit :<br> | Voici l’idée globale retenue pour le circuit :<br> | ||
− | <center>[[Fichier:Julian_1.jpg|vignette|upright=5|centre]]</center> | + | <center>[[Fichier:Julian_1.jpg|vignette|upright=5|centre|Schéma théorique]]</center> |
<br> | <br> | ||
=====Explications :===== | =====Explications :===== | ||
Ligne 207 : | Ligne 581 : | ||
Après plusieurs essais, voici notre circuit définitif sur Altium :<br> | Après plusieurs essais, voici notre circuit définitif sur Altium :<br> | ||
− | [[Fichier:Julian_2.jpg|vignette|upright=5|centre]] | + | [[Fichier:Julian_2.jpg|vignette|upright=5|centre|Circuit sur Altium]] |
<br> | <br> | ||
Nous avons dissocié les deux compteurs afin de pouvoir contrôler la fréquence d’affichage des caractères.<br> | Nous avons dissocié les deux compteurs afin de pouvoir contrôler la fréquence d’affichage des caractères.<br> | ||
Ligne 214 : | Ligne 588 : | ||
<br> | <br> | ||
− | [[Fichier:Julian_3.jpg|vignette|upright=5|centre]] | + | [[Fichier:Julian_3.jpg|vignette|upright=5|centre|Simulation]] |
Dans le rectangle du haut nous pouvons envoyer le code binaire d’un caractère à afficher. Le rectangle du dessous permet d’envoyer ce code en mettant l’horloge à 1. Au milieu nous gérons la fréquence d’affichage (ici 2Hz afin d’avoir le temps de prendre une photo). Puis dans l’avant dernier rectangle on peut voir que notre code binaire se déplace correctement. Et dans le dernier un voit quel afficheur est sélectionné par le décodeur.<br> | Dans le rectangle du haut nous pouvons envoyer le code binaire d’un caractère à afficher. Le rectangle du dessous permet d’envoyer ce code en mettant l’horloge à 1. Au milieu nous gérons la fréquence d’affichage (ici 2Hz afin d’avoir le temps de prendre une photo). Puis dans l’avant dernier rectangle on peut voir que notre code binaire se déplace correctement. Et dans le dernier un voit quel afficheur est sélectionné par le décodeur.<br> | ||
− | <center>[[Fichier:Julian_4.jpg|vignette|upright=2|centre]]</center> | + | <center>[[Fichier:Julian_4.jpg|vignette|upright=2|centre|Tests sur l'oscilloscope]]</center> |
<br> | <br> | ||
On voit ici de D7 à D4 les 4 bascules, et de D0 à D3 les 4 codes binaires envoyés. | On voit ici de D7 à D4 les 4 bascules, et de D0 à D3 les 4 codes binaires envoyés. | ||
+ | <br> | ||
+ | <br> | ||
+ | =====Câblage :===== | ||
<br> | <br> | ||
Après cette simulation concluante, nous avons commencé le câblage. Celui-ci s’est avéré fastidieux dès le départ, car le simple fait d’avoir 4 afficheurs pour lesquels il fallait 16 fils chacun nous promettait de nous y faire consacrer une bonne partie de la séance.<br> | Après cette simulation concluante, nous avons commencé le câblage. Celui-ci s’est avéré fastidieux dès le départ, car le simple fait d’avoir 4 afficheurs pour lesquels il fallait 16 fils chacun nous promettait de nous y faire consacrer une bonne partie de la séance.<br> | ||
Ligne 227 : | Ligne 604 : | ||
Le problème alors rencontré est que nos afficheurs ont une led par petits segments, et deux par grands segments. Après quelques tests avec l’encadrant, nous avons constaté qu’il fallait minimum 3,8V pour un grand segment si on voulait l’allumer avec 20mA. La NanoBoard ne permettait donc pas d’allumer tous les segments (ce sont des afficheurs à anode commune).<br> | Le problème alors rencontré est que nos afficheurs ont une led par petits segments, et deux par grands segments. Après quelques tests avec l’encadrant, nous avons constaté qu’il fallait minimum 3,8V pour un grand segment si on voulait l’allumer avec 20mA. La NanoBoard ne permettait donc pas d’allumer tous les segments (ce sont des afficheurs à anode commune).<br> | ||
− | [[Fichier:Julian_5.jpg]] | + | [[Fichier:Julian_5.jpg|vignette|gauche|Datasheet des afficheurs]] |
+ | [[Fichier:Julian_6.jpg|vignette|upright=1.5|droite|Câblage]] | ||
+ | |||
+ | <br><br><br><br><br><br><br><br> | ||
+ | |||
+ | Un rapide calcul nous a permis de déterminer la valeur des résistances à mettre avant chaque afficheur : une résistance de 50Ω (47Ω) pour un petit segment, une de 300Ω pour un grand (270Ω).<br> | ||
+ | La solution retenue après discussion avec les deux encadrants a été d’utiliser deux amplificateurs (drivers ULN2803) pour avoir une bonne tension sur nos afficheurs. Le problème créé avec cette solution est que nous ne pouvions plus contrôler séparément nos afficheurs. Nous avons donc eu l’idée d’utiliser un transistor par afficheur, qui recevrait l’ordre de commande des sorties de la carte correspondants à celles du décodeur.<br> | ||
+ | Après plusieurs tests, nous avons compris que ceux utilisés (des TMOS) ne pourraient fonctionner car leur tension de seuil VGS est plus élevée que les 3,3V que peut fournir notre carte.<br> | ||
+ | |||
+ | <center>[[Fichier:Julian_7.jpg|upright=2|centre]]</center> | ||
<br> | <br> | ||
<br> | <br> | ||
− | |||
− | |||
− | |||
− | < | + | ==Conclusion :== |
+ | <br> | ||
+ | Ce projet nous a permis de mettre en pratique nos connaissances informatiques et électroniques acquises au cours de l'année.<br> | ||
+ | Beaucoup de notions ont été comprises et travaillées. | ||
+ | Ces projets sont un bon moyens pour nous confronter aux problèmes que nous rencontrerons lors de nos futurs projets professionnels | ||
+ | Nous aurions aimé pouvoir relier directement la partie informatique à la partie électronique afin de pouvoir tester la totalité du projet.<br> | ||
+ | <br> | ||
+ | <br> | ||
<br> | <br> |
Version actuelle datée du 14 juin 2014 à 10:15
Sommaire
Projet SC :
Gestion d'afficheurs 16 segments
Partie programmation
Cette partie sera décomposée en X parties correspondant aux X difficultés rencontrées lors de ce projet.
1. Gérer la liaison série
Pour transmettre notre programme au banc d'essai, il faut tout d'abord initialiser ce banc d'essai et dire à notre contrôleur (ici l'ordinateur) où il se trouve.
Ceci ne constituais pas une grande difficulté étant donné que de nombreux travaux avaient déjà étaient fait sur la liaison série et que le code permettant de l'initialiser était sur le wiki :
stty -F /dev/ttyACM0 9600 cs8 \ -hupcl -icrnl -ixon -opost -onlcr -isig -icanon \ -iexten -echo -echoe -echok -echoctl -echoke ignbrk
source : http://rex.plil.fr/Enseignement/Systeme/Projet.IMA3/systeme018.html
Il fallait rajouter une sécurité à cette initialisation pour éviter de perdre des données :
sleep 9999d 3</dev/ttyACM0 &
source : http://rex.plil.fr/Enseignement/Systeme/Projet.IMA3/systeme018.html
Ces données seront réutilisées lors du passage à la FoxBoard. Notre Port série est maintenant configuré, on peut envoyer notre code !
2. Mise en place de l'application sur ordinateur
A.Un afficheur : un caractère !
Nous avons vite compris que l'afficheur 16 segments était codé sur 16 bits.
Nous avons dans un premier temps affiché un code 16 bits (le 0x0001 par exemple) sur les 8 segments pour comprendre comment on pouvait gérer les 8 afficheurs.
Après plusieurs essais, nous avons opté pour la création d'un tableau qui contiendrai le message à afficher.
Dans le premier code nous avions un compteur d'afficheur qui recevait les cases du tableau. A chaque incrémentation compteur correspondait une incrémentation tableau, ce qui nous permettait d'afficher des caractères différents sur les afficheurs.
B. L'alphabet latin, un bonheur !
Maintenant que nous savons afficher, il faut maîtriser le contenu de l'affichage.
Nous avons donc mis chaque bit à 1 séparément (ex : 0x0001 puis 0x0002 puis 0x0004 ..) et reportés sur papier quel segment s'allumait pour ce bit.
Nous avons ensuite nommé chaque segment pour pouvoir créer nos caractères !
Cette technique nous permet de modéliser un afficheur :
C. Lire un fichier, c'est la base !
Notre application doit permettre de modifier le message affiché. Pour ce faire, notre page html modifiera un fichier et notre code C lira ce fichier pour créer le message. On présente maintenant le code de l'action "creer_message":
void cree_message(FILE* fp) { int i=0,j=0; char car; while(j<8) { x[j]=0x0000; j++;} //Cette boule sert à initialiser les 8 afficheurs au caractère NULL (0x0000) while (!feof(fp)) { fscanf(fp,"%c",&car); while((car!=carac[i])){i++;} //Cette boucle stocke dans x le message du fichier en paramètre x[j]=correspondance[i]; //lit le premier caractere, on le cherche dans le tableau carc[] j++; //on stocke dans x le code 16bits correspondant puis on incrémente la case j du message x i=0; //on met i à 0 pour la recherche du caractère suivant } x[j--]=0x0000; //Avec cette methode le dernier caractère est doublé car le fscanf n'est pas fait avant la boucle while (j<MAX_SIZE) //Ainsi on remet le dernier caractère du message x à NULL puis on met 8 caractère NULL qui serviront { //au défilement x[j]=0x0000; j++; } }
D. Faut que ça bouge !
Dans un afficheur publicitaire, les messages défilent de droite à gauche.
Pour reproduire cet effet, nous procédons en 3 étapes!
Étape 1 : Créer le message et afficher les 8 premiers caractères → Cette étape est décrite dans la partie précédente Étape 2 : Afficher la suite du message pas à pas → Pour ce faire, on utilise deux boucles, dont une qui commence quand les 8 premiers caractères du tableau ont été affichés → On parcours le tableau au complet en incrémentant à chaque période le code que l'afficheur reçoit de 1 dans le tableau
Étape 3 : Une boucle infinie → On utilise un « while 1 » sur tout le main pour pouvoir revenir au début de notre tableau contenant le message et ainsi afficher le message en continu !
Cette action est l'action principale de notre application, c'est-à-dire que nous avons choisi de la mettre dans le main étant donné qu'elle boucle sur 1
Voici donc la partie du main qui gère le défilement:
unsigned char low[MAX_SIZE]; // correspondance est codé sur 16 bits, mais on ne peut envoyer que 8bits à la fois unsigned char high[MAX_SIZE]; // on découpe donc le tableau message en 2 tableaux low et high int sd=serialOpen(SERIAL_DEVICE,SERIAL_BOTH); // ouverture du port série int i=0,z=0,a=0,tot=0; while(1) { FILE*fp=fopen(argv[1],"r"); if(fp==NULL){ perror("fopen(message)"); exit(-1); } // vérification du bon déroulement de l'ouverture du fichier passé en argument cree_message(fp); // on crée le message x for(i=0;i<MAX_SIZE;i++) // i va servir à lire dans le message x { if (i>8) a++; // cette ligne permet d'initialiser rapidement sans devoir décaler les 8 premiers caractères tot=i+a; //NULL, puis on stocke l'endroit où on va lire dans tot (i + le nombre de fois ou on a été for(z=0;z<8;z++) // au dessus de i { low[z] = x[tot] & 0x00ff; // La correspondance est en 16 bits, or l'envoi sur z se fait en 8bits, ces fonctions nous high[z]= x[tot]>>8; // permettent de stocker correctement sur z, z représentant le numéro de l'afficheur if(write(sd,&high[z],sizeof(char))!=1){ perror("main.write"); exit(-1); } //Écriture sur l'afficheur if(write(sd,&low[z],sizeof(char))!=1){ perror("main.write"); exit(-1); } usleep(delai); tot++; } if (tot>MAX_SIZE) i=MAX_SIZE; } // Cette ligne nous permet de sortir un peu plus rapidement de la tot=0; //boucle lorsque le message a été affiché i=0; // on réinitialise les variables pour le message suivant, on ferme fp a=0; z=0; fclose(fp); }
On sait désormais lire notre message et le faire défiler, mais nous sommes loin d'avoir répondu au cahier des charges !
E. Le cahier des charges
Les deux grands axes du cahier des charges concernant la programmation sont les suivants :
1) Par le biais d'une page php (que nous verrons plus tard), nous modifierons un fichier.txt contenant le message à afficher. Ce message peut être modifié pendant l’exécution et dois défiler en continu.
2) Par le biais d'une page php, la vitesse de défilement peut être modifiée.
1) Le fichier texte !
La modification du fichier texte se fait dans une fonction écrire.php, voici son code :
<?php $message=$_REQUEST['message']; //on récupère le message de la page html file_put_contents("note.txt",$message); //on écrit ce message dans note.txt echo "message=$message"; ?>
La question que l'on se pose maintenant est "Comment faire appel à cette fonction?"
Grâce aux commande ajax, on peut récupérer une message sur la page html et appeler le fichier ercire.php
Voici les lignes du code html qui vont permettre de récupérer le message dans une case texte prévue à cet effet:
<input type="text" id="message" value="message"> <input type="submit" value="Envoyer" onclick="javascript:envoyer();">
Voici le code ajax qui va permettre d'appeler ecrire.php avec comme paramètre le message:
<script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> function envoyer(){ var m=$('#message').val(); $.ajax({url: 'ecrire.php', type: 'post', data: {message: m}}); </script>
2) La vitesse de défilement
La vitesse de défilement doit pouvoir se gérer grâce à deux boutons sur la page html.
Un bouton fast qui va appeler la fonction rapide.php et un bouton slow qui va appeler la fonction lent.php
En cliquant sur ces boutons, l'utilisateur va envoyer un signe (SIGUSR1 pour Fast et SIGUSR2 pour slow)
Grâce aux fonctionx lent.php et rapide.php ainsi qu'au pid, le code c (corresp.c) va récupérer le signal envoyé ou non par l'utilisateur
Voici le code des boutons Fast et Slow ainsi que le code ajax qui renvoie aux fonction lent.php et rapide.php :
<input type="submit" value="Fast" onclick="javascript:rapide();"> <input type="submit" value="Slow" onclick="javascript:lent();"> function rapide(){ $.ajax({url: 'rapide.php', type:'post'}); } function lent(){ $.ajax({url: 'lent.php', type:'post'}); }
Passons maintenant à la fonction rapide.php :
define('SIGUSR1',10); // Ici les valeur des signaux SIGUSR1 et SIGUSR2 define('SIGUSR2',12);
$pid=trim(file_get_contents("pid.txt")); // On récupère le pid (envoyé par le code c dans pid.txt) pour pouvoir communiquer avec le .c if(is_numeric($pid)){ posix_kill($pid,SIGUSR1); // On envoie SIGUSR1 au code c $erreur=posix_get_last_error(); // Vérification que l'envoi s'est bien fait if($erreur!=0) echo 'Erreur : '.posix_strerror($erreur)."
";
Pour la fonction lent.php, il suffit de remplacer SIGUSR1 par SIGUSR2 !
Comment le code exploite ces signaux?
Dans le code qui gère le défilement, nous avons vu qu'a chaque fois que les 8 afficheurs étaient remplis, une pause usleep(delai) était effectuée
Ce "delai" est en fait une variable globale. Lorsque le code va recevoir un signal SIGUSR1 ou SIGUSR2, il va appeler respectivement les fonction "rapide" et "lent" et ainsi modifier la valeur de "delai"
Les fonction rapide et lent sont les suivant :
void rapide(int sig){ // le paramètre est un entier qui représente le signal reçu, c'est le 10 et 12 que nous avions défini dans les .php delai=delai/2;}
void lent(int sig){ delai=delai*2;}
Ces fonction sont simples, la complexité réside dans la réception et l'appel à ces fonctions.
Ceci se fait dans le main grâce au code suivant:
FILE*fd=fopen("pid.txt","w"); if(fd==NULL){perror("open(pid)"); exit(-1);} //on écrit le pid dans le fichier pid.txt, pour pouvoir communiquer avec le php fprintf(fd,"%d",getpid()); fclose(fd);
memset(&action,'\0',sizeof(action)); //on ecrase l'adresse de action pour ne pas mélanger les fonctions rapide et lent action.sa_handler=rapide; // on stocke la fonction rapide dans action if(sigaction(SIGUSR1,&action,NULL)<0){perror("sigaction()"); exit(-1);} // on appelle action si on reçoit SIGUSR1 memset(&action,'\0',sizeof(action)); action.sa_handler=lent; // pareil pour SIGUSR2 et lent if(sigaction(SIGUSR2,&action,NULL)<0){perror("sigaction()"); exit(-1);}
Tout notre code est prêt et fonctionne, il reste maintenant à tout embarquer sur la foxBoard !
3. Fox....Board to be alive !
A. Le produit fini
Le produit fini de notre projet est un système embarqué (la foxBoard) qui contiendra notre application et qui, dès que la foXboard sera branchée aux afficheurs, exécutera l'application.
Il fallait toutefois configurer la foxBoard avec minicom pour pouvoir ensuite accéder au ssh et ainsi finaliser ntore projet
B. Les autorisations pour l'exécution
Sur la foxBoard, comme sur l'ordinateur, le code html ne peut pas modifier notre fichier "note.txt" si celui-ci n'est pas autorisé www-data Par un raisonnement similaire, le code html ne peut pas récupérer la valeur dans "pid.txt" si ce fichier n'est pas autorisé sur www-data
Une fois que ces autorisations sont faites, que les fichiers sont placés au bon endroit (var/www/html) et que l'application est compilée, il faut créer un script permettant de l'exécuter au démarrage
C. Le script rc.local
La foxBoard contient (comme tout système unix) un fichier rc.local se lançant au démarrage. Par défaut celui ci est vide mais si vous voulez lancer une application au démarrage, il faut entrer dans ce fichier les lignes de commandes que vous entreriez dans le terminal pour lancer l'application.
Voici notre scipt qui finalise donc le projet:
stty -F /dev/ttyACM0 9600 cs8 \ //initialisation du port série (vu au premier paragraphe) -hupcl -icrnl -ixon -opost -onlcr -isig -icanon \ -iexten -echo -echoe -echok -echoctl -echoke ignbrk sleep 9999d 3</dev/ttyACM0 & //Cette tache est une tache de fond, elle met un certain temps à s'exécuter sleep 5 //on ajoute donc une temporisation avant de passer à l'exécution de l'application ( cd /var/www/html ; su www-data -c "./test note.txt" ) & //Exécution exit 0
4. Les problèmes nous font avancer !
On a trouvé judicieux de recenser les problèmes rencontrés lors de ce projet, nous remercions également Mr Xavier REDON pour l'aide et les explications apportées durant ce projet.
1 --> trouver à quel bit correspond quel segment (difficulté faible, mais nous avons tout de même du réfléchir pour trouver une solution rapide)
2 --> La gestion des signaux était quelque chose de nouveau et a engendré la difficulté 3.
3 --> Comprendre et maîtriser les autorisations.
4 --> Bloquage lors de la réception du signal. En effet notre code fonctionnait mais nous avions oubliés les sécurités, on créait donc une boucle infinie. Suite à une intervention de M. REDON, les vérifications ont été codés et le programme fonctionnait parfaitement.
5 --> le minicom pour configurer la foxBoard.
Sur ces difficultés, nous retiendrons particulièrement les sécurités sur les vérifications de la bon ouverture des fichiers
Le projet est terminé, le cahier des charges comblé, nous vous laissons avec une vidéo du travail final!
Partie électronique :
Première séance :
Découverte du projet et du cahier des charges.
Prise en main du logiciel altium et suivi partiel du tutoriel.
Deuxième séance :
Fin du tutoriel proposé. Compréhension du schéma.
Définition du cahier des charges de notre projet et proposition de schéma électronique.
Découverte d'un possible problème sur nos afficheurs à anode commune (contrôle par la masse)
Troisième séance :
Mise en place du schéma électronique établi à la séance précédente sur altium.
Correction des quelques problèmes rencontrés puis simulation (réussie) du schéma.
Problème des afficheurs confirmé (courant et tension admissibles), étude avec les deux professeurs des solutions possibles.
Câblage d'une solution retenue (driver de leds + 2 demi afficheurs) -> la solution résolve partiellement le problème (on peut fournir une tension et un courant correct).
Commande de 4 transistors pouvant résoudre le dernier problème électronique (contrôle des afficheurs).
Quatrième séance :
Câblage de l’autre moitié du premier afficheur. Le reste ne sera pas câblé car trop long et inutile pour résoudre le problème des transistors.
Les transistors n’ont pas permis de contrôler séparément chacun des afficheurs, car leur tension de seuil de déclenchement est trop élevée par rapport à la tension que l’on récupère déjà à côté pour les drivers de leds et afficheurs.
On a cependant une petite simulation de 3 caractères (IMA) pour montrer que notre montage fonctionne (on peut afficher les caractères désirés, mais le défilement ne s'effectue pas. Il faudrait trouver quatre transistors capables de se déclencher avec les 3,3V max que la nanoboard peut fournir, sachant que les leds s'allument avec une tension minimale de 3,8V).
Explications détaillées :
Après avoir pris en main la NanoBoard grâce au tutoriel proposé (http://rex.plil.fr/Enseignement/Systeme/Projet.IMA3/tutoriel_nanoboard.pdf), nous avons établi un cahier des charges pour notre projet.
Voici l’idée globale retenue pour le circuit :
Explications :
On récupère les informations du port série, ainsi que son signal d’horloge. On mémorise ces informations grâce aux bascules, elles même gérées par un démultiplexeur relié à l’horloge du port série. On cadence ainsi les informations afin que le multiplexeur les reçoivent une par une. Le décodeur va ensuite choisir tour à tour un afficheur grâce au signal d’horloge, et le multiplexeur envoie ainsi une information sur tous les afficheurs, mais seulement un sera allumé à ce moment grâce au décodeur.
Il nous est possible d’envoyer qu’un seul bus de 16 bits sur les afficheurs reliés en dérivation, car la fréquence de sélection du décodeur est bien plus rapide que la fréquence rétinienne de l’homme. On a donc l’impression que le message est fixe avec un caractère affiché sur chaque afficheur, alors qu’en réalité il a toujours qu’un seul afficheur d’allumé.
Après plusieurs essais, voici notre circuit définitif sur Altium :
Nous avons dissocié les deux compteurs afin de pouvoir contrôler la fréquence d’affichage des caractères.
Simulation :
Dans le rectangle du haut nous pouvons envoyer le code binaire d’un caractère à afficher. Le rectangle du dessous permet d’envoyer ce code en mettant l’horloge à 1. Au milieu nous gérons la fréquence d’affichage (ici 2Hz afin d’avoir le temps de prendre une photo). Puis dans l’avant dernier rectangle on peut voir que notre code binaire se déplace correctement. Et dans le dernier un voit quel afficheur est sélectionné par le décodeur.
On voit ici de D7 à D4 les 4 bascules, et de D0 à D3 les 4 codes binaires envoyés.
Câblage :
Après cette simulation concluante, nous avons commencé le câblage. Celui-ci s’est avéré fastidieux dès le départ, car le simple fait d’avoir 4 afficheurs pour lesquels il fallait 16 fils chacun nous promettait de nous y faire consacrer une bonne partie de la séance.
En regardant la datasheet de la NanoBoard sur internet nous avons constaté que les sorties de la carte pouvaient fournir au maximum 3,3V chacune (dont une à 5V), et notre encadrant nous a dit qu’il valait mieux ne pas tirer plus de 20mA par sortie.
Le problème alors rencontré est que nos afficheurs ont une led par petits segments, et deux par grands segments. Après quelques tests avec l’encadrant, nous avons constaté qu’il fallait minimum 3,8V pour un grand segment si on voulait l’allumer avec 20mA. La NanoBoard ne permettait donc pas d’allumer tous les segments (ce sont des afficheurs à anode commune).
Un rapide calcul nous a permis de déterminer la valeur des résistances à mettre avant chaque afficheur : une résistance de 50Ω (47Ω) pour un petit segment, une de 300Ω pour un grand (270Ω).
La solution retenue après discussion avec les deux encadrants a été d’utiliser deux amplificateurs (drivers ULN2803) pour avoir une bonne tension sur nos afficheurs. Le problème créé avec cette solution est que nous ne pouvions plus contrôler séparément nos afficheurs. Nous avons donc eu l’idée d’utiliser un transistor par afficheur, qui recevrait l’ordre de commande des sorties de la carte correspondants à celles du décodeur.
Après plusieurs tests, nous avons compris que ceux utilisés (des TMOS) ne pourraient fonctionner car leur tension de seuil VGS est plus élevée que les 3,3V que peut fournir notre carte.
Conclusion :
Ce projet nous a permis de mettre en pratique nos connaissances informatiques et électroniques acquises au cours de l'année.
Beaucoup de notions ont été comprises et travaillées.
Ces projets sont un bon moyens pour nous confronter aux problèmes que nous rencontrerons lors de nos futurs projets professionnels
Nous aurions aimé pouvoir relier directement la partie informatique à la partie électronique afin de pouvoir tester la totalité du projet.