【问题标题】:Python serial, losing data after switching baudratePython串口,切换波特率后丢失数据
【发布时间】:2015-11-26 17:19:41
【问题描述】:

我尝试使用 python 的串行模块(以及带有光学读取头的 USB 到串行转换器 (FTDI)。它使用 IEC 62056-21 中描述的协议)读取公用事业仪表。已知该设置可与其他软件一起使用。

在以 300bit/s 发送 b'/?!\r\n' 后,仪表响应制造商、固件版本和切换通信速度的建议。所以程序确认速度并请求“数据读取模式”<ack>050<CR><LF>,其中 5 是速度 9600。然后程序切换波特率。

在波特率切换之前一切都很好。正常行为是仪表发送以<STX> 开头并以<ETX> 结尾并包含以<CR><LF> 结尾的几行文本的数据帧。
但是缺少大约 9 行文本。该程序在第 9 行或第 10 行中间的某个地方赶上。有时我会得到一长串 Null 字节。
这是代码(我留下了一些测试遗留下来的cmets):

import serial
import re
from time import sleep

def readframe():
    buf=b''
    while (buf == b'' or buf[-1] != b'\x03'):
        buf+=ser.read(1)
        print(buf)  
    return buf

ser =serial.Serial(port=PORT,baudrate=300,bytesize=serial.SEVENBITS,parity=serial.PARITY_EVEN,stopbits=serial.STOPBITS_ONE,timeout=5)

repeat=True
while repeat:
    ser.setBaudrate(300)
    sleep(1)    
    ser.write(b'/?!\r\n')
    response=ser.readline()
    print(response)
    pattern = re.compile(r'/(...)(\d)\\@(.*)')
    m=pattern.match(response.decode("ASCII"))
    if not m:
        repeat= True
    else: repeat=False

manufacturer,speed,version=m.group(1,2,3)
speedcode=int(speed)
baudrates=(300,600,1200,2400,4800,9600,19200)
s=bytes([6,48,48+speedcode,48,13,10])  #option request data readout mode
print(s)
ser.write(s)
sleep(1)
ser.flush()
#ser.close()
#ser =serial.Serial(port=PORT,baudrate=baudrates[speedcode],bytesize=7,parity='E',stopbits=1,timeout=5)
ser.setBaudrate(9600)
#sleep(1)
#ser.setTimeout=None
frame=readframe()


ser.close()

我尝试了很多事情,比如刷新缓冲区、以不同的速度关闭和重新打开、插入暂停、读取行而不是字节、使用 inWaiting() 等等。 我怀疑在切换波特率时没有缓冲一段时间,所以我丢失了一些数据。 顺便说一句,我在 Windows 上使用它,Winpython 发行版(在我的工作场所这就是为什么)串行模块的版本是 2.7。

以下是应如何进行交流的示例(带有时间和方向的交流记录,部分为德语)。在我的程序中,我只收到来自 0.2.0 的行:

Komm: 11:29:57,62 -- Teilnehmer-Name = Lokale Schnittstelle
Komm: 11:29:58,34 -- Schnittstelle   = SERIELL über COM-Port Nr: 4
Komm: 11:29:58,35 -- Komm Settings   = 300,7,E,1
Send: 11:29:58,57 -- /?!<CR><LF>
Recv: 11:29:59,80 -- /ABB5\@V4.50         <CR><LF>
Send: 11:30:00,01 -- <ACK>050<CR><LF>
Komm: 11:30:00,31 -- Komm Settings   = 9600,7,E,1
Recv: 11:30:00,57 -- <STX>0.0.0(00491465)<CR><LF>
Recv: 11:30:00,60 -- 0.9.1(112957)<CR><LF>
Recv: 11:30:00,66 -- 1.6.1(0000.00*kW)(0000000000)<CR><LF>
Recv: 11:30:00,73 -- 1.6.1*04(0000.00)(0000000000)<CR><LF>
Recv: 11:30:00,79 -- 1.6.2(0000.00*kW)(0000000000)<CR><LF>
Recv: 11:30:00,88 -- 1.6.2*04(0000.00)(0000000000)<CR><LF>
Recv: 11:30:00,91 -- 1.8.1(00000000*kWh)<CR><LF>
Recv: 11:30:00,94 -- 1.8.1*04(00000000)<CR><LF>
Recv: 11:30:00,97 -- 1.8.2(00000000*kWh)<CR><LF>
Recv: 11:30:01,02 -- 1.8.2*04(00000000)<CR><LF>
Recv: 11:30:01,05 -- 0.2.0(05F1)<CR><LF>
Recv: 11:30:01,08 -- !<CR><LF>
Recv: 11:30:01,09 -- <ETX>i Soll: i
Komm: 11:30:01,41 -- Seriell-Status  = Geschlossen

感谢您的阅读,非常感谢您的帮助!

【问题讨论】:

  • 那么在你发送改变速度的命令后,单元立即以新的速度响应?所以也许你的 sleep(1) 是你的程序丢失数据的原因?发送六个字符长的 s 需要 0.2 秒。或者,你能告诉设备切换速度而不发回任何东西,然后改变速度,然后以新的速度向它发送一个命令,要求它发送数据吗?在这种情况下,您的 sleep(1) 只会减慢速度,但不会丢失任何内容。
  • 您的帖子相当混乱和混乱。什么有“光学读取头”? Google 搜索只会找到您关于 “ISC62056-21” 的帖子。 “我们通常切换到 9600bits/s 然后...程序然后切换波特率。” -- 你是在切换两次波特率吗? “正常的行为是,[原文如此] 仪表发送一帧数据,该帧以 . 进行健全性测试:将波特率更改为相同的速度。
  • 我编辑了我的帖子,希望现在更容易理解。有一个错字,当然是IEC标准。仪表正在协商波特率,我的程序确认建议的波特率 9600,然后切换到那个波特率。 @barny:感谢您的提示。你在哪里通过降低睡眠时间我会丢失更少的字节。我现在将它设置为 0.3 秒并得到一切。我想通过调用flush()来获得更优雅的方式。事实证明,flush 什么都不做,文档指出它不是针对非阻塞流实现的。所以我需要 sleep()。
  • :-) 希望你能接受我的回答。

标签: python serial-port byte buffer baud-rate


【解决方案1】:

我猜仪表正在快速切换到新的波特率 - 传输波特率更改命令的五个字符可能需要 0.2 秒,但是您的 sleep(1) 意味着仪表可能已经开始以新的速率和数据发送直到您将波特率更改为 9600 才会丢失。尝试缩短此值吗?

【讨论】:

    【解决方案2】:

    如果它对某人有帮助,在将波特率更改为 .Baudrate = 9600 之前睡觉(0.3)对我有好处。 我用的是合兴 23DL 仪表。

    重要的是你必须有 300ms 才能改变速度。如果你有很多行代码你应该计算睡眠时间()决定。或者测试 0.270 到 0.30 之间的值。

    ...
    time.sleep (0.3)
    ser.Baudrate = speed # any speed
    ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-21
      • 1970-01-01
      • 2011-11-30
      • 1970-01-01
      • 2019-06-04
      • 1970-01-01
      • 1970-01-01
      • 2011-06-01
      相关资源
      最近更新 更多