【电赛学习笔记】MaxiCAM 片上外设操作

前言

本文仅是对MaxiPy官方文档的整理与总结,自学请看官方文档,侵权即删MaixCAM MaixPy 快速开始 - MaixPy

1.GPIO

以基本点灯代码为例进行说明

python 复制代码
from maix import gpio, pinmap, time

pinmap.set_pin_function("A14", "GPIOA14")
led = gpio.GPIO("GPIOA14", gpio.Mode.OUT)
led.value(0)

while 1:
    led.toggle()
    time.sleep_ms(500)

下面逐行逐参数进行介绍

导入模块

from maix import gpio, pinmap, time 从 MaixPy 标准固件里导入 3 个模块/类

gpio :控制 GPIO 电平、方向、中断等功能

pinmap :把芯片引脚复用到想要的"功能名字"

time :延时函数,单位可以是 us、ms、s

pinmap.set_pin_function("A14", "GPIOA14")

功能:把物理引脚 A14 的复用功能设成 GPIOA14。

参数:

• "A14" ------ 芯片封装上的物理引脚名(IO 口 A 组的第 14 号)

• "GPIOA14" ------ 想要映射成的"功能名字";Maix 固件里每个功能都有字符串标识,这个名字正好对应 GPIO 功能。之后用 "GPIOA14" 去创建 gpio 对象,就会真正操作到 A14 这根线。

led = gpio.GPIO("GPIOA14", gpio.Mode.OUT)

创建 GPIO 对象,并初始化方向。

参数:

• "GPIOA14" ------ 上一步映射好的名字,告诉驱动操作哪根线

• gpio.Mode.OUT ------ 枚举常量,表示把该引脚设为输出模式(output),可以驱动 LED。

返回值:led 是一个 gpio.GPIO 实例,后续通过它读写电平。

led.value(0)

把引脚电平拉低(0 = 低电平)

led.toggle()

把当前电平翻转一次

time.sleep_ms(500)

延时 500 毫秒(半秒)

2.按键

电赛中视觉模块按键使用较少,不详述,请见官方文档

MaixCAM MaixPy 按键事件使用 - MaixPy

3.UART

一个注意点:

MaixCAM 的 TX(UART0) 引脚在开机时不能是被拉低 的状态,不然会导致无法开机,是芯片的特性,如果你在做 3.3v5v 的电平转换电路要十分注意不要默认拉低请保持浮空(可以考虑使用电平转换芯片)。以及如果你发现无法开机,也可以先检查一下 TX 是否被拉低了。

数据的发送

python 复制代码
bytes_content = b'\x01\x02\x03'
serial.write(bytes_content)

主要有两个函数write_strwrite函数。

write_str函数来发送字符串write用来发送字节流 ,即strbytes类型,两者可以互相转换,比如:

  • "A" 调用encode()方法变成b"A",反过来b"A"调用decode()方法变成"A"

  • str 没法显示一些不可见字符比如 ASCII 码中的值0,在字符串中也是\0一般作为结束符,在bytes类型中就可以用b"\x00"来储存。

  • 对于非 ASCII 编码的字符串更有用,比如UTF-8编码中中文是由三个字节\xe5\xa5\xbd来表示的,我们可以通过"好".encode("utf-8")得到b"\xe5\xa5\xbd",也可以通过b'\xe5\xa5\xbd'.decode("utf-8)得到"好"

所以对于 str 类型,也可以不用write_str,而是使用serial.write(str_content.encode()) 来发送。

数据的接收

使用read方法进行读取数据,直接:

python 复制代码
while not app.need_exit():
    data = serial.read()
    if data:
        print(data)
    time.sleep_ms(1)

同样,read方法获得的数据也是**bytes** 类型,这里read会读取对方一次性发送的一串数据,如果没有数据就是b''即空字节。

这里用了time.sleep_ms(1)进行睡眠了1ms,用来释放 CPU,不让这个线程占用所有 CPU 资源,而且1ms不影响我们程序的效率,特别是在多线程时有用。

另外read函数有两个参数

  • len :代表想接收的最大长度 ,默认-1代表缓冲区有多少就返回多少,传>0的值则代表最多返回这个长度的数据。
  • timeout
    • 默认 0 代表从缓冲区读取数据立马返回数据 ,如果len-1则返回所有数据,如果指定了len则返回长度不超过len 的数据。
    • <0 代表一直等待直到接收到了数据才返回 ,如果len-1则等待到接收到数据才返回(一串连续接收到的数据,即阻塞式读取所有数据),如果指定了len则等待接收数量达到len才返回。
    • >0 代表无论有没有接收到数据,超过这个时间就会返回

看起来有点复杂,常见的参数组合

  • read(): 即read(-1, 0),从缓冲区读取收到的数据,通常是对方一次性发来的一串数据,等到对方没有发送(一个字符的发送时间内没有再发)就立刻返回。
  • read(len = -1, timeout = -1): 阻塞式读取一串数据,等到对方发送了数据并且一个字符的发送时间内没有再发才返回。
  • read(len = 10, timeout = 1000): 阻塞式读取 10 个字符,读取到 10 个字符或者 超过 1000ms 还没收到就返回已经收到的数据。

设置接受回调函数

下面以官方例程为例进行解释

python 复制代码
from maix import uart, app, time

def on_received(serial : uart.UART, data : bytes):
    print("received:", data)
    # send back
    serial.write(data)

device = "/dev/ttyS0"

serial = uart.UART(device, 115200)
serial.set_received_callback(on_received)

serial.write_str("hello\r\n")
print("sent hello")
print("wait data")

while not app.need_exit():
    time.sleep_ms(100) # sleep to make CPU free

导入模块

from maix import uart, app, time

从 MaixPy 固件中导入 3 个模块

uart :串口收发功能

app :应用管理,用来检测是否应退出(例如按下 HOME 键)

time :延时函数,单位 ms

具体回调函数的定义

def on_received(serial : uart.UART, data : bytes):

定义串口接收回调函数。

参数:

• serial : uart.UART ------ 触发本次回调的串口实例,方便在回调里直接操作该串口(读/写)

• data : bytes ------ 本次接收到的完整一帧数据(底层驱动已经帮你拼好),长度可变

功能:

把收到的内容原样打印到控制台

再用 serial.write(data) 回发(echo)

触发时机:

当 UART 接收缓冲区达到阈值(通常 1 Byte 或 FIFO 半满)或空闲中断时,底层 C 驱动会调用你在 Python 层注册的回调。

回调运行在一个独立线程(或中断上下文转线程),不会阻塞主循环。

指定串口

device = "/dev/ttyS0"

指定要使用的 Linux 设备节点(ttyS0 对应芯片的 UART0)。

serial = uart.UART(device, 115200)

创建 UART 对象

serial = uart.UART(device, 115200)

参数:

• device ------ 字符串,"/dev/ttyS0"

• 115200 ------ 波特率 115200 bps

其余参数保持默认:8N1(8 数据位,无校验,1 停止位),无流控。

设置回调函数

serial.set_received_callback(on_received)

把 on_received 函数注册为「接收完成回调」。

一旦底层有数据到达,驱动会在后台线程里自动调用 on_received(serial, data)。

若再次调用 set_received_callback(None) 可取消回调,回到轮询模式。

串口发送数据

serial.write_str("hello\r\n")

作用:以字符串形式发送 "hello\r\n"。

底层会转成 bytes 后发出。

主循环

while not app.need_exit():

主循环,仅做两件事:

周期性检测是否需要退出程序

通过 time.sleep_ms(100) 主动让出 CPU,降低功耗

注意:真正的数据接收全部发生在回调线程里,主循环无需轮询 serial.read()。

使用其他串口

以uart1为例

python 复制代码
from maix import app, uart, pinmap, time

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

device = "/dev/ttyS1"

serial1 = uart.UART(device, 115200)

其他应用可跳转ButterflyBoy0大佬的使用教程[MaixCam]使用心得二:UART串口通信-CSDN博客