MSP430+DS18B20低功耗电子温度计:硬件设计与单总线时序详解
2026/9/19 12:16:42 网站建设 项目流程

简介:全国大学生电子设计竞赛“超低功耗电子温度计”设计文档,围绕MSP430单片机、DS18B20数字温度传感器、HT1621D驱动的LCD液晶模块与DS1302时钟芯片展开。系统采用单总线采集温度,支持温度/时间切换显示、按键唤醒和蜂鸣器报警,在3.6V电池供电下可长期稳定运行,方案兼顾低功耗、结构简单与性价比,适合电子设计竞赛参赛者和嵌入式入门学习者作为课程设计或备赛参考。压缩包为1个doc文档,515KB,包含方案论证、软硬件单元设计、软件控制流程、系统测试、元器件清单及总电路图,逻辑完整,对照即可理解低功耗测温系统的搭建与调试。文档结合专家点评与通用标准温度计对比、功耗实测数据,从方案论证与比较入手,详细介绍了MSP430同传感器之间的单总线连接方式以及各单元电路设计要点,并梳理了主程序、温度读取、LCD显示切换、时钟同步及按键响应等软件模块,有助于读者掌握MSP430超低功耗设计思路、DS18B20单总线通信、HT1621D驱动LCD和DS1302时钟应用等关键技能。目前已有88人学习下载,对想复现或二次开发该竞赛作品的人是一份高性价比参考资料。

1. 为什么是 MSP430 + DS18B20:低功耗测温方案的选型逻辑

全国大学生电子设计竞赛的仪表类题目里,超低功耗是硬指标。这道电子温度计题的要求很直接:3.6V 电池供电,整机要能工作多年,待机功耗必须压到微安级。最终选定 MSP430 作为主控、DS18B20 作为温度传感器,正是围绕这个指标做的取舍。

MSP430 是 16 位 RISC 单片机,8MHz 主频下指令周期 125ns,整机静态功耗小于 5 微安,从低功耗模式唤醒只需 6 微秒;DS18B20 走单总线传输,-10℃~+85℃ 精度 ±0.5℃,分辨率可编程,配 HT1621D 驱动的 LCD 和 DS1302 时钟芯片,是低功耗仪表的经典组合。相比之下,C8051F020 功能更强,但大量外设在这个题目里用不上,静态功耗和成本都不划算。

这套方案适合参赛学生,也适合做电池供电仪表的嵌入式工程师。按这个组合复现,低成本与低功耗可以同时拿到。下面从电路、时序、测试到复现细节逐层展开。

2. 硬件电路拆解:从 MSP430 最小系统到 HT1621D 驱动的 LCD 与 DS1302 时钟

2.1 最小系统与电源开关

3.6V 电池进入板子后,先经过 TPS76030 稳压到 3.3V 给 MSP430 供电。系统有两个晶振路径:8MHz 主晶振负责指令周期,DS1302 侧另有 32.768kHz 晶振负责时钟走时。最小系统不需要复杂外围,关键是睡眠时如何把传感器和 LCD 彻底断电——只靠软件把端口置低是没用的,器件输入脚会通过内部保护二极管从 VCC 漏电,电流凭空多出几微安。

常见做法是让 P1.7 控制一个 8050 三极管,三极管的导通与截止决定 DS18B20 和 LCD 的供电回路。P1.7 输出高电平,三极管导通,模块上电;输出低电平,模块断电。初始化时先关断所有外设电源,再配置端口,最后进低功耗模式:

#include <msp430.h> void main(void) { WDTCTL = WDTPW | WDTHOLD; // 关看门狗 P1DIR |= BIT7; // P1.7 输出,控制传感器/LCD电源 P1OUT &= ~BIT7; // 默认断电,避免上电瞬间误动作 P2DIR &= ~BIT7; // P2.7 输入,接 DS18B20 数据线 P2REN |= BIT7; // 打开内部上拉,弱上拉兜底 P1IE |= BIT0; // P1.0 按键中断使能 P1IES &= ~BIT0; // 上升沿唤醒 P1IFG = 0x00; // 清空中断标志 __bis_SR_register(LPM3_bits | GIE); // 进入 LPM3,同时开全局中断 }

这段代码里有两个关键点。一是P1OUT &= ~BIT7放在端口方向配置之后,保证模块上电前 I/O 状态已经稳定,否则三极管基极的毛刺会让 LCD 闪一下。二是LPM3_bits会关闭 CPU 和主时钟,只保留 ACLK,DS1302 的通信和按键中断都依赖 32.768kHz 时钟路径;唤醒后 CPU 从断点继续执行,6 微秒内就能恢复工作。

2.2 DS18B20 采集电路

DS18B20 的数据线接 P2.7,外部上拉电阻取 4.7k 到电源侧。注意这个上拉不是直接接 3.3V,而是接到由 P1.7 控制的电源节点上,这样睡眠断电后上拉电阻不会形成漏电路径。原作采用外部供电方式,而不是 DS18B20 的寄生供电,也是出于同样考虑:寄生效应对电源稳定性要求高,外部供电加三极管开关可以在睡眠时切得最干净。

P2.7 需要配置为带上拉的输入口。复位时主机拉低总线至少 480 微秒,然后释放,DS18B20 会在 15~60 微秒后拉低总线约 60~240 微秒作为存在脉冲。这里最容易犯的错是把延时函数误当成微秒来用——__delay_cycles的参数是 CPU 周期数,8MHz 主频下 1 微秒对应 8 个周期,480 微秒要写 480×8,也就是 3840。

2.3 HT1621D 驱动的 LCD 接口

HT1621D 是 32×4 点阵的 LCD 控制器,SEG 和 COM 引脚直接映射到内部显示 RAM。MCU 侧只需要三根线:CS、WR、DATA,占用 I/O 极少。上电后 HT1621D 的 RAM 内容不确定,必须先发命令打开系统振荡器和 LCD 偏压,否则屏幕可能显示乱码或者完全不亮。

写命令的常用序列是:CS 拉低,写入 3 位命令标志 101,再写入 9 位命令数据,最后 CS 拉高。例如发送系统配置命令:

void ht1621_write_command(unsigned char cmd) { unsigned char i; HT1621_CS_L(); ht1621_write_bits(0b101, 3); // 101 表示命令 ht1621_write_bits(cmd, 9); // 9 位命令数据 HT1621_CS_H(); }

0b101是 HT1621D 命令模式标识,后续 9 位数据的具体含义由器件手册定义,常用的有 0x100(打开系统振荡器)和 0x101(开启 LCD 偏压)。写数据到显示 RAM 时,模式标识换成 0b110,后面跟 5 位地址加 8 位数据。这套接口对时序要求不算苛刻,但 CS 必须在整个读写过程中保持低电平,提前拉高会导致命令字节丢失。

2.4 DS1302 时钟电路

DS1302 与单片机之间是同步串行接口,只用 CE、SCLK、I/O 三根线。CE 相当于片选,SCLK 上升沿写入数据、下降沿读出数据,I/O 是双向引脚。外围需要一颗 32.768kHz 晶振,以及一颗可选的 32k 电阻用于涓流充电。VCC1 接备用电池时,主电源掉电后时钟继续走,这个特性在需要记录测温时间的场景里很实用。

原作电路里还有 MAX3232 和 24C02,它们是为调试下载和数据暂存准备的附属电路,量产的测温装置可以不焊。硬件搭建建议按最小系统、DS18B20、LCD、DS1302 的顺序逐个调试,不要一次把所有模块接到 I/O 上,否则出现总线冲突时分不清是时序问题还是电气问题。

各模块接口和供电控制关系汇总如下:

模块主控接口供电控制说明
MSP430F149-3.3V LDO主控,LPM3 睡眠
DS18B20P2.7 单总线P1.7 经 8050 三极管4.7k 上拉至电源侧
HT1621D + LCDCS / WR / DATA与 DS18B20 共用电源开关32×4 点阵,可驱动蜂鸣器
DS1302CE / SCLK / I/O常供电32.768kHz 晶振,31 字节 RAM
按键P1.0~P1.5-唤醒、设置时钟、显示切换
蜂鸣器HT1621D BZ 或独立 I/O随 LCD 供电阈值报警

3. 单总线时序与软件架构:DS18B20 读取、DS1302 时间同步的关键代码

3.1 单总线复位与读写时隙

DS18B20 单总线的时序由主机严格产生。复位脉冲要求主机拉低总线至少 480 微秒再释放,传感器随后返回存在脉冲。写时隙区分 1 和 0:主机拉低总线后,如果在 15 微秒内释放并保持高电平,接收端读到的是 1;如果持续拉低整个 60 微秒时隙,读到的是 0。读时隙与之类似,主机先拉低总线 1~15 微秒,然后释放,并在释放后的第 15 微秒附近采样。

#define DQ_IN (P2IN & BIT7) #define DQ_H (P2OUT |= BIT7) #define DQ_L (P2OUT &= ~BIT7) unsigned char ds18b20_reset(void) { unsigned char val; DQ_L; __delay_cycles(480 * 8); // 8MHz 下 480us DQ_H; __delay_cycles(60 * 8); // 等存在脉冲 val = DQ_IN; // 读到低电平说明设备存在 __delay_cycles(420 * 8); // 补足复位时间 return val; } void ds18b20_write_bit(unsigned char bit) { DQ_L; if (bit) { DQ_H; // 写1:15us 内释放总线 } __delay_cycles(60 * 8); // 保持整个时隙 DQ_H; } unsigned char ds18b20_read_bit(void) { unsigned char bit; DQ_L; DQ_H; // 读时隙开始 __delay_cycles(15 * 8); // 15us 后采样 bit = (DQ_IN) ? 1 : 0; __delay_cycles(45 * 8); // 补满 60us return bit; }

这里的__delay_cycles(480 * 8)在 8MHz 主频下对应 480 微秒,如果换了 16MHz 晶振要改成 480×16。采样点放在 15 微秒不是随便选的,DS18B20 数据手册规定读时隙采样窗口就在这个位置附近;过早可能采到主机自己拉低产生的电平,过晚可能漏掉传感器的输出。单总线操作期间应关中断,否则一次中断嵌套就会让时隙超差,读回的数据变成 0xFF 或 0x00 这类典型错误值。

提示:单总线时序对延时敏感,建议在读写函数执行期间关闭全局中断,完成一字节后再打开。用逻辑分析仪抓总线波形,能直接看到时隙宽度是否合规。

3.2 温度读取流程与分辨率配置

温度读取的完整流程是:复位 → 发送 0xCC 跳过 ROM 匹配 → 发送 0x44 启动温度转换 → 等待转换完成 → 再次复位 → 0xCC → 发送 0xBE 读取暂存器。暂存器共 9 字节,前两个字节是 16 位温度值,第 4 字节是分辨率配置。

float read_temperature(void) { unsigned char i; unsigned int raw; unsigned char data[9]; if (ds18b20_reset()) return -999.0; // 返回负值表示无设备 ds18b20_write_byte(0xCC); // 跳过 ROM ds18b20_write_byte(0x44); // 启动温度转换 __delay_cycles(750 * 8); // 12 位分辨率等待 750ms ds18b20_reset(); // 重新复位 ds18b20_write_byte(0xCC); ds18b20_write_byte(0xBE); // 读暂存器 for (i = 0; i < 9; i++) { data[i] = ds18b20_read_byte(); } raw = data[0] | (data[1] << 8); return raw * 0.0625; // 12 位步进 0.0625℃ }

温度原始值是带符号的,12 位分辨率下每一位代表 0.0625℃,所以温度值等于原始值乘以 0.0625。在比赛现场如果不想引入浮点运算,可以用定点方式处理,比如temp_x100 = raw * 625 / 100,这样精度保持不变,但输出的是百分之一摄氏度的整数,方便后续显示和比较。

DS18B20 的分辨率可以编程,配置存放在暂存器第 4 字节,掉电后由 EEPROM 保持:

配置值分辨率转换时间温度步进适用场景
0x7F12 位750 ms0.0625 ℃高精度记录,竞赛题默认
0x5F11 位375 ms0.125 ℃本设计测温范围足够
0x3F10 位187.5 ms0.25 ℃快速巡检
0x1F9 位93.75 ms0.5 ℃报警型仪表

这个题目检测范围只有 10℃~30℃,要求分辨率 0.5℃ 就够,但原作总结里写的是 0.5℃ 精度。复现时我建议用 11 位配置 0x5F,转换时间比 12 位少一半,每次唤醒都能省约 375 毫秒的工作时间。如果读到 85℃ 这个固定值,多半是转换还没启动就去读暂存器了,检查一下 0x44 是否发送成功。

3.3 DS1302 读写与 BCD 转换

DS1302 的命令字格式是固定的:最高位必须为 1,bit6 选择时钟或 RAM,bit5~1 是寄存器地址,bit0 是读写方向。秒寄存器地址是 0x80,分是 0x82,时是 0x84,日 0x86,月 0x88,星期 0x8A,年 0x8C。读写时间数据都是以 BCD 码形式传输的。

void ds1302_write_byte(unsigned char val) { unsigned char i; DS1302_IO_OUT; // I/O 设为输出 for (i = 0; i < 8; i++) { if (val & 0x01) DS1302_IO_H; else DS1302_IO_L; DS1302_CLK_H; // 上升沿写入 DS1302_CLK_L; val >>= 1; // 低位在前 } } unsigned char ds1302_read_byte(void) { unsigned char i, val = 0; DS1302_IO_IN; // I/O 设为输入 for (i = 0; i < 8; i++) { val >>= 1; if (P3IN & BIT4) val |= 0x80; // 下降沿前读数据 DS1302_CLK_H; DS1302_CLK_L; } return val; }

这里最容易踩的坑是方向切换。DS1302 的 I/O 不是三态总线,读数据前必须把单片机引脚方向从输出改为输入,读完再改回输出,否则读回来的永远是 0xFF。写时间前还要先清写保护:发送命令 0x8E,数据 0x00,写完时间数据后再发 0x8E、0x80 把写保护重新置位。我一般会在读时钟时连读两遍秒寄存器,如果两次相同才使用,避免刚好在进位瞬间读到错误值。

3.4 主循环:测温、显示与再睡眠

软件主流程是个典型的低功耗循环:初始化完成后进入 LPM3 睡眠,按键产生中断唤醒,唤醒后打开传感器和 LCD 电源,延时等待稳定,测温并显示,然后再次关断外设电源、回到睡眠。

void main(void) { init_msp430(); set_ds18b20_resolution(0x5F); // 11 位分辨率,375ms 转换 ds1302_init(); while (1) { __bis_SR_register(LPM3_bits | GIE); // 进入睡眠,等待按键唤醒 P1OUT |= BIT7; // 打开传感器/LCD 电源 __delay_cycles(160000); // 8MHz 下延时 20ms,等电源稳定 temp = read_temperature(); // 读取并换算温度 display_update(temp); // 刷新 LCD P1OUT &= ~BIT7; // 关断外设电源 } }

每次唤醒工作时间控制在 100 毫秒量级,平均电流几乎由睡眠电流决定。按键唤醒后不需要重新初始化外设,因为 MSP430 从 LPM3 唤醒后寄存器内容不变,直接执行后续代码即可。蜂鸣器报警阈值比较应该放在display_update里完成,不要为报警单独增加一次唤醒,否则平均功耗会翻倍。

4. 静态功耗 1 微安是怎么测出来的:睡眠唤醒机制与测试方法

4.1 睡眠时电流从哪里来

整机睡眠时,DS18B20 和 LCD 的电源被三极管切断,仍然带电的只有 MSP430、DS1302 以及必要的上拉电阻。原作实测静态功耗约 1 微安。这 1 微安由几部分构成:MSP430 在 LPM3 模式下自身电流可以到微安以下;DS1302 保持走时的电流常见在 0.3~1 微安;I/O 上拉电阻如果还挂在 3.3V 上,单颗电阻就是 0.7 微安左右。所以数据线的上拉必须接在由 P1.7 控制的电源侧,断电后整条支路都不构成漏电路径。

睡眠前还有一件容易被忽略的事:把所有未使用的 I/O 引脚设置成输出低电平或者开启内部上拉。悬空输入脚会通过保护二极管产生不可控漏电,有时比单片机自身功耗还大。按键引脚也要处理,外部按键用 33k 上拉而不是内部上拉的场景里,漏电会更低。

4.2 平均电流与电池寿命的估算方法

用万用表微安档测睡眠电流时,表笔内阻会引入误差,而且工作态的毫安级电流和睡眠态微安级电流相差三个数量级,万用表很难同时测准。更可靠的做法是串入一个 1Ω 采样电阻,用示波器记录电压波形,再离线积分计算平均电流。计算逻辑很简单:

sleep_uA = 1.0 # 睡眠电流,原作实测约 1uA work_mA = 2.5 # 工作电流:传感器转换 + LCD 显示 work_s = 0.15 # 每次唤醒工作时间 interval_s = 3600 # 每小时唤醒一次 avg_uA = sleep_uA + work_mA * 1e3 * work_s / interval_s print(f"平均电流约 {avg_uA:.2f} uA")

按这个公式算出来,每小时唤醒一次、每次工作 150 毫秒、工作电流 2.5mA,平均电流约 1.10 微安。3.6V、1200mAh 的电池在理论上可以支撑上百年,但实际寿命受电池自放电限制,三到五年是更现实的预期。原作声称「正常工作多年」,这个工程表述是站得住的。

工作态电流与器件批次有关,DS18B20 转换期间约 1~2mA,HT1621D 驱动 LCD 显示时几十到几百微安,具体数值建议实测记录:

工作状态电流量级说明
系统睡眠约 1 uA原作实测,传感器与 LCD 断电
温度转换约 1~2 mADS18B20 转换期间
LCD 显示几十到几百 uA与显示段数和偏压设置有关
DS1302 保持小于 1 mW走时和 RAM 保持

4.3 与标准温度计的对比测试

原作做了 5 次对比测试,数据如下:

测量次数低功耗温度计示数(℃)通用标准温度计示数(℃)
11617
22827
32019
42526
51817

每次偏差都在 1℃ 以内,落在 DS18B20 在 -10℃~+85℃ 区间 ±0.5℃ 精度的合理范围内。剩余偏差主要来自传感器封装热阻和探头位置,不是软件误差。验证时要让两个传感器的探头浸入同一恒温水槽,等 5 分钟以上再读数;在空气中测,对流会让 1℃ 偏差看起来像故障。

5. 复现这个设计时值得注意的 6 个参数细节

5.1 DS18B20 数据线上拉

4.7k 上拉在这个电路里最稳,10k 在长线时上升沿变缓,容易导致读取时序失败。如果读到 85℃,先检查 0x44 转换命令是否执行、等待时间是否足够,而不是急着换传感器。电源刚打开的前几十微秒内总线电平不稳定,唤醒后必须延时 20ms 左右再操作 DS18B20。

5.2 HT1621D 的偏压与 VLCD

HT1621D 命令 0x100 打开系统振荡器,0x101 选择 LCD 偏压。32×4 点阵的段码屏通常用 1/3 偏压,偏压选错会出现整屏偏暗或鬼影。VLCD 电压不要直接接在滤波电容后面,应该用电阻分压稳定在 3.0V 左右,否则屏幕对比度会随电池电压波动。

5.3 DS1302 写保护与 BCD

写时间前先发 0x8E、0x00 清写保护,写完再发 0x8E、0x80 置位。读连续时间字节时 CE 必须保持高电平,中间拉低会导致后续地址丢失。时间校准建议通过串口打印出来核对,不要反复拆电池,DS1302 备用电池脚一旦掉电,时间就回到 2000 年。

5.4 睡眠唤醒的 I/O 电平

进入睡眠前,所有按键引脚都要接上拉,最好是 33k 左右的外部电阻。内部上拉约 35k 也能用,但会略微增加漏电。按键中断触发后先清 P1IFG 再扫键,否则睡眠后残留的中断标志会立即把系统再次唤醒,表现就是按键根本没反应、系统却一直在耗电。

5.5 蜂鸣器报警阈值写入 EEPROM

DS18B20 的上限 TH 和下限 TL 存储在 EEPROM,写入后主循环比较温度值即可,不需要每次转换都重写。EEPROM 写入有约 10ms 的等待时间,频繁写既费电又缩短寿命。报警触发后加 3~5 秒的抑制窗口,防止温度在阈值附近抖动导致蜂鸣器反复响。

5.6 测试时序的验证顺序

先用逻辑分析仪抓 DS18B20 的存在脉冲和时隙宽度,确认单总线通信没问题;再抓 DS1302 的 CE 与 SCLK 对应关系,确认读写方向切换正确;最后测整机平均电流。这个顺序在洞洞板阶段就能完成,等 PCB 打样回来直接焊接测试,能省下大量竞赛现场调试时间。按下按键时用逻辑分析仪抓 SCLK 与 I/O 的对应关系,能直接看出 CE 时序是否符合 DS1302 要求。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询