当前位置:   article > 正文

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

maixcam 串口

前言

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

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

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

串口配置

  1. from maix import uart
  2. devices = uart.list_devices()
  3. serial = uart.UART(devices[0], 115200)

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

  1. from maix import uart, pinmap
  2. pinmap.set_pin_function("A18", "UART1_RX")
  3. pinmap.set_pin_function("A19", "UART1_TX")
  4. device = "/dev/ttyS1"
  5. serial1 = uart.UART(device, 115200)

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

  1. serial = uart.UART(
  2. #端口名称
  3. port: str = '',
  4. #传输的波特率
  5. baudrate: int = 115200,
  6. #数据位
  7. databits: BITS = ...,
  8. #校验位
  9. parity: PARITY = ...,
  10. #停止位
  11. stopbits: STOP = ...,
  12. #流量控制
  13. flow_ctrl: FLOW_CTRL = ...
  14. )
  15. #通常来说做以下配置 波特率115200 数据位8 校验位NONE 停止位1
  16. serial = uart.UART(
  17. devices[0],
  18. 115200,
  19. uart.BITS.BITS_8,
  20. uart.PARITY.PARITY_NONE,
  21. uart.STOP.STOP_1
  22. )

定时器配置

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

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

  1. class Timer():
  2. #定时器类
  3. def __init__(self) -> None:
  4. #计时数
  5. self.count = 0
  6. #计时数上限
  7. self.count_max = 0
  8. #计时完成标识
  9. self.count_flag = 0
  10. timer0 = Timer()
  11. timer0.count_max = 100000

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

  1. def TimerStart(Timer):
  2. if Timer.count < Timer.count_max:
  3. #计时开始,计时器标识位置0
  4. Timer.count_flag = 0
  5. Timer.count += 1
  6. else:
  7. #计时完成,计时器标识位置1
  8. Timer.count_flag = 1
  9. Timer.count = 0
  10. while True:
  11. #使用定时器
  12. TimerStart(timer0)
  13. if timer0.count_flag == 1:
  14. #需要执行的函数
  15. pass

串口发送

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

  1. #发送测试数据类
  2. class TTest():
  3. def __init__(self) -> None:
  4. #发送标识位
  5. self.Tflag = 0
  6. #发送数据内容
  7. self.test_number0 = 0
  8. self.test_number1 = 0
  9. self.test_number2 = 0
  10. TTest0 = TTest()
  11. TTest0.Tflag = 1
  12. TTest0.test_number0 = 0
  13. TTest0.test_number1 = 1
  14. TTest0.test_number2 = 2

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

  1. #串口发送函数
  2. def DataTransimit(head, tail, TData, serial):
  3. data = ()
  4. if TData.Tflag == 1:
  5. data = bytes([
  6. head,
  7. TData.test_number0,
  8. TData.test_number1,
  9. TData.test_number2,
  10. tail
  11. ])
  12. elif TData.Tflag == 2:
  13. data = bytes([
  14. head,
  15. #想要发送的数据
  16. tail
  17. ])
  18. if data != ():
  19. #发送数据
  20. serial.write(data)

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

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

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

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

串口接收 

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

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

  1. #接收测试数据类
  2. class RTest():
  3. def __init__(self) -> None:
  4. #接收标识位
  5. self.Rflag = 0
  6. #发送数据标识位 用于测试是否接收到数据
  7. self.Tflag = 0
  8. #接收数据内容
  9. self.test_number0 = 0
  10. self.test_number1 = 0
  11. self.test_number2 = 0
  12. RTest0 = RTest()
  13. RTest0.Rflag = 1
  14. RTest0.Tflag = 1

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

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

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

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

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

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

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

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

总结

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

  1. from maix import time, uart, pinmap
  2. devices = uart.list_devices()
  3. serial = uart.UART(devices[0], 115200, uart.BITS.BITS_8, uart.PARITY.PARITY_NONE, uart.STOP.STOP_1)
  4. #发送测试数据类
  5. class TTest():
  6. def __init__(self) -> None:
  7. #发送标识位
  8. self.Tflag = 0
  9. #发送数据内容
  10. self.test_number0 = 0
  11. self.test_number1 = 0
  12. self.test_number2 = 0
  13. TTest0 = TTest()
  14. TTest0.Tflag = 1
  15. TTest0.test_number0 = 0
  16. TTest0.test_number1 = 1
  17. TTest0.test_number2 = 2
  18. #串口发送函数
  19. def DataTransimit(head, tail, TData, serial):
  20. data = ()
  21. if TData.Tflag == 1:
  22. data = bytes([
  23. head,
  24. TData.test_number0,
  25. TData.test_number1,
  26. TData.test_number2,
  27. tail
  28. ])
  29. elif TData.Tflag == 2:
  30. data = bytes([
  31. head,
  32. #想要发送的数据
  33. tail
  34. ])
  35. if data != ():
  36. #发送数据
  37. serial.write(data)
  38. #接受测试数据类
  39. class RTest():
  40. def __init__(self) -> None:
  41. #接收标识位
  42. self.Rflag = 0
  43. #发送数据标识位
  44. self.Tflag = 0
  45. #接收数据内容
  46. self.test_number0 = 0
  47. self.test_number1 = 0
  48. self.test_number2 = 0
  49. RTest0 = RTest()
  50. RTest0.Rflag = 1
  51. RTest0.Tflag = 1
  52. #串口接受函数
  53. def ReceiveData(head, tail, length, serial):
  54. BufData = serial.read(40)
  55. if BufData and len(BufData) >= length:
  56. if BufData[0] == head and BufData[length-1] == tail:
  57. return BufData
  58. else:
  59. return None
  60. #接收数据解析函数
  61. def ParseData(RData, BufData):
  62. if BufData != None:
  63. if RData.Rflag == 1:
  64. RData.test_number0 = BufData[1]
  65. RData.test_number1 = BufData[2]
  66. RData.test_number2 = BufData[3]
  67. elif RData.Rflag == 2:
  68. #接收数据内容
  69. pass
  70. class Timer():
  71. #定时器类
  72. def __init__(self) -> None:
  73. #计时数
  74. self.count = 0
  75. #计时数上限
  76. self.count_max = 0
  77. #计时完成标识
  78. self.count_flag = 0
  79. timer0 = Timer()
  80. timer0.count_max = 100000
  81. def TimerStart(Timer):
  82. if Timer.count < Timer.count_max:
  83. #计时开始,计时器标识位置0
  84. Timer.count_flag = 0
  85. Timer.count += 1
  86. else:
  87. #计时完成,计时器标识位置1
  88. Timer.count_flag = 1
  89. Timer.count = 0
  90. while True:
  91. TimerStart(timer0)
  92. if timer0.count_flag == 1:
  93. ParseData(RTest0, ReceiveData(0xAA, 0xBB, 5, serial))
  94. DataTransimit(0xCC, 0xDD, RTest0, serial)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/1010774
推荐阅读
相关标签
  

闽ICP备14008679号