View  Edit  Attributes  History  Attach  Print  Search

PYQTLAB

PyQt Lab' : Port Série : en envoi : Allumer une LED côté Arduino avec un PushButton en mode ON/OFF.

Par X. HINAULT - Juin 2013

Ce que l'on va faire ici

  • Dans ce code PyQt, une interface qui permet d'allumer une LED côté Arduino avec un PushButton en mode ON/OFF.

Pré-requis

  • python 2.7
  • pyqt4.x
  • modules :
    • python-serial

Téléchargement :

  • L'archive des codes est disponible ici : ..

Le fichier d'interface *.py

  • Fichier obtenu automatiquement avec l'utilitaire pyuic4 à partir du fichier *.ui créé avec QtDesigner :
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file
#
# Created: Wed Jan 16 12:06:34 2013
#      by: PyQt4 UI code generator 4.9.1
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    _fromUtf8 = lambda s: s

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName(_fromUtf8("Form"))
        Form.resize(432, 255)
        self.comboBoxPort = QtGui.QComboBox(Form)
        self.comboBoxPort.setGeometry(QtCore.QRect(10, 20, 191, 24))
        self.comboBoxPort.setEditable(True)
        self.comboBoxPort.setObjectName(_fromUtf8("comboBoxPort"))
        self.comboBoxPort.addItem(_fromUtf8(""))
        self.comboBoxPort.addItem(_fromUtf8(""))
        self.comboBoxPort.addItem(_fromUtf8(""))
        self.comboBoxPort.addItem(_fromUtf8(""))
        self.labelPort = QtGui.QLabel(Form)
        self.labelPort.setGeometry(QtCore.QRect(10, 5, 101, 16))
        self.labelPort.setObjectName(_fromUtf8("labelPort"))
        self.comboBoxDebit = QtGui.QComboBox(Form)
        self.comboBoxDebit.setGeometry(QtCore.QRect(10, 65, 106, 24))
        self.comboBoxDebit.setObjectName(_fromUtf8("comboBoxDebit"))
        self.comboBoxDebit.addItem(_fromUtf8(""))
        self.comboBoxDebit.addItem(_fromUtf8(""))
        self.comboBoxDebit.addItem(_fromUtf8(""))
        self.comboBoxDebit.addItem(_fromUtf8(""))
        self.comboBoxDebit.addItem(_fromUtf8(""))
        self.comboBoxDebit.addItem(_fromUtf8(""))
        self.comboBoxDebit.addItem(_fromUtf8(""))
        self.comboBoxDebit.addItem(_fromUtf8(""))
        self.labelDebit = QtGui.QLabel(Form)
        self.labelDebit.setGeometry(QtCore.QRect(10, 50, 111, 16))
        self.labelDebit.setObjectName(_fromUtf8("labelDebit"))
        self.pushButtonInitSerial = QtGui.QPushButton(Form)
        self.pushButtonInitSerial.setGeometry(QtCore.QRect(125, 55, 81, 41))
        self.pushButtonInitSerial.setObjectName(_fromUtf8("pushButtonInitSerial"))
        self.textEditReception = QtGui.QTextEdit(Form)
        self.textEditReception.setGeometry(QtCore.QRect(10, 130, 186, 121))
        self.textEditReception.setObjectName(_fromUtf8("textEditReception"))
        self.labelReception = QtGui.QLabel(Form)
        self.labelReception.setGeometry(QtCore.QRect(10, 110, 191, 16))
        self.labelReception.setObjectName(_fromUtf8("labelReception"))
        self.line_2 = QtGui.QFrame(Form)
        self.line_2.setGeometry(QtCore.QRect(10, 95, 186, 16))
        self.line_2.setFrameShape(QtGui.QFrame.HLine)
        self.line_2.setFrameShadow(QtGui.QFrame.Sunken)
        self.line_2.setObjectName(_fromUtf8("line_2"))
        self.pushButtonLED = QtGui.QPushButton(Form)
        self.pushButtonLED.setGeometry(QtCore.QRect(235, 41, 176, 166))
        self.pushButtonLED.setCheckable(True)
        self.pushButtonLED.setObjectName(_fromUtf8("pushButtonLED"))
        self.line = QtGui.QFrame(Form)
        self.line.setGeometry(QtCore.QRect(203, 5, 16, 246))
        self.line.setFrameShape(QtGui.QFrame.VLine)
        self.line.setFrameShadow(QtGui.QFrame.Sunken)
        self.line.setObjectName(_fromUtf8("line"))

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        Form.setWindowTitle(QtGui.QApplication.translate("Form", "PyQt + PySerial : Terminal Série : pushButton allume LED", None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxPort.setItemText(0, QtGui.QApplication.translate("Form", "/dev/ttyACM0", None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxPort.setItemText(1, QtGui.QApplication.translate("Form", "/dev/ttyACM1", None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxPort.setItemText(2, QtGui.QApplication.translate("Form", "/dev/ttyUSB0", None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxPort.setItemText(3, QtGui.QApplication.translate("Form", "/dev/ttyUSB1", None, QtGui.QApplication.UnicodeUTF8))
        self.labelPort.setText(QtGui.QApplication.translate("Form", "Port Série :", None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxDebit.setItemText(0, QtGui.QApplication.translate("Form", "115200", None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxDebit.setItemText(1, QtGui.QApplication.translate("Form", "57600", None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxDebit.setItemText(2, QtGui.QApplication.translate("Form", "38400", None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxDebit.setItemText(3, QtGui.QApplication.translate("Form", "28800", None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxDebit.setItemText(4, QtGui.QApplication.translate("Form", "19200", None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxDebit.setItemText(5, QtGui.QApplication.translate("Form", "14400", None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxDebit.setItemText(6, QtGui.QApplication.translate("Form", "9600", None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxDebit.setItemText(7, QtGui.QApplication.translate("Form", "4800", None, QtGui.QApplication.UnicodeUTF8))
        self.labelDebit.setText(QtGui.QApplication.translate("Form", "Débit Série (bauds) :", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButtonInitSerial.setText(QtGui.QApplication.translate("Form", "Initialiser", None, QtGui.QApplication.UnicodeUTF8))
        self.labelReception.setText(QtGui.QApplication.translate("Form", "Réception sur le port série : ", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButtonLED.setText(QtGui.QApplication.translate("Form", "ALLUMER LED", None, QtGui.QApplication.UnicodeUTF8))


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    Form = QtGui.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec_())

 

Le fichier d'application *Main.py


#!/usr/bin/python
# -*- coding: utf-8 -*-

# par X. HINAULT - Janv 2013 - Tous droits réservés
# GPLv3 - www.mon-club-elec.fr

# modules a importer
from PyQt4.QtGui import *
from PyQt4.QtCore import *  # inclut QTimer..
import os,sys

import serial # communication serie


from tuto_pyqt_pyserial_terminal_bp_allume_led import * # fichier obtenu à partir QtDesigner et pyuic4

class myApp(QWidget, Ui_Form): # la classe reçoit le Qwidget principal ET la classe définie dans test.py obtenu avec pyuic4
        def __init__(self, parent=None):
                QWidget.__init__(self) # initialise le Qwidget principal
                self.setupUi(parent) # Obligatoire

                #Ici, personnalisez vos widgets si nécessaire

                #Réalisez les connexions supplémentaires entre signaux et slots
                # connecte le signal Clicked de l'objet bouton à l'appel de la fonction voulue
                self.connect(self.pushButtonInitSerial, SIGNAL("clicked()"), self.pushButtonInitSerialClicked)
                self.connect(self.pushButtonLED, SIGNAL("clicked()"), self.pushButtonLEDClicked)

                #initialisation Timer
                self.timer=QTimer() # déclare un timer Qt
                self.connect(self.timer, SIGNAL("timeout()"), self.timerEvent) # connecte le signal timeOut de l'objet timer à l'appel de la fonction voulue

                #--- déclaration utiles ---
                self.serialPort=None # déclaration initiale


        # les fonctions appelées, utilisées par les signaux
        def pushButtonLEDClicked(self): # lors appui bouton envoi série

                print("Bouton LED appuyé")

                # côté Arduino : H allume LED et L : éteint LED
                if self.serialPort: # seulement si le port série existe - n'existe pas (=None) tant que pas initialisé
                        if self.pushButtonLED.isChecked(): # si bouton appuyé
                                # self.serialPort.write(str(self.lineEditChaineEnvoi.text())+'\n'  ) # envoie la chaine sur le port serie              
                                self.serialPort.write('H' ) # envoie la chaine sur le port serie + saut de ligne (pas obligatoire ici - cf prog Arduino)
                                print("Envoi Série : " + 'H' )
                        else: # si bouton pas appuyé
                                # self.serialPort.write(str(self.lineEditChaineEnvoi.text())+'\n'  ) # envoie la chaine sur le port serie              
                                self.serialPort.write('L' ) # envoie la chaine sur le port serie + saut de ligne (pas obligatoire ici - cf prog Arduino)
                                print("Envoi Série : " + 'L' )


        def pushButtonInitSerialClicked(self): # lors appui bouton initialisation série
                print("Bouton Init cliqué")
                if self.serialPort: # si le port existe déjà
                        self.serialPort.close() # ferme le port si existe

                # -- initialise paramètres initialisation
                if self.comboBoxPort.currentText()=="" : # si le champ d'initialisation Port est vide = initialisation par défaut
                        strPortInit="/dev/ttyACM0" # port par défaut
                else :
                        strPortInit=str(self.comboBoxPort.currentText()) #sinon utilise paramètre champ texte pour le port

                strDebitInit=str(self.comboBoxDebit.currentText()) # paramètre champ texte pour debit

                #--- initialisation série avec gestion erreur ---                      
                try: # essaie d'exécuter les instructions
                        self.serialPort=serial.Serial(strPortInit, strDebitInit) # initialise port serie
                        self.serialPort.flushInput() # vide la file d'attente série
                        print("Initialisation Port Série : " + strPortInit +" @ " + strDebitInit +" = OK ") # affiche debug

                        #-- change aspect bouton init
                        self.pushButtonInitSerial.setStyleSheet(QString.fromUtf8("background-color: rgb(0, 255, 0);")) # bouton en vert
                        self.pushButtonInitSerial.setText("Connexion OK")  # change titre bouton

                except: # si erreur initialisation
                        print("Erreur initialisation Série")           

                        #-- change aspect bouton init
                        self.pushButtonInitSerial.setStyleSheet(QString.fromUtf8("background-color: rgb(255, 127, 0);")) # bouton en orange
                        self.pushButtonInitSerial.setText(QString.fromUtf8("Non connecté"))  # change titre bouton

                self.timer.start(10) # lance le timer avec délai en ms - 10 pour réception rapide

        def timerEvent(self): # fonction appelée lors de la survenue d'un évènement Timer - nom fonction indiférrent
                #-- variables de réception --
                self.chaineIn="";
                self.char="";

                # lecture des données reçues           
                if self.serialPort: # seulement si le port série existe
                        self.timer.stop() # stoppe le timer le temps de lire les caractères et éviter "réentrée"

                        if (self.serialPort.inWaiting()): # si au moins un caractère en réception
                                while self.char!='\n': # tant que dernier différent de saut de ligne
                                        self.char=self.serialPort.read() # on lit le caractère
                                        if self.char!='\n': # tant que c'est pas le saut de ligne, on l'ajoute à la chaine
                                                self.chaineIn=self.chaineIn+self.char
                                        else:
                                                #print("saut ligne reçu") # debug
                                                break

                        if len(self.chaineIn)>0: # ... pour ne pas avoir d'affichage si ""     
                                print(self.chaineIn) # affiche la chaîne
                                self.textEditReception.append(self.chaineIn[:-1]) # ajoute le texte au textEdit en enlevant le dernier caractère

                        self.timer.start() # redémarre le timer

def main(args):
        a=QApplication(args) # crée l'objet application
        f=QWidget() # crée le QWidget racine
        c=myApp(f) # appelle la classe contenant le code de l'application
        f.show() # affiche la fenêtre QWidget
        r=a.exec_() # lance l'exécution de l'application
        return r

if __name__=="__main__": # pour rendre le code exécutable
        main(sys.argv) # appelle la fonction main

 

Code Arduino d'exemple

  • Ce programme fonctionne avec le code Arduino suivant :
// --- Programme Arduino ---
// Trame de code générée par le générateur de code Arduino
// du site www.mon-club-elec.fr

// Auteur du Programme : X. HINAULT - Tous droits réservés
// Programme écrit le : 29/1/2011.

// ------- Licence du code de ce programme -----
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License,
//  or any later version.
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

// ////////////////////  PRESENTATION DU PROGRAMME ////////////////////

// -------- Que fait ce programme ? ---------
 /* Ce programme permet d'allumer une LED connectée sur une broche de la carte Arduino à partir d'un bouton inverseur graphique dans l'interface Processing côté PC.  */

// --- Fonctionnalités utilisées ---

// Utilise la connexion série vers le PC

// -------- Circuit à réaliser ---------

// La connexion série vers le PC utilise les broches 0 et 1 (via le câble USB)

// Broche 2 : Une LED connectée en série avec sa résistance

// /////////////////////////////// 1. Entête déclarative ///////////////////////
// A ce niveau sont déclarées les librairies incluses, les constantes, les variables, les objets utiles...

// --- Déclaration des constantes ---

// --- Inclusion des librairies ---

// --- Déclaration des constantes utiles ---

// --- Déclaration des constantes des broches E/S numériques ---

const int LED=2; // Constante pour la broche 2

// --- Déclaration des constantes des broches analogiques ---


// --- Déclaration des variables globales ---

 int octetReception=0; // variable de stockage des valeurs reçues sur le port Série
 String chaineReception=""; // déclare un objet String vide pour reception chaine


// --- Déclaration des objets utiles pour les fonctionnalités utilisées ---


// ////////////////////////// 2. FONCTION SETUP = Code d'initialisation //////////////////////////
// La fonction setup() est exécutée en premier et 1 seule fois, au démarrage du programme

void setup()   { // debut de la fonction setup()

// --- ici instructions à exécuter 1 seule fois au démarrage du programme ---

// ------- Initialisation fonctionnalités utilisées -------  

Serial.begin(115200); // initialise connexion série à 115200 bauds
// IMPORTANT : régler le terminal côté PC avec la même valeur de transmission


// ------- Broches en sorties numériques -------  
 pinMode (LED,OUTPUT); // Broche LED configurée en sortie

// ------- Broches en entrées numériques -------  

// ------- Activation si besoin du rappel au + (pullup) des broches en entrées numériques -------  

// ------- Initialisation des variables utilisées -------  

} // fin de la fonction setup()
// ********************************************************************************

////////////////////////////////// 3. FONCTION LOOP = Boucle sans fin = coeur du programme //////////////////
// la fonction loop() s'exécute sans fin en boucle aussi longtemps que l'Arduino est sous tension

void loop(){ // debut de la fonction loop()


// --- ici instructions à exécuter par le programme principal ---

//---- code type réception valeur sur le port série ---

if (Serial.available()>0) { // si un octet en réception

        octetReception=Serial.read(); // Lit le 1er octet reçu et le met dans la variable

        if (octetReception=='H') { // si Octet reçu est le H

            digitalWrite(LED, HIGH); // allume la LED

        }

        if (octetReception=='L') { // si octet reçu est le L

            digitalWrite(LED, LOW); // éteint la LED

        }

} // fin si octet réception



} // fin de la fonction loop() - le programme recommence au début de la fonction loop sans fin
// ********************************************************************************


// ////////////////////////// FONCTIONS DE GESTION DES INTERRUPTIONS ////////////////////


// ////////////////////////// AUTRES FONCTIONS DU PROGRAMME ////////////////////


// ////////////////////////// Fin du programme ////////////////////
 

Matériel Nécessaire

L'espace de développement Arduino

  • ... pour éditer, compiler le programme et programmer la carte Arduino.

Le matériel suivant pour réaliser le montage associé

  • une plaque d'essai pour montage sans soudures,
  • des straps,
  • une LED rouge 5mm,
  • une résistance 1/4w de 200 Ohms environ,

Instructions de montage

  • La connexion série vers le PC utilise les broches 0 et 1 (via le câble USB)
  • Broche 2 : Une LED connectée en série avec sa résistance

Le schéma théorique du montage

Le schéma théorique du montage (cliquer pour agrandir)

Le circuit du montage

Le schéma du montage à réaliser (cliquer pour agrandir)

Fonctionnement du programme

Structure globale du programme

Ce programme simple comprend :

  • une entête déclarative
  • une partie « configuration » qui ne sera exécutée qu'une fois (fonction setup( ) )
  • une partie constituée d'une boucle sans fin que le programme répètera à l'infini ( fonction loop( ) ) : c'est le coeur du programme.

Déroulement du programme

Le programme se déroule de la façon suivante :

  • Après avoir pris en compte les instructions de la partie déclarative,
  • puis après avoir exécuté la partie configuration ( fonction setup( ) ),
  • le programme bouclera sans fin ( fonction loop ( ) ), exécutant de façon répétée le code compris dans la boucle sans fin.

Le déroulement du programme

Explication du programme

Au niveau de la partie déclarative :

  • On déclare la broche de LED

Au niveau de la fonction d'initialisation setup( ) :

  • On met la broche en sortie

Au niveau de la boucle principale, la fonction loop ( ) :

  • On teste si un caractère est disponible sur le port série :
    • si ce caractères est 'H', on allume la LED
    • si ce caractère est 'L', on éteint la LED

Utilisation

  • Les 2 fichiers suivants sont à enregistrer dans un même répertoire, l'un en nom.py et l'autre en nomMain.py.
  • Puis lancer l'application depuis Geany ou équivalent, en exécutant le fichier nomMain.py
  • L'appui sur le bouton poussoir allume/éteint la LED par l'envoi de la lettre H ou L sur le port série.