MicroPython 在 ESP32 上支持线程(Thread)功能,通过_thread模块实现。线程允许程序并发执行多个任务,适合处理需要同时运行的场景,例如传感器数据采集和网络通信。
_thread模块提供线程管理的核心功能。需注意 MicroPython 的线程实现可能因硬件和固件版本不同而有所差异。
import _thread
import time
def thread_function(name):
for i in range(5):
print("Thread {}: Count {}".format(name, i))
time.sleep(1)
_thread.start_new_thread(thread_function, ("Thread-1",))
运行结果:
Thread Thread-1: Count 0
Thread Thread-1: Count 1
Thread Thread-1: Count 2
Thread Thread-1: Count 3
Thread Thread-1: Count 4
多线程操作共享资源时需使用锁(Lock)避免竞争条件。_thread模块提供简单的锁实现。
lock = _thread.allocate_lock()
shared_data = 0
def safe_increment():
global shared_data
with lock:
shared_data += 1
print("Shared data:", shared_data)
_thread.start_new_thread(safe_increment, ())
运行结果:Shared data: 1
以下实例展示如何在 ESP32 上使用线程处理传感器数据上传和 LED 控制:
import _thread
import time
from machine import Pin
led = Pin(2, Pin.OUT) # ESP32 板载 LED
data_lock = _thread.allocate_lock()
sensor_data = []
def sensor_thread():
while True:
simulated_data = time.ticks_ms() # 模拟传感器数据
with data_lock:
sensor_data.append(simulated_data)
time.sleep(0.5)
def network_thread():
while True:
with data_lock:
if sensor_data:
print("Uploading data:", sensor_data.pop(0))
time.sleep(1)
def led_thread():
while True:
led.value(not led.value())
time.sleep(0.2)
_thread.start_new_thread(sensor_thread, ())
_thread.start_new_thread(network_thread, ())
_thread.start_new_thread(led_thread, ())
ESP32 的 MicroPython 线程存在以下限制:
以下代码展示如何增强线程健壮性:
def robust_thread():
try:
while True:
# 线程主要逻辑
time.sleep(1)
except Exception as e:
print("Thread error:", e)
finally:
print("Thread exiting")
_thread.start_new_thread(robust_thread, ())
MicroPython 的线程调度通常是抢占式的,但具体行为取决于底层实现。开发者无法直接设置线程优先级,需通过延时控制来协调线程执行。
import _thread
import time
def high_freq_task(name,interval):
while True:
# 高频任务
print(name)
time.sleep(interval)
def low_freq_task(name,interval):
while True:
print(name)
time.sleep(interval)
_thread.start_new_thread(high_freq_task, ("High_Freq_Thread",1))
_thread.start_new_thread(low_freq_task, ("Low_Freq_Thread",5))
运行结果:
High_Freq_Thread
High_Freq_Thread
High_Freq_Thread
High_Freq_Thread
Low_Freq_Thread
High_Freq_Thread
High_Freq_Thread
High_Freq_Thread
High_Freq_Thread
High_Freq_Thread
Low_Freq_Thread
参数说明:从上面例程及运行结果,我们很容易知道,第一个参数是线程名称,后面的参数就比较灵活,甚至可以不需要任何参数。
下面代码是我们真实项目中的部分代码:
import _thread as thread
lock = thread.allocate_lock()
def configwifi_task(name):
if wlan.ssid and wlan.password:
with lock:
wlansts = wlan.check_wifi()
if not wlansts :
with lock:
tft.showstring("正在连接到 " + wlan.ssid,Chat_X_Posi,Chat_Hint_Y_Posi,color(0,0xff,0))
try:
with lock:
wlan.wlan.connect(wlan.ssid,wlan.password)
max_wait = 10
while max_wait > 0:
with lock:
wlansts = wlan.check_wifi()
if wlansts:
break
max_wait -= 1
text = "等待连接……" + "{:02d}".format(max_wait)
tft.showstring(text,Chat_X_Posi,Chat_Hint_Y_Posi + 20,color(0,0xff,0))
# print(text)
time.sleep(1)
with lock:
wlansts = wlan.check_wifi()
tft.fill(color(0,0,0))
tft.battery_status(H_Pixel - 20,0,20,12,percent)
tft.show()
if not wlansts:
tft.showstring("连接失败",Chat_X_Posi,Chat_Hint_Y_Posi,color(0,0xff,0))
except Exception as e:
# print(e)
tft.showstring("连接失败",Chat_X_Posi,Chat_Hint_Y_Posi,color(0,0xff,0))
thread.start_new_thread(configwifi_task,("wificonnect",))
先简单说明一下,启动这个线程的原因。我们的项目需要用到WIFI,开始的时候,我们程序启动后直接连接WIFI,但很快发现,WIFI连接有时需要较长时间,甚至有时会接连失败,这就导致我们需要等待较长时间,才能进行后续的操作,所以我们建立了一个专门用于连接WIFI的线程。
之所以把这个线程拿出来作实例讲解,是因为我们刚开始的时候犯了个大错,我们没有添加线程锁机制,导致程序崩溃,启动直接崩溃,最要命的是,我们做这个之前没有备份,差不多3天修改添加的代码全在板上,电脑上最新的代码是3天前的。所以特意拿这部分代码出来做实例,提醒大家线程锁机制的重要性。
启用线程时,多个线程中都有访问的硬件资源一定要添加锁机制。
该线程本身的功能非常简单,就是连接WIFI,并等待10秒,连接成功则立即结束线程,否则提示连接失败结束线程。
来源:https://blog.csdn.net/weald2000/article/details/148203985
RISC-V(发音为“risk-five”)是一个基于精简指令集(RISC)原则的开源指令集架构(ISA)。RISC-V指令集可以自由地用于任何目的,允许任何人设计、制造和销售RISC-V芯片和软件。
本节我们在迭代二的基础上使用四位数码管和OLED显示屏显示相关交互信息。
本节我们在迭代一的基础上增加采集土壤湿度数据,并根据湿度数据来决定是否自动进行浇水动作。
本节我们实现一个基本能工作的手动浇水装置,即通过按下按键来闭合继发器让小水泵进行浇水。
本小节通过点亮LED和串口输出两个程序,来初步掌握ArduinoIDE、了解GPIO和串口使用、同时把开发环境与开发板的连接,上传程序的各环节跑通,
本程序是小鹏物联网智能浇花套件的单机版程序(不连接物联网),供同学们参考。
本文介绍ESP32中的中断机制,以及如何通过GPIO中断实现按钮控制。重点讲解了如何设置中断服务例程、处理中断抖动问题,并提供了消除中断抖动的示例代码。
本文主要介绍在未联网(AP热点)情况下实现WEB交互界面的CSS和javascript库。
本文介绍如何使用Arduino-ESP32库中的API函数获取ESP32的芯片、RAM信息等,并提供了一个示例程序代码。
ESP32系列(包括ESP32-S3)搭载Xtensa双核处理器,默认情况下Arduino框架仅使用单核运行用户代码,通过多核编程,可以充分利用硬件资源来提升系统响应和性能。
ESP32 芯片有34个物理GPIO管脚。每个GPIO管脚都可用作一个通用IO,或连接一个内部的外设信号。IO_MUX ¹、RTC IO MUX 和GPIO交换矩阵用于将信号从外设传输至GPIO管脚。