news 2026/9/10 9:25:14

树莓派Pico+MicroPython温度记录器:文件读写从入门到实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
树莓派Pico+MicroPython温度记录器:文件读写从入门到实战

1. 项目思路与硬件选型:为什么是 Pico 加 MicroPython

做温度数据记录这个事,很多人第一反应是用电脑加传感器,再写个上位机程序。但真正用过就会发现,用树莓派 Pico 这类单片机来做反而更合适。原因其实很简单:Pico 体积小、价格便宜、功耗低,插上电池就能在角落里连续跑几天甚至几周,不需要像电脑那样占地方还费电。而且 MicroPython 这个解释型语言对硬件操作封装得相当友好,读写文件、操作传感器都是几行代码的事,特别适合快速验证想法。

这也就带出了我最想强调的一点:这个项目真正练的不是“测温度”,而是把 MicroPython 下的文件读写这套基本功彻底吃透。温度传感器只是数据来源的示例,你把 DHT11 换成光照传感器、土壤湿度传感器,代码骨架几乎不用大改。这也是为什么我推荐新手从“温度数据记录”入手,而不是一上来就做复杂的 IoT 上报项目。

1.1 硬件准备清单

这个项目需要的硬件非常少,而且大部分玩 Pico 的人手里应该都有存货:

硬件型号建议备注
主控板树莓派 Pico 或 Pico WPico W 带 WiFi,但本教程用不到
温度传感器DS18B20(防水探头版)买带 4.7kΩ 电阻的套件,省事
连接线杜邦线公对母若干至少 3 根
可选Micro USB 数据线能传数据和供电即可

关于温度传感器,我多聊两句。市面上常见的 DHT11、DHT22 和 DS18B20 我都用过,但做数据记录我强烈推荐 DS18B20,原因有三个:

第一个原因是精度和稳定性。DHT11 的精度是 ±2°C,听着还行,但实际测下来偏差能到 3°C 以上,而且响应速度慢,读数波动大。DS18B20 的精度是 ±0.5°C,分辨率可选 9 到 12 位,做环境温度记录绰绰有余。

第二个原因是接线和协议。DHT11 需要自己写时序控制代码,对时序要求极其严格,一旦系统有中断干扰读数就会错乱。DS18B20 走的是 OneWire 单总线协议,MicroPython 里有现成的onewireds18x20库,直接调用就行,稳定得多。

第三个原因更实在——防水。DS18B20 有带不锈钢探头和橡胶线的版本,可以直接扔水里、埋土里测温度。DHT11 裸露在空气中,湿度一大就报废。

1.2 MicroPython 文件系统的特点

既然要做文件读写,就得先了解 Pico 上的 MicroPython 文件系统长什么样。Pico 出厂时带有 2MB 的 Flash 存储,MicroPython 固件会把其中一部分用作文件系统。

这个文件系统的具体格式是LittleFS,和电脑上常见的 FAT32、NTFS 不一样。LittleFS 是专门为嵌入式设备设计的,针对断电写入做了优化,还带断电恢复能力。简单说,即使你在写入过程中突然断电,文件系统也不会整个损坏,最多丢一点刚写的数据。

在 MicroPython 交互式终端里,可以用os模块查看当前目录结构:

import os print(os.listdir('/'))

执行后你会看到类似['boot.py', 'main.py']的输出,这就是 Pico 文件系统的根目录。boot.py是开机最先执行的脚本,main.py是主程序入口,MicroPython 启动完boot.py后会自动执行main.py

这里有个容易踩的坑要提醒一下:Pico 的 Flash 容量有限,写入文件时要注意大小。我用os.statvfs()查过,在 MicroPython 固件下可用空间大约在 1.5MB 左右。记录温度数据如果每 10 秒写一行,24 小时也就 8640 行,按每行 30 字节算,约 260KB,跑一周完全没问题。但如果你打算高频率记录,就得考虑定期清理旧文件,或者把数据上传到远端存储。

2. 文件读写 API 详解:把这几招吃透,Pico 存数据就稳了

文件读写是 MicroPython 中非常基础也非常重要的操作,但很多教程都是一笔带过。这里我把它掰开揉碎了讲清楚,因为后面的温度记录程序好不好用,全看这部分基础牢不牢。

2.1 打开文件的几种模式

在 MicroPython 中操作文件,核心函数就是open()。它的基本用法是:

f = open('data.txt', 'w')

open()的第一个参数是文件名,第二个参数是打开模式。我把常用模式整理成了表格:

模式说明文件不存在时文件存在时
'r'只读报错从头读
'w'只写,覆盖创建清空后写入
'a'追加写创建保留原有内容,从末尾追加
'x'排他创建创建报错(文件已存在)
'rb'/'wb'二进制读/写同上同上

我在实际项目中,数据记录类的写入强烈建议用'a'追加模式。原因是设备在断电重启后,如果程序用'w'模式打开文件,会把历史数据全部清空,之前记录的宝贵数据直接没了。用'a'模式则能在原有文件末尾继续写,数据不丢失。

另外要注意的是,MicroPython 的文件系统不支持目录的递归创建。你想写log/2024/temperature.txt,得先手动创建loglog/2024这两个目录。

import os try: os.mkdir('log') except OSError as e: # 目录已存在时会报错,这里直接忽略 pass
2.2 写入与读取的完整姿势

写入文件,最稳妥的方式是使用with语句。它能自动处理文件关闭,避免因异常导致文件句柄泄漏:

with open('temperature.txt', 'a') as f: f.write('25.5\n')

with语句块的代码执行完后,文件会自动关闭,不需要手动调用f.close()。这个写法有两个好处:一是代码简洁,二是即使写文件过程中抛出异常,文件也会被正确关闭,不会出现数据写入不完整却占用句柄的问题。

读取文件同样可以用with

with open('temperature.txt', 'r') as f: content = f.read() print(content)

如果你的文件很大,一次性read()会很费内存。这时可以按行读取:

with open('temperature.txt', 'r') as f: for line in f: print(line.strip()) # 去掉末尾的换行符
2.3 文件写入的急刹车:flush 到底管什么用

这是不少 Pico 玩家的知识盲区。你写完数据后,数据并不会立刻物理写入 Flash,而是先放在内存缓冲区里,等缓冲满了或者文件关闭时才真正落盘。

这个机制在电脑上问题不大,但在嵌入式设备上却很要命。想象一个场景:你的 Pico 正在采集温度数据,写到第 100 条时突然断电。由于缓冲区里的数据还没落盘,前 99 条数据可能都在,但第 100 条丢失,甚至整个文件都可能出现损坏。

解决方法是主动调用flush()强制把缓冲区数据写入存储:

with open('temperature.log', 'a') as f: f.write('26.3\n') f.flush()

注意:flush()只是把数据从 MicroPython 的缓冲区推送到文件系统层,还没完全落盘到 Flash。但在实际使用中,这个层次已经足够应对绝大多数意外断电场景了。

那每次写完数据都flush()会不会影响性能?会有一点,但温度数据记录本身写入频率低,每秒甚至每几秒才写一次,这个开销完全可忽略。建议每次写入后都调用flush(),换取数据的绝对可靠。

3. 温度数据记录实战:代码逐段拆解

这一章我们进入核心环节。全程带实操细节,照着抄就能在你的 Pico 上跑起来。

3.1 硬件接线

先看硬件连接。DS18B20 有三个引脚:VCC 接 3.3V,GND 接 GND,信号线 DQ 接 GPIO 引脚。以 Pico 的引脚定义来说,物理引脚 36 是 3.3V,物理引脚 38 是 GND,信号线建议接到 GP0(物理引脚 1)。

接线时要注意:DS18B20 的信号线需要接一个 4.7kΩ 的上拉电阻到 3.3V。很多 DS18B20 模块板载了这颗电阻,你买的如果是不带电阻的裸探头,就得自己在面包板上接一个。没有上拉电阻的后果是传感器完全读不出数据,返回全是 85°C 或错误值。

接好线后,可以先跑一小段代码确认传感器能正常读取:

import machine import onewire import ds18x20 import time # 传感器连接到 GP0 ds_pin = machine.Pin(0) ds_sensor = ds18x20.DS18X20(onewire.OneWire(ds_pin)) roms = ds_sensor.scan() print('找到的温度传感器:', roms) while True: ds_sensor.convert_temp() time.sleep_ms(750) # 等待温度转换完成 for rom in roms: print('温度:', ds_sensor.read_temp(rom)) time.sleep(1)

这里有个细节:convert_temp()是触发一次温度转换,然后必须等待至少 750ms才能读取结果。如果没等够时间直接read_temp(),得到的是上一次转换的旧数据。

3.2 添加时间戳:让数据有“上下文”

记录温度如果只记数字,那就失去了记录的意义。你得知道这个温度是什么时候测的。但问题来了,Pico 本身没有实时时钟模块,断电后时间就归零了。

解决思路有几种:

第一种是在程序启动时手动设置时间,适合一次性测试:

import machine import time rtc = machine.RTC() rtc.datetime((2024, 12, 1, 0, 11, 30, 0, 0))

rtc.datetime()的八个参数分别是年、月、日、星期、时、分、秒、微秒。注意星期几这里我填 0 表示周一。设置一次后,只要 Pico 不断电,时间就会一直走。

第二种是联网同步时间,适合 Pico W 用户。Pico W 带 WiFi,可以通过ntptime模块从 NTP 服务器自动获取当前时间。这个方案不受断电影响,但需要网络支持:

import network import ntptime wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect('SSID', 'PASSWORD') while not wlan.isconnected(): pass ntptime.settime() # 同步网络时间

注意:ntptime同步的时间是 UTC 时区,国内用户需要自己加上 8 小时偏移。这个方案适合 Pico W 玩家,普通 Pico 没网就别折腾了。

对于本教程的测试场景,我建议直接用RTC手动设置时间,够用且省事。

3.3 完整代码:温度数据记录器

把上面的知识点融汇贯通,下面给出一个完整可跑的温度记录程序。这个程序会每 10 秒读取一次温度,写入temperature.log文件,并在每行记录中加入时间戳:

import machine import onewire import ds18x20 import time import os import json # 配置:传感器连接在 GP0 DS_PIN = 0 LOG_FILE = 'temperature.log' INTERVAL_SECONDS = 10 # 初始化温度传感器 ds_pin = machine.Pin(DS_PIN) ds_sensor = ds18x20.DS18X20(onewire.OneWire(ds_pin)) roms = ds_sensor.scan() if len(roms) == 0: print('错误:未找到 DS18B20 传感器') raise SystemExit(1) # 设置 RTC 时间(年, 月, 日, 星期, 时, 分, 秒, 微秒) rtc = machine.RTC() rtc.datetime((2024, 12, 1, 0, 10, 30, 0, 0)) def get_timestamp(): """获取格式化的时间字符串""" year, month, day, _, hour, minute, second, _ = rtc.datetime() return '{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}'.format( year, month, day, hour, minute, second) def read_temperature(): """读取温度值并返回格式化字符串""" ds_sensor.convert_temp() time.sleep_ms(750) # 等待转换完成 temps = [] for rom in roms: temp = ds_sensor.read_temp(rom) temps.append('{:.2f}'.format(temp)) return ','.join(temps) def log_data(): """写入一条温度数据到日志文件""" timestamp = get_timestamp() temp_str = read_temperature() line = timestamp + ',' + temp_str + '\n' with open(LOG_FILE, 'a') as f: f.write(line) f.flush() # 强制写入 Flash print(line.strip()) # 同时在终端显示 # 主循环 print('温度记录器启动') print('日志文件:', LOG_FILE) runtime_seconds = 0 while True: try: log_data() except Exception as e: print('写入错误:', e) time.sleep(INTERVAL_SECONDS) runtime_seconds += INTERVAL_SECONDS # 每小时输出一次运行状态 if runtime_seconds % 3600 < INTERVAL_SECONDS: print('已运行 {} 小时'.format(runtime_seconds // 3600))

这段代码我建议你直接复制到 Thonny 保存为main.py,然后重启 Pico 运行。程序会自动创建日志文件,每 10 秒追加一行数据。

一个小建议:测试阶段把INTERVAL_SECONDS改成 2 秒,可以快速验证程序逻辑正确,确认没问题后再改回 10 秒正式跑。

4. 文件读回、格式化与数据迁移:采集完怎么看数据

数据攒了一堆,问题来了:怎么把这些数据变成能分析的格式?怎么从 Pico 上导出来?

4.1 在 Pico 上直接读取文件

如果只是临时看几眼数据,可以在 MicroPython 的 REPL 环境里直接读文件。启用 Thonny 的 Shell 窗口,执行:

with open('temperature.log', 'r') as f: for line in f: print(line.strip())

这种方法适合看最近几条数据。但如果文件很大,全部打印会刷屏,而且 REPL 的终端缓冲区有限,太旧的数据会被挤掉。这时可以加个判断条件,只显示最后 N 行:

lines = [] with open('temperature.log', 'r') as f: lines = f.readlines() # 查看最后 10 行 for line in lines[-10:]: print(line.strip())
4.2 把数据文件导出到电脑

Pico 没有直接拖拽文件到电脑的 USB 协议,得借助一点点小技巧。最常用的方法是用rshell工具,它是一个命令行程序,可以通过串口访问 Pico 的文件系统。

安装 rshell:

pip install rshell

然后连接 Pico,进入文件传输模式:

rshell -p /dev/ttyACM0

在 rshell 的交互环境中,用cp命令把文件复制到电脑:

cp /pyboard/temperature.log /home/pi/data/

如果你不想安装额外工具,也可以用 Thonny 的文件面板。在 Thonny 里,视图下拉菜单勾选“文件”,会显示 Pico 上的文件列表。右键点击你想导出的文件,选“下载到电脑”即可。

4.3 数据分析与可视化

数据导出后是 CSV 格式的文本文件,Excel、WPS、Python pandas、MATLAB 通吃。这里说一个用 pandas 分析的小示例:

import pandas as pd df = pd.read_csv('temperature.log', names=['timestamp', 'temperature']) df['timestamp'] = pd.to_datetime(df['timestamp']) df.set_index('timestamp', inplace=True) print(df.describe())

如果要画图:

import matplotlib.pyplot as plt df.plot() plt.show()

这样就能看到完整的温度变化曲线了。如果是长时间记录比如 24 小时,整个设备也会给你很好的温度变化趋势。

5. 常见的坑与排错心得

最后分享一些实测中遇到的问题。这些坑网上很多教程不会写,但确实会拦住不少人。

5.1 传感器扫描不到设备

ds_sensor.scan()返回空列表,这是刚接触 DS18B20 时最常见的问题。大概率原因是线接错了或者上拉电阻缺失。先检查 VCC、GND、DQ 三根线是否各就各位,再确认 DQ 脚到 3.3V 之间是否接了一个 4.7kΩ 电阻。

还有一个隐蔽坑:某些 USB 数据线只有供电线没有数据线,导致 Thonny 连不上 Pico 或运行不稳定。换一根确认过的数据线试试。

5.2 文件名不能乱取

MicroPython 的 LittleFS 文件系统对文件名有字符限制,某些在电脑上合法的字符在 Pico 上会报错。我试过用冒号:和时间戳拼文件名,直接抛出 OSError。

保险做法是只用大小写字母、数字、短横线和下划线。时间戳我用连字符分隔而不是冒号:

filename = 'log-2024-12-01-10-30.log' # 合法
5.3 写入 flvsh 频率过高

温度记录可能十分钟写一次,没问题。但假如你设计的是一个高速数据记录器,每秒写几十次,就得考虑 Flash 寿命问题了。Flash 的擦写次数是有限制的,典型值在 1 万到 10 万次之间。长期高频写入会缩短 Flash 寿命。

解决方案有两个方向:一是把多条数据攒在内存里,每满一定数量或固定时间间隔再批量写入一次;二是外接 TF 卡,用 SD 卡模块存放高频数据,Pico 内置 Flash 只跑系统。

5.4 电池供电下时间的漂移

如果你的 Pico 用电池供电并长时间运行,RTC 的时钟会逐渐漂移。我用树莓派 Pico 实测过,常温下一天大约漂移 1 到 3 秒。对于温度记录这种分钟级采样场景完全可以忽略,但如果做高精度时间记录,就需要外接带电池的 DS3231 时钟模块。

5.5 文件被写入半行导致解析失败

如果记录过程中 Pico 意外断电,最后一行可能会不完整(比如只写到2024-12-01 10:30,23.就断电了)。用 pandas 读取时会报解析错误。建议读取时加error_bad_lines=False参数跳过坏行:

df = pd.read_csv('temperature.log', names=['timestamp', 'temperature'], error_bad_lines=False)

或者在自己的数据读取代码里跳过长行或不符合格式的行。

5.6 存储写满的处理

跑几天后temperature.log会越来越大,最终把 Flash 塞满。解决方案是在程序里加入磁盘空间检查,一旦可用空间低于阈值就自动轮转文件,比如把当前日志重命名为temperature-20241201.log,然后新建一个空日志继续写:

import os def check_and_rotate(): stat = os.statvfs('/') free_bytes = stat[0] * stat[3] # 块大小 × 空闲块数 if free_bytes < 50 * 1024: # 低于 50KB 时轮转 timestamp = time.strftime('%Y%m%d%H%M') os.rename('temperature.log', 'temperature-%s.log' % timestamp)

这个方案相当于做了一次简单的日志轮转,保证设备能长期稳定运行不用人工干预。

6. 扩展思路:从文件记录到更多实战

掌握了 MicroPython 文件读写的基础,能做的事情其实远不止温度记录。我把这个能力延伸一下,你能立刻联想到很多实际应用场景。

场景一:农田环境监测站。用 Pico 接土壤湿度传感器、光照传感器和 DS18B20。每隔 30 分钟记录一次所有数据,存成 CSV。在田间跑上一个生长季度,把存数据的 SD 卡取回来,就能在电脑上分析出最适宜作物生长的环境参数范围。这个做法已经被很多智慧农业爱好者验证过,成本几十块钱。

场景二:家庭能源审计。Pico 接个电流互感器模块,记录家里大功率电器的启停规律。24 小时的数据全记录在文件里,通过数据分析能发现冰箱每天启停多少次、空调一个晚上平均运行多久。有了这些基础数据,优化用电方案就不是猜测而是有据可依。

场景三:物联网边缘缓存。如果 Pico W 通过 WiFi 上报数据到云平台,网络偶尔中断是常有的事。你可以在本地文件系统里缓存未上报的数据,网络恢复后在断点处续传。这样既保证数据完整,也不用为数据上传失败写复杂的逻辑。MicroPython 的文件系统天然适合做这个事。

场景四:设备运行日志。自制设备跑久了,出问题怎么排查?在关键节点写日志到文件里,比如启动时间、传感器异常记录、内存占用情况。设备出故障时,读一下日志文件就能定位问题。生产级的嵌入式设备都会这么做,你的小项目同样应该。

文件记录能力是整个数据链路的地基。温度也好,湿度也好,电压也好,核心都是“定期采样 + 可靠存储 + 方便读取”,这恰恰是本教程三个模块对应的能力。

最后再说一个我个人的小习惯。每次给 Pico 写完程序,我都会在代码开头加几行注释,标注硬件接线、时间设置说明和近期修改记录。嵌入式项目一放就是几个月,下次翻出来改数据时,这些信息能救老命。也算是给将来的自己省点事。

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

py进球游戏

操场上……“小何&#xff0c;接球&#xff01;”小方喊道。咻&#xff01;“球要进了&#xff01;“小何说。啊&#xff01;不好&#xff01;被防住了&#xff01;结束后……小方&#xff1a;“小何&#xff0c;你会编出进球游戏吗&#xff1f;现实踢球&#xff0c;太没意思&a…

作者头像 李华
网站建设 2026/9/10 9:25:02

扩散模型-2020-理论基础:DDPM【目前“文本生图像”所采用的扩散模型大都是来自于DDPM】【输入:带噪音的图片+文本+噪音程度值;输出:待去除的噪音】【带噪音的图片-输出的噪音=生成的图片】

原始论文:Denoising Diffusion Probabilistic Models 分析论文:Understanding Diffusion Models: A Unified Perspective 分析论文:The Curious Case of Neural Text Degeneration 分析论文:Natural TTS Synthesis by Conditioning WaveNet on Mel Spectrogram Predict…

作者头像 李华
网站建设 2026/9/10 9:23:37

Qwen-Drive-1.0-4B:开源多模态模型统一自动驾驶感知、问答与规划

1. 从模块分立到三合一&#xff1a;Qwen-Drive-1.0-4B 想解决什么问题1.1 传统流水线里感知、规划、问答为什么各干各的做自动驾驶研发的人对这套流程再熟悉不过&#xff1a;环视相机图像进来&#xff0c;先走感知模块&#xff0c;输出3D检测框、车道线、可行驶区域&#xff1b…

作者头像 李华
网站建设 2026/9/10 9:23:16

E710射频读写器开发入门:从源码到读卡距离调试全流程

简介&#xff1a;E710射频读写器示例程序与源码包面向RFID开发者、嵌入式工程师及设备集成人员&#xff0c;提供从底层通讯到上层应用的一整套参考实现&#xff0c;可据此快速掌握读写器初始化、标签识别、数据写入等核心操作&#xff0c;降低项目开发门槛。包内共67个文件&…

作者头像 李华
网站建设 2026/9/10 9:23:01

激光雷达与摄像头融合的船舶吃水深度自动识别方案

干了小半年的港口测量项目&#xff0c;我把激光雷达和摄像头搬到码头边上&#xff0c;做了一个不靠人读的船舶吃水深度识别算法。初期跑通方案到稳定出数&#xff0c;踩的坑比预想多&#xff0c;但这套融合思路基本成熟了&#xff1a;雷达负责几何和距离&#xff0c;摄像头负责…

作者头像 李华