首页 > Python资料 博客日记

[MaixCam]使用心得二:UART串口通信

2024-08-22 09:00:07Python资料围观106

这篇文章介绍了[MaixCam]使用心得二:UART串口通信,分享给大家做个参考,收藏Python资料网收获更多编程知识

前言

        "MaixCam"系列文章主要介绍一下本人在暑假期间使用该摄像头模组的心得。该摄像头模组相较于传统的K210、OpenMV有着很明显的优点:更清晰的LCD屏幕、更强大的支持yolo5的算力、更高清的摄像头。

        我认为如果你电赛选择摄像头模组,想要低学习成本实现电赛题目的基本要求,不想使用树莓派、OpenCV等工具,强烈建议使用MaixCam来替代OpenMV或K210,MaixCam的封装的函数大部分与前两者相同,可以对网上OpenMV和K210的资源轻松进行移植,并且实现效果更好。

        本文只介绍简单的串口通信方式,即传输数据只使用针头帧尾和数据长度,如果你想要适用性更广的方法,即帧头、数据长度、校检和,可以阅读这位博主的文章,讲的十分详细:欠羽-CSDN博客https://blog.csdn.net/adas323?type=blog        最后,如果你想要实现快速配置,直接跳转到总结部分即可。

串口配置

from maix import uart

devices = uart.list_devices()

serial = uart.UART(devices[0], 115200)

        该串口使用的是A16(TX)和A17(RX)引脚,即使用官方附赠的Type-C 转接小板上面的串口引脚。当然你也可以自己注册想要使用的引脚,这里使用A19(TX)和A18(RX)举例:

from maix import uart, pinmap

pinmap.set_pin_function("A18", "UART1_RX")
pinmap.set_pin_function("A19", "UART1_TX")

device = "/dev/ttyS1"

serial1 = uart.UART(device, 115200)

        这里简要介绍一下uart.UART这个函数:

serial = uart.UART(
                   #端口名称
                   port: str = '', 
                   #传输的波特率
                   baudrate: int = 115200,
                   #数据位
                   databits: BITS = ..., 
                   #校验位
                   parity: PARITY = ..., 
                   #停止位
                   stopbits: STOP = ..., 
                   #流量控制
                   flow_ctrl: FLOW_CTRL = ...
                   )

#通常来说做以下配置 波特率115200 数据位8 校验位NONE 停止位1
serial = uart.UART(
                   devices[0], 
                   115200,
                   uart.BITS.BITS_8,
                   uart.PARITY.PARITY_NONE,
                   uart.STOP.STOP_1
                   )

定时器配置

        由于MaixCam的api文档目前还没有Timer相关的定义,即官方还没有移植K210中的Timer函数,所以我只能简易的制作一个定时器,用于每隔一段时间对数据进行接收和发送。

        在这里我创建了一个定时器类,用于不同定时器的计时。其中count_flag为定时器完成计时的标志,每当count_flag == 1,我们将执行一次需要定时的程序。

class Timer():
    #定时器类
    def __init__(self) -> None:
        #计时数
        self.count = 0
        #计时数上限
        self.count_max = 0
        #计时完成标识
        self.count_flag = 0

timer0 = Timer()
timer0.count_max = 100000

        之后创建一个开始计时函数,用于启动定时器和记录定时器是否完成计时。

def TimerStart(Timer):
    if Timer.count < Timer.count_max:
        #计时开始,计时器标识位置0
        Timer.count_flag = 0
        Timer.count += 1
    
    else:
        #计时完成,计时器标识位置1
        Timer.count_flag = 1
        Timer.count = 0

while True:
    #使用定时器
    TimerStart(timer0)
    if timer0.count_flag == 1:
        #需要执行的函数
        pass

串口发送

        这里我创建了一个发送测试数据类,你可以根据发送数据的需要,自己定义需要的类。在该类中有一个"发送标识位",用来判断数据发送的方式,该变量将在后面的函数中使用。

#发送测试数据类
class TTest():
    def __init__(self) -> None:
        #发送标识位
        self.Tflag = 0

        #发送数据内容
        self.test_number0 = 0
        self.test_number1 = 0
        self.test_number2 = 0

TTest0 = TTest()
TTest0.Tflag = 1
TTest0.test_number0 = 0
TTest0.test_number1 = 1
TTest0.test_number2 = 2

        之后我创建了一个用于发送数据的函数,叫"串口发送函数",调用该函数即可直接发送打包好的数据。其中输入的参数为帧头(head),帧尾(tail),想要发送的数据(TData),本文中为TTest0,发送数据的串口(serial),本文中为serial。

#串口发送函数
def DataTransimit(head, tail, TData, serial):
    data = ()
    if TData.Tflag == 1:
        data = bytes([
            head,
            TData.test_number0,
            TData.test_number1,
            TData.test_number2,
            tail
        ])
        
    elif TData.Tflag == 2:
        data = bytes([
            head,
            #想要发送的数据
            tail
        ])

    if data != ():
        #发送数据
        serial.write(data)

        这里简单解释一下write函数,即UART.write函数,它发送的类型为字节类型,如果你想要发送字符串类型,可以使用write_str函数。或者使用str.encode()函数,将字符型转换为字节型后,再使用write函数。

        我们在主函数中调用串口发送函数,就可以实现对数据的发送了。

while True:
    TimerStart(timer0)
    if timer0.count_flag == 1:
        DataTransimit(0xAA, 0xBB, TTest0, serial)

        如图所示,这样数据就带着帧头和帧尾发送出去了。

串口接收 

        串口接收相较于串口发送复杂一些,但是由于我们只使用帧头帧尾,在解析数据的时候逻辑简单,适用于一些低频率数据的接收。

        这里我创建了一个接收测试数据类,你可以根据接收数据的需要,自己定义需要的类。在该类中有一个"接收标识位",用来判断数据接收的方式,该变量将在后面的函数中使用。

#接收测试数据类
class  RTest():
    def __init__(self) -> None:
        #接收标识位
        self.Rflag = 0
        #发送数据标识位 用于测试是否接收到数据        
        self.Tflag = 0

        #接收数据内容
        self.test_number0 = 0
        self.test_number1 = 0
        self.test_number2 = 0


RTest0 = RTest()
RTest0.Rflag = 1
RTest0.Tflag = 1

        之后我创建了一个用于接收数据的函数,叫"串口接收函数",调用该函数可返回缓存数据(BufData),用于后续对函数进行解析。其中输入的参数为帧头(head),帧尾(tail),想要接收的数据长度(length),本文中为5,即帧头、三个测试数字、帧尾,接收数据的串口(serial),本文中为serial。

#串口接收函数
def ReceiveData(head, tail, length, serial):
    BufData = serial.read(40)
    if BufData and len(BufData) >= length:
        if BufData[0] == head and BufData[length-1] == tail:
            return BufData
        else:
            return None

       这里对read函数进行一下解释,即UART.read,该函数调用后返回的是字节或者字符类型,其中read(40)表示最大接收的字节数量,如果你单次发送超过40个字节的数据,这个程序就会报错,如果不想出现这种情况,可以不填写最大接收字节,即read(),它会一直读取缓存区的数据。

        最后使用接收数据解析函数,对数据进行解析,这样RTest0中的数据就改变了。

#接收数据解析函数
def ParseData(RData, BufData):
    if BufData != None:
        if RData.Rflag == 1:
            RData.test_number0 = BufData[1]
            RData.test_number1 = BufData[2]
            RData.test_number2 = BufData[3]
        
        elif RData.Rflag == 2:
            #接收数据内容
            pass

         我们来测试一下效果,接收完数据后再发送出去。

while True:
    TimerStart(timer0)
    if timer0.count_flag == 1:
        ParseData(RTest0, ReceiveData(0xAA, 0xBB, 5, serial))
        DataTransimit(0xCC, 0xDD, RTest0, serial)

        如图所示,接受前发送的三个测试数据为0,接收后数据改变了,证明接收成功了。 

总结

        这一期我们使用MaixCam中的write和read函数,实现了数据的接收和发送,如果你想要快速实现配置,复制一下代码,稍作更改即可。

from maix import time, uart, pinmap

devices = uart.list_devices()
serial = uart.UART(devices[0], 115200, uart.BITS.BITS_8, uart.PARITY.PARITY_NONE, uart.STOP.STOP_1)

#发送测试数据类
class TTest():
    def __init__(self) -> None:
        #发送标识位
        self.Tflag = 0

        #发送数据内容
        self.test_number0 = 0
        self.test_number1 = 0
        self.test_number2 = 0

TTest0 = TTest()
TTest0.Tflag = 1
TTest0.test_number0 = 0
TTest0.test_number1 = 1
TTest0.test_number2 = 2

#串口发送函数
def DataTransimit(head, tail, TData, serial):
    data = ()
    if TData.Tflag == 1:
        data = bytes([
            head,
            TData.test_number0,
            TData.test_number1,
            TData.test_number2,
            tail
        ])
        
    elif TData.Tflag == 2:
        data = bytes([
            head,
            #想要发送的数据
            tail
        ])

    if data != ():
        #发送数据
        serial.write(data)

#接受测试数据类
class  RTest():
    def __init__(self) -> None:
        #接收标识位
        self.Rflag = 0
        #发送数据标识位        
        self.Tflag = 0

        #接收数据内容
        self.test_number0 = 0
        self.test_number1 = 0
        self.test_number2 = 0


RTest0 = RTest()
RTest0.Rflag = 1
RTest0.Tflag = 1

#串口接受函数
def ReceiveData(head, tail, length, serial):
    BufData = serial.read(40)
    if BufData and len(BufData) >= length:
        if BufData[0] == head and BufData[length-1] == tail:
            return BufData
        else:
            return None

#接收数据解析函数
def ParseData(RData, BufData):
    if BufData != None:
        if RData.Rflag == 1:
            RData.test_number0 = BufData[1]
            RData.test_number1 = BufData[2]
            RData.test_number2 = BufData[3]
        
        elif RData.Rflag == 2:
            #接收数据内容
            pass


class Timer():
    #定时器类
    def __init__(self) -> None:
        #计时数
        self.count = 0
        #计时数上限
        self.count_max = 0
        #计时完成标识
        self.count_flag = 0

timer0 = Timer()
timer0.count_max = 100000

def TimerStart(Timer):
    if Timer.count < Timer.count_max:
        #计时开始,计时器标识位置0
        Timer.count_flag = 0
        Timer.count += 1
    
    else:
        #计时完成,计时器标识位置1
        Timer.count_flag = 1
        Timer.count = 0

while True:
    TimerStart(timer0)
    if timer0.count_flag == 1:
        ParseData(RTest0, ReceiveData(0xAA, 0xBB, 5, serial))
        DataTransimit(0xCC, 0xDD, RTest0, serial)


版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐