news 2026/4/18 7:23:10

四位数码管温湿度实时显示系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
四位数码管温湿度实时显示系统

目录

  • 现象
  • 材料
  • 如何连接
  • 代码
  • 重点代码块理解
      • DHT11
      • 数值放大与取整
      • 四位数字拆分与小数点控制
  • 总结
    • 扩展:阻塞与非阻塞
        • 阻塞(Blocking)
        • 非阻塞
    • 对比
    • 总结2

现象

材料

-Arduino Uno控制器
– 1个四位数码管
– 1个DHT11传感器
– 1个面包版

如何连接

可以参考四位数码管原理图结合代码连接

代码

#include <DHT.h> // ====================== DHT11 配置(仅保留温湿度相关) ====================== #define DHTPIN A1 // DHT11数据引脚 #define DHTTYPE DHT11 // 传感器类型 DHT dht(DHTPIN, DHTTYPE); // 温湿度核心变量(控制显示切换和存储数值) float currentTemp = 0.0; // 当前温度 float currentHum = 0.0; // 当前湿度 bool showTemp = true; // true=显示温度,false=显示湿度 unsigned long displaySwitchTime = 0; // 显示切换时间戳 const long switchInterval = 2000; // 2秒切换一次 // DHT11 定时读取控制(非阻塞,避免卡顿显示) unsigned long previousDHTMillis = 0; const long dhtInterval = 2000; // 每2秒读取一次温湿度 // ====================== 四位数码管配置(确保温湿度正常显示) ====================== int ledCount = 8; // 段脚数量(a-g + 小数点) int segCount = 4; // 四位数码管位选数量 // 共阴数码管段码表(0-9):bit0=a, bit1=b, bit2=c, bit3=d, bit4=e, bit5=f, bit6=g, bit7=小数点 const unsigned char DuanMa[10] = { 0x3f, // 0 0x06, // 1 0x5b, // 2 0x4f, // 3 0x66, // 4 0x6d, // 5 0x7d, // 6 0x07, // 7 0x7f, // 8 0x6f // 9 }; // 数码管引脚映射(与你的接线一致,无需修改) int ledPins[] = {7,8,9,10,11,12,13,A0}; // 段脚:a,b,c,d,e,f,g,小数点 int segPins[] = {2,3,5,6}; // 位选:千、百、十、个 unsigned char displayBuffer[4]; // 四位显示缓冲区(对应千、百、十、个位) // ====================== 初始化函数 ====================== void setup() { // 串口初始化(用于查看温湿度数值,方便调试) Serial.begin(9600); while (!Serial); Serial.println("系统启动 - DHT11 + 四位数码管(温湿度显示)"); // DHT11 初始化 dht.begin(); // 数码管引脚设置为输出模式 for(int ledpin = 0; ledpin < ledCount; ledpin++) { pinMode(ledPins[ledpin], OUTPUT); } for(int segpin = 0; segpin < segCount; segpin++) { pinMode(segPins[segpin], OUTPUT); } // 初始读取温湿度并更新显示缓冲区(开机即显示) readDHT(); updateDisplayBuffer(); } // ====================== 主循环(核心:温湿度读取 + 切换 + 数码管显示) ====================== void loop() { unsigned long currentMillis = millis(); // 1. 定时非阻塞读取温湿度 if (currentMillis - previousDHTMillis >= dhtInterval) { previousDHTMillis = currentMillis; readDHT(); } // 2. 每2秒交替切换温度/湿度显示 if (currentMillis - displaySwitchTime >= switchInterval) { displaySwitchTime = currentMillis; showTemp = !showTemp; // 切换显示状态 updateDisplayBuffer(); // 切换后立即更新显示缓冲区 } // 3. 数码管动态扫描(核心:让温湿度稳定显示在四位数码管上) static unsigned long lastScanTime = 0; static int currentDigit = 0; // 当前扫描的数码管位(0=千位,1=百位,2=十位,3=个位) if (currentMillis - lastScanTime >= 3) { // 3ms扫描一次,避免闪烁 lastScanTime = currentMillis; // 消影处理:先关闭当前点亮的数码管,避免重影 digitalWrite(segPins[currentDigit], HIGH); deal(0x00); // 切换到下一位数码管(循环扫描四位) currentDigit = (currentDigit + 1) % 4; // 点亮当前位数码管,显示对应缓冲区的段码(温湿度数值) digitalWrite(segPins[currentDigit], LOW); deal(displayBuffer[currentDigit]); } } // ====================== 读取DHT11温湿度(确保数值准确,用于数码管显示) ====================== void readDHT() { float humidity = dht.readHumidity(); float temperature = dht.readTemperature(); // 数据有效性检查(避免无效数值显示) if (isnan(humidity) || isnan(temperature)) { Serial.println("读取DHT11失败!"); currentTemp = 0.0; currentHum = 0.0; } else { currentTemp = temperature; currentHum = humidity; // 串口打印数值,方便对比数码管显示是否准确 Serial.print("湿度: "); Serial.print(currentHum); Serial.print("% | 温度: "); Serial.print(currentTemp); Serial.println("℃"); } } // ====================== 更新显示缓冲区(核心:将温湿度转换为数码管可识别的段码) ====================== void updateDisplayBuffer() { // 获取当前需要显示的数值(温度或湿度) float displayValue = showTemp ? currentTemp : currentHum; // 转换为整数(放大100倍,保留两位小数:如25.68 → 2568) long intValue = round(displayValue * 100); // 拆分四位数字,存入显示缓冲区(对应四位数码管,百位带小数点) displayBuffer[0] = DuanMa[(intValue / 1000) % 10]; // 千位(整数部分高位) displayBuffer[1] = DuanMa[(intValue / 100) % 10] | 0x80; // 百位(整数部分低位)+ 小数点(0x80=小数点亮) displayBuffer[2] = DuanMa[(intValue / 10) % 10]; // 十位(小数部分高位) displayBuffer[3] = DuanMa[intValue % 10]; // 个位(小数部分低位) // 补0处理:确保四位数码管完整显示,避免高位空缺 if (intValue < 1000) { // 数值小于10(如5.28 → 0528),千位补0 displayBuffer[0] = DuanMa[0]; } if (intValue < 100) { // 数值小于1(如0.68 → 0068),百位补0 displayBuffer[1] = DuanMa[0] | 0x80; } } // ====================== 数码管段码输出(消影+段码写入,确保显示清晰) ====================== void deal(unsigned char value) { // 1. 先关闭所有段脚,消除重影 for(int i = 0; i < 8; i++) { digitalWrite(ledPins[i], LOW); } delayMicroseconds(100); // 短暂延时,增强消影效果 // 2. 逐位写入段码,控制数码管显示对应数字 for(int i = 0; i < 8; i++) { digitalWrite(ledPins[i], bitRead(value, i)); } }

重点代码块理解

1、

DHT11

#define DHTPIN A1 // 温湿度传感器数据引脚(固定接线) #define DHTTYPE DHT11 // 传感器型号(不可随意修改,对应库函数逻辑) DHT dht(DHTPIN, DHTTYPE); // 初始化DHT对象(库函数要求,用于后续读取温湿度)

DHT 是第三方库提供的类,必须通过 dht.begin()(初始化)和 dht.readHumidity()/dht.readTemperature()(读取数据)使用,引脚定义需与实际接线一致。
进行代码的导入时要先安装对应的库文件
温湿度显示
2、

bool showTemp = true; // 显示状态标志位(核心开关) const long switchInterval = 2000; // 2秒切换间隔(可自定义修改)

howTemp 是 “温度 / 湿度” 显示的核心切换开关,true 显示温度、false 显示湿度,通过 !showTemp 实现每 2 秒交替翻转。
3、

数值放大与取整

long intValue = round(displayValue * 100); // 如25.68℃ → 2568(保留两位小数)

温湿度是浮点型(带小数),而数码管只能显示整数,通过放大 100 倍并四舍五入,将 “两位小数” 转换为 “四位整数”,方便四位数码管逐位显示。

四位数字拆分与小数点控制

displayBuffer[0] = DuanMa[(intValue / 1000) % 10]; // 千位(2568→2) displayBuffer[1] = DuanMa[(intValue / 100) % 10] | 0x80; // 百位(2568→5)+ 小数点(0x80=小数点亮) displayBuffer[2] = DuanMa[(intValue / 10) % 10]; // 十位(2568→6) displayBuffer[3] = DuanMa[intValue % 10]; // 个位(2568→8)

通过除法和取余运算,拆分四位整数的每一位;| 0x80 是给百位段码添加小数点(对应数码管的小数点引脚),实现 “25.68” 的显示格式(千位 2、百位 5.、十位 6、个位 8)。
4、
高位补0:
if (intValue < 1000) displayBuffer[0] = DuanMa[0]; // 数值<10(如5.28→0528),千位补0
if (intValue < 100) displayBuffer[1] = DuanMa[0] | 0x80; // 数值<1(如0.68→0068),百位补0
确保四位数码管始终满屏显示,避免高位空缺(如 5.2℃不会显示为 “5.2”,而是 “05.20”),视觉效果更整洁

总结

DHT11采集温湿度 → updateDisplayBuffer()转换为段码(存入displayBuffer) → 动态扫描逐位读取缓冲区,点亮数码管 → 每2秒切换温度/湿度显示

扩展:阻塞与非阻塞

阻塞(Blocking)

阻塞是指程序执行到某段代码时,会暂停在这里等待任务完成,在等待期间无法执行其他任何代码,直到该任务结束后,才会继续向下执行后续逻辑。

非阻塞

非阻塞是指程序执行到某段代码时,不会暂停等待,而是通过 “时间戳对比” 判断任务是否需要执行,若不需要执行则直接跳过,继续执行后续代码;若需要执行则执行该任务,执行完成后继续向下流转

对比

阻塞

void loop() { // 任务1:打印信息 Serial.println("执行任务1"); // 阻塞延时2秒:这2秒内,程序完全暂停,无法执行任何其他代码 delay(2000); // 任务2:仅在2秒延时结束后,才会执行 Serial.println("执行任务2(阻塞方式,2秒一次)"); }

非阻塞

// 定义时间戳变量,用于记录上一次执行任务的时间 unsigned long previousMillis = 0; const long interval = 2000; // 2秒间隔 void loop() { // 获取当前系统时间(上电后的毫秒数,实时更新) unsigned long currentMillis = millis(); // 非阻塞判断:对比当前时间与上一次执行时间的差值,是否达到2秒 if (currentMillis - previousMillis >= interval) { // 记录本次执行的时间(更新时间戳) previousMillis = currentMillis; // 任务2:仅当满足2秒间隔时,才执行 Serial.println("执行任务2(非阻塞方式,2秒一次)"); } // 任务1:不受任务2的影响,会持续快速执行(无卡顿) Serial.println("执行任务1(持续执行,无阻塞)"); }

总结2

阻塞:delay(ms) 主导,程序会 “暂停等待”,期间无法执行其他代码,适用于简单单任务,不适用于你的多功能并行场景;
非阻塞:millis() 主导,通过 “时间戳对比” 判断任务是否执行,无暂停、无卡顿,支持多任务并行(温湿度采集 + 数码管显示 + 显示切换),是你的代码能稳定运行的核心;
你的代码全程采用非阻塞逻辑,这是 Arduino 高级编程的关键,理解它就能编写更复杂、更流畅的嵌入式程序。

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

【TensorRT批处理性能飞跃】:C语言开发者不可错过的4个优化陷阱与对策

第一章&#xff1a;TensorRT批处理优化的背景与意义在深度学习推理应用中&#xff0c;性能和延迟是决定系统可用性的关键因素。随着模型复杂度不断提升&#xff0c;如何在保证精度的同时提升推理吞吐量&#xff0c;成为工业界关注的核心问题。NVIDIA TensorRT 作为高性能推理引…

作者头像 李华
网站建设 2026/4/14 4:47:14

YOLOFuse贡献者招募:欢迎提交PR与Issue

YOLOFuse&#xff1a;构建鲁棒多模态检测系统的开源实践 在智能安防、自动驾驶和夜间巡检等实际场景中&#xff0c;单一可见光摄像头常常“力不从心”——夜幕降临、浓雾弥漫或强光干扰时&#xff0c;目标检测性能断崖式下降。这不仅是个技术挑战&#xff0c;更是制约系统可靠…

作者头像 李华
网站建设 2026/4/18 6:38:27

YOLOFuse MySQL存储检测结果:结构化数据管理

YOLOFuse MySQL存储检测结果&#xff1a;结构化数据管理 在智能监控系统日益复杂的今天&#xff0c;一个核心挑战浮出水面&#xff1a;如何让AI不仅“看得见”&#xff0c;还能“记得住、查得到、管得住”&#xff1f;尤其是在夜间安防、电力巡检或森林防火等关键场景中&#x…

作者头像 李华
网站建设 2026/4/18 6:35:32

python 操作麦克风

目录 查询麦克风&#xff1a; 测试麦克风&#xff1a; 查询麦克风&#xff1a; import sounddevice as sd# 1. 查看所有主机API print(" All Host APIs ") for i, h in enumerate(sd.query_hostapis()):print(f"HostAPI {i}: {h[name]}")print("\n…

作者头像 李华
网站建设 2026/4/13 12:52:05

任务同步效率提升300%?OpenMP 5.3最新同步机制深度剖析

第一章&#xff1a;任务同步效率提升300%&#xff1f;OpenMP 5.3新机制全景透视OpenMP 5.3 在任务调度与同步机制上实现了突破性优化&#xff0c;尤其在细粒度任务依赖管理方面引入了全新指令&#xff0c;显著降低了线程空转与锁竞争开销。实验数据显示&#xff0c;在高并发场景…

作者头像 李华