上位机(nano)与单片机(32)通信之上位机篇

本篇主要介绍下上位机与下位机的通信,使用jetson nano(Ubuntu20.04)和32单片机的通信,使用ttl转usb,可以直接插在usb口上作为串口使用,本文只介绍上位机部分的通信代码

ttl转usb可以在不供电的情况下直接使用(如果你的代码涉及串口,可以放个假的骗一下代码),首先在插入usb的时候我们需要查看下串口名称,终端输入指令

ls -l /dev/tty*

出现的内容应该是这样的(一堆串口名)

通过插拔各输入一次判断下哪个是新出的就能看到串口的名称了(上图USB0就是我的串口名)

接下来写串口的初始化,波特率为115200:

import serial
import time

try:
    # 初始化串口
    serial_port = serial.Serial(
        port="/dev/ttyUSB0",
        baudrate=115200,
        bytesize=serial.EIGHTBITS,
        parity=serial.PARITY_NONE,
        stopbits=serial.STOPBITS_ONE,
    )
    time.sleep(1)  # 等待串口连接稳定

代码中的ttyUSB0就是我的串口名称,根据实际情况修改,串口名称会遇到各种莫名其妙的原因产生改变,建议修改串口名称(就不多说了),修改后的串口是这样的(以/dev/ttyBT为例)

接下来是串口消息的发送,包括int char string,但是int很难使用,所以我们不涉及这个部分:

    # 发送char数据
    char_value = 'A'
    serial_port.write(char_value.encode())
    serial_port.write(';'.encode())

    # 发送字符串数据
    str = "ABCD"
    serial_port.write(str.encode())
    serial_port.write(';'.encode())

需要注意的是,串口的发送有的时候并不会直接发送,需要一个回车或者 ; 作为结束符以供下位机识别(上图使用;作为下位机处理的结束符)

我们甚至可以缩写一下(一般如果输出的内容不改变的话可以使用这个,便捷)

serial_port.write("ABCD;".encode())

串口接收内容(包括读取字节byte和字符char)相比来说字节的兼容性好:

# 接收char数据
        if serial_port.in_waiting > 0:
            char_received = serial_port.read().decode()
            print(f"接收到的char数据: {char_received}")
   
# 接收string数据
        if serial_port.inWaiting() > 0:
            data = serial_port.readline().strip()
            print(f"接收到的string数据: {data}")
            

这个使用的是字节接收的形式接收数据的,兼容性会比较好(大部分的内容都是用字节存储的)这个char_received和data都是字符的形式(二进制),但是可以正常print出来,需要注意下

read()表示读取一个字节的内容,encode()表示把字符转化为字符(如果不转换就是字节),readline()是读取一整行的字节,直到回车\n,strip可以去掉空格的内容然后转化为字符串,根据情况选择

如果你想使用字符的接收可以参考下面的

        if serial_port.in_waiting > 0:
            # char_received = serial_port.read().decode()
            # print(f"接收到的char数据: {char_received}")
            char_byte = serial_port.read()  # 读取一个字节
            char_str = char_byte.decode()  # 将字节转换为字符
            print(f"接收到的字符: {char_str}")

这个代码会把char_str直接改成字符的形式,单片机复位的时候也会发消息到串口,是UTF-8的格式会导致程序直接退出,兼容性较差,不推荐使用(如果使用这个,下面的b就不用写了)

下面可能会用到的还有对接收到的数据进行处理:

        if serial_port.inWaiting() > 0:
            data = serial_port.readline().strip()
            # print(data)
            if data == b"ABCD":  # 注意这里是字节比较
                print("已接收ABCD")
                # serial_port.reset_input_buffer()  # 清理输入缓冲区

这个是使用字节比较,b"ABCD"会把字符串 ABCD 直接转化为二进制的形式,如果没有b就不能被识别,最后一句清空缓冲区不是必须的,在单片机大量发送消息给上位机的时候可能会用到,比如在单片机复位的时候可能存在消息发送过于频繁,那么就需要清空操作,否则会导致接受的代码出现问题

完整代码如下:

import serial
import time
# import struct

try:
    # 初始化串口
    serial_port = serial.Serial(
        port="/dev/ttyUSB0",
        baudrate=115200,
        bytesize=serial.EIGHTBITS,
        parity=serial.PARITY_NONE,
        stopbits=serial.STOPBITS_ONE,
    )
    time.sleep(1)  # 等待串口连接稳定

    # # 发送int数据
    # int_value = 1234
    # int_bytes = struct.pack('>I', int_value)  # 大端字节序
    # serial_port.write(int_bytes)
    # serial_port.write(';'.encode())

    # 接收int数据 
    # if serial_port.in_waiting >= 4:  # int数据大小为4字节
    #     int_received_bytes = serial_port.read(4)
    #     int_received = struct.unpack('>I', int_received_bytes)[0]
    #     print(f"接收到的int数据: {int_received}")

    while 1:
        # # 发送char数据
        # char_value = 'A'
        # serial_port.write(char_value.encode())
        # serial_port.write(';'.encode())

        # 发送字符串数据
        str = "ABCD"
        serial_port.write(str.encode())
        serial_port.write(';'.encode())


        # 接收char数据
        if serial_port.in_waiting > 0:
            # char_received = serial_port.read().decode()
            # print(f"接收到的char数据: {char_received}")
            char_byte = serial_port.read()  # 读取一个字节
            char_str = char_byte.decode()  # 将字节转换为字符
            print(f"接收到的字符: {char_str}")

            if char_str == "A":  # 字符比较 复位回消息可能会产生问题
                print("已接收字符 A")

        if serial_port.inWaiting() > 0:
            data = serial_port.readline().strip()
            print(data)
            if data == b"ABCD":  # 注意这里是字节比较
                print("已接收ABCD")


except serial.SerialException as e:
    print(f"串口错误: {e}")
except Exception as e:
    print(f"其他错误: {e}")
finally:
    if serial_port.is_open:
        serial_port.close()

int发送的时候单片机需要重新写相应的代码,不推荐使用,char和string的话,单片机只需要同一套发送就能兼容了,str的话可以接收复位发来的消息的(需要清缓存)可以用来上位机那边程序的复位

部分情况总结:

推荐使用其他内容前先将串口配置确认无误,查看两边的波特率,串口名称是否改变,接线是否有问题,再进行代码的写入,否则会导致还没建立起联系后面的内容都白写的问题(而且很难检查到哪里的问题)

不要让串口在几秒内多次发送消息,会导致消息的吞并,比如说,我A和B一起发送,可能会导致A刚进缓存区就被B顶掉了,从而导致通信异常,下位机同理,

  • 25
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值