Logo Mon Club Elec

PyQt Lab’ : Port Série : en réception : Réception d’une valeur numérique sur le port série, dans un QwtThermo, le widget d’affichage analogique « vu-mètre », conversion mesure/unité et affichage dans des widgets LCD.

PyQt Lab' : Port Série : en réception : Réception d'une valeur numérique sur le port série, dans un QwtThermo, le widget d'affichage analogique « vu-mètre », conversion mesure/unité et affichage dans des widgets LCD.

PyQt Lab’ : Port Série : en réception : Réception d’une valeur numérique sur le port série, dans un QwtThermo, le widget d’affichage analogique « vu-mètre », conversion mesure/unité et affichage dans des widgets LCD.

Par X. HINAULT – Juin 2013

PyQt Lab’ : Port Série : en réception : Réception d’une valeur numérique sur le port série, dans un QwtThermo, le widget d’affichage analogique « vu-mètre », conversion mesure/unité et affichage dans des widgets LCD.

Ce que l’on va faire ici

  • Dans ce code PyQt, une interface permettant la réception d’une valeur numérique sur le port série, dans un QwtThermo, le widget d’affichage analogique « vu-mètre », conversion mesure/unité et affichage dans des widgets LCD.

Pré-requis

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

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: Sun Feb  3 11:24:41 2013
#      by: PyQt4 UI code generator 4.9.1
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui
from PyQt4.Qwt5 import * # module Qwt

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(610, 275)
        self.labelDebit = QtGui.QLabel(Form)
        self.labelDebit.setGeometry(QtCore.QRect(10, 45, 111, 16))
        self.labelDebit.setObjectName(_fromUtf8(« labelDebit »))
        self.comboBoxPort = QtGui.QComboBox(Form)
        self.comboBoxPort.setGeometry(QtCore.QRect(5, 20, 151, 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.labelReception = QtGui.QLabel(Form)
        self.labelReception.setGeometry(QtCore.QRect(5, 135, 191, 16))
        self.labelReception.setObjectName(_fromUtf8(« labelReception »))
        self.textEditReception = QtGui.QTextEdit(Form)
        self.textEditReception.setGeometry(QtCore.QRect(5, 155, 156, 111))
        self.textEditReception.setLineWrapMode(QtGui.QTextEdit.NoWrap)
        self.textEditReception.setObjectName(_fromUtf8(« textEditReception »))
        self.pushButtonInitSerial = QtGui.QPushButton(Form)
        self.pushButtonInitSerial.setGeometry(QtCore.QRect(5, 95, 101, 31))
        self.pushButtonInitSerial.setObjectName(_fromUtf8(« pushButtonInitSerial »))
        self.comboBoxDebit = QtGui.QComboBox(Form)
        self.comboBoxDebit.setGeometry(QtCore.QRect(5, 60, 111, 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.labelPort = QtGui.QLabel(Form)
        self.labelPort.setGeometry(QtCore.QRect(10, 5, 101, 16))
        self.labelPort.setObjectName(_fromUtf8(« labelPort »))
        self.lcdNumberValeurCalc = QtGui.QLCDNumber(Form)
        self.lcdNumberValeurCalc.setGeometry(QtCore.QRect(450, 140, 96, 36))
        self.lcdNumberValeurCalc.setStyleSheet(_fromUtf8(« background-color: rgb(255, 255, 0);\n« 
« color: rgb(255, 0, 0); »))
        self.lcdNumberValeurCalc.setSmallDecimalPoint(True)
        self.lcdNumberValeurCalc.setMode(QtGui.QLCDNumber.Dec)
        self.lcdNumberValeurCalc.setObjectName(_fromUtf8(« lcdNumberValeurCalc »))
        self.lineEditValeurMax = QtGui.QLineEdit(Form)
        self.lineEditValeurMax.setGeometry(QtCore.QRect(530, 90, 66, 23))
        self.lineEditValeurMax.setObjectName(_fromUtf8(« lineEditValeurMax »))
        self.labelValeurBrute = QtGui.QLabel(Form)
        self.labelValeurBrute.setGeometry(QtCore.QRect(450, 20, 81, 16))
        self.labelValeurBrute.setObjectName(_fromUtf8(« labelValeurBrute »))
        self.labelValeurMin = QtGui.QLabel(Form)
        self.labelValeurMin.setGeometry(QtCore.QRect(455, 75, 71, 16))
        self.labelValeurMin.setObjectName(_fromUtf8(« labelValeurMin »))
        self.labelValeurMax = QtGui.QLabel(Form)
        self.labelValeurMax.setGeometry(QtCore.QRect(530, 75, 71, 16))
        self.labelValeurMax.setObjectName(_fromUtf8(« labelValeurMax »))
        self.lineEditUnite = QtGui.QLineEdit(Form)
        self.lineEditUnite.setGeometry(QtCore.QRect(550, 155, 56, 23))
        self.lineEditUnite.setObjectName(_fromUtf8(« lineEditUnite »))
        self.lineEditValeurMin = QtGui.QLineEdit(Form)
        self.lineEditValeurMin.setGeometry(QtCore.QRect(455, 90, 66, 23))
        self.lineEditValeurMin.setObjectName(_fromUtf8(« lineEditValeurMin »))
        self.labelValeurCalc = QtGui.QLabel(Form)
        self.labelValeurCalc.setGeometry(QtCore.QRect(455, 120, 106, 16))
        self.labelValeurCalc.setObjectName(_fromUtf8(« labelValeurCalc »))
        self.labelUnite = QtGui.QLabel(Form)
        self.labelUnite.setGeometry(QtCore.QRect(550, 140, 51, 13))
        self.labelUnite.setObjectName(_fromUtf8(« labelUnite »))
        self.lcdNumberValeurBrute = QtGui.QLCDNumber(Form)
        self.lcdNumberValeurBrute.setGeometry(QtCore.QRect(450, 35, 96, 36))
        self.lcdNumberValeurBrute.setStyleSheet(_fromUtf8(« background-color: rgb(170, 255, 127);\n« 
« color: rgb(0, 170, 0); »))
        self.lcdNumberValeurBrute.setSmallDecimalPoint(False)
        self.lcdNumberValeurBrute.setObjectName(_fromUtf8(« lcdNumberValeurBrute »))
        self.line = QtGui.QFrame(Form)
        self.line.setGeometry(QtCore.QRect(160, 5, 16, 266))
        self.line.setFrameShape(QtGui.QFrame.VLine)
        self.line.setFrameShadow(QtGui.QFrame.Sunken)
        self.line.setObjectName(_fromUtf8(« line »))
        self.line_2 = QtGui.QFrame(Form)
        self.line_2.setGeometry(QtCore.QRect(435, 5, 16, 266))
        self.line_2.setFrameShape(QtGui.QFrame.VLine)
        self.line_2.setFrameShadow(QtGui.QFrame.Sunken)
        self.line_2.setObjectName(_fromUtf8(« line_2 »))
        self.pushButtonStop = QtGui.QPushButton(Form)
        self.pushButtonStop.setGeometry(QtCore.QRect(115, 85, 41, 41))
        self.pushButtonStop.setObjectName(_fromUtf8(« pushButtonStop »))
        self.qwtThermo = QwtThermo(Form)
        self.qwtThermo.setGeometry(QtCore.QRect(250, 15, 103, 244))
        self.qwtThermo.setAutoFillBackground(True)
        self.qwtThermo.setAlarmEnabled(True)
        self.qwtThermo.setAlarmLevel(512.0)
        self.qwtThermo.setMaxValue(1023.0)
        self.qwtThermo.setPipeWidth(50)
        self.qwtThermo.setProperty(« value », 0.0)
        self.qwtThermo.setObjectName(_fromUtf8(« qwtThermo »))

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

    def retranslateUi(self, Form):
        Form.setWindowTitle(QtGui.QApplication.translate(« Form », « PyQt + PyQwt +PySerial : QwtThermo affiche can brute (0-1023) + conversion », None, QtGui.QApplication.UnicodeUTF8))
        self.labelDebit.setText(QtGui.QApplication.translate(« Form », « Débit Série (bauds) : », 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.labelReception.setText(QtGui.QApplication.translate(« Form », « Réception sur le port série : « , None, QtGui.QApplication.UnicodeUTF8))
        self.pushButtonInitSerial.setText(QtGui.QApplication.translate(« Form », « Initialiser », 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.labelPort.setText(QtGui.QApplication.translate(« Form », « Port Série : », None, QtGui.QApplication.UnicodeUTF8))
        self.lineEditValeurMax.setText(QtGui.QApplication.translate(« Form », « 5000 », None, QtGui.QApplication.UnicodeUTF8))
        self.labelValeurBrute.setText(QtGui.QApplication.translate(« Form », « Valeur brute : », None, QtGui.QApplication.UnicodeUTF8))
        self.labelValeurMin.setText(QtGui.QApplication.translate(« Form », « Valeur mini », None, QtGui.QApplication.UnicodeUTF8))
        self.labelValeurMax.setText(QtGui.QApplication.translate(« Form », « Valeur maxi », None, QtGui.QApplication.UnicodeUTF8))
        self.lineEditUnite.setText(QtGui.QApplication.translate(« Form », « mV », None, QtGui.QApplication.UnicodeUTF8))
        self.lineEditValeurMin.setText(QtGui.QApplication.translate(« Form », « 0 », None, QtGui.QApplication.UnicodeUTF8))
        self.labelValeurCalc.setText(QtGui.QApplication.translate(« Form », « Valeur calculée : », None, QtGui.QApplication.UnicodeUTF8))
        self.labelUnite.setText(QtGui.QApplication.translate(« Form », « Unité : », None, QtGui.QApplication.UnicodeUTF8))
        self.pushButtonStop.setText(QtGui.QApplication.translate(« Form », « Stop », None, QtGui.QApplication.UnicodeUTF8))

from PyQt4.Qwt5 import * # module Qwt

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 – Tous droits réservés – GPLv3
# Jan 2013 – www.mon-club-elec.fr

# — importation des modules utiles —
from PyQt4.QtGui import *
from PyQt4.QtCore import * # inclut Qtimer..

import os,sys

import serial # communication serie
from PyQt4.Qwt5 import * # module Qwt
#from PyQt4.Qwt5.anynumpy import * # pour les fonctions math..
from numpy import interp # pour équivalent map

# — importation du fichier de description GUI —
from tuto_pyqt_pyqwt_pyserial_qwtthermo_can_brutex1_lineedit import *

# classe principale contenant le code actif
class myApp(QWidget, Ui_Form): # la classe reçoit le Qwidget principal ET la classe définie dans test.py obtenu avec pyuic4

        # Note : ici self représente la classe

        def __init__(self, parent=None):
                QWidget.__init__(self) # initialise le Qwidget principal
                self.setupUi(parent) # Obligatoire

                # —— code actif initial ——

                #Réalisez les connexions supplémentaires entre signaux et slots
                self.connect(self.pushButtonInitSerial, SIGNAL(« clicked() »), self.pushButtonInitSerialClicked)
                self.connect(self.pushButtonStop, SIGNAL(« clicked() »), self.pushButtonStopClicked)

                #===== Initialisation QwtThermo – à mettre avant QTimer ++  ========           
                self.qwtThermo.setFillColor(QColor(0,255,0)) # fixe la couleur de remplissage sous niveau alarme
                self.qwtThermo.setAlarmColor(QColor(255,0,0)) # fixe couleur remplissage au dessus niveau alarme

                #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
                self.chaineIn=«  » # variable pour réception

        #— les fonctions appelées, utilisées par les signaux
        def pushButtonInitSerialClicked(self):
                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
                        # initialise port serie avec délai attente en réception en sec
                        self.serialPort=serial.Serial(strPortInit, strDebitInit, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE, 0.100)                     
                        #self.serialPort=serial.Serial(strPortInit, strDebitInit) # initialise port serie forme réduite
                        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
                # pour optimiser la réception d’une chaîne envoyée à répétition, utiliser une valeur similaire à la valeur d’émission sur le port série

        def pushButtonStopClicked(self):
                print(« Bouton Stop cliqué »)

                #– stoppe la réception série —
                if self.serialPort: # si le port existe déjà
                        self.serialPort.close() # ferme le port si existe
                        self.timer.stop() # stoppe le timer

                #– 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

        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= » » – pas systématique – seulement si un saut de ligne a été reçu
                self.char=«  »;
                self.flagSautLigne=False # drapeau saut de ligne reçu

                # 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 »

                        while (self.serialPort.inWaiting()): # tant que au moins un caractère en réception
                                self.char=self.serialPort.read() # on lit le caractère
                                #self.chaineIn=self.chaineIn+self.char          # forme minimale…

                                if self.char==\n: # si saut de ligne, on sort du while
                                        print(« saut ligne reçu ») # debug
                                        self.flagSautLigne=True # drapeau saut de ligne reçu
                                        break # sort du while
                                else: #tant que c’est pas le saut de ligne, on l’ajoute à la chaine
                                        self.chaineIn=self.chaineIn+self.char  

                        # fin while                            

                        # en sortie du while, on se place ici
                        print self.chaineIn
                        print self.flagSautLigne
                        # teste si chaine valide = non vide et saut de ligne = True…
                        if len(self.chaineIn)>1 and self.flagSautLigne==True: # … 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 (CR)

                                self.chaineIn=self.chaineIn[:-1] # retire dernier caractère avant extraire valeur numérique (LF)

                                if self.chaineIn.isalnum(): # si la chaine est un chiffre
                                        print(« que des chiffres ») # debug
                                        self.valeur=float(self.chaineIn)

                                        self.qwtThermo.setValue(self.valeur) # fixe la valeur du qwtDial à partir de la valeur reçue sur port série

                                        # actualise lcdNumber
                                        self.lcdNumberValeurBrute.display(self.valeur) # affiche la valeur

                                        # équiv map : interp(256,[1,512],[5,10]) (package numpy)
                                        self.valeurCalc=interp(self.valeur, [0,1023],[float(self.lineEditValeurMin.text()),float(self.lineEditValeurMax.text())]) # équiv map
                                        self.lcdNumberValeurCalc.display(self.valeurCalc)

                                # fin if isalnum

                                self.chaineIn=«  »; # dans le if : une fois chaine valide (=non vide et avec saut de ligne) traitée

                        # fin if len>0 # fin traitement chaine valide…

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

                # fin if Serial Port

        # fin def timerEvent

        #— fonctions actives
        # …

# fonction principale exécutant l’application Qt                       
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

# pour rendre le fichier *.py exécutable
if __name__==« __main__ »: # pour rendre le code exécutable
        main(sys.argv) # appelle la fonction main
 

Code Arduino d’exemple

// — constantes des broches —

const int RVar=0; //declaration constante de broche analogique

// — Déclaration des variables globales —
int mesureBrute=0;// Variable pour acquisition résultat brut de conversion analogique numérique

//**************** FONCTION SETUP = Code d’initialisation *****

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

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

} // fin de la fonction setup()

//***** FONCTION LOOP = Boucle sans fin *****

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

// acquisition conversion analogique-numerique (CAN) sur la voie analogique
mesureBrute=analogRead(RVar);

// affiche valeur numerique entière ou à virgule au format décimal
Serial.println(mesureBrute);

delay(500);

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

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
  • La valeur numérique reçue sur le port série s’affiche sous forme d’un widget analogique de type bargraph avec champ de conversion de la valeur.
Noter cet article

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Archive Mon Club Elec

Articles populaires

Newsletter

Inscrivez-vous maintenant et bénéficiez d'un soutien continu pour réaliser vos travaux électriques en toute sécurité.