1. 程式人生 > >樹莓派+Python+pyserial 2.7實現串列埠通訊

樹莓派+Python+pyserial 2.7實現串列埠通訊

手上有個CCD Camera(Barcode Reader/Scanner Module),它是通過RS232通訊的,用RS232轉USB的轉接線連線樹莓派,即可完成硬體連線。對於串列埠通訊,可以通過pyserial實現。

首先,安裝pyserial:

tar zxvf pyserial-2.7.tar.gz
cd pyserial-2.7
python setup.py install

通過命令lsusb檢視串列埠是否存在:

通過命令python -m serial.tools.list_ports可以檢視大可用的埠:

測試通訊:

通過以上的準備後,就可以寫一個簡單的Python程式來實現串列埠通訊:

import serial
from time import sleep
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=0.5) 
def recv(serial):  
    data
    while True:  
        data =serial.read(30)  
        if data == '':  
            continue
        else:
            break
        sleep(0.02) 
    return data  
while True:  
    data =recv(ser)  
    ser.write(data)

來自官網的Sample(wxTerminal.py)也很不錯,可以通過UI選擇和配置埠:

#!/usr/bin/env python
# generated by wxGlade 0.3.1 on Fri Oct 03 23:23:45 2003

#from wxPython.wx import *
import wx
import wxSerialConfigDialog
import serial
import threading

#----------------------------------------------------------------------
# Create an own event type, so that GUI updates can be delegated
# this is required as on some platforms only the main thread can
# access the GUI without crashing. wxMutexGuiEnter/wxMutexGuiLeave
# could be used too, but an event is more elegant.

SERIALRX = wx.NewEventType()
# bind to serial data receive events
EVT_SERIALRX = wx.PyEventBinder(SERIALRX, 0)

class SerialRxEvent(wx.PyCommandEvent):
    eventType = SERIALRX
    def __init__(self, windowID, data):
        wx.PyCommandEvent.__init__(self, self.eventType, windowID)
        self.data = data

    def Clone(self):
        self.__class__(self.GetId(), self.data)

#----------------------------------------------------------------------

ID_CLEAR        = wx.NewId()
ID_SAVEAS       = wx.NewId()
ID_SETTINGS     = wx.NewId()
ID_TERM         = wx.NewId()
ID_EXIT         = wx.NewId()

NEWLINE_CR      = 0
NEWLINE_LF      = 1
NEWLINE_CRLF    = 2

class TerminalSetup:
    """Placeholder for various terminal settings. Used to pass the
       options to the TerminalSettingsDialog."""
    def __init__(self):
        self.echo = False
        self.unprintable = False
        self.newline = NEWLINE_CRLF

class TerminalSettingsDialog(wx.Dialog):
    """Simple dialog with common terminal settings like echo, newline mode."""
    
    def __init__(self, *args, **kwds):
        self.settings = kwds['settings']
        del kwds['settings']
        # begin wxGlade: TerminalSettingsDialog.__init__
        kwds["style"] = wx.DEFAULT_DIALOG_STYLE
        wx.Dialog.__init__(self, *args, **kwds)
        self.checkbox_echo = wx.CheckBox(self, -1, "Local Echo")
        self.checkbox_unprintable = wx.CheckBox(self, -1, "Show unprintable characters")
        self.radio_box_newline = wx.RadioBox(self, -1, "Newline Handling", choices=["CR only", "LF only", "CR+LF"], majorDimension=0, style=wx.RA_SPECIFY_ROWS)
        self.button_ok = wx.Button(self, -1, "OK")
        self.button_cancel = wx.Button(self, -1, "Cancel")

        self.__set_properties()
        self.__do_layout()
        # end wxGlade
        self.__attach_events()
        self.checkbox_echo.SetValue(self.settings.echo)
        self.checkbox_unprintable.SetValue(self.settings.unprintable)
        self.radio_box_newline.SetSelection(self.settings.newline)

    def __set_properties(self):
        # begin wxGlade: TerminalSettingsDialog.__set_properties
        self.SetTitle("Terminal Settings")
        self.radio_box_newline.SetSelection(0)
        self.button_ok.SetDefault()
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: TerminalSettingsDialog.__do_layout
        sizer_2 = wx.BoxSizer(wx.VERTICAL)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_4 = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Input/Output"), wx.VERTICAL)
        sizer_4.Add(self.checkbox_echo, 0, wx.ALL, 4)
        sizer_4.Add(self.checkbox_unprintable, 0, wx.ALL, 4)
        sizer_4.Add(self.radio_box_newline, 0, 0, 0)
        sizer_2.Add(sizer_4, 0, wx.EXPAND, 0)
        sizer_3.Add(self.button_ok, 0, 0, 0)
        sizer_3.Add(self.button_cancel, 0, 0, 0)
        sizer_2.Add(sizer_3, 0, wx.ALL|wx.ALIGN_RIGHT, 4)
        self.SetAutoLayout(1)
        self.SetSizer(sizer_2)
        sizer_2.Fit(self)
        sizer_2.SetSizeHints(self)
        self.Layout()
        # end wxGlade

    def __attach_events(self):
        self.Bind(wx.EVT_BUTTON, self.OnOK, id = self.button_ok.GetId())
        self.Bind(wx.EVT_BUTTON, self.OnCancel, id = self.button_cancel.GetId())
    
    def OnOK(self, events):
        """Update data wil new values and close dialog."""
        self.settings.echo = self.checkbox_echo.GetValue()
        self.settings.unprintable = self.checkbox_unprintable.GetValue()
        self.settings.newline = self.radio_box_newline.GetSelection()
        self.EndModal(wx.ID_OK)
    
    def OnCancel(self, events):
        """Do not update data but close dialog."""
        self.EndModal(wx.ID_CANCEL)

# end of class TerminalSettingsDialog


class TerminalFrame(wx.Frame):
    """Simple terminal program for wxPython"""
    
    def __init__(self, *args, **kwds):
        self.serial = serial.Serial()
        self.serial.timeout = 0.5   #make sure that the alive event can be checked from time to time
        self.settings = TerminalSetup() #placeholder for the settings
        self.thread = None
        self.alive = threading.Event()               
        # begin wxGlade: TerminalFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.text_ctrl_output = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE|wx.TE_READONLY)
        
        # Menu Bar
        self.frame_terminal_menubar = wx.MenuBar()
        self.SetMenuBar(self.frame_terminal_menubar)
        wxglade_tmp_menu = wx.Menu()
        wxglade_tmp_menu.Append(ID_CLEAR, "&Clear", "", wx.ITEM_NORMAL)
        wxglade_tmp_menu.Append(ID_SAVEAS, "&Save Text As...", "", wx.ITEM_NORMAL)
        wxglade_tmp_menu.AppendSeparator()
        wxglade_tmp_menu.Append(ID_SETTINGS, "&Port Settings...", "", wx.ITEM_NORMAL)
        wxglade_tmp_menu.Append(ID_TERM, "&Terminal Settings...", "", wx.ITEM_NORMAL)
        wxglade_tmp_menu.AppendSeparator()
        wxglade_tmp_menu.Append(ID_EXIT, "&Exit", "", wx.ITEM_NORMAL)
        self.frame_terminal_menubar.Append(wxglade_tmp_menu, "&File")
        # Menu Bar end

        self.__set_properties()
        self.__do_layout()
        # end wxGlade
        self.__attach_events()          #register events
        self.OnPortSettings(None)       #call setup dialog on startup, opens port
        if not self.alive.isSet():
            self.Close()

    def StartThread(self):
        """Start the receiver thread"""        
        self.thread = threading.Thread(target=self.ComPortThread)
        self.thread.setDaemon(1)
        self.alive.set()
        self.thread.start()

    def StopThread(self):
        """Stop the receiver thread, wait util it's finished."""
        if self.thread is not None:
            self.alive.clear()          #clear alive event for thread
            self.thread.join()          #wait until thread has finished
            self.thread = None
        
    def __set_properties(self):
        # begin wxGlade: TerminalFrame.__set_properties
        self.SetTitle("Serial Terminal")
        self.SetSize((546, 383))
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: TerminalFrame.__do_layout
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_1.Add(self.text_ctrl_output, 1, wx.EXPAND, 0)
        self.SetAutoLayout(1)
        self.SetSizer(sizer_1)
        self.Layout()
        # end wxGlade

    def __attach_events(self):
        #register events at the controls
        self.Bind(wx.EVT_MENU, self.OnClear, id = ID_CLEAR)
        self.Bind(wx.EVT_MENU, self.OnSaveAs, id = ID_SAVEAS)
        self.Bind(wx.EVT_MENU, self.OnExit, id = ID_EXIT)
        self.Bind(wx.EVT_MENU, self.OnPortSettings, id = ID_SETTINGS)
        self.Bind(wx.EVT_MENU, self.OnTermSettings, id = ID_TERM)
        self.text_ctrl_output.Bind(wx.EVT_CHAR, self.OnKey)        
        self.Bind(EVT_SERIALRX, self.OnSerialRead)
        self.Bind(wx.EVT_CLOSE, self.OnClose)

    def OnExit(self, event):
        """Menu point Exit"""
        self.Close()

    def OnClose(self, event):
        """Called on application shutdown."""
        self.StopThread()               #stop reader thread
        self.serial.close()             #cleanup
        self.Destroy()                  #close windows, exit app

    def OnSaveAs(self, event):
        """Save contents of output window."""
        filename = None
        dlg = wx.FileDialog(None, "Save Text As...", ".", "", "Text File|*.txt|All Files|*",  wx.SAVE)
        if dlg.ShowModal() ==  wx.ID_OK:
            filename = dlg.GetPath()
        dlg.Destroy()
        
        if filename is not None:
            f = file(filename, 'w')
            text = self.text_ctrl_output.GetValue()
            if type(text) == unicode:
                text = text.encode("latin1")    #hm, is that a good asumption?
            f.write(text)
            f.close()
    
    def OnClear(self, event):
        """Clear contents of output window."""
        self.text_ctrl_output.Clear()
    
    def OnPortSettings(self, event=None):
        """Show the portsettings dialog. The reader thread is stopped for the
           settings change."""
        if event is not None:           #will be none when called on startup
            self.StopThread()
            self.serial.close()
        ok = False
        while not ok:
            dialog_serial_cfg = wxSerialConfigDialog.SerialConfigDialog(None, -1, "",
                show=wxSerialConfigDialog.SHOW_BAUDRATE|wxSerialConfigDialog.SHOW_FORMAT|wxSerialConfigDialog.SHOW_FLOW,
                serial=self.serial
            )
            result = dialog_serial_cfg.ShowModal()
            dialog_serial_cfg.Destroy()
            #open port if not called on startup, open it on startup and OK too
            if result == wx.ID_OK or event is not None:
                try:
                    self.serial.open()
                except serial.SerialException, e:
                    dlg = wx.MessageDialog(None, str(e), "Serial Port Error", wx.OK | wx.ICON_ERROR)
                    dlg.ShowModal()
                    dlg.Destroy()
                else:
                    self.StartThread()
                    self.SetTitle("Serial Terminal on %s [%s, %s%s%s%s%s]" % (
                        self.serial.portstr,
                        self.serial.baudrate,
                        self.serial.bytesize,
                        self.serial.parity,
                        self.serial.stopbits,
                        self.serial.rtscts and ' RTS/CTS' or '',
                        self.serial.xonxoff and ' Xon/Xoff' or '',
                        )
                    )
                    ok = True
            else:
                #on startup, dialog aborted
                self.alive.clear()
                ok = True

    def OnTermSettings(self, event):
        """Menu point Terminal Settings. Show the settings dialog
           with the current terminal settings"""
        dialog = TerminalSettingsDialog(None, -1, "", settings=self.settings)
        result = dialog.ShowModal()
        dialog.Destroy()
        
    def OnKey(self, event):
        """Key event handler. if the key is in the ASCII range, write it to the serial port.
           Newline handling and local echo is also done here."""
        code = event.GetKeyCode()
        if code < 256:                          #is it printable?
            if code == 13:                      #is it a newline? (check for CR which is the RETURN key)
                if self.settings.echo:          #do echo if needed
                    self.text_ctrl_output.AppendText('\n')
                if self.settings.newline == NEWLINE_CR:
                    self.serial.write('\r')     #send CR
                elif self.settings.newline == NEWLINE_LF:
                    self.serial.write('\n')     #send LF
                elif self.settings.newline == NEWLINE_CRLF:
                    self.serial.write('\r\n')   #send CR+LF
            else:
                char = chr(code)
                if self.settings.echo:          #do echo if needed
                    self.text_ctrl_output.WriteText(char)
                self.serial.write(char)         #send the charcater
        else:
            print "Extra Key:", code

    def OnSerialRead(self, event):
        """Handle input from the serial port."""
        text = event.data
        if self.settings.unprintable:
            text = ''.join([(c >= ' ') and c or '<%d>' % ord(c)  for c in text])
        self.text_ctrl_output.AppendText(text)

    def ComPortThread(self):
        """Thread that handles the incomming traffic. Does the basic input
           transformation (newlines) and generates an SerialRxEvent"""
        while self.alive.isSet():               #loop while alive event is true
            text = self.serial.read(1)          #read one, with timout
            if text:                            #check if not timeout
                n = self.serial.inWaiting()     #look if there is more to read
                if n:
                    text = text + self.serial.read(n) #get it
                #newline transformation
                if self.settings.newline == NEWLINE_CR:
                    text = text.replace('\r', '\n')
                elif self.settings.newline == NEWLINE_LF:
                    pass
                elif self.settings.newline == NEWLINE_CRLF:
                    text = text.replace('\r\n', '\n')
                event = SerialRxEvent(self.GetId(), text)
                self.GetEventHandler().AddPendingEvent(event)
                #~ self.OnSerialRead(text)         #output text in window
            
# end of class TerminalFrame


class MyApp(wx.App):
    def OnInit(self):
        wx.InitAllImageHandlers()
        frame_terminal = TerminalFrame(None, -1, "")
        self.SetTopWindow(frame_terminal)
        frame_terminal.Show(1)
        return 1

# end of class MyApp

if __name__ == "__main__":
    app = MyApp(0)
    app.MainLoop()

相關推薦

樹莓+Python+pyserial 2.7實現串列通訊

手上有個CCD Camera(Barcode Reader/Scanner Module),它是通過RS232通訊的,用RS232轉USB的轉接線連線樹莓派,即可完成硬體連線。對於串列埠通訊,可以通過pyserial實現。 首先,安裝pyserial: tar zxvf

樹莓3B+ 安裝系統;搭建python,opencv環境;實現串列通訊

一:安裝系統 二:通過VNC訪問樹莓派(無線和有線) 1.樹莓派設定 安裝vnc sudo apt-get update sudo apt-get install tightvncserver 設定vnc密碼(一定要設定,要不然無法

ros系統下通過pyserial模組實現串列通訊Python

經過幾天的摸索終於實現了: 在ros系統下,訂閱Twist/cmd_vel 訊息,經過USB轉串列埠通訊,實現了通過燈帶實時反映小車(差速)執行狀態的功能。 通訊部分主要依賴pyserial模組的功能實現。 #!/usr/bin/env python #codi

樹莓3B在Qt下使用串列傳送資料

一、解除串口占用 使用putty的時候神奇的發現樹莓派竟然是支援serial進行操作。試了試,和在ssh下使用沒有多少區別,速度也很快。 樹莓派的串列埠主要也就是被這個佔用了,配置釋放之後才能使用它來進行串列埠通訊。 在命令列裡輸入如下指令:

C++實現串列通訊上位機軟體

串列埠使用的是RS232匯流排進行通訊,通訊方式是半雙工。有兩種方式可以實現串列埠通訊,一種是通過ActiveX控制元件這種方法程式簡單,但欠靈活。第二個是可以通過呼叫Windows的API函式,本例程通過第二種方式。 一般通過四步來完成通訊(1)開啟串列埠(2)配置串列埠(3)讀寫串列埠(4)

【C語言實現串列通訊知識點整理(四)】關於執行緒和程序

轉載:https://www.cnblogs.com/fuchongjundream/p/3829508.html 因為在外部檔案中呼叫結構體沒有用extern修飾,導致獲取不到正確的值,一直糾結線上程上。現在大概總結執行緒和程序的特點: 概念 1、程序(process) 狹義定義:

【C語言實現串列通訊知識點整理(三)】串列開啟、設定資料成功後進行資料讀寫

int OpenDev(char *Dev) { int fd = open(Dev,O_RDWR | O_NOCTTY | O_NONBLOCK); if(-1 == fd) { perror("Can't Open Serial Port"); return -1;

【C語言實現串列通訊知識點整理(二)】遇到的問題整理(待續....)

1.c編譯錯誤--error:stray \357 in program UTF-8編碼問題。UTF-8編碼有BOM和無BOM格式。BOM,ByteOrderMark(位元組標記順序),表明使用UTF8來進行編碼。UTF-8的BOM通常為3個位元組EF BB BF。轉換成對應的字元檢視,就是‘\

【C語言實現串列通訊知識點整理(一)】執行緒、開啟串列、設定波特率、設定校驗位、互斥鎖等實現基本的通訊

  部分程式碼借鑑地址:https://blog.csdn.net/wangqingchuan92/article/details/73497354/ 謝謝! 1.建立執行緒線上程內進行串列埠之間的收發 void CREAT_pthread(void) { pthr

VC中實現串列通訊的摸索過程

串列埠通訊對於需要進行嵌入式開發的小夥伴們來說是必不可少的,甚至說是無法迴避的。而VC卻又不像C#或者QT那樣人性化,沒有自帶串列埠類(貌似VC6時代還有一個串列埠控制元件可以下載然後通過安裝到VC6中),所以我們不得不到處尋找開源的串列埠通訊程式碼。 這裡我找到的是CSerialPor

基於C#實現串列通訊Demo

https://www.cnblogs.com/Zed-H/p/8651882.html 1.基本概念   2.前端winForm佈局如下(僅僅為了實現功能,佈局略醜)   3.程式碼實現如下 1 nam

MFC串列通訊(二)——使用MSComm控制元件實現串列通訊

  由於專案需要,最近在寫一個簡單的串列埠通訊,基於MFC框架,寫完之後特此回顧記錄一下學習的過程: 串列埠通訊主體框架 (1) 初始化介面(自動獲取全部可用串列埠) (2) 開啟串列埠 (讀取串列埠號,初始化串列埠引數(波特率、校驗位、資料位等),若

windows純C++實現串列通訊

點h檔案 #ifndef _WZSERIALPORT_H #define _WZSERIALPORT_H #include <iostream> using namespace std; /* 作者:歐陽偉 日期:2017-12-14 類名:WZ

Qt實踐(二)——實現串列通訊

如果用Qt寫程式作為上位機,然後通過和usb和下位機通訊的時候,就需要用到Qt中的串列埠通訊了。 使用Qt中的串列埠通訊的時候需要用到的兩個標頭檔案分別為: #include <QtSerialPort/QSerialPort> #include <Qt

Arduino與MATLAB實現串列通訊來畫圖

自己編好Arduino的程式,需要在MATLAB中呼叫串列埠,讀取資料,我們就需要用到MATLAB中的串列埠物件serial。 比如讀取感測器的值來繪圖、處理攝像頭等等。 簡單的讀取感測器的電壓值 Arduino程式 int analogPin = 5;

Labview VISA實現串列通訊例項講解 轉

1.安裝VISA驅動 VISA驅動不含在軟體包中,必須要自己去下載。 VISA(Virtual Instrument Software Architecture,簡稱為"Visa"),即虛擬儀器軟體結構,是VXI plug&play聯盟制定的I/O介面軟體標準及其規

Python】_pyserial模組_串列通訊

(一)serial模組安裝 Windows開啟cmd,用pip安裝pyserial: pip install pyserial (二)檢視COM口工具 vspd:一款本地虛擬串列埠的軟體(需要破解版) 下載後執行exe檔案,用dll檔案貼上複製掉原始檔,完成破

用C語言實現串列通訊程式

1. 首先安裝虛擬串列埠vspd軟體,用於建立虛擬串列埠進行互聯除錯2.開啟vspd軟體,選擇COM1和COM4,點選Add pair,把COM1和COM4互聯3.開啟虛擬串列埠助手,設定串列埠號為COM1,波特率為19200,其他設定使用預設值,點選連線4.用C語言編寫串列

在ubuntu下利用minicom實現串列通訊

    windos有串列埠除錯助手,linux下也有這樣的工具——minicom。不過,minicom和linux下的許多工具都一樣,也是命令列模式,沒有圖形化介面供我們享受。作為一款串列埠除錯工具,雖然難看但總比沒有的好。     為什麼linux下的工具都這麼的簡樸,沒什麼華麗的介面,好像回到瞭解放前

在C#中使用SerialPort類實現串列通訊

表1                                                      SerialPort類的常用屬性 名  稱 說  明 BaseStream 獲取 SerialPort 物件的基礎 Stream 物件 Ba