[Annexe] Ordinateur et voie série dans un autre langage de programmation

Maintenant que vous savez comment utiliser la voie série avec Arduino, il peut être bon de savoir comment visualiser les données envoyées avec vos propres programmes (l’émulateur terminal Windows ou le moniteur série Arduino ne comptent pas :P ). Cette annexe a donc pour but de vous montrer comment utiliser la voie série avec quelques langages de programmation. Les langages utilisés ci-dessous ont été choisis arbitrairement en fonction de mes connaissances, car je ne connais pas tous les langages possibles et une fois vu quelques exemples, il ne devrait pas être trop dur de l’utiliser avec un autre langage. Nous allons donc travailler avec :

Afin de se concentrer sur la partie "Informatique", nous allons reprendre un programme travaillé précédemment dans le cours. Ce sera celui de l’exercice : Attention à la casse. Pensez donc à le charger dans votre carte Arduino avant de faire les tests. :P

En C++ avec Qt

Avant de commencer cette sous-partie, il est indispensable de connaître la programmation en C++ et savoir utiliser le framework Qt. Si vous ne connaissez pas tout cela, vous pouvez toujours aller vous renseigner avec un tutoriel C++ !

Le C++, OK, mais pourquoi Qt ?

J’ai choisi de vous faire travailler avec Qt pour plusieurs raisons d’ordres pratiques.

  • Qt est multiplateforme, donc les réfractaires à Linux (ou à Windows) pourront quand même travailler.
  • Dans le même ordre d’idée, nous allons utiliser une librairie tierce pour nous occuper de la voie série. Ainsi, aucun problème pour interfacer notre matériel que l’on soit sur un système ou un autre !
  • Enfin, j’aime beaucoup Qt et donc je vais vous en faire profiter :)

En fait, sachez que chaque système d’exploitation à sa manière de communiquer avec les périphériques matériels. L’utilisation d’une librairie tierce nous permet donc de faire abstraction de tout cela. Sinon il m’aurait fallu faire un tutoriel par OS, ce qui, on l’imagine facilement, serait une perte de temps (écrire trois fois environ les mêmes choses) et vraiment galère à maintenir.

Installer QextSerialPort

QextSerialPort est une librairie tierce réalisée par un membre de la communauté Qt. Pour utiliser cette librairie, il faut soit la compiler, soit utiliser les sources directement dans votre projet.

1ère étape : télécharger les sources

Le début de tout cela commence donc par récupérer les sources de la librairie. Pour cela, rendez-vous sur la page google code du projet. A partir d’ici vous avez plusieurs choix. Soit vous récupérez les sources en utilisant le gestionnaire de source mercurial (Hg). Il suffit de faire un clone du dépôt avec la commande suivante :

hg clone https:// code.google.com/p/qextserialport/

Sinon, vous pouvez récupérer les fichiers un par un (une dizaine). C’est plus contraignant mais ça marche aussi si vous n’avez jamais utilisé de gestionnaire de sources (mais c’est vraiment plus contraignant !)

Cette dernière méthode est vraiment déconseillée. En effet, vous vous retrouverez avec le strict minimum (fichiers sources sans exemples ou docs).

La manipulation est la même sous Windows ou Linux !

Compiler la librairie

Maintenant que nous avons tous nos fichiers, nous allons pouvoir compiler la librairie. Pour cela, nous allons laisser Qt travailler à notre place.

  • Démarrez QtCreator et ouvrez le fichier .pro de QextSerialPort
  • Compilez…
  • C’est fini !

Normalement vous avez un nouveau dossier à côté de celui des sources qui contient des exemples, ainsi que les librairies QExtSerialPort.

Installer la librairie : Sous Linux

Une fois que vous avez compilé votre nouvelle librairie, vous allez devoir placer les fichiers aux bons endroits pour les utiliser. Les librairies, qui sont apparues dans le dossier "build" qui vient d’être créé, vont être déplacées vers le dossier /usr/lib. Les fichiers sources qui étaient avec le fichier ".pro" pour la compilation sont à copier dans un sous-dossier "QextSerialPort" dans le répertoire de travail de votre projet courant.

A priori il y aurait un bug avec la compilation en mode release (la librairie générée ne fonctionnerait pas correctement). Je vous invite donc à compiler aussi la debug et travailler avec.

Installer la librairie : Sous Windows

Ce point est en cours de rédaction, merci de patienter avant sa mise en ligne. :)

Infos à rajouter dans le .pro

Dans votre nouveau projet Qt pour traiter avec la voie série, vous aller rajouter les lignes suivantes à votre .pro :

INCLUDEPATH += QextSerialPort

CONFIG(debug, debug|release):LIBS += -lqextserialportd
else:LIBS += -lqextserialport
Ajout au .pro

La ligne "INCLUDEPATH" représente le dossier où vous avez mis les fichiers sources de QextSerialPort. Les deux autres lignes font le lien vers les librairies copiées plus tôt (les .so ou les .dll selon votre OS).

Les trucs utiles
L’interface utilisée

Comme expliqué dans l’introduction, nous allons toujours travailler sur le même exercice et juste changer le langage étudié. Voici donc l’interface sur laquelle nous allons travailler, et quels sont les noms et les types d’objets instanciés :

interface Qt
interface Qt

Cette interface possède deux parties importantes : La gestion de la connexion (en haut) et l’échange de résultat (milieu -> émission, bas -> réception). Dans la partie supérieure, nous allons choisir le port de l’ordinateur sur lequel communiquer ainsi que la vitesse de cette communication. Ensuite, deux boîtes de texte sont présentes. L’une pour écrire du texte à émettre, et l’autre affichant le texte reçu. Voici les noms que j’utiliserai dans mon code :

Widget Nom Rôle
QComboBox comboPort Permet de choisir le port série
QComboBox comboVitesse Permet de choisir la vitesse de communication
QButton btnconnexion (Dé)Connecte la voie série (bouton "checkable")
QTextEdit boxEmission Nous écrirons ici le texte à envoyer
QTextEdit boxReception Ici apparaitra le texte à recevoir
Liste des widgets utilisé
Lister les liaisons séries

Avant de créer et d’utiliser l’objet pour gérer la voie série, nous allons en voir quelques-uns pouvant être utiles. Tout d’abord, nous allons apprendre à obtenir la liste des ports série présents sur notre machine. Pour cela, un objet a été créé spécialement, il s’agit de QextPortInfo. Voici un exemple de code leur permettant de fonctionner ensemble :

// L'objet mentionnant les infos
QextSerialEnumerator enumerateur;
// on met ces infos dans une liste
QList<QextPortInfo> ports = enumerateur.getPorts();
Récuperation de la liste des ports séries

Une fois que nous avons récupéré une énumération de tous les ports, nous allons pouvoir les ajouter au combobox qui est censé les afficher (comboPort). Pour cela on va parcourir la liste construite précédemment et ajouter à chaque fois une item dans le menu déroulant :

// on parcourt la liste des ports
for(int i=0; i<ports.size(); i++)
   ui->ComboPort->addItem(ports.at(i).physName);
Remplissage du combobox des ports séries

Les ports sont nommés différemment sous Windows et Linux, ne soyez donc pas surpris avec mes captures d’écrans, elles viennent toutes de Linux.

Une fois que la liste des ports est faite (attention, certains ports ne sont connectés à rien), on va construire la liste des vitesses, pour se laisser le choix le jour où l’on voudra faire une application à une vitesse différente. Cette opération n’est pas très compliquée puisqu’elle consiste simplement à ajouter des items dans la liste déroulante "comboVitesse".

ui->comboVitesse->addItem("300");
ui->comboVitesse->addItem("1200");
ui->comboVitesse->addItem("2400");
ui->comboVitesse->addItem("4800");
ui->comboVitesse->addItem("9600");
ui->comboVitesse->addItem("14400");
ui->comboVitesse->addItem("19200");
ui->comboVitesse->addItem("38400");
ui->comboVitesse->addItem("57600");
ui->comboVitesse->addItem("115200");
Remplissage du combobox des vitesses

Votre interface est maintenant prête. En la démarrant maintenant vous devriez être en mesure de voir s’afficher les noms des ports séries existant sur l’ordinateur ainsi que les vitesses. Un clic sur le bouton ne fera évidemment rien puisque son comportement n’est pas encore implémenté.

Gérer une connexion

Lorsque tous les détails concernant l’interface sont terminés, nous pouvons passer au cœur de l’application : la communication série. La première étape pour pouvoir faire une communication est de se connecter (tout comme vous vous connectez sur une borne WiFi avant de communiquer et d’échanger des données avec cette dernière). C’est le rôle de notre bouton de connexion. A partir du système de slot automatique, nous allons créer une fonction qui va recevoir le clic de l’utilisateur. Cette fonction instanciera un objet QextSerialPort pour créer la communication, règlera cet objet et enfin ouvrira le canal. Dans le cas où le bouton était déjà coché (puisqu’il sera "checkable" rappelons-le) nous ferons la déconnexion, puis la destruction de l’objet QextSerialPort créé auparavant. Pour commencer nous allons donc déclarer les objets et méthodes utiles dans le .h de la classe avec laquelle nous travaillons :

private:
// l'objet représentant le port
QextSerialPort * port;

// une fonction utile que j'expliquerais après
BaudRateType getBaudRateFromString(QString baudRate);

private slots:
// le slot automatique du bouton de connexion
void on_btnconnexion_clicked();

Ensuite, il nous faudra instancier le slot du bouton afin de traduire un comportement. Pour rappel, il devra :

  • Créer l’objet "port" de type QextSerialPort
  • Le régler avec les bons paramètres
  • Ouvrir la voie série

Dans le cas où la voie série est déjà ouverte (le bouton est déjà appuyé) on devra la fermer et détruire l’objet. Voici le code commenté permettant l’ouverture de la voie série (quelques précisions viennent ensuite) :

// Slot pour le click sur le bouton de connexion
void Fenetre::on_btnconnexion_clicked() {
    // deux cas de figures à gérer,
    // soit on coche (connecte), soit on décoche (déconnecte)

    // on coche -> connexion
    if(ui->btnconnexion->isChecked()) {
        // on essaie de faire la connexion avec la carte Arduino
        // on commence par créer l'objet port série
        port = new QextSerialPort();
        // on règle le port utilisé (sélectionné dans la liste déroulante)
        port->setPortName(ui->ComboPort->currentText());
        // on règle la vitesse utilisée
        port->setBaudRate(
            getBaudRateFromString(ui->comboVitesse->currentText()));
        // quelques règlages pour que tout marche bien
        port->setParity(PAR_NONE);// parité
        port->setStopBits(STOP_1);// nombre de bits de stop
        port->setDataBits(DATA_8);// nombre de bits de données
        port->setFlowControl(FLOW_OFF);// pas de contrôle de flux
        // on démarre !
        port->open(QextSerialPort::ReadWrite);
        // change le message du bouton
        ui->btnconnexion->setText("Deconnecter");

        // on fait la connexion pour pouvoir obtenir les évènements
        connect(port,SIGNAL(readyRead()), this, SLOT(readData()));
        connect(ui->boxEmission,SIGNAL(textChanged()),this,SLOT(sendData()));
    }
    else {
        // on se déconnecte de la carte Arduino
        port->close();
        // puis on détruit l'objet port série devenu inutile
        delete port;
        ui->btnconnexion->setText("Connecter");
    }
}
Gestion du bouton de connexion

Ce code n’est pas très compliqué à comprendre. Cependant quelques points méritent votre attention. Pour commencer, pour régler la vitesse du port série on fait appel à la fonction "setBaudRate". Cette fonction prend un paramètre de type BaudRateType qui fait partie d’une énumération de QextSerialPort. Afin de faire le lien entre le comboBox qui possède des chaines et le type particulier attendu, on crée et utilise la fonction "getBaudRateFromString". A partir d’un simple BaudRateType.

BaudRateType Fenetre::getBaudRateFromString(QString baudRate) {
    int vitesse = baudRate.toInt();
    switch(vitesse) {
        case(300):return BAUD300;
        case(1200):return BAUD1200;
        case(2400):return BAUD2400;
        case(4800):return BAUD4800;
        case(9600):return BAUD9600;
        case(14400):return BAUD14400;
        case(19200):return BAUD19200;
        case(38400):return BAUD38400;
        case(57600):return BAUD57600;
        case(115200):return BAUD115200;
        default:return BAUD9600;
    }
}
Gestion du changement de vitesse

Un autre point important à regarder est l’utilisation de la fonction open() de l’objet QextSerialPort. En effet, il existe plusieurs façons d’ouvrir un port série :

  • En lecture seule \to QextSerialPort::ReadOnly
  • En écriture seule \to QextSerialPort::WriteOnly
  • En lecture/écriture \to QextSerialPort::ReadWrite

Ensuite, on connecte simplement les signaux émis par la voie série et par la boite de texte servant à l’émission (que l’on verra juste après). Enfin, lorsque l’utilisateur re-clic sur le bouton, on passe dans le NULL.

Ce code présente le principe et n’est pas parfait ! Il faudrait par exemple s’assurer que le port est bien ouvert avant d’envoyer des données (faire un test if(port->isOpen()) par exemple).

Émettre et recevoir des données

Maintenant que la connexion est établie, nous allons pouvoir envoyer et recevoir des données. Ce sera le rôle de deux slots qui ont été brièvement évoqués dans la fonction connect() du code de connexion précédent.

Émettre des données

L’émission des données se fera dans le slot "sendData". Ce slot sera appelé à chaque fois qu’il y aura une modification du contenu de la boîte de texte "boxEmission". Pour l’application concernée (l’envoi d’un seul caractère), il nous suffit de chercher le dernier caractère tapé. On récupère donc le dernier caractère du texte contenu dans la boite avant de l’envoyer sur la voie série. L’envoi de texte se fait à partir de la fonction toAscii() et on peut donc les utiliser directement. Voici le code qui illustre toutes ces explications (ne pas oublier de mettre les déclarations des slots dans le .h) :

void Fenetre::sendData() {
    // On récupère le dernier caractère tapé
    QString caractere = ui->boxEmission->toPlainText().right(1);
    // si le port est instancié (donc ouvert a priori)
    if(port != NULL)
        port->write(caractere.toAscii());
}
Envoi de données
Recevoir des données

Le programme étudié est censé nous répondre en renvoyant le caractère émis mais dans une casse opposée (majuscule contre minuscule et vice versa). En temps normal, deux politiques différentes s’appliquent pour savoir si des données sont arrivées. La première est d’aller voir de manière régulière (ou pas) si des caractères sont présents dans le tampon de réception de la voie série. Cette méthode dite de *Polling n’est pas très fréquemment utilisée. La seconde est de déclencher un évènement lorsque des données arrivent sur la voie série. C’est la forme qui est utilisée par défaut par l’objet readyRead()) est émis par l’objet et peut donc être connecté à un slot. Pour changer le mode de fonctionnement, il faut utiliser la méthode QextSerialPort::EventDriven pour la seconde (par défaut). Comme la connexion entre le signal et le slot est créée dans la fonction de connexion, il ne nous reste qu’à écrire le comportement du slot de réception lorsqu’une donnée arrive. Le travail est simple et se résume en deux étapes :

  • Lire le caractère reçu grâce à la fonction QextSerialPort
  • Le copier dans la boite de texte "réception"
void Fenetre::readData() {
    QByteArray array = port->readAll();
    ui->boxReception->insertPlainText(array);
}
Réception de données

Et voilà, vous êtes maintenant capable de travailler avec la voie série dans vos programmes Qt en C++. Au risque de me répéter, je suis conscient qu’il y a des lacunes en terme de "sécurité" et d’efficacité. Ce code a pour but de vous montrer les bases de la classe pour que vous puissiez continuer ensuite votre apprentissage. En effet, la programmation C++/Qt n’est pas le sujet de ce tutoriel. :ninja: Nous vous serons donc reconnaissants de ne pas nous harceler de commentaires relatifs au tuto pour nous dire "bwaaaa c’est mal codéééééé". Merci ! :)

En C# (.Net)

 Dans cette partie (comme dans les précédentes) je pars du principe que vous connaissez le langage et avez déjà dessiné des interfaces et créé des actions sur des boutons par exemple. Cette sous-partie n’est pas là pour vous apprendre le C# !

Là encore je vais reprendre la même structure que les précédentes sous-parties.

Les trucs utiles
L’interface et les imports

Voici tout de suite l’interface utilisée ! Je vous donnerai juste après le nom que j’utilise pour chacun des composants (et tant qu’à faire je vous donnerai aussi leurs types).

L'interface en C#
L’interface en C#

Comme cette interface est la même pour tout ce chapitre, nous retrouvons comme d’habitude le bandeau pour gérer la connexion ainsi que les deux boîtes de texte pour l’émission et la réception des données. Voici les types d’objets et leurs noms pour le bandeau de connexion :

 Composant Nom Rôle
System.Windows.Forms.ComboBox comboPort Permet de choisir le port série
System.Windows.Forms.ComboBox comboVitesse Permet de choisir la vitesse de communication
System.Windows.Forms.Button btnConnexion (Dé)Connecte la voie série (bouton "checkable")
System.Windows.Forms.TextBox boxEmission Nous écrirons ici le texte à envoyer
System.Windows.Forms.TextBox boxReception Ici apparaitra le texte à recevoir
Liste des widgets utilisé

Avant de commencer les choses marrantes, nous allons d’abord devoir ajouter une librairie : celle des liaisons séries. Elle se nomme simplement using System.IO.Ports;. Nous allons en profiter pour rajouter une variable membre de la classe de type SerialPort que j’appellerai "port". Cette variable représentera, vous l’avez deviné, notre port série !

SerialPort port

Maintenant que tous les outils sont prêts, nous pouvons commencer !

Lister les liaisons séries

La première étape sera de lister l’ensemble des liaisons séries sur l’ordinateur. Pour cela nous allons nous servir d’une fonction statique de la classe String. Chaque case du tableau sera une chaîne de caractère comportant le nom d’une voie série. Une fois que nous avons ce tableau, nous allons l’ajouter sur l’interface, dans la liste déroulante prévue à cet effet pour pouvoir laisser le choix à l’utilisateur au démarrage de l’application. Dans le même élan, on va peupler la liste déroulante des vitesses avec quelques-unes des vitesses les plus courantes. Voici le code de cet ensemble. Personnellement je l’ai ajouté dans la méthode InitializeComponent() qui charge les composants.

private void Form1_Load(object sender, EventArgs e)
{
    // on commence par lister les voies séries présentes
    String[] ports = SerialPort.GetPortNames(); // fonction statique
    // on ajoute les ports au combo box
    foreach (String s in ports)
        comboPort.Items.Add(s);

    // on ajoute les vitesses au combo des vitesses
    comboVitesse.Items.Add("300");
    comboVitesse.Items.Add("1200");
    comboVitesse.Items.Add("2400");
    comboVitesse.Items.Add("4800");
    comboVitesse.Items.Add("9600");
    comboVitesse.Items.Add("14400");
    comboVitesse.Items.Add("19200");
    comboVitesse.Items.Add("38400");
    comboVitesse.Items.Add("57600");
    comboVitesse.Items.Add("115200");
}
Intialisation du combobox des vitesses

Si vous lancez votre programme maintenant avec la carte Arduino connectée, vous devriez avoir le choix des vitesses mais aussi d’au moins un port série. Si ce n’est pas le cas, il faut trouver pourquoi avant de passer à la suite (Vérifiez que la carte est bien connectée par exemple).

Gérer une connexion

Une fois que la carte est reconnue et que l’on voit bien son port dans la liste déroulante, nous allons pouvoir ouvrir le port pour établir le canal de communication entre Arduino et l’ordinateur. Comme vous vous en doutez surement, la fonction que nous allons écrire est celle du clic sur le bouton. Lorsque nous cliquons sur le bouton de connexion, deux actions peuvent être effectuées selon l’état précédent. Soit nous nous connectons, soit nous nous déconnectons. Les deux cas seront gérés en regardant le texte contenu dans le bouton ("Connecter" ou "Deconnecter"). Dans le cas de la déconnexion, il suffit de fermer le port à l’aide de la méthode close(). Dans le cas de la connexion, plusieurs choses sont à faire. Dans l’ordre, nous allons commencer par instancier un nouvel objet de type BaudRate et ainsi de suite. Voici le code commenté pour faire tout cela. Il y a cependant un dernier point évoqué rapidement juste après et sur lequel nous reviendrons plus tard.

private void btnConnexion_Click(object sender, EventArgs e)
{
    // on gère la connexion/déconnexion
    if (btnConnexion.Text == "Connecter") // alors on connecte
    {
        // crée un nouvel objet voie série
        port = new SerialPort();
        // règle la voie série
        // parse en int le combo des vitesses
        port.BaudRate = int.Parse(comboVitesse.SelectedItem.ToString());
        port.DataBits = 8;
        port.StopBits = StopBits.One;
        port.Parity = Parity.None;
        // récupère le nom sélectionné
        port.PortName = comboPort.SelectedItem.ToString();

        // ajoute un gestionnaire de réception
        // pour la réception de donnée sur la voie série
        port.DataReceived +=
            new SerialDataReceivedEventHandler(DataReceivedHandler);

        port.Open(); // ouvre la voie série

        btnConnexion.Text = "Deconnecter";
    }
    else // sinon on déconnecte
    {
        port.Close(); // ferme la voie série
        btnConnexion.Text = "Connecter";
    }
}
Gestion du bouton de connexion

Le point qui peut paraître étrange est la ligne 16, avec la propriété Handler() qui devra être appelée lorsque des données arriveront. Je vais vous demander d’être patient, nous en reparlerons plus tard lorsque nous verrons la réception de données. A ce stade du développement, lorsque vous lancez votre application vous devriez pouvoir sélectionner une voie série, une vitesse, et cliquer sur "Connecter" et "Déconnecter" sans aucun bug.

Émettre et recevoir des données

La voie série est prête à être utilisée ! La connexion est bonne, il ne nous reste plus qu’à envoyer les données et espérer avoir quelque chose en retour. ;)

Envoyer des données

Pour envoyer des données, une fonction toute prête existe pour les objets char qui serait envoyé un par un. Dans notre cas d’utilisation, c’est ce deuxième cas qui nous intéresse. Nous allons donc implémenter la méthode TextChanged du composant "boxEmission" afin de détecter chaque caractère entré par l’utilisateur. Ainsi, nous enverrons chaque nouveau caractère sur la voie série, un par un. Le code suivant, commenté, vous montre la voie à suivre.

// lors d'un envoi de caractère
private void boxEmission_TextChanged(object sender, EventArgs e)
{
    // met le dernier caractère dans un tableau avec une seule case le contenant
    char[] car = new char[] {boxEmission.Text[boxEmission.TextLength-1]};
    // on s'assure que le port est existant et ouvert
    if(port!=null && port.IsOpen)
    {
        // envoie le tableau de caractère,
        // depuis la position 0, et envoie 1 seul élément
        port.Write(car,0,1);
    }
}
Envoi de données
Recevoir des données

La dernière étape pour pouvoir gérer de manière complète notre voie série est de pouvoir afficher les caractères reçus. Cette étape est un petit peu plus compliquée. Tout d’abord, revenons à l’explication commencée un peu plus tôt. Lorsque nous démarrons la connexion et créons l’objet boxReception. Dans l’idéal nous aimerions faire de la façon suivante :

// gestionnaire de la réception de caractère
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
    String texte = port.ReadExisting();
    boxReception.Text += texte;
}
Réception de données

Cependant, les choses ne sont pas aussi simples cette fois-ci. En effet, pour des raisons de sécurité sur les processus, C# interdit que le texte d’un composant (boxReception) soit modifié de manière asynchrone, quand les données arrivent. Pour contourner cela, nous devons créer une méthode "déléguée" à qui on passera notre texte à afficher et qui se chargera d’afficher le texte quand l’interface sera prête. Pour créer cette déléguée, nous allons commencer par rajouter une méthode dite de callback pour gérer la mise à jour du texte. La ligne suivante est donc à ajouter dans la classe, comme membre :

// une déléguée pour pouvoir mettre à jour le texte de la boite de réception
// de manière "thread-safe"
delegate void SetTextCallback(string text);

Le code de la réception devient alors le suivant :

// gestionnaire de la réception de caractère
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
    String texte = port.ReadExisting();
    // boxReception.Text += texte;
    SetText(texte);
}

private void SetText(string text)
{
    if (boxReception.InvokeRequired)
    {
        SetTextCallback d = new SetTextCallback(SetText);
        boxReception.Invoke(d, new object[] { text });
    }
    else
    {
        boxReception.Text += text;
    }
}
Réception de données avec la déléguée

Je suis désolé si mes informations sont confuses. Je ne suis malheureusement pas un maitre dans l’art des threads UI de C#. Cependant, un tas de documentation mieux expliqué existe sur internet si vous voulez plus de détails.

Une fois tout cela instancié, vous devriez avoir un terminal voie série tout beau fait par vous même ! Libre à vous maintenant toutes les cartes en main pour créer des applications qui communiqueront avec votre Arduino et feront des échanges d’informations avec.

En Python

Comme ce langage à l’air d’être en vogue, je me suis un peu penché dessus pour vous fournir une approche de comment utiliser python pour se servir de la voie série. Mon niveau en python étant équivalent à "grand débutant", je vais vous proposer un code simple reprenant les fonctions utiles à savoir le tout sans interface graphique. Nul doute que les pythonistes chevronnés sauront creuser plus loin :)

 Comme pour les exemples dans les autres langages, on utilisera l’exercice "Attention à la casse" dans l’Arduino pour tester notre programme.

Pour communiquer avec la voie série, nous allons utiliser une librairie externe qui s’appelle pySerial.

Installation
Ubuntu

Pour installer pySerial sur votre une machine Ubuntu c’est très simple, il suffit de lancer une seule commande :

sudo apt-get install python3-serial

Vous pouvez aussi l’installer à partir des sources à l’adresse suivante : https:// pypi.python.org/pypi/pyserial . Ensuite, décompresser l’archive et exécuter la commande : (pour python 2)

python setup.py install

(pour python 3)

python3 setup.py install
Windows

Si vous utilisez Windows, il vous faudra un logiciel capable de décompresser les archives de types tar.gz (comme 7-zip par exemple). Ensuite vous devrez récupérer les sources à la même adresse que pour Linux : https:// pypi.python.org/pypi/pyserial . Enfin, comme pour Linux encore il vous suffira d’exécuter la commande qui va bien :

python setup.py install
Utiliser la librairie

Pour utiliser la librairie, il vous faudra tout d’abord l’importer. Pour cela, on utilise la commande import :

import serial

mais comme seule une partie du module nous intéresse vraiment (Serial) on peut restreindre :

from serial import Serial

(notez l’importance des majuscules/minuscules)

Ouvrir un port série

Maintenant que le module est bien chargé, nous allons pouvoir commencer à l’utiliser. La première chose importante à faire est de connaître le port série à utiliser. On peut obtenir une liste de ces derniers grâce à la commande :

python -m serial.tools.list_ports

Si comme chez moi cela ne fonctionne pas, vous pouvez utiliser d’autres méthodes.

  • Sous Windows : en allant dans le gestionnaire de périphériques pour trouver le port série concerné (COMx)
  • Sous Linux : en utilisant la commande ls /dev, vous pourrez trouver le nom du port série sous le nom "ttyACMx" par exemple
Le port USB de l'Arduino
Le port USB de l’Arduino

Lorsque le port USB est identifié, on peut créer un objet de type Serial. Le constructeur que l’on va utiliser prend deux paramètres, le nom du port série et la vitesse à utiliser (les autres paramètres (parité…) conviennent par défaut).

port = Serial('/dev/ttyACM0', 9600)

Une fois cet objet créé, la connexion peut-être ouverte avec la fonction open()

port.open()

Pour vérifier que la voie série est bien ouverte, on utilisera la méthode "isOpen()" qui retourne un booléen vrai si la connexion est établie.

Envoyer des données

Maintenant que la voie série est ouverte, nous allons pouvoir lui envoyer des données à traiter. Pour le bien de l’exercice, il nous faut récupérer un (des) caractère(s) à envoyer et retourner avec la casse inversée. Nous allons donc commencer par récupérer une chaîne de caractère de l’utilisateur :

chaine = input("Que voulez vous transformer ? ")

Puis nous allons simplement l’envoyer avec la fonction "write". Cette fonction prend en paramètre un tableau de bytes. Nous allons donc transformer notre chaîne pour convenir à ce format avec la fonction python "bytes()" qui prend en paramètres la chaine de caractères et le format d’encodage.

bytes(chaine, 'UTF-8')

Ce tableau peut directement être envoyé dans la fonction write() :

port.write(bytes(chaine, 'UTF-8'))
Recevoir des données

La suite logique des choses voudrait que l’on réussisse à recevoir des données. C’est ce que nous allons voir maintenant. ;) Nous allons tout d’abord vérifier que des données sont arrivées sur la voie série via la méthode inWaiting(). Cette dernière nous renvoie le nombre de caractères dans le buffer de réception de la voie série. S’il est différent de 0, cela signifie qu’il y a des données à lire. S’il y a des caractères, nous allons utiliser la fonction "read()" pour les récupérer. Cette fonction retourne les caractères (byte) un par un dans l’ordre où il sont arrivés. Un exemple de récupération de caractère pourrait-être :

while(port.inWaiting() != 0):
    car = port.read() #on lit un caractère
    print(car) #on l'affiche
Lecture des données en python

Vous en savez maintenant presque autant que moi sur la voie série en python :P ! Je suis conscient que c’est assez maigre comparé aux autres langages, mais je ne vais pas non plus apprendre tout les langages du monde :D

Code exemple complet et commenté
#!/usr/bin/python3
# -*-coding:Utf-8 -*

from serial import Serial
import time

port = Serial('/dev/ttyACM0', 9600)

port.open()

# test que le port est ouvert
if (port.isOpen()):
    # demande de la chaîne à envoyer
    chaine = input("Que voulez vous transformer ? ")
    # on écrit la chaîne en question
    port.write(bytes(chaine, 'UTF-8'))
    # attend que des données soit revenues
    while(port.inWaiting() == 0):
        # on attend 0.5 seconde pour que les données arrive
        time.sleep(0.5)

    # si on arrive là, des données sont arrivées
    while(port.inWaiting() != 0):
        # il y a des données !
        car = port.read() #on lit un caractère
        print(car) #on l'affiche
else:
    print ("Le port n'a pas pu être ouvert !")
Code complet d’utilisation de la liaison série en python

Cette annexe vous aura permis de comprendre un peu comment utiliser la voie série en général avec un ordinateur. Avec vos connaissances vous êtes dorénavant capable de créer des interfaces graphiques pour communiquer avec votre arduino. De grandes possibilités s’offrent à vous, et de plus grandes vous attendent avec les parties qui suivent…