QuecPython+UART:物联网设备通信指南+应用示例

UART的基础知识前面已经介绍过了,本文主要介绍UART的特点以及QuecPython的应用实例。

特点与应用

特点:

  1. 简单性: UART通信的硬件和编程复杂度相对较低。UART本身通常是在微控制器或其他处理器的硬件中实现的,所以在硬件层面上不需要额外的芯片。

  2. 无需时钟同步: 因为UART是异步的,所以发送和接收设备不需要共享一个时钟信号。这降低了硬件设计的复杂性。

  3. 灵活性: UART通信可以调整数据位长度、停止位数量和奇偶校验等参数,以适应不同的通信需求。

  4. 可靠性: 尽管UART通信没有错误修复功能,但它的奇偶校验能提供一定程度的错误检测。

  5. 限制: UART的通信速度(波特率)有一定的限制,而且通信速度越高,数据错误的可能性也越大。此外,UART的通信距离通常也有限制,对于很长的距离,可能需要使用RS-422或RS-485等差分信号标准。

应用:

  1. 嵌入式系统: UART常用于微控制器和其他低级硬件设备的通信,例如传感器、记忆卡、GPS模块等。

  2. 串行通信: UART可以用于RS-232、RS-422和RS-485接口的串行通信,用于连接如打印机、调制解调器、显示器等设备。

  3. 电脑硬件: 在早期的电脑硬件中,UART用于鼠标和键盘等外设的接口。

  4. 电信设备: 在无线通信和电信设备中,UART用于与SIM卡和其他设备通信。

  5. 蓝牙模块: 在蓝牙模块中,UART用于与主设备进行通信。

  6. IOT设备: 在物联网设备中,UART用于低速的设备间通信。

数据流

基于QuecPython EC600U模组介绍UART数据流。

发送数据的数据流:

当软件FIFO中无数据超过500ms时,结束数据传输。

TX通信:发送数据->数据发送完毕发送事件->触发中断->触发回调函数发送事件到对应的线程处理->对应线程触发用户自定义回调函数。

其触发中断类型只有一种:TX_COMPLETE。

接收数据的数据流:

RX通信有两个中断,dma中断(数据接收到64byte),超时中断(接收数据字节数少于64而不产生dma中断的情况,时长40ms)。

其触发中断的类型有两种:RX_ARRIVED 和 RX_OVERFLOW。

当软件FIFO满时,再接收数据会造成数据溢出,出现丢数据问题。溢出的同时会上报RX_OVERFLOW事件。故串口接收数据需要及时处理,否则出现数据丢失,数据接收不全问题,当大量数据传输时,可考虑硬件流控。

RX通信:接收数据满64字节或超时->触发中断->触发回调函数发送事件到对应的线程处理->对应的线程触发用户定义回调函数。

应用示例

主要介绍如何使用 UART 具体的应用示例:

基础收发

QuecPython提供了简化的方法来在通信模组上使用 Python 进行 UART 通信。对于实时应用或需要高效处理 UART 信息的场景,使用回调函数(基于中断)进行 UART 读取是一种非常有效的方法。

实验前需了解UART QuecPython接口,请参考machine.UART

实验步骤:

  1. 初始化UART

    from machine import UART
    # 初始化 UART1
    uart1 = UART(UART.UART1, 115200, 8, 0, 1, 0)
    
  2. 写入UART

    发送数据到 UART 是非常简单的:

    uart1.write('Hello UART1')
    
  3. 使用回调数据读取数据

    在 UART 上使用回调函数,通常涉及到设置一个 IRQ(中断请求)来监听 UART 事件,如数据接收。当这些事件触发时,相关的回调函数会被执行。

    你需要确保回调函数尽可能短,以减少对其他系统任务的干扰。同时数据来之后,应立即读取,防止底层软件FIFO溢出导致数据丢失

    def uart_callback(arg):
        _queue.put(para[2])
     
    # 设置中断
    uart1.set_callback(uart_callback)
    

示例:

import _thread
import utime
from machine import UART
from queue import Queue

class Example_uart(object):
    def __init__(self, no=UART.UART2, bate=115200, data_bits=8,parity=0, stop_bits=1, flow_control=0):
        self.uart = UART(no, bate, data_bits, parity, stop_bits, flow_control)
        self._queue = Queue(5)
        _thread.start_new_thread(self.handler_thread, ())
        self.uart.set_callback(self.callback)

    def callback(self, para):
        print("call para:{}".format(para))
        if(0 == para[0]):
            self._queue.put(para[2])

    def uartWrite(self, msg):
        print("write msg:{}".format(msg))
        self.uart.write(msg)

    def uartRead(self, len):
        msg = self.uart.read(len)
        utf8_msg = msg.decode()
        print("UartRead msg: {}".format(utf8_msg))
        return utf8_msg

    def uartWrite_test(self):
        for i in range(10):
            write_msg = "Hello count={}".format(i)
            self.uartWrite(write_msg)
            utime.sleep(1)

    def handler_thread(self):
        while True:
            recv_len = self._queue.get()
            self.uartRead(recv_len)

if __name__ == "__main__":
    uart_test = Example_uart()
    uart_test.uartWrite_test()

常见问题和故障

UART是一种非常简单和直接的通信协议,但在实际应用中也可能遇到一些问题。以下是一些常见的问题以及可能的故障排查步骤:

1.数据接收不正确或无法接收数据

这可能是由于几种原因引起的,包括:波特率设置错误、硬件连接问题、中断处理程序问题、缓冲区溢出等。故障排查步骤可能包括:

  • 检查发送端和接收端的波特率设置是否一致。如果它们的波特率不匹配,可能会导致接收的数据出现错误。

  • 检查硬件连接,确保TX和RX线正确连接,并且地线(GND)也要正确连接。

  • 如果使用了中断处理程序,确保它能正确地处理接收到的数据,并且不会错过任何数据。

  • 检查接收缓冲区。如果缓冲区太小或处理速度太慢,可能会导致数据丢失。可以考虑增大缓冲区或优化处理程序。

2.数据发送不正确或无法发送数据

这可能是由于几种原因引起的,包括:硬件连接问题、发送缓冲区问题、发送程序问题等。故障排查步骤可能包括:

  • 检查硬件连接,确保TX线正确连接,并且地线(GND)也要正确连接。

  • 检查发送缓冲区和发送程序。确保发送的数据被正确地放入缓冲区,并且发送程序能正确地从缓冲区取出数据并发送出去。

3.通信距离问题

UART通信的距离有限,如果通信距离过长,可能会导致信号衰减,从而影响数据的接收。如果需要在更长的距离进行通信,可能需要使用RS-422或RS-485等差分信号标准。

4.干扰问题

在有电磁干扰的环境中,UART通信可能会受到影响。如果有可能的话,尝试减少电磁干扰,使用屏蔽线来减少干扰或者采用电容滤波以降低噪声和电磁干扰。如果干扰过大,可能需要使用差分信号标准或光电隔离。

在进行故障排查时,一种常见的方法是使用逻辑分析器或示波器来观察UART的信号,这可以帮助确定问题的来源。在软件层面,也可以使用调试工具来观察和分析程序的运行情况。