无法在 wxpython GUI 中使用 arduino 串行通信 [英] Unable to get arduino serial communication working in wxpython GUI

查看:25
本文介绍了无法在 wxpython GUI 中使用 arduino 串行通信的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是用于更新 GUI 中标签的定义:

This is the definition which is used to update the labels in the GUI:

    def updateV(self, event):
    """"""
    global v
    ser = serial.Serial( port='COM3', baudrate=9600)
    x = ser.read()          # read one byte
    ser.close()
    print x
    if v>3:
        self.labelOne.SetBackgroundColour('red')
        self.labelOne.SetLabel('Battery Voltage : ' + x)

    else:
        self.labelOne.SetBackgroundColour('white')
        self.labelOne.SetLabel('Battery Voltage : ' + str(v))


    self.Refresh()

这是我一直在使用的简单 arduino 代码:

This is the simple arduino code i have been using:

int a;
void setup() {
Serial.begin(9600);// put your setup code here, to run once:

}

void loop() {
a=5;
Serial.println(a);
delay(10);
}

我一直在使用这个定义来更新我的 GUI 标签.我最近开始使用该代码在我的 GUI 上设置串行通信.从逻辑上讲,使用 wx 库的 mainloop(),我想我可以更新x"值并将其打印在 GUI 上.但是即使python控制台定期打印5,所有GUI窗口也显示为0.0.请帮忙!我对此很陌生.

I have been using this definition to update my labels for my GUI. I recently started to set up serial communication on my GUI using that code. Logically using the mainloop() of the wx library, i thought i could update the 'x' value and get it printed on the GUI. But all the GUI window shows in 0.0 even though the python console prints 5 regularly. Please help! I am pretty new to this.

推荐答案

你的问题是 ser.read() 会阻塞.即使您调整了 serial.Serial 实例的超时时间,它仍然会使 GUI 保持忙碌.在那种情况下,我不知道强制"刷新/wx.Yield() 的方法,它根本行不通.阻塞调用的标准解决方案是启动一个线程或定期轮询(例如使用 wx.Timer).但是,我只能使线程工作.该示例基于 pyserial 中的 wxTerminal.

Your issue is that ser.read() will block. Even if you tweak the timeout of your serial.Serial instance, it still will keep the GUI busy. In that situation I do not know a method to "force" a refresh/wx.Yield(), it simply will not work. The standard solution for blocking calls is to spin up a thread or poll regularily (e. g. with wx.Timer). However, I was only able to make threading work. The example is based on wxTerminal in pyserial.

# -*- coding: utf-8 -*-

import wx
import serial
from threading import Thread

ARDUINO_NEWLINE = '\r\n'

class serial_reader(object):
    def __init__(self, callback=None):
        """Creates serial reader.

        :param callback: callable, gets called when byte on serial arrives.
        """
        self.callback = callback

        self.thread = None

        # Signal if serial is alive and should be read
        self.alive = False

    def start_reader(self, serial_cfg):
        """Start the receiver thread.

        :param serial_cfg: dictionary, gets unpacked to parameters for :class:`serial.Serial`
        """

        self.ser_cfg = serial_cfg
        self.serial = serial.Serial(**serial_cfg)
        # set != None so it will not block for longer than timeout on shutdown
        self.serial.timeout = 0.1
        self.alive = True

        self.thread = Thread(target=self.serial_read)
        self.thread.daemon = True
        self.thread.start()

    def stop_reader(self):
        """Stop the receiver thread, wait util it is finished."""
        if self.thread is not None:
            # signal no more reads
            self.alive = False
            # wait until thread has finished
            self.thread.join()
            self.thread = None

        # cleanup
        self.serial.close()

    def serial_read(self):
        """Thread that handles the incoming traffic."""

        while self.alive:
            try:
                text = self.serial.read()
                if text and self.callback:
                    # return value to main loop in thread-safe manner
                    wx.CallAfter(self.callback, text)
            except serial.serialutil.SerialException:
                # will happen when Windows goes in sleep mode
                print 'serial.serialutil.SerialException'


class ser_frm(wx.Frame):
    def __init__(self, *args, **kwds):
        wx.Frame.__init__(self, *args, **kwds)        
        self.txt = wx.TextCtrl(self, -1, '', style=wx.TE_MULTILINE)

class serial_controller(object):
    def __init__(self, app):
        self.app = app

        # buffer for serial data
        self.ser_buf = ''

        self.frm = ser_frm(None, -1, 'testfrm')

        # setup serial configuration
        self.serial_cfg = {'port': 'COM4', 'baudrate': 9600}        
        # When parameter dsrdtr is set to True, the Arduino
        # will not reset on serial open, for details see
        # http://playground.arduino.cc/Main/DisablingAutoResetOnSerialConnection
        self.serial_cfg['dsrdtr'] = True

        self.ser_rd = serial_reader(callback=self.on_serial)
        tit = 'Arduino on port {port} at baudrate {baudrate}'.format(**self.serial_cfg)
        self.frm.SetTitle(tit)
        self.ser_rd.start_reader(self.serial_cfg)

        self.frm.Show()

        self.frm.Bind(wx.EVT_CLOSE, self.on_close)

    def on_close(self, evt):
        """Shutdown serial read thread before closing."""
        if self.ser_rd.alive:
            self.ser_rd.stop_reader()
        evt.Skip()

    def on_serial(self, text):
        """Handle input from the serial port."""
        self.ser_buf += text
        if self.ser_buf.endswith(ARDUINO_NEWLINE):
            if self.frm.txt.GetInsertionPoint() > 1000:
                self.frm.txt.SetValue('')
            self.frm.txt.AppendText(self.ser_buf)
            self.ser_buf = ''


if __name__ == "__main__":
    app = wx.App(redirect=False)
    serialctr = serial_controller(app)
    app.MainLoop()

编辑:没有必要在带有片上 USB 的 Arduinos 上修改 DSR/DTR(例如 Arduino micro),因此删除该行

EDIT: It is not necessary to tinker with DSR/DTR on Arduinos with USB on chip (e.g. the Arduino micro), so delete the line

self.serial_cfg['dsrdtr'] = True

它仍然可以正常工作.

这篇关于无法在 wxpython GUI 中使用 arduino 串行通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆