{"id":2683,"date":"2020-04-18T17:51:49","date_gmt":"2020-04-18T15:51:49","guid":{"rendered":"http:\/\/www.ardpylab.fr\/?page_id=2683"},"modified":"2020-05-10T17:00:10","modified_gmt":"2020-05-10T15:00:10","slug":"reception-et-envoi-simultanes-par-python","status":"publish","type":"page","link":"https:\/\/www.ardpylab.fr\/?page_id=2683","title":{"rendered":"R\u00e9ception et envoi simultan\u00e9ment"},"content":{"rendered":"\n<h2 style=\"text-align: center;\"><strong><em>(de donn\u00e9es par un programme Python)<\/em><\/strong><\/h2>\n<p>&nbsp;<\/p>\n\n\n\n<p>&nbsp;<\/p>\n<p>Les programmes Python de communication avec l&rsquo;Arduino \u00e9tudi\u00e9s jusqu\u2019\u00e0 pr\u00e9sent, permettaient soit de recevoir, soit d\u2019envoyer des donn\u00e9es. Mais pour qu\u2019il soit complet, le programme Python doit pouvoir g\u00e9rer les deux actions simultan\u00e9ment.<\/p>\n<p>Le probl\u00e8me se pose quand on demande \u00e0 l\u2019utilisateur de saisir au clavier une donn\u00e9e et que l\u2019Arduino continu d\u2019envoyer des informations. Le programme Python \u00e9tant bloqu\u00e9 sur la saisie de l\u2019utilisateur, les donn\u00e9es envoy\u00e9es par le microcontr\u00f4leur ne peuvent pas \u00eatre lues.<\/p>\n<p>Pour effectuer, l\u2019envoi et la r\u00e9ception des donn\u00e9es simultan\u00e9ment, il suffit de cr\u00e9er deux boucles, l\u2019une pour la gestion de la r\u00e9ception, et l\u2019autre pour la gestion de l\u2019envoi.<\/p>\n<p>C\u2019est de la programmation parall\u00e8le, c&rsquo;est-\u00e0-dire que plusieurs instructions de code s&rsquo;ex\u00e9cuteront en m\u00eame temps, ou presque en m\u00eame temps.<\/p>\n<p>Pour cela, nous allons utiliser le module <strong>\u201d<\/strong><strong>threading\u201d<\/strong> qui permet d\u2019ex\u00e9cuter un code ind\u00e9pendamment du code principal, ce code est appel\u00e9 un <strong>\u201d<\/strong><strong>thread\u201d<\/strong><\/p>\n<p>Avant de l\u2019utiliser dans un programme Python, il faut bien-s\u00fbr, l\u2019importer&nbsp;:<\/p>\n<p><strong>import threading<\/strong><\/p>\n<p>et cr\u00e9er une classe qui h\u00e9rite de <strong>threading.Thread <\/strong>:<\/p>\n\n\n\n<figure class=\"wp-block-table\">\n<table style=\"width: 100%; height: 39px;\">\n<tbody>\n<tr style=\"height: 21px;\">\n<td style=\"height: 21px; padding-left: 40px;\" bgcolor=\"#FFFFCC\">\n<p><span style=\"color: #000000;\">class MyThread(threading.Thread):<\/span><\/p>\n<p><span style=\"color: #000000;\">&nbsp;&nbsp;&nbsp; def __init__(self, target):<\/span><\/p>\n<p><span style=\"color: #000000;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; threading.Thread.__init__(self)<\/span><\/p>\n<p><span style=\"color: #000000;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.target = target<\/span><\/p>\n<p><span style=\"color: #000000;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.StopThread = False<\/span><\/p>\n<p><span style=\"color: #000000;\">&nbsp;&nbsp;&nbsp; <\/span><br><span style=\"color: #000000;\">&nbsp; &nbsp; def run(self):<\/span><\/p>\n<p><span style=\"color: #000000;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while not self.StopThread:<\/span><\/p>\n<p><span style=\"color: #000000;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;self.target()<\/span><br><br><\/p>\n<p><span style=\"color: #000000;\">&nbsp;&nbsp;&nbsp; def stop(self):<\/span><\/p>\n<p><span style=\"color: #000000;\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.StopThread = True<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n\n\n\n<p>Ensuite, il faut cr\u00e9er un objet thread\u00a0:<\/p>\n<p style=\"padding-left: 40px;\"><strong>Thread = MyThread(target)<\/strong><\/p>\n<p>\u00a0et d\u00e9finir la fonction \u201d<strong>target\u201d<\/strong>\u00a0qui est appel\u00e9e au lancement du thread et contient le code qui doit s&rsquo;ex\u00e9cuter en parall\u00e8le du reste du programme.<\/p>\n<p>Le thread est lanc\u00e9 \u00e0 l\u2019aide de l\u2019instruction : <strong>Thread.start() <\/strong><\/p>\n<p>La m\u00e9thode \u201d<strong>run()\u201d<\/strong> du thread est alors appel\u00e9 qui elle-m\u00eame appelle la fonction \u201d<strong>target\u201d<\/strong>\u00a0qui s\u2019ex\u00e9cute en boucle tant que le thread n\u2019est pas arr\u00eat\u00e9 \u00e0 la fin du programme par\u00a0: <strong>Thread.stop()<\/strong><\/p>\n<p><u><br \/><\/u><u>Exemple<\/u>\u00a0:<\/p>\n<p>Reprenons le programme (<strong>\u201d<\/strong><strong><a href=\"https:\/\/www.ardpylab.fr\/?page_id=2587\/#conv3\" data-wplink-url-error=\"true\">Parseint.ino<\/a>\u201d<\/strong>) \u00e0 t\u00e9l\u00e9verser dans la m\u00e9moire de l\u2019Arduino qui permet de r\u00e9gler la luminosit\u00e9 de la DEL rouge du <a href=\"https:\/\/www.ardpylab.fr\/?page_id=2497\/#circuit\" data-wplink-url-error=\"true\">circuit<\/a> support des exemples.<\/p>\n<p>Ce programme demande \u00e0 l\u2019utilisateur de saisir la valeur souhait\u00e9e de la luminosit\u00e9 (nombre entier entre 1 et 255), puis renvoie la valeur choisie.<\/p>\n<p>Dans le programme Python (<strong>\u201d<a href=\"https:\/\/www.ardpylab.fr\/downloads\/pyserial\/writethread.zip\" data-wplink-url-error=\"true\">WriteThread.py<\/a>\u201d<\/strong>) associ\u00e9 au programme Arduino, nous allons cr\u00e9er un <strong>\u201d<\/strong><strong>thread\u201d<\/strong> pour la r\u00e9ception des donn\u00e9es envoy\u00e9s par l\u2019Arduino et une boucle <strong>\u201d<\/strong><strong>while True\u201d<\/strong>\u00a0pour la saisie des valeurs de luminosit\u00e9 qui aura lieu apr\u00e8s chaque r\u00e9ception suivant le d\u00e9roulement suivant\u00a0:<\/p>\n<p style=\"padding-left: 40px;\">&#8211; Premi\u00e8re r\u00e9ception : L\u2019Arduino demande de saisir la luminosit\u00e9 (chaine de caract\u00e8res re\u00e7ue et affich\u00e9e dans la console Python par le \u201dthread\u201d)<\/p>\n<p style=\"padding-left: 40px;\">&#8211; Saisie de la luminosit\u00e9 par l\u2019utilisateur (chaine de caract\u00e8res envoy\u00e9e par la \u201dboucle while True\u201d)<\/p>\n<p style=\"padding-left: 40px;\">&#8211; Deuxi\u00e8me r\u00e9ception : L\u2019Arduino renvoie la valeur choisie (nouvelle chaine de caract\u00e8res re\u00e7ue et affich\u00e9e dans la console Python par le \u201dthread\u201d)<\/p>\n<p style=\"padding-left: 40px;\">&#8211; Nouvelle saisie de la luminosit\u00e9 par l\u2019utilisateur (chaine de caract\u00e8res envoy\u00e9e par la \u201dboucle while True\u201d)<\/p>\n<p style=\"padding-left: 40px;\">&#8211; etc, \u2026<br \/><br \/><\/p>\n\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-2500 aligncenter\" style=\"border: 3px solid #eeeeee; padding: 3px; margin: 3px;\" src=\"https:\/\/www.ardpylab.fr\/wp-content\/uploads\/2020\/04\/com-ardpy-ms5.png\" alt=\"\" width=\"614\" height=\"336\" \/><\/figure>\n<\/div>\n<p>\u00a0<\/p>\n\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/www.ardpylab.fr\/downloads\/pyserial\/codes\/py\/WriteThread.py\" data-wplink-url-error=\"true\"><img loading=\"lazy\" decoding=\"async\" width=\"672\" height=\"1024\" class=\"wp-image-2709 aligncenter\" style=\"border: 3px solid #eeeeee; padding: 3px; margin: 3px;\" src=\"https:\/\/www.ardpylab.fr\/wp-content\/uploads\/2020\/04\/com-ardpy-pc12-672x1024.png\" alt=\"\" srcset=\"https:\/\/www.ardpylab.fr\/wp-content\/uploads\/2020\/04\/com-ardpy-pc12-672x1024.png 672w, https:\/\/www.ardpylab.fr\/wp-content\/uploads\/2020\/04\/com-ardpy-pc12-197x300.png 197w, https:\/\/www.ardpylab.fr\/wp-content\/uploads\/2020\/04\/com-ardpy-pc12-768x1170.png 768w, https:\/\/www.ardpylab.fr\/wp-content\/uploads\/2020\/04\/com-ardpy-pc12.png 909w\" sizes=\"auto, (max-width: 672px) 100vw, 672px\" \/><\/a><\/figure>\n<\/div>\n<p>R\u00e9sultats dans la console Python&nbsp;:<\/p>\n\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"670\" height=\"314\" class=\"wp-image-2711 aligncenter\" style=\"border: 3px solid #eeeeee; padding: 3px; margin: 3px;\" src=\"https:\/\/www.ardpylab.fr\/wp-content\/uploads\/2020\/04\/com-ardpy-pc13.png\" alt=\"\" srcset=\"https:\/\/www.ardpylab.fr\/wp-content\/uploads\/2020\/04\/com-ardpy-pc13.png 670w, https:\/\/www.ardpylab.fr\/wp-content\/uploads\/2020\/04\/com-ardpy-pc13-300x141.png 300w\" sizes=\"auto, (max-width: 670px) 100vw, 670px\" \/><\/figure>\n<\/div>\n\n\n\n<p><strong><u><br \/>D\u00e9roulement du programme<\/u><\/strong><strong>\u00a0:<\/strong><\/p>\n<p>&#8211; <span style=\"text-decoration: underline;\">Importation des librairies et d\u00e9finition de fonctions<\/span>\u00a0(idem programmes pr\u00e9c\u00e9dents avec en plus) :<\/p>\n<p style=\"padding-left: 40px;\">. Importation de la biblioth\u00e8que <strong>\u201d<\/strong><strong>threading\u201d<\/strong>\u00a0pour la cr\u00e9ation des threads,<\/p>\n<p style=\"padding-left: 40px;\">. Cr\u00e9ation de la classe <strong>\u201d<\/strong><strong>My<\/strong><strong>Thread\u201d<\/strong>,<\/p>\n<p style=\"padding-left: 40px;\">. D\u00e9finition de la fonction <strong>\u201d<\/strong><strong>ImportDonneeSerial()\u201d<\/strong>\u00a0qui sera la fonction appel\u00e9e en boucle par le thread et qui permet de recevoir les donn\u00e9es envoy\u00e9es par l\u2019Arduino.<br \/><br \/><\/p>\n<p>&#8211; <span style=\"text-decoration: underline;\">D\u00e9claration des constantes et variables<\/span>\u00a0:<\/p>\n<p style=\"padding-left: 40px;\">. <strong>donnees = \u201d <\/strong>(variable pour stocker les donn\u00e9es qui transitent par le port s\u00e9rie),<\/p>\n<p style=\"padding-left: 40px;\">. <strong>DonneeRecue = 0 <\/strong>(compteur des donn\u00e9es re\u00e7ues, incr\u00e9mentation de la variable dans la fonction g\u00e9rant la r\u00e9ception des donn\u00e9es).<br \/><br \/><\/p>\n<p>&#8211; <span style=\"text-decoration: underline;\">Connexion \u00e0 l&rsquo;Arduino<\/span>\u00a0(idem programmes pr\u00e9c\u00e9dents) :<\/p>\n<p>Si l\u2019ouverture du port s\u00e9rie a r\u00e9ussi, on cr\u00e9e un objet \u201d<strong>thread<\/strong>\u201d dont l\u2019argument est la fonction \u00e0 appeler, et on le lance :<\/p>\n<p style=\"padding-left: 40px;\"><strong>SerialThread = MyThread(ImportDonneeSerial)<\/strong><\/p>\n<p style=\"padding-left: 40px;\"><strong>SerialThread.start()<br \/><br \/><\/strong><\/p>\n<p>&#8211; Boucle principale du programme (boucle \u201dwhile True\u201d) :<\/p>\n<p style=\"padding-left: 40px;\">&#8211;&gt; Attente de la saisie de la valeur la luminosit\u00e9 si la demande par l\u2019Arduino a \u00e9t\u00e9 envoy\u00e9 et re\u00e7ue <strong>(<\/strong><strong>if DonneeRecue==1<\/strong>) et envoie de la donn\u00e9e \u00e0 l\u2019Arduino:<\/p>\n<p style=\"padding-left: 80px;\"><strong>SerialPort.write(str(saisie).encode(&lsquo;utf-8&rsquo;))<\/strong><\/p>\n<p style=\"padding-left: 40px;\">&#8211;&gt; R\u00e9initialisation du compteur des donn\u00e9e re\u00e7ues (<strong>DonneeRecue=0<\/strong>) si un envoi a \u00e9t\u00e9 fait.<br \/><br \/><\/p>\n<p>&#8211; Fin du programme en appuyant sur Ctrl-C\u00a0:<\/p>\n<p style=\"padding-left: 40px;\">&#8211;&gt; Arr\u00eat du thread en cours : <strong>SerialThread.stop()<\/strong> \u00a0<\/p>\n<p>\u00a0<\/p>\n\n\n<div  class=\"grids-section grids-is-stretch\" style=\"--_gs-gap-desktop:0px 0px;--_gs-m-desktop:0 0 0 0;--_gs-p-desktop:0 0 0 0;--_gs-bg-desktop:transparent none;--_gs-bg-xp-desktop:0px;--_gs-zi-desktop:auto;--_gs-d-desktop:block;--_gs-mw-desktop:calc(100% - 0 - 0);--_gs-gap-tablet:0px 0px;--_gs-m-tablet:0 0 0 0;--_gs-p-tablet:0 0 0 0;--_gs-bg-tablet:transparent none;--_gs-bg-xp-tablet:0px;--_gs-zi-tablet:auto;--_gs-d-tablet:block;--_gs-mw-tablet:calc(100% - 0 - 0);--_gs-gap-mobile:0px 0px;--_gs-m-mobile:0 0 0 0;--_gs-p-mobile:0 0 0 0;--_gs-bg-mobile:transparent none;--_gs-bg-xp-mobile:0px;--_gs-zi-mobile:auto;--_gs-d-mobile:block;--_gs-mw-mobile:calc(100% - 0 - 0);--_gs-columns:2;--_gs-rows:1\"><div class=\"grids-s-w_i\">\n<div class=\"grids-area\" style=\"--_ga-column:1\/2;--_ga-row:1\/2;--_ga-m-desktop:0 0 0 0;--_ga-p-desktop:0 0 0 0;--_ga-bg-desktop:transparent none;--_ga-zi-desktop:auto;--_ga-d-desktop:flex;--_ga-mw-desktop:calc(100% - 0 - 0);--_ga-m-tablet:0 0 0 0;--_ga-p-tablet:0 0 0 0;--_ga-bg-tablet:transparent none;--_ga-zi-tablet:auto;--_ga-d-tablet:flex;--_ga-mw-tablet:calc(100% - 0 - 0);--_ga-m-mobile:0 0 0 0;--_ga-p-mobile:0 0 0 0;--_ga-bg-mobile:transparent none;--_ga-zi-mobile:auto;--_ga-d-mobile:flex;--_ga-mw-mobile:calc(100% - 0 - 0)\">\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><a href=\"https:\/\/www.ardpylab.fr\/?page_id=2678\"><img loading=\"lazy\" decoding=\"async\" width=\"50\" height=\"28\" src=\"https:\/\/www.ardpylab.fr\/wp-content\/uploads\/2020\/03\/moins.jpg\" alt=\"\" class=\"wp-image-107\"\/><\/a><\/figure><\/div>\n\n<\/div>\n\n<div class=\"grids-area\" style=\"--_ga-column:2\/3;--_ga-row:1\/2;--_ga-m-desktop:0 0 0 0;--_ga-p-desktop:0 0 0 0;--_ga-bg-desktop:transparent none;--_ga-zi-desktop:auto;--_ga-d-desktop:flex;--_ga-mw-desktop:calc(100% - 0 - 0);--_ga-m-tablet:0 0 0 0;--_ga-p-tablet:0 0 0 0;--_ga-bg-tablet:transparent none;--_ga-zi-tablet:auto;--_ga-d-tablet:flex;--_ga-mw-tablet:calc(100% - 0 - 0);--_ga-m-mobile:0 0 0 0;--_ga-p-mobile:0 0 0 0;--_ga-bg-mobile:transparent none;--_ga-zi-mobile:auto;--_ga-d-mobile:flex;--_ga-mw-mobile:calc(100% - 0 - 0)\">\n\n<div class=\"wp-block-image\"><figure class=\"alignright size-large\"><a href=\"https:\/\/www.ardpylab.fr\/?page_id=2725\"><img loading=\"lazy\" decoding=\"async\" width=\"50\" height=\"28\" src=\"https:\/\/www.ardpylab.fr\/wp-content\/uploads\/2020\/03\/plus.jpg\" alt=\"\" class=\"wp-image-106\"\/><\/a><\/figure><\/div>\n\n<\/div>\n<\/div><\/div>\n\n\n\n","protected":false},"excerpt":{"rendered":"<p>(de donn\u00e9es par un programme Python) &nbsp; &nbsp; Les programmes Python de communication avec l&rsquo;Arduino \u00e9tudi\u00e9s jusqu\u2019\u00e0 pr\u00e9sent, permettaient soit de recevoir, soit d\u2019envoyer des donn\u00e9es. Mais pour qu\u2019il soit complet, le programme Python doit pouvoir g\u00e9rer les deux actions simultan\u00e9ment. Le probl\u00e8me se pose quand on demande \u00e0 l\u2019utilisateur de saisir au clavier une [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-2683","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.ardpylab.fr\/index.php?rest_route=\/wp\/v2\/pages\/2683","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ardpylab.fr\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.ardpylab.fr\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.ardpylab.fr\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ardpylab.fr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2683"}],"version-history":[{"count":0,"href":"https:\/\/www.ardpylab.fr\/index.php?rest_route=\/wp\/v2\/pages\/2683\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.ardpylab.fr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2683"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}