1. 项目概述:一块圆屏的无限可能
最近在捣鼓一个小玩意儿,Elecrow出品的CrowPanel 1.28英寸圆形显示屏。这可不是一块普通的屏幕,它自带一颗ESP32-C3核心,出厂就刷好了MicroPython固件,开箱即用。对于像我这样喜欢快速原型开发,又不想在底层硬件配置上耗费太多时间的玩家来说,这简直是“懒人”福音。你拿到手,连上电脑,用Thonny IDE就能直接开写Python代码,点灯、画图、联网,几分钟就能看到效果。它解决的核心问题,就是极大地降低了嵌入式图形界面(GUI)和物联网(IoT)设备的入门门槛和开发周期。无论你是想做个桌面小摆件显示天气和时间,还是想为你的智能家居项目做一个酷炫的圆形状态显示器,甚至是想学习MicroPython和嵌入式GUI开发,这块板子都是一个绝佳的起点。它的核心价值在于“集成”与“即用”——显示屏、主控、开发环境全部为你准备好,你只需要专注于创意和逻辑本身。
2. 硬件深度解析:不只是“屏幕+MCU”那么简单
拿到CrowPanel 1.28,第一感觉是精致。圆形的设计在众多方方正正的开发板中显得别具一格。但它的内涵远比外观更值得深究。
2.1 核心硬件规格与选型逻辑
这块板子的核心是一颗ESP32-C3芯片。为什么是它?而不是更常见的ESP32或ESP8266?这里面的考量很实际。ESP32-C3是一个基于RISC-V架构的单核芯片,主打高性价比和低功耗。对于一块1.28英寸、分辨率240x240的圆形屏幕来说,驱动它进行基本的图形渲染和UI更新,ESP32-C3的性能绰绰有余。更重要的是,它原生支持Wi-Fi和蓝牙5.0(LE),这意味着你的显示项目可以轻松接入网络,获取在线数据,或者通过手机蓝牙进行配置,而无需额外模块。这种“All-in-One”的设计,避免了复杂的飞线和模块堆叠,让项目成品更加整洁、可靠。
屏幕本身是一块IPS材质的圆形LCD,拥有宽广的可视角度和不错的色彩表现。240x240的分辨率在1.28英寸的尺寸上,像素密度足够高,显示文字和简单图标非常清晰。屏幕通过SPI接口与ESP32-C3通信,这是一种高速、全双工的同步通信协议,专门为点对点、短距离、需要较高数据速率的场景设计,驱动屏幕刷新再合适不过。
板载的硬件资源还包括用户按键、复位按键、RGB LED(WS2812)以及一个用于供电和编程的Type-C接口。特别要提的是那个RGB LED,它直接连接在ESP32-C3的一个GPIO上,你可以用MicroPython的neopixel库轻松控制它,实现各种灯光效果,为你的项目增添氛围感。这种设计体现了模块的“友好性”,它没有把所有的GPIO都引出来做成排针(那样会破坏圆形美感且增加体积),而是将最常用、最能体现交互性的硬件(按键、彩灯)集成在了板子上,让你在不焊接任何外设的情况下就能完成丰富的交互实验。
2.2 接口与供电设计考量
Type-C接口的选择无疑是紧跟潮流的。它解决了正反插的问题,供电和数据传输一体,非常方便。在实际使用中,你可以通过这个接口由电脑USB供电(约5V/500mA),也可以使用移动电源供电,这使得项目可以轻易地脱离电脑独立运行。需要注意的是,虽然ESP32-C3功耗不高,但在屏幕全亮、Wi-Fi全速工作时,电流可能会达到150mA以上,因此建议使用质量可靠的USB线缆和电源,避免因供电不足导致屏幕闪烁或系统重启。
板子背面清晰地标注了主要的测试点和未使用的GPIO引脚。如果你有更进阶的需求,比如连接传感器、舵机或其他外设,可以通过焊接排针或直接飞线到这些测试点上。这种设计在美观和扩展性之间取得了很好的平衡:默认状态下它是一个完整的、漂亮的产品;当你需要扩展时,它依然为你保留了可能性。
3. 开发环境搭建:从零到“Hello World”
要让CrowPanel跑起来,软件环境的准备是关键第一步。整个过程围绕Thonny IDE和MicroPython展开,对新手极其友好。
3.1 Thonny IDE安装与配置要点
Thonny是一款专为Python初学者设计的IDE,但它对MicroPython的支持做得非常好,成为了许多MicroPython开发者的首选。首先,你需要去Thonny的官网下载对应你操作系统(Windows、macOS、Linux)的安装包。安装过程一路“下一步”即可,没有坑。
安装完成后,首次运行Thonny,你需要进行关键配置,让它识别你的CrowPanel。
- 用Type-C数据线将CrowPanel连接到电脑。通常,Windows系统会自动安装USB转串口芯片(通常是CH340或CP210x)的驱动,如果系统没有自动安装,你需要根据设备管理器中的提示,去芯片厂商官网下载对应驱动手动安装。
- 打开Thonny,点击右下角的状态栏,那里默认可能显示“Python 3.x.x”。点击它,在弹出的菜单中选择“MicroPython (ESP32)”。
- 这时会弹出一个配置窗口。关键步骤来了:
- 端口选择:在“Port”下拉列表中,你会看到一个新的串行端口,例如
COM3(Windows)或/dev/cu.usbserial-XXXX(macOS/Linux)。选择它。 - 解释器选择:确保解释器是“MicroPython (ESP32)”。
- 连接:点击“OK”。如果一切正常,Thonny底部的Shell(交互窗口)会显示类似
>>>的MicroPython提示符,并且会打印出ESP32-C3的一些固件信息。
- 端口选择:在“Port”下拉列表中,你会看到一个新的串行端口,例如
注意:如果连接时提示“无法打开端口”或“访问被拒绝”,通常是因为端口被其他程序(如旧的串口终端、其他IDE)占用了。关闭所有可能占用串口的软件再重试。在Linux/macOS上,有时需要将用户添加到
dialout组以获得串口权限。
3.2 首次连接与固件确认
连接成功后,我们首先验证一下板子的基本状态。在Shell中,你可以直接输入MicroPython命令并立即执行。
>>> import machine >>> import esp32 >>> print(machine.freq()) # 查看CPU频率 >>> print(esp32.idf_version()) # 查看底层ESP-IDF版本信息更重要的是,检查一下屏幕驱动相关的模块是否可用。CrowPanel通常使用st7789驱动芯片。尝试导入一下:
>>> import st7789如果没有报错,恭喜你,硬件和基础固件工作正常。如果报ImportError,说明当前固件可能没有包含st7789的驱动。这时你有两个选择:一是使用Elecrow可能提供的专用固件进行刷写(通过esptool.py工具);二是利用MicroPython的生态,我们可以在代码中直接配置SPI和引脚来驱动屏幕,后面会详细说明。
实操心得:第一次连接时,建议在Shell里多玩一下,比如用machine.Pin控制板载LED闪烁,感受一下实时交互的乐趣。这能快速建立信心,并验证你的开发环境是完全畅通的。
4. MicroPython驱动圆形显示屏的核心原理
在方形屏幕上绘图是常见的,但圆形屏幕带来了一些独特的挑战和技巧。理解其底层驱动原理,能让你更好地驾驭它。
4.1 ST7789驱动芯片与SPI通信
CrowPanel的屏幕大概率使用了ST7789V或类似的驱动芯片。这块芯片内部有一个称为“显存”(GRAM)的区域,对应着屏幕上的每一个像素点。我们的任务就是通过ESP32-C3的SPI总线,向ST7789的GRAM中写入颜色数据。
SPI通信需要四根线:
- SCK (Serial Clock):时钟线,由主设备(ESP32-C3)产生,用于同步数据。
- MOSI (Master Out Slave In):主设备输出,从设备输入,也就是ESP32-C3向屏幕发送数据/命令的线。
- DC (Data/Command):这是一根关键的控制线。它告诉屏幕,当前通过MOSI发送的是“命令”(如设置屏幕扫描方向、开/关显示)还是“数据”(即具体的像素颜色值)。通常低电平表示命令,高电平表示数据。
- CS (Chip Select):片选线,低电平有效。当有多个SPI设备时,用这根线来选择与哪个设备通信。CrowPanel上只有一个SPI设备,这根线有时会直接接地(始终选中)。
在MicroPython中,我们需要先初始化SPI总线,然后初始化屏幕驱动对象。以下是一个典型的初始化代码框架:
import machine import st7789 from time import sleep # 1. 定义引脚 (根据CrowPanel的实际接线调整,以下为常见配置) spi_sck = machine.Pin(2, machine.Pin.OUT) spi_mosi = machine.Pin(3, machine.Pin.OUT) spi_miso = machine.Pin(10, machine.Pin.IN) # 驱动屏幕通常不需要MISO,但SPI对象需要定义 spi_dc = machine.Pin(1, machine.Pin.OUT) spi_cs = machine.Pin(0, machine.Pin.OUT) spi_rst = machine.Pin(4, machine.Pin.OUT) # 复位引脚 # 2. 初始化SPI总线,设置频率(越高刷新越快,但过高可能不稳定) spi = machine.SPI(1, baudrate=40000000, polarity=0, phase=0, sck=spi_sck, mosi=spi_mosi, miso=spi_miso) # 3. 初始化显示屏对象 display = st7789.ST7789( spi, 240, # 宽度 240, # 高度 reset=spi_rst, dc=spi_dc, cs=spi_cs, rotation=0 # 旋转角度,0为默认 ) # 4. 初始化显示 display.init() sleep(0.1) display.fill(st7789.BLACK) # 清屏为黑色4.2 圆形区域的绘制与优化
在240x240的方形显存上显示圆形内容,本质是在方形画布上操作。但我们可以通过两种思路来获得更好的圆形体验:
- 仅更新圆形区域:计算一个半径为120像素的圆形区域,只更新这个区域内的像素。这需要我们在绘图函数中,对每个像素点计算其到屏幕中心(120,120)的距离,如果距离大于120,则跳过或绘制为背景色。虽然每次绘图都有一次距离计算的开销,但避免了在屏幕四角无效区域进行绘制,节省了SPI数据传输时间。
- 使用圆形遮罩(Mask):这是一种更高效的方式。我们预先在内存中计算好一个“遮罩”,它是一个二维布尔数组,大小也是240x240。数组中的每个值表示对应像素点是否在圆形内(True/False)。在每次绘制前或绘制时,根据遮罩决定是否更新该像素。这种方式将计算开销从每次绘图转移到了初始化时的一次性计算,适合需要频繁刷新的动态图形。
注意事项:ESP32-C3的内存有限(通常约400KB RAM),一个240x240的布尔数组(如果用一个字节存储一个布尔值)会占用约57.6KB,是可以接受的。但如果用更节省内存的方式(如位数组),可以进一步减少开销。在实际编程中,需要平衡内存占用和CPU计算速度。
5. 从基础到进阶:图形与UI实战
掌握了驱动原理,我们就可以开始创造视觉内容了。我们从最简单的画点画线开始,逐步构建复杂的用户界面。
5.1 基础图形绘制与文本显示
大多数MicroPython的屏幕驱动库(如st7789的配套库st7789_mpy)会提供一些基本的绘图函数,或者兼容一个叫framebuf的标准帧缓冲模块。我们可以利用framebuf来绘制基本图形。
# 假设display对象已经初始化,并且有一个framebuffer属性或方法 # 许多驱动库会将display本身作为framebuf对象使用 # 1. 绘制一个填充的矩形(作为背景) display.fill_rect(40, 40, 160, 160, st7789.color565(64, 128, 255)) # 天蓝色矩形 # 2. 绘制一个空心矩形(边框) display.rect(50, 50, 140, 140, st7789.color565(255, 255, 255)) # 白色边框 # 3. 绘制文本 (需要先有字体文件,或使用内置的位图字体) # 这里演示使用framebuf的简单文本(内置8x8字体,通常不美观) display.text("Hello Circle!", 70, 110, st7789.color565(255, 255, 0)) # 黄色文字 # 4. 绘制直线 display.line(60, 60, 180, 180, st7789.color565(0, 255, 0)) # 绿色对角线 display.line(180, 60, 60, 180, st7789.color565(255, 0, 0)) # 红色对角线 # 5. 绘制单个像素点 display.pixel(120, 120, st7789.color565(255, 255, 255)) # 在中心画一个白点实操心得:
framebuf内置的字体非常小且简陋。为了在圆形屏幕上显示美观的汉字和图标,强烈建议使用外部字体文件。你可以将.py格式的字体文件(如font.py,里面定义了字模数据)上传到板子的文件系统中,然后在代码中导入使用。网上有很多MicroPython专用的字体转换工具,可以将TTF字体转换成字模代码。
5.2 构建动态界面:时钟与天气站示例
让我们结合网络功能,做一个实用的圆形桌面时钟天气站。这个例子会综合运用图形绘制、文本显示、网络请求和定时刷新。
第一步:连接Wi-Fi
import network import time def connect_wifi(ssid, password): wlan = network.WLAN(network.STA_IF) wlan.active(True) if not wlan.isconnected(): print('Connecting to network...') wlan.connect(ssid, password) # 等待连接,最多10秒 for i in range(10): if wlan.isconnected(): break time.sleep(1) if wlan.isconnected(): print('Network config:', wlan.ifconfig()) return True else: print('Connection failed') return False # 替换成你的Wi-Fi信息 connect_wifi("Your_SSID", "Your_Password")第二步:获取网络时间(NTP)和天气数据MicroPython提供了ntptime模块来同步网络时间。天气数据则需要从一个免费的API获取,比如OpenWeatherMap。
import ntptime import urequests import json # 设置时区(例如,东八区 UTC+8) UTC_OFFSET = 8 * 3600 def sync_time(): try: ntptime.settime() # 从默认NTP服务器同步时间 print("Time synced via NTP") except Exception as e: print("NTP sync failed:", e) def get_local_time(): # 获取从NTP同步后的本地时间(秒数),并加上时区偏移 local_time_seconds = time.time() + UTC_OFFSET # 转换为时间元组 time_tuple = time.localtime(local_time_seconds) return time_tuple # (year, month, day, hour, minute, second, weekday, yearday) # 获取天气数据(需要API Key) def get_weather(api_key, city): url = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}&units=metric" try: response = urequests.get(url) data = json.loads(response.text) response.close() temp = data['main']['temp'] desc = data['weather'][0]['description'] return temp, desc except Exception as e: print("Weather fetch failed:", e) return None, None第三步:设计圆形界面并定时刷新我们需要设计一个在圆形区域内显示时间、日期、温度和天气描述的界面。为了流畅,我们采用局部刷新策略,只更新变化的部分(如秒数、分钟数)。
# 这是一个简化的主循环框架 last_second = -1 last_minute = -1 weather_update_interval = 600 # 每10分钟更新一次天气 last_weather_update = 0 temp = "--" desc = "N/A" def draw_static_elements(): # 绘制静态背景,如圆形边框、固定的文字标签(“温度”、“天气”) display.fill(st7789.BLACK) # 画一个圆形的外框 for r in range(118, 121): # 画一个粗一点的圆环 for angle in range(0, 360, 2): # 步长为2,提高速度 rad = math.radians(angle) x = int(120 + r * math.cos(rad)) y = int(120 + r * math.sin(rad)) display.pixel(x, y, st7789.color565(100, 100, 100)) # 绘制静态文字,比如顶部的“CLOCK”,底部的城市名 # 这里需要用到你加载的字体对象,假设为`my_font` # my_font.text(display, "CLOCK", x, y, color) def draw_dynamic_elements(now, temp, desc): # 绘制动态内容:时间、日期、温度、天气描述 hour_min = "{:02d}:{:02d}".format(now[3], now[4]) sec = "{:02d}".format(now[5]) date_str = "{:04d}/{:02d}/{:02d}".format(now[0], now[1], now[2]) # 1. 绘制时分(字体较大,居中偏上) # my_large_font.text(display, hour_min, x1, y1, color) # 2. 绘制秒(字体较小,在时分下方) # my_small_font.text(display, sec, x2, y2, color) # 3. 绘制日期(屏幕底部) # my_font.text(display, date_str, x3, y3, color) # 4. 绘制温度和天气描述(屏幕左右或下方) # my_font.text(display, f"{temp}°C", x4, y4, color) # my_font.text(display, desc, x5, y5, color) # 主循环 sync_time() draw_static_elements() while True: now = get_local_time() current_second = now[5] current_minute = now[4] # 每分钟检查是否需要更新天气 if time.time() - last_weather_update > weather_update_interval: temp, desc = get_weather("YOUR_API_KEY", "Beijing") last_weather_update = time.time() # 天气更新后需要重绘整个动态区域 draw_dynamic_elements(now, temp, desc) # 每秒重绘秒数,每分钟重绘整个时间(因为分钟变了) if current_second != last_second: # 只擦除和重绘秒数区域,而不是整个动态区域,以提高效率 # 这里需要实现一个局部擦除函数,例如用背景色矩形覆盖旧秒数 # erase_area(sec_x, sec_y, sec_width, sec_height) # my_small_font.text(display, f"{current_second:02d}", sec_x, sec_y, color) last_second = current_second if current_minute != last_minute: # 分钟改变,需要重绘整个时间区域(时分秒) draw_dynamic_elements(now, temp, desc) last_minute = current_minute time.sleep(0.1) # 降低CPU占用这个示例涵盖了从网络连接到UI更新的完整流程。关键在于分层绘制(静态背景一次,动态内容频繁更新)和局部刷新(只更新变化的文本区域),这是保证显示流畅且不闪烁的核心技巧。
6. 高级技巧与性能优化
当项目变得复杂时,性能和管理代码的复杂度成为挑战。这里分享几个进阶技巧。
6.1 使用LVGL构建复杂图形界面
framebuf的功能对于复杂UI来说太基础了。此时,LVGL(Light and Versatile Graphics Library)是一个强大的选择。它是一个开源的嵌入式图形库,支持按钮、标签、滑块、图表等丰富的控件,并且有丰富的动画效果。
在MicroPython上使用LVGL,通常需要一个叫lv_micropython的移植版本。你需要将LVGL的库文件(一堆.py文件)上传到板子的文件系统。由于ESP32-C3内存有限,需要精心配置LVGL,只启用你需要的控件和功能,并可能使用外部PSRAM(如果板子支持)来作为图形缓冲区。
初始化LVGL并创建一个简单按钮的代码框架如下:
import lvgl as lv import display_driver # 这是一个用于连接lvgl和具体屏幕驱动的模块,需要自己实现或寻找适配st7789的版本 # 初始化lvgl lv.init() # 初始化显示驱动和输入设备驱动(如果有点击触摸功能) disp = display_driver.driver() # 这个函数需要你根据具体屏幕实现 # 创建一个活跃的屏幕对象 scr = lv.scr_act() # 创建一个按钮 btn = lv.btn(scr) btn.set_size(100, 50) btn.center() # 为按钮添加标签 label = lv.label(btn) label.set_text("Click Me!") label.center() # 定义按钮点击事件回调 def btn_event_cb(e): print("Button clicked!") btn.add_event_cb(btn_event_cb, lv.EVENT.CLICKED, None) # 在主循环中定期调用lvgl的任务处理器 while True: lv.timer_handler() time.sleep_ms(5)使用LVGL会将你的项目提升到一个新的水平,但也会增加学习曲线和资源消耗。对于CrowPanel 1.28,运行中等复杂度的LVGL界面是可行的,但需要仔细优化。
6.2 内存管理与代码组织优化
MicroPython运行在资源受限的环境下,良好的编程习惯至关重要。
- 避免全局变量:尽量使用局部变量。函数执行完毕后,局部变量的内存会被回收,而全局变量会一直存在。
- 及时关闭资源:使用完文件、网络连接(
urequests返回的响应对象)后,记得调用.close()方法。 - 使用
gc模块:MicroPython有垃圾回收器。在内存紧张时,可以手动调用gc.collect()来回收内存。在创建大量临时对象(比如在循环中拼接字符串)的前后,手动回收一下很有帮助。 - 模块化编程:将代码拆分成多个
.py文件。例如,config.py存放Wi-Fi密码和API密钥,display_helper.py存放所有屏幕绘图函数,network_manager.py处理网络连接和数据获取。在主程序main.py中导入它们。这样不仅代码清晰,而且MicroPython的导入机制会对字节码进行缓存,有时比把所有代码写在一个文件里更节省内存。 - 使用
_开头命名:对于不需要被其他模块导入的变量或函数,用下划线开头(如_internal_data)。这虽然不改变功能,但是一种良好的约定,提醒你这是内部使用的。 - 冻结模块:对于永远不会改变的第三方库(如LVGL),可以将它们“冻结”到MicroPython固件中。这需要你重新编译固件,但这样做之后,这些模块会存储在只读的Flash中,而不是占用宝贵的RAM。这对于大型库来说是终极的节省RAM的方法。
7. 常见问题与排查实录
在实际操作中,你肯定会遇到各种各样的问题。这里记录了一些典型问题及其解决方法。
7.1 连接与驱动问题
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| Thonny无法连接,提示“无法打开端口” | 1. 驱动未安装。 2. 端口被占用。 3. 线缆仅供电,无数据功能。 | 1. 检查设备管理器(Windows)或ls /dev/tty*/ls /dev/cu*(macOS/Linux),查看是否有新的串口设备出现。若无,安装CH340/CP210x驱动。2. 关闭所有串口终端、Arduino IDE、PlatformIO等软件,重试。 3. 换一根确认支持数据传输的USB线。 |
| 连接后Shell无反应,或输出乱码 | 1. 波特率等串口参数不匹配。 2. 板子未进入MicroPython模式(可能处于Bootloader模式)。 | 1. 在Thonny的MicroPython配置中,尝试调整波特率(通常115200)。 2. 尝试按住板上的“BOOT”或“FLASH”按钮再上电,然后松开按钮,再尝试连接。这会让板子进入固件上传模式,此时需要再用Thonny选择正确的端口和解释器连接。 |
导入st7789等模块失败 | 1. 当前固件未包含该驱动。 2. 驱动文件未上传到板子。 | 1. 检查固件信息。考虑刷写包含st7789驱动的MicroPython固件。2. 通过Thonny的文件管理器(View -> Files),将 st7789.py等驱动文件上传到板子的根目录。 |
7.2 编程与运行问题
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 程序运行一段时间后死机或重启 | 1. 内存泄漏(如未关闭网络连接、创建了大量未释放的对象)。 2. 看门狗(WDT)超时。 | 1. 使用gc.mem_free()在关键位置打印剩余内存,监控内存变化。确保urequests.get()后调用.close()。2. 在长时间循环中,加入 time.sleep_ms(10)或调用machine.idle(),以喂看门狗。也可以暂时禁用看门狗(不推荐用于最终产品):from machine import WDT; wdt = WDT(timeout=0)# 禁用 |
| 屏幕显示闪烁或残影 | 1. 刷新速度太快,SPI通信不稳定。 2. 全屏刷新导致。 | 1. 尝试降低SPI波特率(如从40MHz降到20MHz)。 2. 采用局部刷新策略,只更新屏幕上变化的部分,而不是每次都用 fill清空整个屏幕。 |
| Wi-Fi连接不稳定 | 1. 信号弱。 2. 代码中重连逻辑不健壮。 | 1. 确保板子离路由器不要太远。 2. 实现一个带重试机制和错误处理的Wi-Fi连接函数,并在主循环中定期检查连接状态,断线后自动重连。 |
| 上传文件到板子失败 | 1. 文件系统已满。 2. 文件正在被运行的程序打开。 | 1. 使用import os; os.listdir()和os.statvfs('/')查看文件列表和剩余空间。删除不用的文件。2. 重启板子(确保 main.py没有打开你要上传的文件),然后再上传。 |
独家避坑技巧:
- 给
main.py加个“安全锁”:在main.py开头写一个5秒的延迟time.sleep(5),然后才是你的主程序。这样,如果你上传了一个有错误的main.py导致板子不断重启,你还有5秒时间通过Thonny连接到板子,快速删除或修改main.py文件,救活你的设备。 - 使用
try...except包裹主循环:在main.py的while True循环外层包裹一个try...except,并在except中打印错误信息到串口。这样即使程序崩溃,你也能在Thonny的Shell里看到错误原因,而不是一个无声的重启。 - 善用Thonny的文件系统功能:Thonny的文件管理器不仅用于上传下载。你可以直接在上面编辑板子里的文件,保存后会即时生效。这对于调试和修改配置文件非常方便。
玩转CrowPanel 1.28这块圆屏的过程,就是一个典型的嵌入式开发缩影:从硬件认识到环境搭建,从驱动理解到应用实现,再到问题排查和性能优化。它麻雀虽小,五脏俱全,给了我们一个完美的舞台去实践MicroPython编程、硬件交互和物联网创意。最重要的是,它让这一切的开始变得足够简单,让你能把更多精力花在“创造”本身,而不是纠缠于复杂的底层配置。无论是作为一个学习工具,还是一个快速原型平台,它都值得你花时间去探索。