程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2023-06(1)

Python 之 Serial串口通信

发布于2019-08-07 11:58     阅读(1649)     评论(0)     点赞(2)     收藏(0)


0 Serial方法

1、导入pyserial模块

import serial

2、打开串行口

// 打开串口0, 9600,8N1,连接超时0.5秒
import serial
ser=serial.Serial("/dev/ttyUSB0",9600,timeout=0.5) #使用USB连接串行口
ser=serial.Serial("/dev/ttyAMA0",9600,timeout=0.5) #使用树莓派的GPIO口连接串行口
ser=serial.Serial(1,9600,timeout=0.5)#winsows系统使用com1口连接串行口
ser=serial.Serial(“com1”,9600,timeout=0.5)#winsows系统使用com1口连接串行口
ser=serial.Serial("/dev/ttyS1",9600,timeout=0.5)#Linux系统使用com1口连接串行口
print ser.name#打印设备名称
print ser.port#打印设备名
ser.open() #打开端口
s = ser.read(10)#从端口读10个字节
ser.write(“hello”)#向端口些数据
ser.close()#关闭端口
data = ser.read(20) #是读20个字符
data = ser.readline() #是读一行,以/n结束,要是没有/n就一直读,阻塞。
data = ser.readlines()和ser.xreadlines()#都需要设置超时时间
ser.baudrate = 9600 #设置波特率
ser.isOpen() #看看这个串口是否已经被打开

3、获得串行口状态

串行口的属性:
name:设备名字
portstr:已废弃,用name代替
port:读或者写端口
baudrate:波特率
bytesize:字节大小
parity:校验位
stopbits:停止位
timeout:读超时设置
writeTimeout:写超时
xonxoff:软件流控
rtscts:硬件流控
dsrdtr:硬件流控
interCharTimeout:字符间隔超时

属性的使用方法:
ser=serial.Serial("/dev/ttyAMA0",9600,timeout=0.5)
ser.open()

print ser.name
print ser.port
print ser.baudrate#波特率
print ser.bytesize#字节大小
print ser.parity#校验位N-无校验,E-偶校验,O-奇校验
print ser.stopbits#停止位
print ser.timeout#读超时设置
print ser.writeTimeout#写超时
print ser.xonxoff#软件流控
print ser.rtscts#硬件流控
print ser.dsrdtr#硬件流控
print ser.interCharTimeout#字符间隔超时

ser.close()

4、设置串行口状态

需要用的常量

bytesize:FIVE BITS、SIXBITS、SEVENBITS、EIGHTBITS
parity: PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE
stopbits: STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO
异常:
ValueError:参数错误
SerialException:找不到设备或不能配置

ser.baudrate=9600#设置波特率

ser.bytesize=8#字节大小
ser.bytesize=serial.EiGHTBITS#8位数据位

ser.parity=serial.PARITY_EVEN#偶校验
ser.parity=serial.PARITY_NONE#无校验
ser.parity=serial.PARITY_ODD#奇校验

ser.stopbits=1#停止位
ser.timeout=0.5#读超时设置
ser.writeTimeout=0.5#写超时
ser.xonxoff#软件流控
ser.rtscts#硬件流控
ser.dsrdtr#硬件流控
ser.interCharTimeout#字符间隔超时

5、Readline方法的使用

是读一行,以/n结束,要是没有/n就一直读,阻塞。

使用readline()时应该注意:打开串口时应该指定超时,否则如果串口没有收到新行,则会一直等待。如果没有超时,readline会报异常。

6、serial.Serial类——原生端口

class serial.Serial
{
init(port=None, baudrate=9600, bytesize=EIGHTBITS,parity=PARITY_NONE, stopbits=STOPBITS_ONE, timeout=None, xonxoff=False, rtscts=False, writeTimeout=None, dsrdtr=False, interCharTimeout=None)

#其中:
# bytesize:FIVEBITS、SIXBITS、SEVENBITS、EIGHTBITS
# parity: PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE
# stopbits: STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO
#异常:
#ValueError:参数错误
#SerialException:找不到设备或不能配置

open():打开串口

close():立即关闭串口

del():析构函数

read(size=1):从串口读size个字节。如果指定超时,则可能在超时后返回较少的字节;如果没有指定超时,则会一直等到收完指定的字节数。

write(data):发送data,并返回发送字节数。如果bytes和bytearray可用(python 2.6以上),则接受其作为参数;否则接受str作为参数。
#异常:SerialTimeoutException——配置了写超时并发生超时时发生此异常。

inWaiting():返回接收缓存中的字节数

flush():等待所有数据写出。

flushInput():丢弃接收缓存中的所有数据

flushOutput():终止当前写操作,并丢弃发送缓存中的数据。

sendBreadk(duration=0.25):发送BREAK条件,并于duration时间之后返回IDLE

setBreak(level=True):根据level设置break条件。

setRTS(level=True)

setDTR(level=True)

getCTS()

getDSR()

getRI()

getCD()

#只读属性:
name:设备名字
portstr:已废弃,用name代替
port:读或者写端口
baudrate:波特率
bytesize:字节大小
parity:校验位
stopbits:停止位
timeout:读超时设置
writeTimeout:写超时
xonxoff:软件流控
rtscts:硬件流控
dsrdtr:硬件流控
interCharTimeout:字符间隔超时

#端口设置可以被读入字典,也可从字典加载设置:
getSettingDict():返回当前串口设置的字典
applySettingDict(d):应用字典到串口设置

#对提供io库的系统(python 2.6或以上),Serial从io.RawIOBase派生。对其它系统,从FileLike派生。

#异常:
exception serial.SerialException
exception serial.SerialTimeoutException

#常量:
serial.VERSION:pyserial版本

#模块函数和属性:
serial.device(number)

serial.serial_for_url(url, *args, **kwargs)

serial.protocol_handler_packages()

serial.to_bytes(sequence):接收一个字符串或整数列表sequence,返回bytes实例

1 确定串口名称

1.1 WINDOWS

获取可用串口列表

#!/usr/bin/env python
#-*- coding: utf-8 -*
import serial
import serial.tools.list_ports

plist = list(serial.tools.list_ports.comports())

if len(plist) <= 0:
    print ("The Serial port can't find!")
else:
    plist_0 =list(plist[0])
    serialName = plist_0[0]
    serialFd = serial.Serial(serialName,9600,timeout = 60)
    print ("check which port was really used >",serialFd.name)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这里插入图片描述

import serial #导入模块

import serial.tools.list_ports
port_list = list(serial.tools.list_ports.comports())
print(port_list)
if len(port_list) == 0:
   print('无可用串口')
else:
    for i in range(0,len(port_list)):
        print(port_list[i])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
1.2 LINUX

查询从系统启动到现在串口插拔的信息,显示串口Ubuntu连接的端口号:

在终端输入:

dmesg | grep ttyS*

在这里插入图片描述
在这里插入图片描述

在Ubuntu下装了CuteCom,但当打开 /dev/ttyUSB0 时,总提示错误,打开失败时:

用 Minicom 可以正常读取 ttyUSB0。

sudo chmod 666 /dev/ttyUSB0

这样修改后, CuteCom 就可以正常打开 USB 串口了

1,pycharm程序端代码。


#usr/bin/python3
# -*- coding: utf-8 -*-
import serial
from time import sleep
 
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=0.5)
 
 
def recv(serial):
        global 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)
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

在pycharm上的程序:

在这里插入图片描述

程序效果为: 运行后,在CuteCom发生的代码, 程序这边会原文返回发给CuteCom。

1.3 Python(Linux下)获取串口的idv和idp以及serial序列号

串口端口的获取脚本

# coding=utf-8
#

__author__ = 'Haleydu'
__editTime__ = '2018.12.7'

import serial.tools.list_ports
import serial
import os
import re

class AutoMatchSerialPort:
    #一.获取串口 or 判断是否存在该串口
    def getSerial(self,needdev=''):
        needSerial=''
        port_list = list(serial.tools.list_ports.comports())
        if len(port_list) <= 0:
            print ("The Serial port can't find!")
        else:
        #1.过滤,获取需要的串口
            for i in list(port_list):
                if i.name==needdev:
                    needSerial=i.name
                print(i.name,end=',')
            print('\n')
        #2.返回获取的目的串口为了绑定
        return needSerial

   # 二.根据端口号返回ID号和硬件号
    def getSerialIDAndSer(self,dev):
        cmd = "udevadm info --attribute-walk --name=" + dev
        result = self.execCmd(cmd)
        pat1 = "ATTRS{idVendor}==.?(\d\d\d\d).?"
        pat2 = "ATTRS{idProduct}==.?(\d\d\d\d).?"
        pat3 = 'ATTRS{serial}==.([A-Za-z0-9]+).'
        ret1 = re.search(pat1,result)
        ret2 = re.search(pat2,result)
        ret3 = re.search(pat3,result)
        idv = ret1.group(1)
        idp = ret2.group(1)
        ser = ret3.group(1)
        return idv,idp,ser

    # 三.根据ID号或者序列号返回串口的端口号,也可以用别名直接调用该串口(运行后需要拔插目的串口后生效)
    def getSerialPort(self,idv='',idp='',ser='',alias='ttyUSB_test'):
        if idv==''or idp=='':
            contentID = 'ATTRS{serial}=="'+ser+', MODE:="0777", SYMLINK+="'+ alias +'" \n'
        elif ser=='':
            contentID = '", ATTRS{idVendor}=="'+idv+'", ATTRS{idProduct}=="'+idp+'", MODE:="0777", SYMLINK+="'+ alias +'" \n'
        else:
            contentID = 'ATTRS{serial}=="'+ser+'", ATTRS{idVendor}=="'+idv+'", ATTRS{idProduct}=="'+idp+'", MODE:="0777", SYMLINK+="'+ alias +'" \n'

        path='/etc/udev/rules.d/getSerialPort_'+alias+'.rules'
        if os.path.exists(path):
            #print('存在文件')
            f = open(path,"w")
            f.write(contentID)
            f.flush()
            f.close()
            #print('创建成功')
            #print('重新拔插串口后生效')
        else:
            #print('不存在文件,开始创建getSerialPort_'+alias+'.rules的udev规则文件')
            f = open(path,"w")
            f.write(contentID)
            f.flush()
            f.close()
            #print('创建成功')
            #print('重新拔插串口后生效')
        #重启udev规则
        #sudo /etc/init.d/udev restart
        #根据ID获得端口号
        cmd = "udevadm info --attribute-walk --name=" + alias
        result = self.execCmd(cmd)
        pat = '(ttyUSB.)'
        ret = re.search(pat,result)
        dev=''
        try:
            dev = ret.group(1)
        except AttributeError:
            if dev=='':
                print('重新拔插串口后生效')
        return dev


    #调用终端,获取终端输出
    def execCmd(self,cmd):  
        r = os.popen(cmd)  
        result = r.read()  
        r.close()  
        return result  

if __name__ == '__main__':
    am=AutoMatchSerialPort()
    am.getSerial()
    print('ttyUSB0:' + str(am.getSerialIDAndSer("ttyUSB0")))
    print('ttyUSB1:' + str(am.getSerialIDAndSer("ttyUSB1")))
    print('0403:6002,FT2NPXY4,ttyUSB_1:' + am.getSerialPort('0403','6002','FT2NPXY4','ttyUSB_1'))
    print('0403:6001,FTSYWCXZ,ttyUSB_2:' + am.getSerialPort('0403','6001','FTSYWCXZ','ttyUSB_2'))
    


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102

2 SERIAL 串口操作

参考文档:
https://blog.csdn.net/qq_14997473/article/details/80875722:Python学习笔记——串口配置以及发送数据

https://blog.csdn.net/ubuntu14/article/details/75335106:python实现串口自动触发工作

(1) 安装pyserial库

pip install pyserial
  • 1

serial = serial.Serial(‘COM1’, 115200) 打开COM1并设置波特率为115200,COM1只适用于Windows
serial = serial.Serial(‘/dev/ttyS0’, 115200) 打开/dev/ttyS0并设置波特率为115200, 只适用于Linux

(2) pyserial库常用函数介绍
serial = serial.Serial(‘COM1’, 115200) 打开COM1并设置波特率为115200,COM1只适用于Windows

serial = serial.Serial(‘/dev/ttyS0’, 115200) 打开/dev/ttyS0并设置波特率为115200, 只适用于Linux

print serial .portstr 能看到第一个串口的标识

serial .write(“hello”) 往串口里面写数据

serial .close() 关闭serial 表示的串口

serial .open() 打开串口

data = serial .read(num) 读num个字符

data = serial .readline() 读一行数据,以/n结束,要是没有/n就一直读,阻塞。

serial .baudrate = 9600 设置波特率

print serial 可查看当前串口的状态信息

serial .isOpen() 当前串口是否已经打开

serial.inWaiting() 判断当前接收的数据

serial.flushInput() 清除输入缓冲区数据

serial.flushOutput() 中止当前输出并清除输出缓冲区数据
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
(3) 实例: 获取从其他串口发送来的数据并回显
#!/usr/bin/python 
# coding=UTF-8 
import serial 
################################################### 
# 
# 功 能: 将接收到的数据已hex显示 
# 参 数: 串口接受到的数据 
# 返 回: 转换后的数据 
# 
################################################### 
def hexshow(data): 
  hex_data = '' hLen = len(data) 

  for i in xrange(hLen): 
    hvol = ord(data[i]) 
    hhex = '%02x' % hvol 
    hex_data += hhex+' '

  print 'hexshow:', hex_data 
################################################### 
# 
# 功 能: 将需要发送的字符串以hex形式发送 
# 参 数: 待发送的数据 
# 返 回: 转换后的数据 
# 
################################################### 
def hexsend(string_data=''): 
  hex_data = string_data.decode("hex") 
  return hex_data 

if __name__ == '__main__': 
  serial = serial.Serial('/dev/ttyS0', 115200) 
  print serial 

  if serial.isOpen(): 
    print("open success") 
  else: 
    print("open failed") 


  try: 

    while True: 
      count = serial.inWaiting() 
      if count > 0: 
        data = serial.read(count) 
        if data != b'': 
          print("receive:", data) 
          serial.write(data) 
        else: 
          serial.write(hexsend(data)) 

  except KeyboardInterrupt: 
    if serial != None: 
      serial.close()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
16进制处理
import serial #导入模块
try:
  portx="COM3"
  bps=115200
  #超时设置,None:永远等待操作,0为立即返回请求结果,其他值为等待超时时间(单位为秒)
  timex=None
  ser=serial.Serial(portx,bps,timeout=timex)
  print("串口详情参数:", ser)

  #十六进制的发送
  result=ser.write(chr(0x06).encode("utf-8"))#写数据
  print("写总字节数:",result)

  #十六进制的读取
  print(ser.read().hex())#读一个字节

  print("---------------")
  ser.close()#关闭串口

except Exception as e:
    print("---异常---:",e)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
其他
import serial #导入模块
try:

  #端口,GNU / Linux上的/ dev / ttyUSB0 等 或 Windows上的 COM3 等
  portx="COM3"
  #波特率,标准值之一:50,75,110,134,150,200,300,600,1200,1800,2400,4800,9600,19200,38400,57600,115200
  bps=115200
  #超时设置,None:永远等待操作,0为立即返回请求结果,其他值为等待超时时间(单位为秒)
  timex=5
  # 打开串口,并得到串口对象
  ser=serial.Serial(portx,bps,timeout=timex)
  print("串口详情参数:", ser)



  print(ser.port)#获取到当前打开的串口名
  print(ser.baudrate)#获取波特率

  result=ser.write("我是东小东".encode("gbk"))#写数据
  print("写总字节数:",result)


  #print(ser.read())#读一个字节
  # print(ser.read(10).decode("gbk"))#读十个字节
  #print(ser.readline().decode("gbk"))#读一行
  #print(ser.readlines())#读取多行,返回列表,必须匹配超时(timeout)使用
  #print(ser.in_waiting)#获取输入缓冲区的剩余字节数
  #print(ser.out_waiting)#获取输出缓冲区的字节数

  #循环接收数据,此为死循环,可用线程实现
  while True:
         if ser.in_waiting:
             str=ser.read(ser.in_waiting ).decode("gbk")
             if(str=="exit"):#退出标志
                 break
             else:
               print("收到数据:",str)

  print("---------------")
  ser.close()#关闭串口


except Exception as e:
    print("---异常---:",e)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

3 解决 ImportError: No module named ‘serial’ 问题

在pycharm里编写Python串口程序的时候,编译时提示 ImportError: No module named ‘serial’

解决办法:

安装 serial module
这里区分python2和 python3:

首先需要在终端输入:

sudo apt install python-pip //python2
sudo apt install python3-pip    //python3
  • 1
  • 2

在这里插入图片描述
安装python3的 pip3的时候,如果时国内的软件源可能安装不上,(当时用中国科学技术大学的软件源,python3-pip下载有问题),换成ubuntu官网成功下载。

如果系统已经安装过了pip,就不需要这一步了。
然后通过:

pip install pyserial    //python2
pip3 install pyserial   //python3
  • 1
  • 2

在这里插入图片描述

可以从pyserial下载这里去获取源码进行熟悉和学习。

4 PYCHARM 里面的no module name serial错误

在这里插入图片描述
错误原因在于:==interpreter的选择==
在这里插入图片描述

安装目录下的python,其模块只有一个setuptools,所以找不到serial
在这里插入图片描述
ANACONDA下的python.exe里面包含了多个模块,所以应该将interpreter改为该目录下的python.exe

5 TypeError: ‘bool’ object is not callable

因为 isOpen是属性所以有如下做法

 def isOpen(self):
        return True

  def is_active(self):
        return True

  def is_anonymous(self):
        return False
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

不是方法,将sOpen()括号去掉,完美解决!



所属网站分类: 技术文章 > 博客

作者:djhsj7

链接:https://www.pythonheidong.com/blog/article/10550/4e8a9320da97fb0c1c92/

来源:python黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

2 0
收藏该文
已收藏

评论内容:(最多支持255个字符)