circuitpython虽然说是基于micropython,但是实际上与micropython有很大的区别,在此记录一下蛋疼的点以及对应应对方案:
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)SPI、I2C使用不一样:
使用另外的接口了
4)键盘模块不一样,虽然做了简单的包装,但是完全把中断的接口屏蔽并封装了,重新包装一下,勉强还是可以用。之前的键盘模块整合circuitpython后的代码:
from lib.epui import *
import 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 CSwitchButton(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(CSwitchButton.pins)
CSwitchButton.pins.append(self.pin)
CSwitchButton.buttons.append(self)
@classmethod
def init_keypad(cls):
CSwitchButton.keys = keypad.Keys(tuple(CSwitchButton.pins), value_when_pressed=False, pull=True)
@classmethod
def sync_button(cls):
while True: # 拉取所有的状态
event = CSwitchButton.keys.events.get()
if event is None:
break
button = CSwitchButton.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) > CSwitchButton.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
import machine
class MSwitchButton(BaseSwitchButton):
"""Switch Button Class
支持防抖及持续按的按键检测模块Micropython
"""
continuous_period = 1000 # 连续按多少秒进入持续触发
throttle_ms = 400 # 坑爹会触发多次,做一下节流
def __init__(self, pin: Pin):
"""
:param pin:
"""
self.__pin = pin
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) < MSwitchButton.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) > MSwitchButton.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 = CSwitchButton(12) if CIRCUIT else MSwitchButton(Pin(2, Pin.IN, Pin.PULL_UP))
if CIRCUIT:
CSwitchButton.init_keypad()
print('start')
while True:
if CIRCUIT:
CSwitchButton.sync_button()
my_switch.check_continuous()
pressed = continuous = False
if not CIRCUIT:
irq_state = machine.disable_irq()
[pressed, continuous] = my_switch.pull_state()
if CIRCUIT:
time.sleep(0.1)
else:
machine.enable_irq(irq_state)
time.sleep_ms(100)
if pressed:
print(f'OK 被{"持续按下" if continuous else "按下"}')
4)没有协程模块。这个没有打包在固件里,但是单独有py代码提供,看了下,似乎勉强能用:
https://github.com/adafruit/Adafruit_CircuitPython_asyncio/tree/main
5)没有framebuffer。这个没有打包在固件里,也有单独的py代码
GitHub - adafruit/Adafruit_CircuitPython_framebuf: CircuitPython framebuf module, based on the Python framebuf module
但是……这个模块是用python重新实现的,居然没实现blit,这个最能提升性能的块拷贝居然没有。。。OMG
好吧,没有也没关系,大不了咱从micropython去搬,请看相关文章《编译带smartconfig、framebuffer的circuitpython》