MATLAB Language
Utiliser des ports série
Recherche…
Introduction
Les ports série sont une interface commune pour communiquer avec des capteurs externes ou des systèmes intégrés tels que Arduinos. Les communications série modernes sont souvent implémentées sur des connexions USB utilisant des adaptateurs USB-série. MATLAB fournit des fonctions intégrées pour les communications série, y compris les protocoles RS-232 et RS-485. Ces fonctions peuvent être utilisées pour les ports série matériels ou les connexions série USB "virtuelles". Les exemples illustrent les communications série dans MATLAB.
Paramètres
Paramètre de port série | ce qu'il fait |
---|---|
BaudRate | Définit le débit en bauds. Le plus commun aujourd'hui est 57600, mais 4800, 9600 et 115200 sont également fréquemment vus |
InputBufferSize | Le nombre d'octets conservés en mémoire. Matlab a une FIFO, ce qui signifie que les nouveaux octets seront supprimés. La valeur par défaut est 512 octets, mais elle peut facilement être définie sur 20 Mo sans problème. Il y a seulement quelques cas extrêmes où l'utilisateur voudrait que ce soit petit |
BytesAvailable | Le nombre d'octets en attente de lecture |
ValuesSent | Le nombre d'octets envoyés depuis l'ouverture du port |
ValuesReceived | Le nombre d'octets lus depuis l'ouverture du port |
BytesAvailableFcn | Spécifiez la fonction de rappel à exécuter lorsqu'un nombre spécifié d'octets est disponible dans le tampon d'entrée ou qu'un terminateur est lu |
BytesAvailableFcnCount | Indiquez le nombre d'octets devant être disponibles dans le tampon d'entrée pour générer un événement bytes-available |
BytesAvailableFcnMode | Indiquez si l'événement d' bytes-available est généré après qu'un nombre spécifié d'octets est disponible dans le tampon d'entrée ou après la lecture d'un terminateur |
Créer un port série sur Mac / Linux / Windows
% Define serial port with a baud rate of 115200
rate = 115200;
if ispc
s = serial('COM1', 'BaudRate',rate);
elseif ismac
% Note that on OSX the serial device is uniquely enumerated. You will
% have to look at /dev/tty.* to discover the exact signature of your
% serial device
s = serial('/dev/tty.usbserial-A104VFT7', 'BaudRate',rate);
elseif isunix
s = serial('/dev/ttyusb0', 'BaudRate',rate);
end
% Set the input buffer size to 1,000,000 bytes (default: 512 bytes).
s.InputBufferSize = 1000000;
% Open serial port
fopen(s);
Lecture depuis le port série
En supposant que vous avez créé le port série objet s
comme dans cet exemple, puis
% Read one byte
data = fread(s, 1);
% Read all the bytes, version 1
data = fread(s);
% Read all the bytes, version 2
data = fread(s, s.BytesAvailable);
% Close the serial port
fclose(s);
Fermer un port série même perdu, supprimé ou écrasé
En supposant que vous avez créé le port série objet s
comme dans cet exemple, puis de le fermer
fclose(s)
Cependant, il peut arriver que vous perdiez accidentellement le port (par exemple, effacer, écraser, modifier la portée, etc.) et fclose(s)
ne fonctionnerait plus. La solution est facile
fclose(instrfindall)
Plus d'infos sur instrfindall()
.
Écriture sur le port série
En supposant que vous avez créé le port série objet s
comme dans cet exemple, puis
% Write one byte
fwrite(s, 255);
% Write one 16-bit signed integer
fwrite(s, 32767, 'int16');
% Write an array of unsigned 8-bit integers
fwrite(s,[48 49 50],'uchar');
% Close the serial port
fclose(s);
Choisir votre mode de communication
Matlab prend en charge la communication synchrone et asynchrone avec un port série. Il est important de choisir le bon mode de communication. Le choix dépendra de:
- comment se comporte l’instrument avec lequel vous communiquez.
- Quelles autres fonctions votre programme principal (ou GUI) devra-t-il faire en dehors de la gestion du port série?
Je définirai trois cas différents à illustrer, du plus simple au plus exigeant. Pour les 3 exemples, l'instrument auquel je me connecte est une carte de circuit avec un inclinomètre, qui peut fonctionner dans les 3 modes que je vais décrire ci-dessous.
Mode 1: synchrone (maître / esclave)
Ce mode est le plus simple. Cela correspond au cas où le PC est le maître et l'instrument est l' esclave . L’instrument n’envoie rien au port série seul, il ne répond qu’une réponse après avoir reçu une question / commande du maître (le PC, votre programme). Par exemple:
- Le PC envoie une commande: "Donnez-moi une mesure maintenant"
- L'appareil reçoit la commande, effectue la mesure puis renvoie la valeur de mesure sur la ligne série: "La valeur de l'inclinomètre est XXX".
OU
- Le PC envoie une commande: "Passer du mode X au mode Y"
- L'instrument reçoit la commande, l'exécute, puis envoie un message de confirmation à la ligne série: " Commande exécutée " (ou " Commande NON exécutée "). Ceci est communément appelé une réponse ACK / NACK (pour "Acknowledge (d)" / "NOT Acknowledged").
Résumé: dans ce mode, l’instrument (l’ esclave ) envoie uniquement des données à la ligne série immédiatement après avoir été invité par le PC (le maître )
Mode 2: Asynchrone
Maintenant, supposons que j'ai démarré mon instrument, mais c'est plus qu'un simple capteur muet. Il surveille constamment sa propre inclinaison et tant qu'il est vertical (dans une tolérance, disons +/- 15 degrés), il reste silencieux. Si l'appareil est incliné de plus de 15 degrés et se rapproche de l'horizontale, il envoie un message d'alarme à la ligne série, suivi immédiatement par une lecture de l'inclinaison. Tant que l'inclinaison est supérieure au seuil, il continue à envoyer une lecture d'inclinaison toutes les 5 secondes.
Si votre programme principal (ou interface graphique) attend constamment que le message arrive sur la ligne série, il peut le faire très bien ... mais il ne peut rien faire d'autre entre-temps. Si le programme principal est une interface graphique, il est extrêmement frustrant d’avoir une interface graphique apparemment "figée" car elle n’acceptera aucune entrée de la part de l’utilisateur. Essentiellement, il est devenu l' esclave et l'instrument est le maître . À moins d’avoir un moyen sophistiqué de contrôler votre interface graphique à partir de l’instrument, ceci est à éviter. Heureusement, le mode de communication asynchrone vous permettra:
- définir une fonction distincte qui indique à votre programme quoi faire lorsqu'un message est reçu
- conservez cette fonction dans un coin, elle ne sera appelée et exécutée que lorsqu'un message arrive sur la ligne série. Le reste du temps, l'interface graphique peut exécuter tout autre code à exécuter.
Résumé: Dans ce mode, l’instrument peut envoyer un message à la ligne série à tout moment (mais pas nécessairement tout le temps). Le PC n'attend pas de façon permanente pour un message à traiter. Il est autorisé à exécuter tout autre code. Seulement quand un message arrive, il active une fonction qui lira et traitera ce message.
Mode 3: Streaming ( temps réel )
Maintenant, libérons toute la puissance de mon instrument. Je le mets dans un mode où il enverra constamment des mesures à la ligne série. Mon programme souhaite recevoir ces paquets et les afficher sur une courbe ou un affichage numérique. S'il n'envoie qu'une valeur toutes les 5 secondes comme ci-dessus, pas de problème, conservez le mode ci-dessus. Mais mon instrument complet envoie un point de données à la ligne série à 1000 Hz, c'est-à-dire qu'il envoie une nouvelle valeur chaque milliseconde. Si je reste dans le mode asynchrone décrit ci-dessus, il y a un risque élevé (en fait une certitude garantie) que la fonction spéciale que nous avons définie pour traiter chaque nouveau paquet prendra plus de 1 ms (si vous voulez tracer ou afficher la valeur, les fonctions graphiques sont assez lentes, ne prenant même pas en compte le filtrage ou le FFT du signal). Cela signifie que la fonction commencera à s'exécuter, mais avant la fin, un nouveau paquet arrivera et déclenchera à nouveau la fonction. La deuxième fonction est placée dans une file d'attente pour exécution et ne démarre que lorsque le premier est terminé ... mais à ce moment-là, quelques nouveaux paquets sont arrivés et chacun a placé une fonction à exécuter dans la file d'attente. Vous pouvez rapidement prévoir le résultat: au moment où je trace les 5èmes points, il y a déjà des centaines de personnes qui attendent d'être tracées aussi ... la gui ralentit, finit par se figer, la pile grandit, les tampons se remplissent Finalement, il vous reste un programme complètement gelé ou simplement un programme écrasé.
Pour résoudre ce problème, nous déconnecterons encore davantage le lien de synchronisation entre le PC et l’instrument. Nous laisserons l'instrument envoyer des données à son propre rythme, sans déclencher immédiatement une fonction à chaque arrivée de paquet. Le tampon du port série accumulera simplement les paquets reçus. Le PC ne collecte les données dans le tampon qu'à un rythme qu'il peut gérer (un intervalle régulier, configuré du côté du PC), fait quelque chose (pendant que le tampon est rempli par l'instrument), puis collecte un nouveau lot de données. les données du tampon ... et ainsi de suite.
Résumé: Dans ce mode, l’instrument envoie des données en continu, qui sont collectées par le tampon du port série. À intervalles réguliers, le PC collecte les données du tampon et fait quelque chose avec lui. Il n'y a pas de lien de synchronisation matérielle entre le PC et l'instrument. Tous deux exécutent leurs tâches à leur propre rythme.
Traitement automatique des données reçues d'un port série
Certains appareils connectés via un port série envoient des données à votre programme à un débit constant (données en continu) ou envoient des données à des intervalles imprévisibles. Vous pouvez configurer le port série pour qu'il exécute une fonction automatiquement afin de gérer les données à chaque fois qu'il arrive. C'est ce qu'on appelle la "fonction de rappel" pour l'objet port série.
Deux propriétés du port série doivent être définies pour utiliser cette fonctionnalité: le nom de la fonction souhaitée pour le rappel ( BytesAvailableFcn
) et la condition qui doit déclencher l'exécution de la fonction de rappel ( BytesAvailableFcnMode
).
Il existe deux manières de déclencher une fonction de rappel:
- Lorsqu'un certain nombre d'octets a été reçu sur le port série (généralement utilisé pour les données binaires)
- Lorsqu'un certain caractère est reçu sur le port série (généralement utilisé pour du texte ou des données ASCII)
Les fonctions de rappel ont deux arguments d'entrée obligatoires, appelés obj
et event
. obj
est le port série. Par exemple, si vous souhaitez imprimer les données reçues du port série, définissez une fonction pour imprimer les données appelées newdata
:
function newdata(obj,event)
[d,c] = fread(obj); % get the data from the serial port
% Note: for ASCII data, use fscanf(obj) to return characters instead of binary values
fprintf(1,'Received %d bytes\n',c);
disp(d)
end
Par exemple, pour exécuter la fonction newdata
chaque fois que 64 octets de données sont reçus, configurez le port série comme newdata
:
s = serial(port_name);
s.BytesAvailableFcnMode = 'byte';
s.BytesAvailableFcnCount = 64;
s.BytesAvailableFcn = @newdata;
Avec du texte ou des données ASCII, les données sont généralement divisées en lignes avec un "caractère de terminaison", comme le texte d'une page. Pour exécuter la fonction newdata
chaque fois que le caractère de retour chariot est reçu, configurez le port série comme newdata
:
s = serial(port_name);
s.BytesAvailableFcnMode = 'terminator';
s.Terminator = 'CR'; % the carriage return, ASCII code 13
s.BytesAvailableFcn = @newdata;