circuitpython与micropython部分差别(劝退攻略)

文章详细列举了CircuitPython与MicroPython之间的主要区别,包括基础模块的不同、PIN接口的差异、键盘模块的封装、协程模块和framebuffer模块的缺失以及时间模块的不一致。此外,还提到了CircuitPython的根分区默认为只读和Zlib库的限制。作者分享了如何针对这些问题进行代码调整和移植,以及解决方法,如自定义时间模块和移植特定功能到CircuitPython。
摘要由CSDN通过智能技术生成

见过circuitpython介绍的,一般都垂涎circuitpython新增的模块。例如可以py直接驱动摄像头、支持MP3软解、numpy库、矩阵LED驱动等。但是理想很丰满,现实很骨感,骨感到你认为有的东西,它其实没有(或者换了另外一种方式)。

circuitpython虽然说是基于micropython,但是实际上与micropython有很大的区别,别天真的认为micropython能跑的代码拿到circuitpython就可以跑起来。在此记录一下蛋疼的点以及对应应对方案:

1)基础模块不一样,没有machine,改用了microcontroller,其他的模块也是,造成micropython的代码在circuitpython里几乎无法运行。这叫什么基于micropython,完全已经改头换面了。。。

2)PIN接口不一样,无法根据参数动态指定PIN,我写了一段代码,根据名称将int值和PIN做了对应:

import sys
import gc

CIRCUIT: bool = (sys.implementation.name == 'circuitpython')   # 是否circuitpython

if CIRCUIT:
    # circuitpython的IO映射
    import microcontroller
    iomapper: dict[int, microcontroller.Pin] = {}

    for pin_str in dir(microcontroller.pin):
        pin = getattr(microcontroller.pin, pin_str)
        if isinstance(pin, microcontroller.Pin):
            iomapper[int(pin_str[4:])] = pin

然后iomapper[10]即获取到IO10
3)IO读写、SPI、I2C使用不一样:

使用另外的两个模块busio和digitalio
busio提供了SPI,而digitalio提供了IO电平读取和设置。
IO写类似如下:注意mpy是用的0和1表示高低电平,而cpy是用的True和False

    def digital_write(self, pin: Pin | digitalio.DigitalInOut, value):
        if CIRCUIT:
            pin.value = (value > 0)
        else:
            pin.value(value)

4)键盘模块不一样,虽然做了简单的包装,但是完全把中断的接口屏蔽并封装了,重新包装一下,勉强还是可以用。之前的键盘模块整合circuitpython后的代码:
 

from lib.epui import *
import lib.time as time

if CIRCUIT:
    from microcontroller import Pin
else:
    from machine import Pin

"""
micropython switch check module
By @Jim 2023-2025
"""

class BaseSwitchButton:
    """
    按钮接口
    支持防抖及持续按的按键检测模块
    """
    def check_continuous(self):
        """
        检测是否在持续按下
        :return:
        """
        pass

    def pull_state(self) -> tuple(bool, bool):
        """
        拉取状态
        :return: (期间是否被按下,是否被持续按下)
        """
        return (None, None)

if CIRCUIT:
    import lib.adafruit_ticks as adafruit_ticks
    import keypad

    class SwitchButton(BaseSwitchButton):
        """Switch Button Class
        支持防抖及持续按的按键检测模块Circuitpython
        """

        continuous_period = 1000  # 连续按多少秒进入持续触发

        pins: list[Pin] = []
        buttons = []

        def __init__(self, pin_num: int):
            self.__pressed = False
            self.__continuous = False
            self.__press_tick = 0
            self.__stat_on = False  # 是否按下状态

            self.pin = iomapper[pin_num]
            if self.pin is None:
                raise ValueError(f'pin number {pin_num} not available')
            self.key_number = len(SwitchButton.pins)
            SwitchButton.pins.append(self.pin)
            SwitchButton.buttons.append(self)

        @classmethod
        def init_keypad(cls):
            SwitchButton.keys = keypad.Keys(tuple(SwitchButton.pins), value_when_pressed=False, pull=True)

        @classmethod
        def sync_button(cls):
            while True:     # 拉取所有的状态
                event = SwitchButton.keys.events.get()
                if event is None:
                    break
                button = SwitchButton.buttons[event.key_number]
                if event.pressed:
                    button.__pressed = True  # 记录有按下
                    button.__press_tick = event.timestamp
                    button.__stat_on = True
                if event.released:
                    button.__stat_on = False

        def check_continuous(self):
            if self.__stat_on:     # 按下
                if adafruit_ticks.ticks_diff(adafruit_ticks.ticks_ms(), self.__press_tick) > SwitchButton.continuous_period:
                    self.__continuous = True
                    self.__pressed = True

        def pull_state(self) -> tuple(bool, bool):
            result = (self.__pressed, self.__continuous)
            self.__pressed = False
            self.__continuous = False
            return result
else:   # micropython
    class SwitchButton(BaseSwitchButton):
        """Switch Button Class
        支持防抖及持续按的按键检测模块Micropython
        """

        continuous_period = 1000  # 连续按多少秒进入持续触发
        throttle_ms = 400    # 坑爹会触发多次,做一下节流

        def __init__(self, pin_num: int):
            """
            :param pin_num:
            """
            self.__pin = Pin(pin_num, Pin.IN, Pin.PULL_UP)
            self.__pin.irq(handler=self.__switch_change, trigger=Pin.IRQ_FALLING)  # 下降沿触发

            self.__pressed = False
            self.__continuous = False
            self.__press_tick = 0

        def __switch_change(self, _):
            if time.ticks_diff(time.ticks_ms(), self.__press_tick) < SwitchButton.throttle_ms:   # throttle
                return
            self.__pressed = True
            self.__press_tick = time.ticks_ms()
            self.__continuous = False

        def check_continuous(self):
            if self.__pin.value() == 0:     # 按下
                if time.ticks_diff(time.ticks_ms(), self.__press_tick) > SwitchButton.continuous_period:
                    self.__continuous = True
                    self.__pressed = True

        def pull_state(self) -> tuple(bool, bool):
            result = (self.__pressed, self.__continuous)
            self.__pressed = False
            self.__continuous = False
            return result

        def sleep(self):    # 休眠irq
            self.__pin.irq(trigger=0)

        def awake(self):
            self.__pin.irq(handler=self.__switch_change, trigger=Pin.IRQ_FALLING)  # 下降沿触发

if __name__ == '__main__':
    my_switch = SwitchButton(12 if CIRCUIT else 2)
    if CIRCUIT:
        SwitchButton.init_keypad()
    else:
        from machine import disable_irq, enable_irq

    print('start')
    while True:
        if CIRCUIT:
            SwitchButton.sync_button()
        my_switch.check_continuous()
        pressed = continuous = False
        if not CIRCUIT:
            irq_state = disable_irq()
        [pressed, continuous] = my_switch.pull_state()
        if CIRCUIT:
            time.sleep(0.1)
        else:
            enable_irq(irq_state)
            time.sleep_ms(100)

        if pressed:
            print(f'OK 被{"持续按下" if continuous else "按下"}')

4)没有协程模块。这个没有打包在固件里,但是单独有py代码提供,看了下,似乎勉强能用(话说Micropython的协程也是打包的一堆py):

https://github.com/adafruit/Adafruit_CircuitPython_asyncio/tree/main

5)如果画图一般是从framebuffer开始,但是没有framebuffer,只有一个高度封装的framebufferio。这个没有打包在固件里,也有单独的py代码

GitHub - adafruit/Adafruit_CircuitPython_framebuf: CircuitPython framebuf module, based on the Python framebuf module

但是……上面这个模块是用python重新实现的,居然没实现blit,这个最能提升性能的块拷贝居然没有。。。OMG,解决的办法就是移植,本人已将framebuffer1.20的版本移植到circuitpython(已提供固件),framebuffer1.20比1.19多了很多好东西,例如画椭圆(包括圆形,圆角矩形一下变得简单了),多边形填充,这样就解决了绘图的问题

好吧,没有也没关系,大不了咱从micropython去搬,请看相关文章《编译带smartconfig、framebuffer的circuitpython》

6)zlib只有decompress,没有DecompIO
circuitpython尽落下些好东西,decompress将解压缩的数据放到内存里。而DecompIO可以实现流式解压。比方说要处理一个10M的文本进行流式检索,那么DecompIO可以流失处理,而decompress则是无能力为了,又比方说可以把一个二叉树索引链表放到压缩文件里。。。等等

最后还是只能移植,本人成功完成了从micropython移植对应的功能到circuitpython的移植

7) 根分区默认挂载的是只读的,也就意味着所有的写操作都会失败。解决办法:在code.py添加:

import storage

storage.remount("/", False) #坑爹,默认挂载的是readonly

然后拔电重启

8)时间模块不一样,tuple里多了一个没鸟用的-1,自己写了一个time模块抹平了两个系统的差别:
 

"""
同时兼容micropython和circuitpython的时间模块
这样抹平了平台差异
@Jim 2023-07
"""

from lib.epui import *

if CIRCUIT:
    from lib.adafruit_ticks import *
    from time import *

    def sleep_ms(ms: int):
        sleep(ms/1000)

    def sleep_us(us: int):
        sleep(us/1000000)

    wrap_mktime = mktime
    wrap_localtime = localtime
    def mktime(t: struct_time | tuple) -> int:
        if isinstance(t, tuple) and len(t) == 8:
            l = list(t)
            l.append(-1)
            return wrap_mktime(tuple(l))
        else:
            return wrap_mktime(t)

    def localtime(secs: int = None) -> tuple:
        s_t = wrap_localtime(secs)
        s_t = list(s_t)
        del s_t[-1]
        return tuple(s_t)
else:
    from utime import *

下面是本人编译的模块移植版本:
circuitpython模块一览

🐍Wi-Fi: off | REPL | 8.2.0-dirty\

Adafruit CircuitPython 8.2.0-dirty on 2023-07-22; S2Mini with ESP32S2-S2FN4R2

>>> help('modules')
__future__        countio           msgpack           sys
__main__          digitalio         neopixel          terminalio
_asyncio          displayio         neopixel_write    time
_pixelmap         dualbank          nvm               touchio
adafruit_bus_device                 errno             onewireio         traceback
adafruit_bus_device.i2c_device      espidf            os                ulab
adafruit_bus_device.spi_device      espnow            paralleldisplay   ulab.numpy
adafruit_pixelbuf espulp            ps2io             ulab.numpy.fft
aesio             fontio            pulseio           ulab.numpy.linalg
alarm             framebuf          pwmio             ulab.scipy
analogbufio       framebufferio     rainbowio         ulab.scipy.linalg
analogio          frequencyio       random            ulab.scipy.optimize
array             gc                re                ulab.scipy.signal
atexit            getpass           rgbmatrix         ulab.scipy.special
audiobusio        hashlib           rotaryio          ulab.utils
audiocore         i2cperipheral     rtc               usb_cdc
audiomixer        i2ctarget         sdcardio          usb_hid
audiomp3          io                select            usb_midi
binascii          ipaddress         sharpdisplay      uselect
bitbangio         json              smartconfig       vectorio
bitmaptools       keypad            socketpool        watchdog
board             math              ssl               wifi
builtins          mdns              storage           zlib
busio             memorymap         struct
canio             microcontroller   supervisor
collections       micropython       synthio
Plus any modules on the filesystem

下载 https://download.csdn.net/download/applebomb/88074245

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
劝退计算机视觉是指一些人或机构认为计算机视觉领域发展已经陷入瓶颈,建议学生或研究者转向其他领域进行研究或学习。我认为对于劝退计算机视觉的观点,我们需要进行客观的评估和判断。 首先,虽然计算机视觉领域在某些问题上面临挑战,但它仍然是一个充满活力和发展潜力的领域。计算机视觉在许多实际应用中具有重要价值,如图像识别、智能驾驶、医学影像等。随着技术的不断发展和创新,我们可以期待计算机视觉领域仍然有很多未被发掘的机会和问题等待解决。 其次,计算机视觉作为人工智能领域的一个重要分支,与其他领域的交叉融合也具有广阔的前景。例如,计算机视觉与自然语言处理、机器学习、图像生成等领域的结合,可以推动更多复杂任务的解决。因此,有时在计算机视觉领域遇到困难时,可以考虑从多个角度思考和解决问题,而不是轻易放弃。 最后,个人的兴趣和热情也是选择研究方向的重要因素。如果你对计算机视觉领域充满兴趣,并且愿意投入时间和精力进行深入学习和研究,那么劝退计算机视觉可能不是一个明智的选择。相反,你可以通过深入研究和不断学习来应对挑战,并为该领域的发展做出贡献。 综上所述,劝退计算机视觉是一个有争议的观点。我认为我们应该客观评估计算机视觉领域的发展前景,并根据个人兴趣和热情做出选择。无论选择哪个领域,都需要坚持学习和创新,为科学技术的进步做出自己的贡献。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值