从串行端口写入和读取

Posted

技术标签:

【中文标题】从串行端口写入和读取【英文标题】:Write and read from a serial port 【发布时间】:2017-05-30 06:15:36 【问题描述】:

我正在使用以下 python 脚本在串口 ttyUSB1 上编写 AT+CSQ。 但是我什么都看不懂。

但是,当我在 minicom 上触发 AT+CSQ 时,我得到了所需的结果。

这个脚本可能有什么问题?

日志: 手动脚本

root@imx6slzbha:~# python se.py
Serial is open
Serial is open in try block also
write data: AT+CSQ
read data:
read data:
read data:
read data:

日志:

Minicom 控制台

1. ate
OK

2. at+csq
+CSQ: 20,99

3. at+csq=?
OKSQ: (0-31,99),(99)

如何在以下 python 脚本中接收这些结果?

import serial, time

#initialization and open the port

#possible timeout values:

#    1. None: wait forever, block call

#    2. 0: non-blocking mode, return immediately

#    3. x, x is bigger than 0, float allowed, timeout block call

ser = serial.Serial()

ser.port = "/dev/ttyUSB1"

ser.baudrate = 115200

ser.bytesize = serial.EIGHTBITS #number of bits per bytes

ser.parity = serial.PARITY_NONE #set parity check: no parity

ser.stopbits = serial.STOPBITS_ONE #number of stop bits

ser.timeout = None          #block read

#ser.timeout = 0             #non-block read

ser.timeout = 3              #timeout block read

ser.xonxoff = False     #disable software flow control

ser.rtscts = False     #disable hardware (RTS/CTS) flow control

ser.dsrdtr = False       #disable hardware (DSR/DTR) flow control

ser.writeTimeout = 2     #timeout for write

try:

    ser.open()

    print("Serial is open")

except Exception, e:

    print "error open serial port: " + str(e)

    exit()

if ser.isOpen():

    try:

        print("Serial is open in try block also")

        ser.flushInput() #flush input buffer, discarding all its contents

        ser.flushOutput()#flush output buffer, aborting current output

                     #and discard all that is in buffer

        #write data

        ser.write("AT+CSQ")
        time.sleep(1)
#       ser.write("AT+CSQ=?x0D")

        print("write data: AT+CSQ")
#       print("write data: AT+CSQ=?x0D")

        time.sleep(2)  #give the serial port sometime to receive the data

        numOfLines = 1

        while True:

            response = ser.readline()

            print("read data: " + response)

            numOfLines = numOfLines + 1

            if (numOfLines >= 5):

                break

        ser.close()

    except Exception, e1:

        print "error communicating...: " + str(e1)

else:

    print "cannot open serial port "

【问题讨论】:

1.在 minicom 上,您似乎首先发送了 ate,没有看到您以格式非常糟糕的 Python 代码发送它。 2. 当您在 minicom 中发送字符串时,您还按下回车键,该键也以“\r”或“\n”的形式发送(不确定哪个,可能无关紧要),当您在 python 中发送字符串时您必须明确地将输入键的击键放入您发送的字符串中,因为它不会自动发送。因此,可能需要确保您发送“ate\n”(或者它可能是 \r,不确定)然后检查 OK 响应,然后类似地将“\r”(或“\n”)添加到您发送的其他字符串。 拜托,请正确格式化问题中的代码。 嗨,hlovdal,我能够使用现有代码来获取所需的输出,抱歉,格式不正确。 :( 这是我的输出:root@imx6slzbha:~/python_exercises# python serial_tty_working.py 端口已打开 写入数据:AT+CSQ=?x0D 读取数据:读取数据:读取数据:^RSSI:19 读取数据:读取数据:^ HCSQ:"LTE",46,53,161,30 我可以使用 strip() 轻松获取 LTE RSSI。谢谢您知道如何使用单个 python 脚本编写多个命令并逐行读取输出。谢谢 【参考方案1】:

您的 AT 命令处理有两个非常根本的缺陷:

time.sleep(1)

if (numOfLines >= 5):

他们有多糟糕?在您修复这些问题之前,任何事情都不会奏效,我的意思是完全改变您发送和接收命令和响应的方式。

向调制解调器发送 AT 命令是一种与任何其他协议一样的通信协议,其中某些部分和行为是必需的,而不是可选的。就像您不会编写一个完全忽略从 HTTP 服务器返回的响应的 HTTP 客户端一样,您绝不能编写一个向调制解调器发送 AT 命令并完全忽略调制解调器发回的响应的程序。

AT 命令是一种链路层协议,窗口大小为 1 - 1。因此,在发送命令行后,发送方必须等待,直到收到来自调制解调器的响应,即它已完成对命令行的处理,这种响应称为最终结果代码

如果调制解调器在响应最终结果代码之前使用了 70 毫秒,则您必须等待至少 70 毫秒才能继续,如果它使用 4 秒,您必须等待至少 4 秒才能继续,如果它需要几分钟(是的,存在可能需要几分钟才能完成的 AT 命令)您必须等待几分钟。如果调制解调器在一小时内没有响应,您唯一的选择是 1) 继续等待,2) 放弃或 3) 断开连接,重新连接并重新开始。

这就是为什么sleep 是一种可怕的方法,在最好的情况下是浪费时间的定时炸弹。它就像踢狗一样有用,以使它们移动。是的,它有时可能确实有效,但在某些时候你会为采用这种方法而感到抱歉......

关于numOfLines,任何人都无法提前知道调制解调器将响应多少条线路。如果您的调制解调器只响应带有ERROR 最终结果代码的一行怎么办?代码会死锁。

所以这个行号计数必须完全消失,而是你的代码应该发送一个命令行,然后等待来自调制解调器的响应行 reading and parsing 的最终结果代码。

但在深入研究该答案之前,请先阅读 V.250 规范,至少是第 5 章的全部内容。这是定义 AT 命令基础知识的标准,例如会教你命令和一个命令行。以及如何correctly terminate 一个你没有做的命令行,所以调制解调器永远不会开始处理你发送的命令。

【讨论】:

以上是关于从串行端口写入和读取的主要内容,如果未能解决你的问题,请参考以下文章

使用串行端口,我收到一个错误:尝试读取或写入受保护的内存

从串行端口(C/C++)读取时,如何实现 read() 超时

使用python在串行通信中读取输入缓冲区

使用定时器提高读/写串行端口的速度

如何确定 linux 串行端口上剩余的写入/输出缓冲区空间量?

从两个串口异步读取