树莓派实现串口通信

阅读更多

手上有个CCD Camera(Barcode Reader/Scanner Module),它是通过RS232通信的,用RS232转USB的转接线连接树莓派,即可完成硬件连接。对于串口通信,可以通过pyserial实现。

首先,安装pyserial:

从https://pypi.python.org/pypi/pyserial下载最新版本的安装包,再通过下面的命令完成安装:

[plain]  view plain copy
 
  1. tar zxvf pyserial-2.7.tar.gz  
  2. cd pyserial-2.7  
  3. python setup.py install  

通过命令lsusb查看串口是否存在:

树莓派实现串口通信_第1张图片

通过命令python -m serial.tools.list_ports可以查看大可用的端口:

测试通信:

树莓派实现串口通信_第2张图片

通过以上的准备后,就可以写一个简单的Python程式来实现串口通信:

[python]  view plain copy 在CODE上查看代码片
 
  1. import serial  
  2. from time import sleep  
  3. ser = serial.Serial('/dev/ttyUSB0'9600, timeout=0.5)   
  4. def recv(serial):    
  5.     data  
  6.     while True:    
  7.         data =serial.read(30)    
  8.         if data == '':    
  9.             continue  
  10.         else:  
  11.             break  
  12.         sleep(0.02)   
  13.     return data    
  14. while True:    
  15.     data =recv(ser)    
  16.     ser.write(data)  

 

来自官网的Sample(wxTerminal.py)也很不错,可以通过UI选择和配置端口:

[python]  view plain copy 在CODE上查看代码片
 
  1. #!/usr/bin/env python  
  2. # generated by wxGlade 0.3.1 on Fri Oct 03 23:23:45 2003  
  3.   
  4. #from wxPython.wx import *  
  5. import wx  
  6. import wxSerialConfigDialog  
  7. import serial  
  8. import threading  
  9.   
  10. #----------------------------------------------------------------------  
  11. # Create an own event type, so that GUI updates can be delegated  
  12. # this is required as on some platforms only the main thread can  
  13. # access the GUI without crashing. wxMutexGuiEnter/wxMutexGuiLeave  
  14. # could be used too, but an event is more elegant.  
  15.   
  16. SERIALRX = wx.NewEventType()  
  17. # bind to serial data receive events  
  18. EVT_SERIALRX = wx.PyEventBinder(SERIALRX, 0)  
  19.   
  20. class SerialRxEvent(wx.PyCommandEvent):  
  21.     eventType = SERIALRX  
  22.     def __init__(self, windowID, data):  
  23.         wx.PyCommandEvent.__init__(selfself.eventType, windowID)  
  24.         self.data = data  
  25.   
  26.     def Clone(self):  
  27.         self.__class__(self.GetId(), self.data)  
  28.   
  29. #----------------------------------------------------------------------  
  30.   
  31. ID_CLEAR        = wx.NewId()  
  32. ID_SAVEAS       = wx.NewId()  
  33. ID_SETTINGS     = wx.NewId()  
  34. ID_TERM         = wx.NewId()  
  35. ID_EXIT         = wx.NewId()  
  36.   
  37. NEWLINE_CR      = 0  
  38. NEWLINE_LF      = 1  
  39. NEWLINE_CRLF    = 2  
  40.   
  41. class TerminalSetup:  
  42.     """Placeholder for various terminal settings. Used to pass the 
  43.        options to the TerminalSettingsDialog."""  
  44.     def __init__(self):  
  45.         self.echo = False  
  46.         self.unprintable = False  
  47.         self.newline = NEWLINE_CRLF  
  48.   
  49. class TerminalSettingsDialog(wx.Dialog):  
  50.     """Simple dialog with common terminal settings like echo, newline mode."""  
  51.       
  52.     def __init__(self, *args, **kwds):  
  53.         self.settings = kwds['settings']  
  54.         del kwds['settings']  
  55.         # begin wxGlade: TerminalSettingsDialog.__init__  
  56.         kwds["style"] = wx.DEFAULT_DIALOG_STYLE  
  57.         wx.Dialog.__init__(self, *args, **kwds)  
  58.         self.checkbox_echo = wx.CheckBox(self, -1"Local Echo")  
  59.         self.checkbox_unprintable = wx.CheckBox(self, -1"Show unprintable characters")  
  60.         self.radio_box_newline = wx.RadioBox(self, -1"Newline Handling", choices=["CR only""LF only""CR+LF"], majorDimension=0, style=wx.RA_SPECIFY_ROWS)  
  61.         self.button_ok = wx.Button(self, -1"OK")  
  62.         self.button_cancel = wx.Button(self, -1"Cancel")  
  63.   
  64.         self.__set_properties()  
  65.         self.__do_layout()  
  66.         # end wxGlade  
  67.         self.__attach_events()  
  68.         self.checkbox_echo.SetValue(self.settings.echo)  
  69.         self.checkbox_unprintable.SetValue(self.settings.unprintable)  
  70.         self.radio_box_newline.SetSelection(self.settings.newline)  
  71.   
  72.     def __set_properties(self):  
  73.         # begin wxGlade: TerminalSettingsDialog.__set_properties  
  74.         self.SetTitle("Terminal Settings")  
  75.         self.radio_box_newline.SetSelection(0)  
  76.         self.button_ok.SetDefault()  
  77.         # end wxGlade  
  78.   
  79.     def __do_layout(self):  
  80.         # begin wxGlade: TerminalSettingsDialog.__do_layout  
  81.         sizer_2 = wx.BoxSizer(wx.VERTICAL)  
  82.         sizer_3 = wx.BoxSizer(wx.HORIZONTAL)  
  83.         sizer_4 = wx.StaticBoxSizer(wx.StaticBox(self, -1"Input/Output"), wx.VERTICAL)  
  84.         sizer_4.Add(self.checkbox_echo, 0, wx.ALL, 4)  
  85.         sizer_4.Add(self.checkbox_unprintable, 0, wx.ALL, 4)  
  86.         sizer_4.Add(self.radio_box_newline, 000)  
  87.         sizer_2.Add(sizer_4, 0, wx.EXPAND, 0)  
  88.         sizer_3.Add(self.button_ok, 000)  
  89.         sizer_3.Add(self.button_cancel, 000)  
  90.         sizer_2.Add(sizer_3, 0, wx.ALL|wx.ALIGN_RIGHT, 4)  
  91.         self.SetAutoLayout(1)  
  92.         self.SetSizer(sizer_2)  
  93.         sizer_2.Fit(self)  
  94.         sizer_2.SetSizeHints(self)  
  95.         self.Layout()  
  96.         # end wxGlade  
  97.   
  98.     def __attach_events(self):  
  99.         self.Bind(wx.EVT_BUTTON, self.OnOK, id = self.button_ok.GetId())  
  100.         self.Bind(wx.EVT_BUTTON, self.OnCancel, id = self.button_cancel.GetId())  
  101.       
  102.     def OnOK(self, events):  
  103.         """Update data wil new values and close dialog."""  
  104.         self.settings.echo = self.checkbox_echo.GetValue()  
  105.         self.settings.unprintable = self.checkbox_unprintable.GetValue()  
  106.         self.settings.newline = self.radio_box_newline.GetSelection()  
  107.         self.EndModal(wx.ID_OK)  
  108.       
  109.     def OnCancel(self, events):  
  110.         """Do not update data but close dialog."""  
  111.         self.EndModal(wx.ID_CANCEL)  
  112.   
  113. # end of class TerminalSettingsDialog  
  114.   
  115.   
  116. class TerminalFrame(wx.Frame):  
  117.     """Simple terminal program for wxPython"""  
  118.       
  119.     def __init__(self, *args, **kwds):  
  120.         self.serial = serial.Serial()  
  121.         self.serial.timeout = 0.5   #make sure that the alive event can be checked from time to time  
  122.         self.settings = TerminalSetup() #placeholder for the settings  
  123.         self.thread = None  
  124.         self.alive = threading.Event()                 
  125.         # begin wxGlade: TerminalFrame.__init__  
  126.         kwds["style"] = wx.DEFAULT_FRAME_STYLE  
  127.         wx.Frame.__init__(self, *args, **kwds)  
  128.         self.text_ctrl_output = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE|wx.TE_READONLY)  
  129.           
  130.         # Menu Bar  
  131.         self.frame_terminal_menubar = wx.MenuBar()  
  132.         self.SetMenuBar(self.frame_terminal_menubar)  
  133.         wxglade_tmp_menu = wx.Menu()  
  134.         wxglade_tmp_menu.Append(ID_CLEAR, "&Clear", "", wx.ITEM_NORMAL)  
  135.         wxglade_tmp_menu.Append(ID_SAVEAS, "&Save Text As...", "", wx.ITEM_NORMAL)  
  136.         wxglade_tmp_menu.AppendSeparator()  
  137.         wxglade_tmp_menu.Append(ID_SETTINGS, "&Port Settings...", "", wx.ITEM_NORMAL)  
  138.         wxglade_tmp_menu.Append(ID_TERM, "&Terminal Settings...", "", wx.ITEM_NORMAL)  
  139.         wxglade_tmp_menu.AppendSeparator()  
  140.         wxglade_tmp_menu.Append(ID_EXIT, "&Exit", "", wx.ITEM_NORMAL)  
  141.         self.frame_terminal_menubar.Append(wxglade_tmp_menu, "&File")  
  142.         # Menu Bar end  
  143.   
  144.         self.__set_properties()  
  145.         self.__do_layout()  
  146.         # end wxGlade  
  147.         self.__attach_events()          #register events  
  148.         self.OnPortSettings(None)       #call setup dialog on startup, opens port  
  149.         if not self.alive.isSet():  
  150.             self.Close()  
  151.   
  152.     def StartThread(self):  
  153.         """Start the receiver thread"""          
  154.         self.thread = threading.Thread(target=self.ComPortThread)  
  155.         self.thread.setDaemon(1)  
  156.         self.alive.set()  
  157.         self.thread.start()  
  158.   
  159.     def StopThread(self):  
  160.         """Stop the receiver thread, wait util it's finished."""  
  161.         if self.thread is not None:  
  162.             self.alive.clear()          #clear alive event for thread  
  163.             self.thread.join()          #wait until thread has finished  
  164.             self.thread = None  
  165.           
  166.     def __set_properties(self):  
  167.         # begin wxGlade: TerminalFrame.__set_properties  
  168.         self.SetTitle("Serial Terminal")  
  169.         self.SetSize((546383))  
  170.         # end wxGlade  
  171.   
  172.     def __do_layout(self):  
  173.         # begin wxGlade: TerminalFrame.__do_layout  
  174.         sizer_1 = wx.BoxSizer(wx.VERTICAL)  
  175.         sizer_1.Add(self.text_ctrl_output, 1, wx.EXPAND, 0)  
  176.         self.SetAutoLayout(1)  
  177.         self.SetSizer(sizer_1)  
  178.         self.Layout()  
  179.         # end wxGlade  
  180.   
  181.     def __attach_events(self):  
  182.         #register events at the controls  
  183.         self.Bind(wx.EVT_MENU, self.OnClear, id = ID_CLEAR)  
  184.         self.Bind(wx.EVT_MENU, self.OnSaveAs, id = ID_SAVEAS)  
  185.         self.Bind(wx.EVT_MENU, self.OnExit, id = ID_EXIT)  
  186.         self.Bind(wx.EVT_MENU, self.OnPortSettings, id = ID_SETTINGS)  
  187.         self.Bind(wx.EVT_MENU, self.OnTermSettings, id = ID_TERM)  
  188.         self.text_ctrl_output.Bind(wx.EVT_CHAR, self.OnKey)          
  189.         self.Bind(EVT_SERIALRX, self.OnSerialRead)  
  190.         self.Bind(wx.EVT_CLOSE, self.OnClose)  
  191.   
  192.     def OnExit(self, event):  
  193.         """Menu point Exit"""  
  194.         self.Close()  
  195.   
  196.     def OnClose(self, event):  
  197.         """Called on application shutdown."""  
  198.         self.StopThread()               #stop reader thread  
  199.         self.serial.close()             #cleanup  
  200.         self.Destroy()                  #close windows, exit app  
  201.   
  202.     def OnSaveAs(self, event):  
  203.         """Save contents of output window."""  
  204.         filename = None  
  205.         dlg = wx.FileDialog(None"Save Text As..."".", "", "Text File|*.txt|All Files|*",  wx.SAVE)  
  206.         if dlg.ShowModal() ==  wx.ID_OK:  
  207.             filename = dlg.GetPath()  
  208.         dlg.Destroy()  
  209.           
  210.         if filename is not None:  
  211.             f = file(filename, 'w')  
  212.             text = self.text_ctrl_output.GetValue()  
  213.             if type(text) == unicode:  
  214.                 text = text.encode("latin1")    #hm, is that a good asumption?  
  215.             f.write(text)  
  216.             f.close()  
  217.       
  218.     def OnClear(self, event):  
  219.         """Clear contents of output window."""  
  220.         self.text_ctrl_output.Clear()  
  221.       
  222.     def OnPortSettings(self, event=None):  
  223.         """Show the portsettings dialog. The reader thread is stopped for the 
  224.            settings change."""  
  225.         if event is not None:           #will be none when called on startup  
  226.             self.StopThread()  
  227.             self.serial.close()  
  228.         ok = False  
  229.         while not ok:  
  230.             dialog_serial_cfg = wxSerialConfigDialog.SerialConfigDialog(None, -1, "",  
  231.                 show=wxSerialConfigDialog.SHOW_BAUDRATE|wxSerialConfigDialog.SHOW_FORMAT|wxSerialConfigDialog.SHOW_FLOW,  
  232.                 serial=self.serial  
  233.             )  
  234.             result = dialog_serial_cfg.ShowModal()  
  235.             dialog_serial_cfg.Destroy()  
  236.             #open port if not called on startup, open it on startup and OK too  
  237.             if result == wx.ID_OK or event is not None:  
  238.                 try:  
  239.                     self.serial.open()  
  240.                 except serial.SerialException, e:  
  241.                     dlg = wx.MessageDialog(None, str(e), "Serial Port Error", wx.OK | wx.ICON_ERROR)  
  242.                     dlg.ShowModal()  
  243.                     dlg.Destroy()  
  244.                 else:  
  245.                     self.StartThread()  
  246.                     self.SetTitle("Serial Terminal on %s [%s, %s%s%s%s%s]" % (  
  247.                         self.serial.portstr,  
  248.                         self.serial.baudrate,  
  249.                         self.serial.bytesize,  
  250.                         self.serial.parity,  
  251.                         self.serial.stopbits,  
  252.                         self.serial.rtscts and ' RTS/CTS' or '',  
  253.                         self.serial.xonxoff and ' Xon/Xoff' or '',  
  254.                         )  
  255.                     )  
  256.                     ok = True  
  257.             else:  
  258.                 #on startup, dialog aborted  
  259.                 self.alive.clear()  
  260.                 ok = True  
  261.   
  262.     def OnTermSettings(self, event):  
  263.         """Menu point Terminal Settings. Show the settings dialog 
  264.            with the current terminal settings"""  
  265.         dialog = TerminalSettingsDialog(None, -1, "", settings=self.settings)  
  266.         result = dialog.ShowModal()  
  267.         dialog.Destroy()  
  268.           
  269.     def OnKey(self, event):  
  270.         """Key event handler. if the key is in the ASCII range, write it to the serial port. 
  271.            Newline handling and local echo is also done here."""  
  272.         code = event.GetKeyCode()  
  273.         if code < 256:                          #is it printable?  
  274.             if code == 13:                      #is it a newline? (check for CR which is the RETURN key)  
  275.                 if self.settings.echo:          #do echo if needed  
  276.                     self.text_ctrl_output.AppendText('\n')  
  277.                 if self.settings.newline == NEWLINE_CR:  
  278.                     self.serial.write('\r')     #send CR  
  279.                 elif self.settings.newline == NEWLINE_LF:  
  280.                     self.serial.write('\n')     #send LF  
  281.                 elif self.settings.newline == NEWLINE_CRLF:  
  282.                     self.serial.write('\r\n')   #send CR+LF  
  283.             else:  
  284.                 char = chr(code)  
  285.                 if self.settings.echo:          #do echo if needed  
  286.                     self.text_ctrl_output.WriteText(char)  
  287.                 self.serial.write(char)         #send the charcater  
  288.         else:  
  289.             print "Extra Key:", code  
  290.   
  291.     def OnSerialRead(self, event):  
  292.         """Handle input from the serial port."""  
  293.         text = event.data  
  294.         if self.settings.unprintable:  
  295.             text = ''.join([(c >= ' 'and c or '<%d>' % ord(c)  for c in text])  
  296.         self.text_ctrl_output.AppendText(text)  
  297.   
  298.     def ComPortThread(self):  
  299.         """Thread that handles the incomming traffic. Does the basic input 
  300.            transformation (newlines) and generates an SerialRxEvent"""  
  301.         while self.alive.isSet():               #loop while alive event is true  
  302.             text = self.serial.read(1)          #read one, with timout  
  303.             if text:                            #check if not timeout  
  304.                 n = self.serial.inWaiting()     #look if there is more to read  
  305.                 if n:  
  306.                     text = text + self.serial.read(n) #get it  
  307.                 #newline transformation  
  308.                 if self.settings.newline == NEWLINE_CR:  
  309.                     text = text.replace('\r''\n')  
  310.                 elif self.settings.newline == NEWLINE_LF:  
  311.                     pass  
  312.                 elif self.settings.newline == NEWLINE_CRLF:  
  313.                     text = text.replace('\r\n''\n')  
  314.                 event = SerialRxEvent(self.GetId(), text)  
  315.                 self.GetEventHandler().AddPendingEvent(event)  
  316.                 #~ self.OnSerialRead(text)         #output text in window  
  317.               
  318. # end of class TerminalFrame  
  319.   
  320.   
  321. class MyApp(wx.App):  
  322.     def OnInit(self):  
  323.         wx.InitAllImageHandlers()  
  324.         frame_terminal = TerminalFrame(None, -1, "")  
  325.         self.SetTopWindow(frame_terminal)  
  326.         frame_terminal.Show(1)  
  327.         return 1  
  328.   
  329. # end of class MyApp  
  330.   
  331. if __name__ == "__main__":  
  332.     app = MyApp(0)  
  333.     app.MainLoop()  

你可能感兴趣的:(python,嵌入式)