Tr57 Rapport
Tr57 Rapport
Tr57 Rapport
13 janvier 2009
1 Partie embarquée 3
1.1 Présentation du matériel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Présentation de PICOS18 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Découverte de PICOS18 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.4 Fichiers sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.5 Mise en œuvre de la liaison série . . . . . . . . . . . . . . . . . . . . . . . . 5
1.6 Mise en œuvre de l’ADC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.7 Mise en œuvre du module PWM . . . . . . . . . . . . . . . . . . . . . . . . 9
1.8 Structure de l’application . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.9 Communication PC/microcontrôleur . . . . . . . . . . . . . . . . . . . . . . 10
2 Partie débarquée 13
2.1 Présentation de Visual C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2 Traitement des données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.1 Réception sur la liaison série . . . . . . . . . . . . . . . . . . . . . . 13
2.2.2 Affichage dans un graphique . . . . . . . . . . . . . . . . . . . . . . . 14
2.3 Marche/arrêt du moteur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.4 Choix du mode de consigne . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4.1 Consigne analogique . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4.2 Consigne numérique . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Conclusion 18
2
Introduction
Dans le cadre des travaux pratiques de l’unité de valeur TR57 — Commande en temps
réel, nous avons choisi de travailler sur le projet impliquant l’utilisation du noyau mutli-
tâche temps réel PICOS18.
Contrairement aux autres sujets de projet proposés, celui-ci ne portait pas sur la réa-
lisation d’une application particulière, mais plutôt sur l’utilisation d’un outil, en l’occur-
rence PICOS18. L’application finale n’était donc pas une finalité, et le but premier était
de comprendre et de maı̂triser les problématiques liées au temps réel en utilisant un outil
approprié.
Évidemment, pour que le projet n’en soit que plus intéressant, nous avons choisi d’uti-
liser le microcontrôleur afin de commander un moteur à courant continu. De plus, afin de
compléter la partie développement embarqué sur microcontrôleur, nous devions réaliser
une interfaçe de supervision et de commande sur PC. Celle-ci devait être réalisée avec
Visual C++, l’environnement de développement pour Windows conçu par Microsoft.
Ce rapport présentera donc les travaux menés durant le semestre aussi bien sur la
partie microcontrôleur que sur la partie interface PC.
1 Partie embarquée
1.1 Présentation du matériel
Afin de mener à bien notre projet, comme le schématise la figure 1, nous avions à notre
disposition, dans la salle de TP, le matériel suivant :
– Une carte de développement pour micrôcontoleur intégrant un PIC18F458.
– Un module MPLAB ICD2 qui est un débogueur temps réel et un programmateur
pour les micrôcontroleurs PIC.
– Une carte moteur nous permettant de disposer des connecteurs pour les sorties PWM
et pour les entrées de l’ADC.
– Une moteur à courant continu pour réaliser les tests.
– Un PC comportant les environnements de développement MPLAB et Visual C++.
3
Nous allons profiter de cette partie pour rappeler une petite astuce de configuration
qui permet d’éviter d’avoir à débrancher l’ICD2 de la carte PIC pour que le programme
démarre. Il faut donc se rendre dans les paramètres de l’ICD2 via le menu correspondant
dans MPLAB et se rendre dans l’onglet Program. Ensuite, comme le montre la figure 2, il
faut cocher la case Run after sucessful program.
4
int.c Gestion des interruptions.
taskdesc.c Description des tâches et des alarmes.
tsk taskX Fonction associée à la tâche portant le numéro X.
L’ensemble de ces fichiers, ainsi que le fichier du linker nommé 18F458.lkr devront être
ajoutés au projet créé avec MPLAB.
Attention, suite à quelques problèmes, nous avons remarqué que les initialisations rela-
tives aux interruptions doivent être effectuées de préference après le démarrage du noyau,
dans une des tâches par exemple.
F osc
BaudRate = (1)
16 ∗ (SP BRG + 1)
5
On peut maintenant tester que notre liaison série fonctionne en envoyant un caractère
avec la commande TXREG = data;. Avant d’envoyer un second caractère, il faudra s’assurer
que le premier a été transmis et bloquer l’exécution de la tâche avec la boucle while(
TXSTAbits.TRMT==0); dans le cas échéant. On aura au préalable connecté la carte PIC au
PC et lancé un terminal pour port série sur le PC.
Afin de tester la réception, nous avons placé le code du listing 2 dans la routine
InterruptVectorL du fichier int.c. Les données reçues sont placées dans un buffer circu-
laire et un évenement sera posté pour qu’elles soient traitées dans une autre tâche. Notons
au passage que le flag RCIF du registre PIR1 est remis à zéro automatiquement lors de la
lecture du caractère reçu.
F osc
4×k
CCP R1 = −1 (2)
F ech
6
10 CCP1CON=0x0B; /* Mode comparaison, flag CCPIF mis à 1 à chaque période*/
11 }
Comme le montre le listing 4, il faut maintenant configurer les conversions sur la voie
désirée. Ici, nous voulons convertir la voie 1. On remarque sur la datasheet (voir figure 3)
qu’il est impossible de configurer AN1 en analogique en conservant AN0 en numérique,
nous ne pourrons donc plus faire clignoter la LED de la première tâche puisque celle-ci est
connectée sur AN0.
Listing 4 – Configuration de l’ADC
1 void initADC(void)
2 {
3 /* Généralement on règle l’horloge de conversion de l’ADC à 2 * Tosc */
4 /* or pour un bon fonctionnment en TP on doit mettre 64 * Tosc */
5 ADCON0=0x89; /* Activer ADC, Voie 1 */
6 ADCON1=0xC0; /* Résultat justifié à droite, toutes les voies analogiques */
7 }
A noter qu’il ne faut pas oublier d’activer les interruptions liées à l’ADC, comme le
montre le listing 5 si l’on veut que cela fonctionne. Nous avons remarqué qu’il est préférable
des les activer (ou les réactiver) une fois le noyau lancé pour ne pas avoir de problèmes.
Listing 5 – Activation des interruptions liées à l’ADC
1 PIR1bits.ADIF=0; /* ADCint flag à 0 */
2 IPR1bits.ADIP=0; /* ADCint priority low */
3 PIE1bits.ADIE=1; /* Autorise ADCint */
4 PIR1bits.CCP1IF=0; /* CCP1 flag à 0 */
5 IPR1bits.CCP1IP=0; /* CCP1int priority low */
6 PIE1bits.CCP1IE=1; /* Autorise CCP1int*/
7
8 INTCONbits.GIE=1; /* Activation globale des interruptions */
Comme le montre la valeur assignée au registre CCP1CON, le module CCP1 est confi-
guré en mode comparaison. De plus, on remarque sur la figure 4 qu’il est explicitement
7
mentioné que la conversion sera lancée automatiquement si le module ADC est activé.
Or dans la pratique, nous avons remarqué que la conversion ne se lance pas. La solution
trouvée est donc de lancer une conversion manuellement (voir listing 6) dans la routine
InterruptVectorL du fichier int.c, lorsque le flag CCPIF est mis à 1. Bien sûr, cela nous
oblige à attendre la fin de la conversion en insérant une boucle while, ce n’est donc pas
optimisé. La valeur convertie sera récuperée dans une autre tâche.
8
5 ClearEvent(EVENT_FINCONV); /* Clear évenement */
6 u = (ADRESH<<8) + ADRESL; /* Récuperation valeure convertie */
7 TXREG = ’U’;
8 while(TXSTAbits.TRMT==0);
9 TXREG = u; /* Envoi 8 bits de poids faibles */
10 while(TXSTAbits.TRMT==0);
11 // TXREG = x>>8; /* Envoi 2 bits de poids fort */
12 // while(TXSTAbits.TRMT==0);
13 }
F osc
4×k
P R2 = −1 (3)
F ech
Le rapport cylcique de la PWM étant sur 10 bits (8 bits de poid fort dans ECCPR1L
et 2 bits de poids faibles dans ECCP1CONbits.EDC1B1 et ECCP1CONbits.EDC1B0), il faudrait
procéder comme le montre le listing 9 pour modifier sa valeur.
Or dans notre application, nous modifions la valeur du rapport cyclique en fonction de
la valeur retournée par l’ADC, qui elle, est sur 8 bits dans la pratique. Le plus judicieux et
donc d’assigner notre valeur ADC sur 8 bits aux 8 bits de poids fort du rapport cyclique
avec la commande ECCPR1L = u. Ainsi, le rapport cylcique peut être modifié sur toute sa
plage avec seulement une perte de précision.
9
3 ECCP1CONbits.EDC1B1 = u>>1;
4
5 ECCPR1L = u>>2; /* 8 bits poid fort du rapport cyclique de la PWM */
10
caractère ASCII à une valeur. La valeur n’excedant jamais 1 octet, la trame fera donc 2
octets au total. Le tableau 2 montre le protocole basique mis en place.
La figure 5 montre l’organigramme de la tâche de traitement des données du buffer
circulaire.
Le traitement des données est réalisé à l’aide de structures switch/case, ce qui rend le
tout assez simple et lisible comme on peut le voir sur le listing 10.
11
Fig. 5 – Organigramme de la tâche de traitement des données du buffer circulaire
12
2 Partie débarquée
2.1 Présentation de Visual C++
Visual C++ est un environnement de développement intégré, conçu par Microsoft, pour
réaliser des applications en langage C ou C++ à destination du système d’exploitation
Microsoft Windows. Il fait partie de la suite de logiciels Visual Studio. Notons au passage
qu’une version du logiciel est disponible gratuitement pour les étudiants par le programme
MSDN Academic Alliance 5 .
L’utilisation des Windows Forms va nous permettre de disposer d’une palette d’outils
fournie et de fonctions diverses permettant de construire graphiquement la fenêtre de
l’application Windows sans avoir à écrire le code C++ correspondant.
5
http://msdn.microsoft.com/fr-fr/academic/default.aspx
6
Dans le constructeur par exemple
13
2.2.2 Affichage dans un graphique
Au début du projet, nous affichions simplement les données du buffer dans un indicateur
de texte. Nous avons donc mis en place une solution plus conviviale pour visualiser les
données : l’affichage dans un graphique. Nous avons choisi d’afficher les données à la
manière d’un oscilloscope, c’est-à-dire avec un balayage de notre fenêtre.
Pour se faire, nous avons utilisé un contrôle PictureBox destiné à afficher une image.
Cette fonction est appelée automatiquement par Windows lorsque l’évènement de tracé
du contenu de l’élément est activé (lors de l’activation en premier plan de l’application
par exemple). Comme cela a été fait dans le listing 11, on peut forcer le déclenchement de
l’événement par l’instruction pictureBox1->Invalidate().
Dans le listing 12, on considère le tableau TraceSerie à l’échelle de la fenêtre PictureBox
qui sera completé à l’aide d’une boucle for. Notons ici que le graphique est prévu pour
recevoir des données allant de 0 à 255 puisque nous avons vu précédemment qu’elles étaient
codées sur 8 bits.
Listing 12 – Affichage des données dans un graphique
1 private: System::Void pictureBox1_Paint(System::Object^ sender, System::Windows::
Forms::PaintEventArgs^ e) {
2 Graphics^ g = e->Graphics; /* pointeur sur fen^etre graphique */
3 Pen^ pen; /* variable définissant le style de tracé */
4 double y0,dy;
5 if(pictureBox1->Width <5) return; /* détecte si fen^etre est trop
petite pour ^etre affichée */
6 if(pictureBox1->Height <5) return;
7 TraceSerie = gcnew array< PointF >(nb_ech); /* PointF : paire de
coordonnées x et y */
8 dy = 255; /* ymax-ymin */
9 y0 = 0; /* ymin */
10 for(UInt32 i=0;i<nb_ech;i++)
11 {
12 /* abscisse */
13 TraceSerie[i].X = pictureBox1->Width*(double)i/(double)nb_ech;
14 /* ordonnée */
15 TraceSerie[i].Y = (pictureBox1->Height-5)-(pictureBox1->Height
-5)*(TabSerie[i]-y0)/dy;
16 }
17 pen = gcnew Pen(Color::Blue,1.0f); /* choix style de tracé */
18 g->DrawLines(pen,TraceSerie); /* trace courbe */
19 }
14
tableau buf_serie puis sera envoyée par l’instruction serialPort1->Write(buf_serie,0,2)
. Il ne faudra toutefois pas oublier de préciser la longueur de notre trame en octet, soit 2
ici.
Listing 13 – Envoi de la commande marche/arrêt
1 private: System::Void marche_CheckedChanged(System::Object^ sender, System::
EventArgs^ e) {
2 array<Byte>^ buf_serie = gcnew array<Byte>(2);
3 if (marche->Checked)
4 {
5 /* Marche */
6 buf_serie[0]=’o’;
7 buf_serie[1]=’1’;
8 }
9 else
10 {
11 /* Arret */
12 buf_serie[0]=’o’;
13 buf_serie[1]=’0’;
14 }
15 serialPort1->Write(buf_serie,0,2);
16 }
15
Fig. 6 – Capture d’écran de l’application en mode analogique
Une fois le bon mode selectionné, plusieurs possibilitées s’offrent à l’utilisateur (voir
figure 7). Il peut d’abord utiliser la glissière à disposition, ou alors incrémenter la consigne
via le bouton poussoir, ou encore sélectionner une valeur numérique dans la boı̂te de texte.
Notons que toutes les valeurs sont liées et mises à jour à chaque changement sur l’une des
commandes. Enfin, l’utilisateur doit valider son choix afin que celui-ci soit envoyé sur la
16
liaison série (voir listing 17).
17
Listing 17 – Envoi de la consigne de rapport cyclique par la liaison série
1 private: System::Void valid_num_Click(System::Object^ sender, System::EventArgs^
e) {
2 array<Byte>^ buf_serie = gcnew array<Byte>(2);
3 if (cons_num->Checked)
4 {
5 buf_serie[0]=’r’;
6 buf_serie[1]=val_num->Value;
7 serialPort1->Write(buf_serie,0,2);
8 }
9 }
Conclusion
Ce projet nous a permis d’approfondir et de « toucher du doigt » les différentes no-
tions, relatives aux systèmes temps réel et au noyau PICOS18, étudiées en cours et en TD.
Il nous a permis d’acquérir une grande experience dans le domaine des systèmes embar-
qués et plus particulièrement dans la programmation de microcontroleurs. Ce point est
important pour nous, puisque le sujet de nos projets de fin d’étude implique l’utilisation
de microcontrôleurs.
Le but premier de ce projet étant de comprendre et des maı̂triser les problématiques
liées au temps réel en utilisant un outil approprié, l’application finale est assez libre et
donc moins importante que ce que nous avons appris durant le semestre.
L’utilisation de PICOS18 ne nous a pas posé beaucoup de problèmes, en effet, le noyau
est assez documenté et bien conçu. Cependant, nous avons rencontré de nombreux pro-
blèmes lors de la programmation. Nous pensons, en accord avec notre professeur, que la
documentation technique du microcontrôleur comporte des anomalies.
Nous avons également eu la possibilité de découvrir Visual C++, l’environnement de
développement intégré de Microsoft qui est largement utilisé dans les entreprises, et dont
l’utilisation nous a beaucoup rappelé la programmation avec Visual Basic.
18