news 2026/5/15 19:04:21

利用CircuitPython内置传感器实现CPU温度监控与本地日志记录

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
利用CircuitPython内置传感器实现CPU温度监控与本地日志记录

1. 项目概述:从芯片温度到数据洞察

在嵌入式项目里,给设备“把脉”是基本功。CPU温度,这个看似简单的数据点,其实是窥探硬件运行状态的绝佳窗口。它不仅能告诉你芯片是不是在“发烧”,更能间接反映环境变化、负载情况,甚至是散热设计的有效性。以前做这类监控,往往得外挂一个温度传感器,再折腾ADC采样和校准,流程繁琐。直到我发现,很多现代微控制器,比如Adafruit常用的SAMD21系列,其CPU内部就集成了温度传感器,并且CircuitPython已经把它做成了一个开箱即用的属性。

这个项目的核心,就是绕开复杂的硬件电路,直接利用microcontroller.cpu.temperature这个“内置仪表”,把读取到的温度数据,以文本日志的形式,实时记录到开发板自带的闪存文件系统中。整个过程,你只需要几行Python代码,无需焊接,无需额外的元器件,真正体现了CircuitPython“快速原型”的理念。它非常适合用于长期部署的设备健康监测、环境温度趋势分析(需注意CPU温度与环境温度的差异和滞后性),或是作为学习嵌入式数据采集与文件IO的入门实践。

2. 核心思路与方案选型解析

2.1 为什么选择CircuitPython与内置传感器?

这个方案的核心优势在于“极简”。传统MCU开发,无论是用Arduino C还是裸机C,读取内部温度传感器都需要直接操作芯片的寄存器,涉及复杂的模数转换、校准系数计算,对新手极不友好。CircuitPython的microcontroller模块将这些底层细节全部封装,提供了一个直接的.temperature属性,返回的就是摄氏度浮点数,极大地降低了技术门槛。

选择文件系统记录而非无线传输或外接SD卡,是基于场景的权衡。对于很多低功耗、离线或原型验证阶段的项目,首先需要的是可靠、简单的数据落地方案。开发板内置的闪存(通常有几MB)虽然空间有限,但记录温度这类小数据绰绰有余。直接写入文件系统,数据立即可通过USB在电脑上查看,流程闭环,调试方便。这个方案奠定了数据流的基础:感知(CPU温度) -> 处理(可选单位转换) -> 存储(本地文件)

2.2 权限管理:一个关键的设计挑战

这里遇到一个嵌入式系统里经典的矛盾:开发便利性与运行时安全性的冲突。CircuitPython设备连接电脑后,其内部存储会作为一个U盘(USB Mass Storage)挂载,方便我们直接拖拽修改code.py等文件。但如果在程序运行(code.py)时,也允许Python代码向同一个文件系统写入数据,就会产生访问冲突,可能导致数据损坏。

因此,CircuitPython默认将文件系统设置为“只读”模式供代码访问,以保证USB侧可写。我们的日志程序需要写文件,就必须改变这个默认行为。这就是boot.pystorage模块出场的原因。boot.py在系统启动、USB连接建立之前执行,在这里我们可以用storage.remount(“/”, False)将根目录重新挂载为可写。但这样一来,USB侧就失去了写入权限,你无法再通过电脑直接编辑代码了。

为了解决这个两难问题,原教程给出了一个巧妙的硬件交互方案:通过一个物理开关(或跳线)来动态决定启动时的挂载模式。具体来说,在boot.py中检测某个GPIO引脚(如D0)的电平。如果该引脚被接地(拉低),则启动为“代码可写”模式,用于数据记录;如果该引脚悬空或拉高,则保持默认的“USB可写”模式,方便代码更新。这种设计将控制权交给了硬件状态,非常符合嵌入式开发“硬软结合”的思维。

3. 硬件准备与软件环境搭建

3.1 硬件选型与连接

本项目对硬件要求极低。核心是一块支持CircuitPython且CPU内置温度传感器的开发板。Adafruit Gemma M0、Trinket M0、Feather M0系列,以及功能更丰富的Circuit Playground Express、Metro M4等,只要是基于SAMD21(Cortex-M0+)或SAMD51(Cortex-M4F)等系列芯片的板子,通常都支持。购买前最好查阅官方文档,确认microcontroller.cpu.temperature属性可用。

对于实现“选择性挂载”功能,你需要准备一个物理开关或一根跳线。以Gemma M0为例:

  1. 找一根杜邦线或直接用金属镊子/导线。
  2. 将开发板的D0引脚(或你代码中定义的其他引脚)与GND(地)引脚短接。 这个短接动作,就是在告诉boot.py:“这次启动,请允许我的代码写入文件系统”。当你需要更新代码时,断开这个短接即可。

注意:Circuit Playground Express板载了一个滑动开关,其电路已经连接到了D7引脚。因此,对于CPX,你无需额外飞线,直接使用这个开关即可,在代码中将检测的引脚改为board.D7

3.2 CircuitPython固件更新与库确认

确保你的开发板运行的是CircuitPython 2.0.0或更高版本,因为storage模块和microcontroller.cpu.temperature属性是从该版本引入的。更新固件是第一步:

  1. 访问CircuitPython官网,找到你的板型对应的最新.uf2固件文件。
  2. 将板子通过USB连接电脑,并快速双击复位按钮,使其进入BOOTLOADER模式(此时电脑会出现一个名为CPLAYBOOTFEATHERBOOT等的U盘)。
  3. 将下载的.uf2文件拖入该U盘。盘符会自动弹出,稍等片刻,板子重启后就会出现一个新的名为CIRCUITPY的U盘,这表明CircuitPython固件已刷写成功。

固件本身已包含microcontrollerstorageboarddigitalio等核心模块,无需额外安装库文件,这为我们省去了很多依赖管理的麻烦。

4. 核心代码实现与分步详解

4.1 创建动态挂载控制的boot.py

这个文件是系统启动的钥匙,它只执行一次。我们将实现通过硬件引脚状态决定文件系统权限的逻辑。

# SPDX-FileCopyrightText: 2017 Limor Fried for Adafruit Industries # SPDX-License-Identifier: MIT import board import digitalio import storage # 1. 初始化硬件开关引脚 # 这里以D0为例,如果你用CPX的滑动开关,请改为 board.D7 switch_pin = board.D0 switch = digitalio.DigitalInOut(switch_pin) # 2. 配置引脚为输入模式,并启用内部上拉电阻 switch.direction = digitalio.Direction.INPUT switch.pull = digitalio.Pull.UP # 默认内部上拉到高电平 # 3. 根据引脚电平决定挂载模式 # switch.value 在引脚被拉低(接地)时为 False,悬空/拉高时为 True # 我们需要在引脚接地(False)时,让代码可写(readonly=False) storage.remount("/", readonly=switch.value)

代码解读与实操要点

  • digitalio.Pull.UP:启用内部上拉电阻至关重要。它确保在引脚悬空时,其电平能被稳定地拉至高电平(逻辑1True),避免因静电干扰产生误判。只有当用导线明确将引脚与GND连接时,电平才会被拉低至False
  • storage.remount(“/“, readonly=switch.value):这是权限切换的核心。readonly参数为True时,代码只能读不能写,但USB可写(方便我们更新程序)。为False时,代码可读写,USB则变为只读。我们将引脚电平switch.value直接赋值给它,实现了硬件控制逻辑。
  • 重要警告:写完boot.py并保存后,你必须先弹出(Eject)CIRCUITPYU盘,再物理按下板子上的复位按钮boot.py才会在新的一次完整上电启动流程中执行。仅在REPL中按Ctrl+D软复位是无效的。

4.2 主程序code.py:温度记录与状态指示

这是项目的主循环,负责持续读取温度并写入文件,同时通过LED提供状态反馈。

# SPDX-FileCopyrightText: 2017 Limor Fried for Adafruit Industries # SPDX-License-Identifier: MIT import time import board import digitalio import microcontroller # 1. 初始化状态指示灯LED # 大部分板子的板载LED连接在D13引脚 led = digitalio.DigitalInOut(board.D13) led.switch_to_output() try: # 2. 以追加模式打开日志文件 with open("/temperature_log.txt", "a") as log_file: while True: # 3. 读取CPU温度(单位:摄氏度) temp_c = microcontroller.cpu.temperature # (可选)转换为华氏度 # temp_f = (temp_c * 9 / 5) + 32 # log_file.write(‘{:.2f}\n’.format(temp_f)) # 4. 格式化并写入数据 # 使用 {0:f} 确保写入的是浮点数格式,避免科学计数法 log_file.write(‘{0:f}\n’.format(temp_c)) # 立即刷新缓冲区,确保数据写入物理存储,避免断电丢失 log_file.flush() # 5. 翻转LED状态,指示一次写入完成 led.value = not led.value # 6. 设置采样间隔(单位:秒) time.sleep(1) except OSError as e: # 7. 异常处理:处理文件写入失败的情况 blink_delay = 0.5 # 默认错误闪烁频率:1Hz (亮0.5s, 灭0.5s) # 错误码 28: 设备空间不足 if e.args[0] == 28: blink_delay = 0.25 # 空间不足时快速闪烁:2Hz # 在实际项目中,这里可以尝试删除旧文件或停止记录 # 错误码 30: 文件系统为只读(可能boot.py未正确设置,或D0未接地) # elif e.args[0] == 30: # blink_delay = 1.0 # 只读错误慢闪:0.5Hz # # 可以添加更明确的错误指示,如特定颜色RGB灯 # 进入错误指示循环 while True: led.value = not led.value time.sleep(blink_delay)

代码深度解析与避坑指南

  1. 文件打开模式:使用“a“(append) 模式而非“w“(write)。“w“模式每次打开都会清空文件原有内容,只适合单次运行。而“a“模式会在文件末尾追加数据,非常适合长期日志记录,即使设备断电重启,新的数据也会接在旧数据之后。
  2. flush()的重要性:在嵌入式系统中,为了延长Flash寿命和提升性能,写入操作经常先缓存在内存中。log_file.flush()方法强制将缓冲区数据立即写入物理存储。如果不调用flush(),在突然断电的情况下,最近几秒的数据可能会丢失。对于关键数据记录,这是一个必要的安全措施。
  3. 错误处理的艺术try-except块是生产级代码的必备。我们主要捕获OSError。除了教程提到的错误码28(空间不足),错误码30同样关键,它表示“只读文件系统错误”。如果你的程序一运行就进入错误闪烁,且闪烁频率是默认的1Hz(而非快速的2Hz),很大概率就是错误码30,即boot.py的挂载模式没有切换成功,代码没有写入权限。此时应检查:
    • boot.py文件是否存在且语法正确。
    • 是否已通过“弹出U盘 -> 物理复位”的流程重启。
    • 硬件上D0引脚是否已可靠接地。
  4. 采样率与功耗权衡time.sleep(1)表示每秒记录一次。对于温度这种变化相对缓慢的量,这个频率通常足够。如果你想降低功耗,可以增大休眠间隔,比如time.sleep(10)(每10秒一次)。但要注意,过于频繁的写操作(如sleep(0.1))会加速Flash磨损,且温度读数本身也有一定的响应时间,过高频率无意义。

5. 系统部署、数据获取与可视化

5.1 完整工作流部署

  1. 硬件连接:用导线将板子的D0(或你指定的引脚)与GND短接。
  2. 文件部署:在电脑上,打开CIRCUITPY盘。首先创建(或编辑)boot.py,写入4.1节的代码。然后创建code.py,写入4.2节的代码。
  3. 启动记录:安全弹出CIRCUITPYU盘,然后按下板子上的物理复位按钮。此时,板载LED应开始以1秒为周期稳定闪烁,表明程序正在正常运行并记录数据。
  4. 停止与数据读取:当需要停止记录并读取数据时,首先断开D0与GND的短接线,然后再次物理复位板子。这次启动,由于boot.py检测到D0为高电平,文件系统会以“USB可写”模式挂载。此时将板子连接电脑,打开CIRCUITPY盘,就能直接看到并打开temperature_log.txt文件,里面是按行存储的温度值。

5.2 数据处理与简单可视化

获取到的temperature_log.txt是纯文本文件,每一行一个温度值(摄氏度)。你可以用任何文本编辑器或脚本语言处理。

使用Python进行简单分析

import matplotlib.pyplot as plt # 读取数据 with open(‘temperature_log.txt‘, ‘r‘) as f: # 过滤空行并转换为浮点数列表 data = [float(line.strip()) for line in f if line.strip()] # 基本统计 print(f“数据点数: {len(data)}“) print(f“平均温度: {sum(data)/len(data):.2f} °C“) print(f“最高温度: {max(data):.2f} °C“) print(f“最低温度: {min(data):.2f} °C“) # 绘制趋势图 plt.figure(figsize=(10, 5)) plt.plot(data) plt.title(‘CPU Temperature Log‘) plt.xlabel(‘Sample Number‘) plt.ylabel(‘Temperature (°C)‘) plt.grid(True) plt.tight_layout() plt.show()

这段脚本能帮你快速计算温度的平均值、极值,并绘制出温度随时间(采样序列)变化的曲线图,非常直观。

5.3 项目扩展思路

基础功能实现后,你可以从多个维度扩展这个项目:

  • 多传感器融合:结合板载或外接的光照、湿度传感器(如I2C接口的BME280),在日志中同时记录多条数据线,用逗号分隔,形成CSV格式。
  • 时间戳记录:CircuitPython的time模块可以获取自上次启动以来的相对时间(time.monotonic())。虽然不能提供真实世界时间,但可以记录采样间隔。如果需要绝对时间,可以考虑外接一个便宜的RTC(实时时钟)模块。
  • 条件触发记录:修改循环逻辑,仅在温度超过某个阈值(如temp_c > 60)时才进行记录和LED报警,实现简单的过热保护监测。
  • 低功耗优化:对于电池供电场景,可以将主循环中的time.sleep()替换为microcontroller.cpu.sleep()等更深度的休眠指令,并在休眠期间完全关闭外设,仅依靠内部定时器唤醒,大幅降低待机功耗。
  • 数据导出自动化:编写一个电脑端的Python脚本,当设备以“USB可写”模式连接时,自动将temperature_log.txt文件复制到电脑指定位置,并清空板子上的旧文件,实现半自动化的数据收集。

这个项目麻雀虽小,五脏俱全,涵盖了嵌入式开发中传感器数据采集、文件I/O操作、硬件交互、异常处理等多个核心环节。通过动手实践,你能深刻理解软硬件协同的工作原理,为后续更复杂的物联网应用打下坚实的基础。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/15 19:04:20

Adobe-GenP激活工具:5分钟解锁Adobe创意套件全功能

Adobe-GenP激活工具:5分钟解锁Adobe创意套件全功能 【免费下载链接】Adobe-GenP Adobe CC 2019/2020/2021/2022/2023 GenP Universal Patch 3.0 项目地址: https://gitcode.com/gh_mirrors/ad/Adobe-GenP Adobe-GenP是一款专为Adobe Creative Cloud用户设计的…

作者头像 李华
网站建设 2026/5/15 19:04:19

一根网线,双机互联:从局域网通信到共享公网访问的实战指南

1. 为什么需要双机直连? 记得刚工作那会儿,公司IT部门还没给我配电脑,我只好把自己的笔记本和台式机搬到工位。两台机器之间要频繁传代码和测试数据,用U盘来回倒腾实在太麻烦。后来隔壁工位的老张扔给我一根网线:"…

作者头像 李华
网站建设 2026/5/15 19:03:42

AI安全入门:新手必懂的AI安全核心概念与边界

AI安全入门:新手必懂的AI安全核心概念与边界📝 本章学习目标:本章是基础入门部分,帮助零基础读者建立对AI安全合规治理的初步认知。通过本章学习,你将全面掌握"AI安全入门:新手必懂的AI安全核心概念与…

作者头像 李华
网站建设 2026/5/15 19:02:48

别再死记硬背了!Vivado伪双口RAM的wea、ena信号到底怎么用?一个实例讲透

Vivado伪双口RAM控制信号实战指南:从原理到避坑 第一次接触Vivado的伪双口RAM时,那些密密麻麻的控制信号确实让人头疼。尤其是wea和ena这两个看似简单却暗藏玄机的信号,稍不注意就会导致数据读取异常或者意外覆盖。记得去年我在一个图像处理项…

作者头像 李华
网站建设 2026/5/15 19:02:48

基于BMapGL与MapVGL,实战城市人流热力图可视化

1. 从零开始搭建热力图开发环境 第一次接触百度地图GL版开发时,我也被各种配置搞得晕头转向。现在把完整的环境搭建流程梳理出来,帮你避开我踩过的那些坑。BMapGL作为百度地图的WebGL版本,相比传统API渲染效率提升明显,特别适合数…

作者头像 李华
网站建设 2026/5/15 19:02:18

广州南沙名酒回收市场深度测评:哪家店铺回收更靠谱?专业排名揭晓

引言随着生活水平的提高,名酒收藏逐渐成为一种时尚。然而,当名酒不再适合收藏或需要变现时,选择一家靠谱的回收店铺至关重要。本文将针对广州南沙地区的名酒回收市场进行深度测评,为您揭晓哪家店铺回收更靠谱,并提供一…

作者头像 李华