Protocole PIC <=> MATLAB <=> LABVIEW
Transmission de données
Communication entre un microcontrôleur PIC et un PC exécutant Labview ou Matlab.
I) Objectif
Concevoir un outil permettant de suivre graphiquement l'évolution de différentes variables d'un programme tournant dans le microcontrôleur. Ces variables peuvent être des valeurs capturées par les Convertisseur Analogique Numérique (CAN) ou d'autres périphériques interne ou externe au microcontrôleur. Ces valeurs pourront être traitées ou analysées dans un algorithme de traitement (Matlab ou Labview) dont on pourra visualiser graphiquement les résultats en temps réel. Cela permet de prototyper des algorithmes rapidement avant de les développer pour le microcontrôleur. On s'affranchit ainsi lors des difficultés inhérentes à la programmation sur microcontrôleur : précision des calculs, place mémoire, optimisation.
II) Fonctionnement général
La transmission d'une série d'octets par le port, série est facilement réalisable entre le microcontrôleur et le PC. Cependant, la réception d'une série d'octets ne permet pas de suivre l'évolution de différentes variables du programme du microcontrôleur. Une couche de protocole supplémentaire est nécessaire. Celle-ci va définir, pour chaque donnée envoyée, un canal et le type de donnée transmise (octet ou mot). Il est alors possible de monitorer différentes variables du microcontrôleur en traçant leurs évolutions respectives au cours du temps.
La configuration de la transmission série doit être identique dans le pic et au niveau de l'ordinateur réceptionnant les données sous Matlab ou Labview. J'utilise la transmission série à des vitesses variant de 9600 bauds à 115 200 bauds, sans bit de stop, avec un bit de start et sans contrôle de flux. Toute autre configuration est possible.
Le protocole réalisé permet d'attribuer à chaque variable émise l'un des 16 canaux ainsi que l'un des 4 types de données.
Trois programmes ont été réalisés :
- les fonctions écrites en C pour le microcontrôleur.
- Un programme décodant la trame ainsi qu'une interface utilisateur permettant d'effectuer du traitement sur les données reçues en temps réel sous matlab. On dispose de toute la puissance de calcul de matlab ainsi que de ses capacités graphiques. Il est aussi possible de traiter les données dans un schéma Simulink.
- Un programme décodant la trame sous labview. Les données peuvent ainsi être injectées dans un VI (Virtual Instrument).
Les deux modules réalisés pour Labview et pour Matlab sont indépendants. Chacun permet d'analyser les données reçues. Les différences sont les suivantes :
Matlab | Labview | |
---|---|---|
Temps réel | n'est pas conçu pour cela |
++ |
Graphiques | plus souple |
meilleur pour l'affichage graphique simple en
temps réel |
Calculs | calcul vectoriel, algorithme .m |
nécessite de réaliser un schéma |
Enregistrement de données | très rapide à réaliser : >>save
nomVariable |
L'aspect temps réel de Labview permet
de logger des données pour des laps définis |
Interface dédiée pour une application du microcontrôleur | difficile |
Possibilité de réaliser des faces avant
controlants |
Un module a été développé sous
labview permettant d'écrire des paramètres dans le microcontrôleur,
notamment dans l'EEPROM permettant ainsi d'ajuster des paramètres
de calculs. Ce module n'a pas été porté sous matlab.
III) Protocole au niveau binaire
Le microcontrôleur transmet les variables en spécifiant pour chacune son type et le canal auquel elle est rattachée. L'octet contrôle précédant chaque donnée à la structure suivante :
- bits 7-4 : n° du canal (0 à 15)
- bits 3-2 : type de donnée correspondant au nombre d'octets composant la donnée (1 à 4)
- bits 1-0 : signature de l'octet contrôle = "01"
Lorsque la donnée est composée de plusieurs octets, l'octet de poids faible est émis en premier.

fig1. Exemple d'une trame de donnée
La trame de donnée présenté sur la figure 1 représente les valeurs (int16) 8CB8h et (char) AAh émises respectivement sur le canal 0 et 1. Seule deux des quatres types de données possible sont actuellement utilisé :
- type 00 : char ( 1 octet)
- type 01 : int16 (2 octets)
Ces données peuvent être interprétées comme étant signé ou non signé à la réception.
IV) Fonction d'émission de données du microcontrôleur
Les fonctions écrites pour le pic permettent de construire et d'envoyer les trames de données comme celle de la figure 1. Deux contraintes vont orienter la manière d'implanter ces fonctions. La première est la place mémoire programme et RAM disponible dans le microcontrôleur. Celle-ci étant limité, il faut en utiliser un minimum afin de laisser de la place au programme principal. La seconde contrainte est l'aspect temps réel. L'émission sur le port série du PIC ne doit pas bloquer l'exécution du programme principal. Un tel blocage modifierait le comportement du programme principal lorsque celui-ci à des contraintes de temps à respecter. La fonction d'émission doit être rapide et non bloquante.
Deux fonctions et une interruption sont utilisées :
void initRS232e(unsigned char ValSPBRG) : permet de configurer le périphérique série du PIC. Cette fonction appelée une unique fois pendant la phase d'initialisation du microcontrôleur peut nécessiter une adaptation préalable pour être utilisé sur différents PIC. La valeur ValSPBRG configure la vitesse de l'interface série.
bit send232Buff(int valeur, unsigned char cannal) : construit la trame à envoyer et la mémorise dans un buffer circulaire. Lorsque le buffer circulaire ne dispose de pas assez de place pour y placer la nouvelle donnée, la fonction retourne '0' et la variable n'est pas émise. Si l'on veut s'assurer que la variable sera bien émise, il faut utiliser la fonction ainsi :
while(send232Buff( valeur , cannal ));
//--Variables à ajouter en global : unsigned char RS232Tab[16]; unsigned char RS232PtrHaut = 0; unsigned char RS232PtrBas = 0; bit send232Buff(int valeur, unsigned char cannal) { unsigned char Tmp; unsigned char Tmp2; Tmp = ~(RS232PtrHaut - RS232PtrBas); // Tmp = 7 - (Haut - Bas) modulo 16 Tmp = Tmp & 0b00001111; Tmp2 = (cannal & 0b00000011)+2; // Nbr bits à envoye if (Tmp >= Tmp2) { // Si on a la place ds le buffer d'envoye RS232Tab[RS232PtrHaut] = ((cannal << 2) & 0b11111100) | 1; // envoie 6 derniers bits du canal et bit 1=0 ; bit 0=1 // signature octet controle en poids faible RS232PtrHaut = (RS232PtrHaut + 1) & 0b00001111; for(Tmp=1; Tmp < Tmp2 ; Tmp++) { RS232Tab[RS232PtrHaut] = valeur & 0b11111111; valeur = valeur >> 8; RS232PtrHaut = (RS232PtrHaut + 1) & 0b00001111; } Tmp = 0; // bufferisation réussit TXIE = 1; // enable interrupt } else Tmp = 1; return Tmp; }
void interrupt IntVector(void) { if (TXIE && TXIF) : L'interruption Tx qui est appelée à chaque fin d'émission d'octet par la périphérique série du PIC envoie les octets du buffer circulaire un à un jusqu'à ce qu'il soit vide.
#pragma interrupt_level 0 void interrupt IntVector(void) { if (TXIE && TXIF) { if ( RS232PtrHaut != RS232PtrBas ) { TXREG = RS232Tab[RS232PtrBas]; RS232PtrBas = (RS232PtrBas + 1) & 0b00001111; if (RS232PtrHaut == RS232PtrBas) TXIE = 0; // enleve interrupt } else TXIE = 0; // enleve interrupt } }
L'utilisation d'une interruption permet de ne pas monopoliser le microcontrôleur pendant l'émission des octets. L'exécution de son programme peut ainsi continuer pendant que le buffer est transmis. La routine d'interruption est très simple donc très rapide perturbant très peu les interruptions du programme principal. L'interruption peut être placée en "low priority" sur les pic 18f.
V) Réception sous Matlab
Matrice Rn
-
2 channel
- 10 premières variables reçu
Matlab acquiert pendant un laps de temps défini par l'utilisateur inférieur à la seconde la trame de données en provenance du microcontrôleur. Le décodage optimal de la trame est ensuite réalisé et génère une matrice. Chaque variable reçue est indexée chronologiquement. Chaque colonne de la matrice créée correspond à son n° de canal, et chaque ligne correspond à l'indexe de la variable reçue. Chaque ligne de la matrice contient l'unique variable ayant l'indexe de son le n° de la ligne. Lorsque la matrice à plusieurs colonnes ( plusieurs canaux), elle est complétée par des "Not a Number" : 'NaN'.
Sur l'interface utilisateur présenté sur la figure 2, le transfert série se fait à 57600 bauds sur le COM 5. Les 5000 dernières lignes de la matrice sont enregistrés dans la variable R, et la variable Rn contient les dernières 1000 lignes. La réception d'une trame et son analyse s'effectuent toutes les 0,1 secondes. Enfin, à droites de l'interface se trouvent les indications de la transmission en cours. On voit ainsi que la dernière trame de données reçues contenait 135, soit un débit réel de 11956Kb/s ce qui signifie que le microcontrôleur n'émet pas les variables de manière continue. Ces 135 octets une fois décodés génèrent une matrice de 45 lignes, soit 45 variables, qui est concaténée à Rn et à R. La variable R contient actuellement 3119 lignes et 2 colonnes qui correspondent aux deux cannaux.
fig 2. Interface de réception Matlab
- "Connexion" et "Reset" permettent d'activer ou de désactiver le port série
- "Start" et "Stop" démarrent et arrêtent la réception et l'analyse des données
- "Save as" enregistre la variable R dans le fichier Data1.mat
- "ResetBuffer" efface le contenu de la variable R
- "Plot Buffer" effectue la commande plot(R)
- "Default", "diff Signe" , "Simulink" et "Emission" écrivent les programmes basiques dans l'espace éditable permettant respectivement de tracer des données non signées, tracer des données signées, d'envoyer les données en entrée d'un schéma simulink et d'envoyer des données brutes via le port série vers le microcontrôleur.
2 axes de l'accéléromètre ADXL 213
recueillis avec Matlab
unité y arbitraire et x en seconde.
Les ports COM disparaissant peu à peu des PC et notamment des portables, on peut utiliser des adaptateurs série=>USB avec leur driver de port série virtuel. Un tel adaptateur a été ici utilisé : le port COM 5 est un port COM virtuel.
Les commandes matlab traitant la matrice R ou Rn sont écrites dans le carré blanc central. Il est aussi possible d'appeler des fichiers de commandes .m permettant de sauver les algorithmes et de bénéficier de la coloration syntaxique de l'environnement matlab. L'extension "statistical toolbox" peut être utile ici pour effectuer des calculs sur les matrices contenant des 'NaN'. Une fonction a été écrite afin de construire une nouvelle matrice ne comprenant plus de 'Nan''.
La flexibilité et la puissance de Matlab sont très appréciables dans beaucoup d'applications. Cependant, la visualisation de données en temps réel est saccadée comme le montre l'animation ci-dessus. La réalisation d'interfaces pour paramétrer un algorithme du microcontrôleur est très compliquée du fait de la difficulté à réaliser des interfaces graphiques avec matlab. C'est pourquoi un algorithme équivalent a été réalisé sous Labview.
VI) Réception sous Labview
Le schéma de réception réalisé sous laview est utilisé comme un sous bloc inclus dans un autre VI. À chaque appel de ce bloc, celui-ci lit puis décode la trame de données arrivées depuis le précédent appel du VI.
PIC_Labview.vi
Le VI prend comme entrée
- Les paramètres de la connexion série : 'VISA ressource name'
- Le nombre d'octets minimum devant être
dans le buffet de réception du port série avant de commencer le décodage
de la trame reçu : 'buffer size'.
En plaçant ici 0, le VI devient non bloquant même lorsque le microcontrôleur n'émet aucune donnée.
Les sortis sont :
- Une copie du "visa ressource name" : "dup VISA ressource name"
- Les données des quatre premiers canaux ("Channel 0-3") avec les temps estimés d'arrivé de chaque donnée (" T 0-3")
- Les données des 16 canaux (Channel 0-15) avec les temps estimés ("T 0-15") sont définies comme variables globales dans le VI.
demo_PIC_Labview.vi
Le schéma ci-contre affiche les données reçues sur les canaux 2 et 3. Il est constitué d'une boucle "while" contenant le bloc "PIC_Labview.vi". Celui-ci lit une trame constituée d'au minimum 24 octets, décode et renvoie les données décodées. Celles-ci sont ensuite converties du format unsigned 16 en signed 16 et sont affichées. La connexion série est ouverte avant l'entrée dans la boucle. À l'arrêt de la boucle, la connexion série est refermée, libérant cette ressource pour l'ordinateur. L'animation ci-dessous montre la face avant du VI. L'animation est ici saccadée, mais le tracé défile sous Labview de manière fluide.
demo_PIC_Labview : face avant
2 axes de l'accéléromètre ADXL 213 cablés sur un PIC 18f1320
unité y arbitraire et x : n° du sample
Les fonctions décrites pour le PIC, sous Matlab et sous Labview permettent au microcontrôleur de transmettre des données vers un ordinateur. Pour pouvoir modifier ou optimiser des paramètres de l'algorithme tournant dans le microcontrôleur, il faut pouvoir lui transmettre les modifications à effectuer.
VII) Changement en Temps réel de paramètres stockés dans le microcontrôleur
Des fonctions de lectures-écriture de paramètres permettent de modifier avec Labview des paramètres de l'algorithme s'exécutant dans le microcontrôleur pendant le fonctionnement de celui-ci. Certains paramètres sont enregistrés dans l'EEPROM du microcontrôleur permettant ainsi d'être persistant même après une réinitialisation. D'autres paramètres peuvent être stockés dans la RAM. La lecture ou écriture de paramètres satisfait les contraintes suivantes :
- compatibilité avec le protocole microcontrôleur --> PC
- robustesse du protocole : le microcontrôleur ne doit pas interpréter du "bruit" comme des paramètres à écrire
- limiter le nombre d'écritures dans l'EEPROM qui ne supporte qu'un nombre fini de cycles d'écriture.
- temps réel : l'émission de données doit modifier au minimum l'exécution du programme principal
- taille mémoire limité du microcontrôleur
Trois types de séquences d'octets permettent au PC de lire et écrire des paramètres dans le microcontrôleur. Ces séquences ne sont pas symétriques dans le sens où deux séquences sont destinées à être envoyées uniquement par le PC alors que la troisième est destinée à être envoyée par le microcontrôleur. Le PC est le maître de ces opérations.
Les deux séquences émises par le PC sont :
commande écriture
- Demande d'écriture : Cette séquence envoie l'adresse comprise entre 0 et 255 de destination, la donnée qui est composée de deux octets et un octet de checksum calculé à partir de l'adresse et de la donnée. Deux octets de signature de cette commande, 55h AAh sont placés devant les trois autres octets.
- Demande de lecture : envoie l'adresse à lire comprise entre 0 et 255 avec les deux octets de signature 66h 66h.

commande lecture
Le checksum et la signature d'une commande d'écriture permettent de limiter les erreurs d'interprétation de commande d'écriture.
La séquence émise par le microcontrôleur est :
- Donnée lue : en réponse à une demande de lecture. La séquence est constituée par l'octet de signature 66h suivi de l'adresse de la donnée lue comprise entre 0 et 255 et les deux octets constituant la donnée.

lecture
lecture
sur le canal 0
Cette dernière séquence est constituée de 2 X 2 octets qui peuvent être vue comme deux int16. Il est possible de transmettre ces deux int16 par l'un des canaux du protocole définit précédemment (on utilisera par défaut le canal 0). Ce protocole sert de couche infèrieur à la transmission. Ainsi, le microcontrôleur dispose d'un canal dédié à la gestion de paramètres avec Labview et de quinze autres canaux pour visualiser l'impacte de modification de paramètres sur les algorithmes de filtrages où autre implantés dans le pic.
Le microcontrôleur peut interpréter des adresses de paramètres comme correspondant à des emplacements dans l'EEPROM ou dans la RAM.
Deux raisons nous poussent à réduire le nombre de transmissions de paramètres du PC vers le pic. D'une part, l'EEPROM d'un microcontrôleur ne peut n'effectuer qu'un nombre limité de cycles d'écriture. De plus, moins on envoie de données vers le microcontrôleur, moins on perturbe l'exécution de son programme. Pour minimiser le nombre d'écritures, on crée deux tableaux de 256 int16, chacun représentant l'ensemble des paramètres. Le premier tableau correspond aux paramètres définis graphiquement par l'utilisateur via la face avant du VI. L'autre tableau est une copie des paramètres contenus dans le microcontrôleur. À l'initialisation, les 256 paramètres du microcontrôleur sont lus avec la commande de lecture et enregistrés dans ce second tableau. Le VI analyse alors les différences entre les deux tableaux. Pour chaque paramètre qui diffère, le VI envoie au microcontrôleur une commande d'écriture suivie d'une commande de lecture qui permettra de mettre à jour le second tableau.
La réception se fait dans le microcontrôleur à l'aide de l'interruption RX placé en "low priority" sur les PIC 18f. L'interruption qui est déclenché lors de la réception d'un octet se contente de l'enregistrer dans un buffer circulaire de 8 octets définit en variable global. Ce buffer est analysé et vidé au fur et à mesure par une tache de fond. Ainsi, le déroulement du programme principal est très peu perturbé. En revanche, le PC doit émettre les données doucement pour laisser le temps à la tache de fond de les traiter. La vitesse d'arrivé des octets par le port série est cependant faible devant les 10MIPS affichées par un PIC cadence à 40Mhz.
La routine d'analyse du buffer détecte aussi l'arrivée consécutive de 10 valeurs 10h. Ceci permet à l'excellent bootloader tinybld de réinitialiser le microcontrôleur et de le reprogrammer sans avoir à toucher au montage électronique.
VIII) Exemples d'utilisation et ressources
Le protocole PIC ==> Labview est utilisé par les projets décrits aux pages suivantes :
- Autopilote d'aile volante (drone) en 2005
- Autopilote d'aile volante (drone) en 2003 (pdf)
- Stimulateur cochléaire
Il a servi dans de nombreux autres projets électroniques dont le mixeur 2 axes ou le pilote automatique non décrits ici. Les microcontrôleurs testés avec ce protocole sont : PIC 16f628 16f648 16f877 18f1320. Mais il est adaptable à tous les autres microcontrôleurs y compris les dsPIC 30f. À noté que le nouveaux microcontrôleur microchip (18f4550 et 18f2550) supporte directement l'USB. Il est donc possible de transmettre des données via l'USB au travers d'une émulation de port série. Ce système permet d'atteindre des débits bien supèrieur à ceux obtenus avec une vraie liaison série.
Ressources : bientôt ici