资讯动态

51单片机驱动OLED与DS18B20显示温度时间

发布时间:2026/10/21 9:05:44 来源:尧图企业网站定制
简介这份zip压缩包是一个基于51单片机、DS18B20数字温度传感器与OLED显示屏的实时温度时间显示项目面向单片机初学者、电子爱好者及嵌入式开发者也适合作为课程设计或毕业设计的参考。压缩包共31个文件大小约107KB包含C语言源文件main.c、iic.c、temp.c等、头文件、Keil工程文件uvproj、hex烧录文件以及一张效果图此外还有编译生成的obj与lst中间文件方便查看工程全貌。资源已有2347人学习下载。项目核心涉及DS18B20的一线总线协议读取、OLED屏的I2C驱动以及时间显示逻辑代码结构清晰注释与模块划分便于理解。通过烧录hex文件或在Keil中打开源码进行编译调试读者可直观掌握传感器数据采集与显示设备交互的方法同时也能学习51单片机外设编程和软硬件协同设计的实用技巧。1. OLED显示屏 DS18B20一块小屏把温度和时间都装进去空调房里永远吵不准温度是几度买的成品温度计电池半年一换屏幕还灰蒙蒙看不清。某开发者手里刚好有一堆吃灰的 51 单片机最小系统板、一块 0.96 寸 OLED、一个 DS18B20 温度传感器于是花了两个晚上拼出这个「OLED 显示屏 DS18B20 显示温度和时间」的小项目。它做的是这么一件事用 51 单片机同时驱动两块外设一块是四针 IIC 接口的 OLED 显示屏另一块是单总线协议的 DS18B20 数字温度传感器中间再挂一个 DS1302 时钟芯片让屏幕不仅显示实时温度还同步显示年月日、时分秒。适合的人群很明确刚学完单片机基础、想把手头传感器整合成完整小系统的学生开发者以及想给智能家居做个低成本状态面板的嵌入式爱好者。整个项目逻辑不复杂但把通信协议、时序配合、显示刷新这些基本功全练了一遍。2. 硬件架构和通信原理OLED、DS18B20、DS1302 是怎么凑到一起的2.1 系统整体框图三条总线的分工这个项目的本质是一个多外设协同的单片机系统。主控是经典的 STC89C52 或者 STC12 系列工作在 5V 供电下。三个外设分别挂在不同的通信接口上避免相互干扰。OLED 显示屏标准 0.96 寸分辨率 128x64驱动芯片是 SSD1306走 IICI2C总线默认从机地址 0x78写或 0x7A读。IIC 只需要两根线SCL时钟和 SDA数据。DS18B20 温度传感器走 1-Wire 单总线协议一根数据线既供电又传数据DQ 引脚需要外接一个 4.7kΩ 上拉电阻到 VCC。DS1302 时钟芯片也是 3 线接口CE片选、SCLK时钟、IO数据用来记录时间系统断电后靠纽扣电池 CR2032 继续走时。为什么这么组合因为这三样东西刚好是嵌入式入门阶段最典型的三类通信方式IIC、单总线、三线 SPI 变体。做完这个项目你对这三种总线的手动时序模拟就都有了代码层面的理解不是对着数据手册空看而是自己写代码去操作每一位。2.2 引脚分配表一个可行的默认接法这里给出一个常用的引脚分配方便你对照自己的开发板接线。不同开发板的 P2 口、P3 口位置可能不一样但无所谓只要在宏定义里改引脚编号就行。外设引脚单片机端口说明OLEDSCLP1.0IIC 时钟线OLEDSDAP1.1IIC 数据线DS18B20DQP1.2单总线数据线需外接上拉电阻DS1302CEP1.3时钟芯片片选DS1302SCLKP1.4时钟芯片串行时钟DS1302IOP1.5时钟芯片数据线DS18B20 的 VCC 和 GND 分别接 5V 和地DS1302 的 VCC2 接 5VVCC1 接 3V 纽扣电池。OLED 是四针模块VCC 接 5V 也能工作因为模块上通常自带稳压和电平转换但长时间的稳妥做法还是参考模块说明书有些纯裸屏必须接 3.3V。接线完成后先别急着上电。用万用表量一遍 VCC 和 GND 之间有没有短路这是做硬件最容易翻车的一步杜邦线插错一个孔位上电瞬间芯片就冒烟了。2.3 SSD1306 驱动原理写命令和写数据的区别OLED 屏幕的核心是 SSD1306 驱动芯片它内部有一块 1KB 的显存分成 8 页Page每页 128 个字节。你往这块显存里写什么屏幕就显示什么。写显存有两个基本操作写命令和写数据。写命令时IIC 总线上的字节格式是这样走的START - 从机地址(0x78) - 控制字节(0x00) - 命令字节 - STOP控制字节为 0x00 表示后面跟的是命令为 0x40 表示后面跟的是显示数据。这个区别是整个驱动代码的基础。初始化屏幕时你要发一串初始化命令比如关闭显示、设置显示时钟分频比、设置多路复用比、设置显示偏移、开启显示等。多数代码段里你会看到类似这样的初始化函数void OLED_Init(void) { OLED_WriteCmd(0xAE); // 关闭显示 OLED_WriteCmd(0x20); // 设置内存寻址模式 OLED_WriteCmd(0x02); // 页寻址模式 OLED_WriteCmd(0xC8); // 扫描方向从上到下 OLED_WriteCmd(0x40); // 起始行 0 OLED_WriteCmd(0x81); // 对比度设置 OLED_WriteCmd(0xCF); // 对比度值 OLED_WriteCmd(0xA1); // 段重映射正常方向 OLED_WriteCmd(0xA6); // 正常显示(不是反色) OLED_WriteCmd(0xA8); // 多路复用比设置 OLED_WriteCmd(0x3F); // 64 行 OLED_WriteCmd(0xD3); // 显示偏移 OLED_WriteCmd(0x00); // 偏移 0 OLED_WriteCmd(0xD5); // 显示时钟分频 OLED_WriteCmd(0x80); // 分频值 OLED_WriteCmd(0x8D); // 电荷泵设置 OLED_WriteCmd(0x14); // 开启电荷泵 OLED_WriteCmd(0xAF); // 开启显示 OLED_Clear(); }这段初始化的关键点是电荷泵设置。0x8D 命令后面必须跟 0x14 来开启内部升压电路。很多人屏幕亮不起来的典型原因就是漏了这一步或者写成了 0x10 关闭电荷泵。OLED 本身不自发光如果没有内部电荷泵升压屏幕就是漆黑一片。初始化完成后整屏显示什么由显存内容决定。2.4 DS18B20 时序读温度的核心难点DS18B20 是单总线器件所有通信都在一根线上完成所以时序要求非常严。读写每一位数据都要精确控制时间和顺序。读一次温度的基本流程分为四步复位、跳过 ROM因为总线上只有一个传感器、启动温度转换、读暂存器数据。时序代码的要点是// 复位 DS18B20 bit DS18B20_Reset(void) { bit presence; DQ 0; delay_us(480); // 拉低至少 480us DQ 1; delay_us(60); // 释放总线后等 60us presence DQ; // 读存在脉冲0 表示有设备应答 delay_us(420); return presence; }复位时序里主机先拉低总线 480 微秒以上然后释放。DS18B20 会在 60~240 微秒内把总线拉低作为应答脉冲。如果你读到 presence 不为 0说明总线上没有设备或者接线有问题。这里容易踩的坑是延时函数的精度单片机主频不同同样写一个delay_us(10)实际延时可能差好几倍。最好的做法是用逻辑分析仪或者示波器看波形没有的话就观察温度读取是否稳定不稳定就调整延时参数。接下来是写一位和读一位的时序。写 1 位时主机拉低总线后在 15 微秒内释放总线表示写 1保持拉低则表示写 0。读一位时主机拉低总线 1 微秒后释放紧接着采样总线电平。// 读一个字节 unsigned char DS18B20_ReadByte(void) { unsigned char i, data_byte 0; for (i 0; i 8; i) { data_byte 1; DQ 0; _nop_(); _nop_(); DQ 1; _nop_(); _nop_(); if (DQ) data_byte | 0x80; delay_us(60); } return data_byte; }这段代码里的data_byte 1把上一次的数据往低位移动然后判断当前位是否为 1如果是就把最高位置 1这样最后组出来的字节是最低位先接收符合小端顺序。读出来的温度是两个字节低字节的高 4 位是小数部分高字节是符号位和整数部分。要把原始值换算成可显示的温度值需要按 0.0625 的精度进行转换temp_value (read_val 0x07FF) * 0.0625; // 去除符号位后乘精度 if (read_val 0x8000) temp_value -temp_value; // 负数处理2.5 DS1302 时钟芯片与按键配合的校时思路DS1302 负责提供时间数据它内部维护了一套寄存器分别对应秒、分、时、日、月、周、年。每个寄存器存的都是 BCD 码所以写入时要转换读出时也要转换。比如十进制数 23 在 BCD 码里是 0x23直接往寄存器里写 23 是不对的写 0x23 才能表示 23 点。读时间的代码一般长这样unsigned char DS1302_ReadByte(void) { unsigned char i, temp 0; for (i 0; i 8; i) { temp 1; if (IO) temp | 0x80; SCLK 1; SCLK 0; } return temp; }含义是每一个时钟上升沿读取一位数据因为 DS1302 是低位先出的结构所以组装的时候用右移。这个习惯和 DS18B20 一致但是和很多 SPI 外设高位先出不一样写驱动脚本时要注意区分否则读出来的数据就像打乱了一样。3. 核心代码逐段拆解从初始化到屏幕上出现一行温度3.1 主程序骨架一个大循环里的三步流程程序的结构非常清晰分为三步初始化硬件、在 while 循环里读传感器数据、将格式化后的文本渲染到 OLED 上。主函数如下void main(void) { OLED_Init(); // 初始化 OLED DS1302_Init(); // 初始化时钟芯片 DS18B20_Init(); // 初始化温度传感器端口 OLED_ShowString(0, 0, Temp:, 16); // 静态提示文字 while (1) { DS18B20_StartConvert(); // 启动一次温度转换 temp DS18B20_GetTemp(); // 读取转换后的温度值 DS1302_GetTime(); // 读取当前时间存到全局结构体 OLED_ShowNum(0, 2, temp, 3, 16); // 显示温度整数部分 OLED_ShowString(45, 2, ., 16); // 小数点 OLED_ShowNum(53, 2, temp_decimal, 1, 16); // 小数部分 OLED_ShowNum(0, 5, time.year, 2, 16); OLED_ShowString(32, 5, -, 16); OLED_ShowNum(40, 5, time.month, 2, 16); // ... 时间显示略 delay_ms(200); // 刷新率控制太快会闪烁 } }这里有个常见的性能问题DS18B20 每次温度转换需要 750ms 的最大转换时间如果在转换过程中delay_ms死等整个系统会卡顿时间的秒数跳动会不流畅。常见做法是启动转换后先去读时钟、刷新显示等下一轮循环再读温度。这样温度滞后一点但界面不会卡顿。我开始写这个项目时用了死等的办法结果显示的时间每秒钟跳两次界面总是一顿一顿的。3.2 OLED 显示函数设计坐标和大小如何控制为了让屏幕上的文字排版可控需要封装一整套坐标定位的底层函数。SSD1306 的最小操作单位是页每页高 8 像素横坐标 0~127。常见的字库大小是 6x8ASCII 字符占 6 列 8 行和 8x16占 8 列 16 行。我的显示函数包含下面几个OLED_ShowChar(x, y, char, size)先判断字符码如果是换行符就换行处理否则从字库里取模数据然后写入显存。OLED_ShowString(x, y, str, size)循环调 ShowChar每显示一个字符 x 坐标加 (size/22)。OLED_ShowNum(x, y, num, len, size)把一个数字拆成个十百千位每位加 0 转成字符显示。字符串显示函数是其中最容易出错的地方。如果 x 坐标递增方式不对连续显示的长字符串在屏幕中间会出现断裂重叠。我一般固定用 len 参数控制显示长度先把数字按% 10拆成单个数位再循环处理这样无论是两位数温度还是四位年份都能对齐。实际上手时很难一次写对调试建议是先用 OLED 显示固定字符串确认坐标正确再接入动态数据。这里也推荐采用查表法做字库方便特殊符号定制。在这个项目里我用到的字模是自行提取的 ASCII 码 0~9、A~Z 加上摄氏度符号。DS18B20 温度要显示为类似 26.5其中小数点右侧是 .5 而不是 0.5所以数据结构上把整数部分和小数部分从函数里分离出来会更好。小数部分来自 DS18B20 的低字节低四位变化范围是 0~15对应 0.0 到 0.9375 度。简单处理时用它除以16*10得到一位小数这么做虽然不算精确但视觉上够用而且显示格式更加自然。3.3 串口打印辅助调试看不见的时候先打出来很多人 OLED 上没有任何输出时第一反应是改显示代码但往往真正的问题出在传感器数据读取。这种场景下我是强烈建议留一个串口调试输出的。51 单片机的 UART 初始化和发送一个字节的代码很简单void UART_Init() { SCON 0x50; // 模式18位UART允许接收 TMOD | 0x20; // 定时器1工作于模式28位自动重装 TH1 0xFD; // 波特率 9600 11.0592MHz TL1 0xFD; TR1 1; // 启动定时器1 } void UART_SendByte(unsigned char dat) { SBUF dat; while (!TI); TI 0; }波特率设置的关键在于晶振频率。11.0592MHz 晶振下 TH1 0xFD 对应 9600 波特率用 12MHz 晶振时算出来的波特率不准串口收到的就是乱码。所以做这个项目请尽量用 11.0592MHz 晶振的板子。把读出的温度和时间的原始十六进制数通过串口发到电脑用串口助手看一遍就能判断是传感器的问题还是屏幕显示的问题。这算是调嵌入式的一个基本心法显示是最容易隐藏真相的环节先把数据原始值打出来能省两小时排查时间。3.4 一个完整的中断驱动刷新率与按键扫描的配合主循环里除了读数据还有按键扫描的任务。为了让屏幕刷新流畅需要把按键扫描放在主循环里轮询避免用中断去处理机械按键的抖动。项目里一般设置两个按键一个切换显示模式温度/时间/同时显示另一个进入时间校准模式。按键消抖的稳妥写法是状态机方式。判断按键按下等 10ms 再读一次确实是低电平才认为是有效按下。这种写法不会出现松手误触发而且在中断里敲抖容易把时间片吃掉所以我建议都放在主循环里每轮扫描一遍当前键值保存到全局变量。校时状态下短按“模式”键来到下一个要调整的字段年/月/日/时/分/秒长按“调整”键完成数字递增把 BCD 码和十进制做转换后写回 DS1302 寄存器。具体实现上很多模块的做法是先把要修改的字段从time结构体里转成十进制修改后重新转换为 BCD 再写入同时通过一个标志位指明当前写的是哪个寄存器地址。4. 从零跑起来搭建电路、烧录固件、整机调试与常见踩坑4.1 需要的硬件清单和连线确认这里先给一份完整的物料清单方便核对手里缺什么51 单片机开发板或最小系统板STC89C52RC / STC12C5A60S2 均可0.96 寸 IIC 接口 OLEDSSD1306 驱动DS18B20 温度传感器TO-92 封装要注意引脚顺序DS1302 时钟芯片 32.768KHz 晶振 纽扣电池座10kΩ 电位器或者直接接一个 4.7kΩ 电阻杜邦线若干5V 电源USB-TTL 模块就能供电USB-TTL 下载模块比如 CH340 芯片的那种实物连线时DS18B20 的引脚朝向要让半圆形面对自己从左到右分别是 GND、DQ、VCC。这个顺序和常见的三极管封装一样很多人接反了导致温度读出来是 85 度。DS1302 的晶振要尽量靠近芯片引脚如果用长导线连接晶振时钟极容易停振或者走时不准。OLED 模块的 SDA 和 SCL 不要接反否则屏幕完全没反应。IIC 总线上拉电阻一般模块已经自带如果你用的是裸屏就要在 SCL 和 SDA 上各接一个 4.7kΩ 上拉电阻到 VCC。4.2 烧录和验证下载程序后如何判断每条链路是否通了STC 单片机的下载方式是冷启动下载先点下载按钮再给单片机上电。打开烧录软件选择对应的芯片型号波特率可以从 9600 开始尝试软件会自动识别。如果提示握手失败检查串口号是否选对以及板子上有没有把串口模块的 TX 和 RX 接反。下载成功后第一件事不是看温度而是看 OLED 上有没有显示静态文字。如果屏幕有显示但温度是 85 度这是 DS18B20 没有正确复位成功的典型表现。85 度是 DS18B20 上电后的默认温度值复位成功并且读取到非零数据就会刷新掉。如果温度固定不变且一直是 0 或者 127多半是数据线接触不良或上拉电阻缺失。第二件事是看时间是否在走。如果时间在走且比真实时间慢很多检查 32.768KHz 晶振的负载电容一般 6pF 到 12.5pF 均可。如果时间直接不走很可能 IO 线序接错了重点查 CE 和 SCLK 是否接对。OLED 无显示时用万用表测 SCL 和 SDA 的电压正常应当在 3.3V 左右。如果电压几乎为 0 且模块发烫多半是模块的 VCC 接到了 GND。屏幕有背光但无字符则检查 IIC 从机地址有的 OLED 模块地址是 0x7A 而不是 0x78在驱动代码头部把地址宏改掉即可。整机调试顺序建议是先把 OLED 点亮再单独读 DS18B20 测试程序最后才接 DS1302分步验证可以大幅缩小排查范围。4.3 核心代码编译环境的搭建代码使用 Keil C51 开发环境这不是最新的工具但是这个项目用起来最稳。打开 Keil新建工程选择芯片型号为 AT89C52 或者对应 STC 型号然后在工程里添加main.c、oled.c、ds18b20.c、ds1302.c等源文件。编译前需要改两个地方在 Options for Target 里把晶振频率改成 11.0592MHz这个值影响串口波特率的计算但是对普通延时函数也有影响。查看代码里的延时函数确认和晶振频率一致。我在处理这个项目时喜欢设置生成 hex 文件// Keil 配置路径Options for Target - Output - Create HEX File // 勾选后编译会在工程目录下生成 .hex 文件 // 烧录软件打开这个文件即可写入单片机 Flash。实际项目里常见的编译报错是缺少头文件reg51.h或者intrins.h这两个文件在 Keil 安装目录的INC文件夹下。如果使用的是开源 SDCC 编译器头文件的写法略有不同需要把sbit P1_0 P1^0;改成__sbit __at (0x90) P1_0;但对新手来说直接用 Keil 最省心。编译通过但烧录后没有现象时先核对生成的 hex 文件的大小如果只有几十个字节有可能是 main 函数是空的或者代码根本没写进编译路径检查工程里的 C 文件是否全部添加了。4.4 避坑记录这个项目最常见的 5 个问题以下是我做这类 OLED DS18B20 项目时积累的几条真实踩坑记录你可以直接对着排查。现象 1DS18B20 温度始终显示 85修改延时也没用。原因是传感器根本没有被复位成功过。解决用万用表量 DQ 引脚电压正常空闲时应该被上拉到高电平约 4.8V 以上。如果量到的是低电平检查 DQ 是否误接到了 GND或者杜邦线内部断路。还有一种可能DS18B20 的 VCC 接成了 3.3V部分型号在低压下工作不稳定。现象 2OLED 屏幕亮但没有文字背光亮画面全黑。原因是 IIC 通信失败可能地址错误或者 OLED 的 RST 引脚悬空。解决先把 RST 引脚接到 VCC 或者单片机的某个 IO 口拉高然后检查 IIC 地址宏在抓不到波形的情况下用示波器或者逻辑分析仪看 SDA 上有没有非 ACK 的反馈。更诡异的情况是 OLED 控制器在初始化时被反复复位命令被丢弃这种情况检查 OLED 的 RST 引脚有没有被别的代码误操作。现象 3时钟能走但偏慢一天慢十几分钟。原因是 32.768KHz 晶振匹配电容不对。解决DS1302 的晶振引脚下一般接 6pF 电容不要使用直插晶振的长引脚尽量剪短。还有模块上如果你用的是芯片内部晶振不接外部晶振也没问题但 K 级晶振和 C 级负载电容要匹配。给 DS1302 换一颗晶振是最快的验证法。现象 4屏幕内容闪烁或者有残影。原因是 OLED 刷新方式不对或主循环太频繁或每次清屏后立即重新绘制导致人眼可见闪烁。解决不要每次调用OLED_Clear()改为只更新数字变化区域例如把温度显示位置设置成局部刷新函数OLED_ShowNum只重绘那 16x24 像素区域不要全部刷新。或者把刷新周期拉长到 100ms 以上但更优雅的做法是画一个带背景色的矩形覆盖旧值再写新值。现象 5串口调试输出乱码。原因是波特率计算和实际晶振不匹配。解决确认板子上晶振是 11.0592MHz 还是 12MHz。如果是 12MHz把 TH1 改成 0xF3 左右对应 9600 会有 2% 误差不行就直接改用 STC 下载软件送的“串口助手”里的自动波特率功能先发送 0xAA 同步。读取这一串数据时把温度原始数据用十六进制打印比较明确。5. 二次开发的改造思路显示升级、数据记录、低功耗化5.1 显示界面改造从文本模式到图形化仪表盘原项目默认是纯文本模式温度和时间以字符串形式显示改造成图形界面并不难。SSD1306 支持在显存里直接画点可以通过画矩形框、填充区块、画进度条等方式做仪表效果。常见的设计是上半屏用大字显示温度下半屏用进度条显示温度区间比如 0~50 度对应到 128 像素的横向进度条时间用小字号放在右上角。实现上只需要扩展几个基础画图函数void OLED_DrawLine(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) { // 使用逐点插值方式计算斜率后逐像素写显存 } void OLED_FillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t mode) { uint8_t i, j; for (i y; i y h; i) { for (j x; j x w; j) { OLED_DrawPoint(j, i, mode); } } }实际效果类似实时仪表盘温度的数值变化就变成了进度条长度的变化。这里建议在OLED_FillRect里先判断区域是否越界尤其是 x 坐标可能为负数的情况。因为进度条随着温度变化可能会出现负数坐标如果不做边界裁切写入的位置会错乱到其他页。界面改造的另外一点是增加状态切换动画比如按下按键时用OLED_DisplayOff()和OLED_DisplayOn()实现屏幕进入待机也可以做成短按切换显示模式只看时间/只看温度/同时显示。切换动画不要做得太复杂SSD1306 刷新率本身只有几十帧动画太频繁反而造成闪烁。5.2 扩展数据记录功能把温度历史画成曲线DS18B20 的温度读取频率并不高每次转换要 750ms 左右这反而适合做定时采样记录。改造思路是让主循环每 10 秒读一次温度存到一个环形缓冲区里然后在屏幕上绘制反映最近 1 小时温度变化的小型折线图。OLED 只有 128x64 分辨率水平方向能画 128 个点可以画成一小时内的 120 个采样点每点间隔 5 秒。实现折线图的核心是维护一个与温度对应的 Y 坐标数组#define TEMP_HISTORY_SIZE 120 uint8_t temp_history[TEMP_HISTORY_SIZE]; // 存换算后的温度值 uint8_t hist_index 0; void UpdateHistory(uint8_t current_temp) { if (hist_index TEMP_HISTORY_SIZE) { temp_history[hist_index] current_temp; } else { // 循环覆盖最旧的数据点 memmove(temp_history[0], temp_history[1], TEMP_HISTORY_SIZE - 1); temp_history[TEMP_HISTORY_SIZE - 1] current_temp; } }注意memmove移动数组需要包含string.h在 51 环境下这会增加编译体积但一般 Keil 默认就支持。这个函数完成的是数组整体移位不是内存波动。绘制折线图时把每个历史点换算成屏幕 Y 坐标后依次连接相邻点。连接两个相邻点用的是前面提到的OLED_DrawLine函数如果相邻点对应的 Y 坐标差距超过 1 像素中间用补点的方式画出竖线。这部分是纯显存操作不存在复杂的算法坑但要留意显示区域只有 64 行高如果温度超过 50 度Y 坐标会直接超出范围必须在换算时做钳位y 60 - (temp * 60) / 50; // 把 0~50 度映射到 0~60 行 if (y 0) y 0; // 超出屏幕上边界直接截断钳位是这类图形显示里最容易忽略的步骤温度异常偏高时曲线会反向画到屏幕顶部和状态栏重叠看上去像是屏幕上多了一根乱线。加了这个判断后无论如何数据不会越界。5.3 低功耗版本电池供电的改造要点原项目接 USB 供电整机功耗折算下来大概在 50~80mA。想改成纽扣电池或者锂电池供电最大的问题在 OLED 和降压电路上。SSD1306 待机时可执行OLED_DisplayOff()但显存内容不变待机电流能降到几十微安。单片机则可以用 STC 的掉电模式定时唤醒读一次温度并刷新屏幕然后继续睡眠。一个可行的电池版结构是3.7V 锂电池经过 HT7333 稳压到 3.3V 给单片机和传感器供电DS1302 走独立电池这样主机关机也能保持时间OLED 的对比度在电池模式下需要调低原初始化命令里 0x81 对比度可以改成 0x40屏幕暗一点但电池能多用一倍时间。唤醒逻辑如果用 STC 单片机内部定时器或者外部 32.768KHz 晶振的定时唤醒可以做成一个每 30 秒唤醒一次、点亮屏幕 3 秒后关闭的“息屏显示”模式。有人会想用 DS1302 闹钟功能来做定时唤醒思路是可以的但 51 单片机的掉电唤醒需要特定的中断引脚支持需要查看具体型号的数据手册。这里有一个经验掉电模式用外部中断唤醒最稳定按下按键立刻唤醒屏幕比定时唤醒简单也不用额外占用 DS1302 的闹钟寄存器。成本角度讲电池供电加上 OLED 模块仍然比同类的 温湿度墨水屏便宜很多作为 DIY 项目已经很划算。5.4 从原项目到自己的框架代码组织方式的改进原项目的所有代码往往放在几个大文件里函数之间直接互相调用改起来一开始还行后面扩展曲线、新增设置页时全局变量满天飞。建议自己重构的时候把公共部分抽出来比如bsp_oled.c / bsp_oled.h所有屏幕底层驱动和画图接口bsp_ds18b20.c / bsp_ds18b20.h温度传感读时序bsp_ds1302.c / bsp_ds1302.h时钟芯片驱动app_main.c业务逻辑显示数据编排按键状态机这样后续想换用 0.96 寸彩色 OLED 或者换用 DHT11 温湿度传感器只需要改对应驱动文件主界面逻辑不用动。头文件里用宏定义做接口比如温度读取函数名称GetTemperature()在ds18b20.h里声明实际在bsp_ds18b20.c中实现。如果想更换传感器只需要修改底层函数实现而上层的app_main.c中即使调用了同一个函数名替换链接库即可。我从这次拆解过程中得到的最大习惯是每接一个外设先从数据手册提取它的最小操作时序再写一个独立的测试小工程点亮了才接进总工程。从那以后我每次做多外设项目都强制先走一遍这个流程把每个模块单独验证可靠再整机联调很少再遇到画面乱跳、数据不对这种玄学层面的问题。希望这套拆机思路帮到你尤其在你准备把手头的开发板和传感器拼成真正有用的东西时。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑