news 2026/6/11 3:02:52

告别点灯焦虑:用STM32F103和TM1616做个简易温湿度显示器(代码开源)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
告别点灯焦虑:用STM32F103和TM1616做个简易温湿度显示器(代码开源)

从零打造桌面温湿度监测站:STM32F103与TM1616的完美组合

你是否厌倦了市面上千篇一律的电子温湿度计?想亲手打造一个既实用又能展示技术实力的桌面小工具?今天我们就用STM32F103C8T6这块经典单片机,搭配TM1616数码管驱动芯片和DHT11传感器,制作一个完全自定义的温湿度显示器。不同于简单的驱动测试,我们将从实际应用角度出发,解决显示闪烁、功耗优化等真实场景中的问题。

1. 硬件选型与搭建

1.1 核心组件介绍

这个项目的硬件架构非常简单,只需要三个主要部件:

  • STM32F103C8T6最小系统板:作为主控,价格低廉且性能足够
  • TM1616数码管驱动模块:支持4位7段数码管显示,内置亮度调节
  • DHT11温湿度传感器:单总线接口,测量范围20-90%RH和0-50℃

提示:选择TM1616而非TM1637的主要原因是前者支持8级亮度调节,更适合需要长时间运行的桌面设备。

1.2 硬件连接示意图

将各模块按照以下方式连接:

STM32引脚连接目标备注
PB6DHT11数据线需接4.7K上拉电阻
PB7TM1616 STB片选信号
PB8TM1616 CLK时钟信号
PB9TM1616 DIO数据输入/输出
3.3V各模块VCC供电
GND各模块GND共地

2. TM1616驱动深度优化

2.1 基础驱动封装

原始驱动代码虽然能用,但直接放在主循环中会导致显示闪烁。我们需要将其封装成更健壮的显示库:

// tm1616.h #ifndef __TM1616_H #define __TM1616_H #include "stm32f10x.h" #define TM1616_STB_PIN GPIO_Pin_7 #define TM1616_CLK_PIN GPIO_Pin_8 #define TM1616_DIO_PIN GPIO_Pin_9 #define TM1616_PORT GPIOB typedef enum { LED_OFF = 0x00, LED_ON = 0x08 } TM1616_PowerState; typedef enum { BRIGHTNESS_1 = 0, BRIGHTNESS_2, // ... 其他亮度等级 BRIGHTNESS_8 } TM1616_Brightness; void TM1616_Init(void); void TM1616_DisplayDigits(uint8_t digits[4]); void TM1616_SetBrightness(TM1616_Brightness level); void TM1616_SetPower(TM1616_PowerState state); #endif

2.2 显示刷新策略优化

常见的显示闪烁问题通常源于不合理的刷新方式。我们采用双缓冲技术来解决:

// tm1616.c static uint8_t displayBuffer[4] = {0}; static uint8_t backBuffer[4] = {0}; void TM1616_UpdateDisplay(void) { // 原子操作切换缓冲区 memcpy(displayBuffer, backBuffer, 4); TM1616_DisplayDigits(displayBuffer); } void TM1616_SetDigit(uint8_t position, uint8_t value) { if(position < 4) { backBuffer[position] = value; } }

3. 温湿度数据采集与处理

3.1 DHT11驱动实现

DHT11的通信时序要求严格,我们需要精确的微秒级延时:

// dht11.c #define DHT11_PIN GPIO_Pin_6 #define DHT11_PORT GPIOB uint8_t DHT11_ReadData(float *temperature, float *humidity) { uint8_t data[5] = {0}; // 主机发起开始信号 GPIO_ResetBits(DHT11_PORT, DHT11_PIN); Delay_us(18000); GPIO_SetBits(DHT11_PORT, DHT11_PIN); Delay_us(40); // 等待传感器响应 if(!GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) { uint32_t timeout = 10000; while(!GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN) && timeout--); timeout = 10000; while(GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN) && timeout--); // 读取40位数据 for(uint8_t i=0; i<5; i++) { for(uint8_t j=0; j<8; j++) { while(!GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)); Delay_us(30); data[i] <<= 1; if(GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)) { data[i] |= 1; while(GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN)); } } } // 校验数据 if(data[4] == (data[0]+data[1]+data[2]+data[3])) { *humidity = data[0] + data[1]*0.1; *temperature = data[2] + data[3]*0.1; return 1; } } return 0; }

3.2 数据滤波算法

原始传感器数据常有波动,我们需要添加简单的滑动平均滤波:

#define FILTER_WINDOW_SIZE 5 typedef struct { float tempBuffer[FILTER_WINDOW_SIZE]; float humiBuffer[FILTER_WINDOW_SIZE]; uint8_t index; } SensorFilter; void Filter_Init(SensorFilter *filter) { memset(filter, 0, sizeof(SensorFilter)); } void Filter_AddData(SensorFilter *filter, float temp, float humi) { filter->tempBuffer[filter->index] = temp; filter->humiBuffer[filter->index] = humi; filter->index = (filter->index + 1) % FILTER_WINDOW_SIZE; } float Filter_GetAverage(float *buffer) { float sum = 0; for(uint8_t i=0; i<FILTER_WINDOW_SIZE; i++) { sum += buffer[i]; } return sum / FILTER_WINDOW_SIZE; }

4. 系统整合与功耗优化

4.1 主程序架构设计

采用状态机模式管理显示内容切换和传感器读取:

typedef enum { SHOW_TEMP, SHOW_HUMI, SHOW_ALT } DisplayMode; void System_Run(void) { static DisplayMode mode = SHOW_TEMP; static uint32_t lastReadTime = 0; static SensorFilter filter; // 每2秒读取一次传感器 if(HAL_GetTick() - lastReadTime > 2000) { float temp, humi; if(DHT11_ReadData(&temp, &humi)) { Filter_AddData(&filter, temp, humi); } lastReadTime = HAL_GetTick(); } // 每5秒切换显示模式 switch(mode) { case SHOW_TEMP: DisplayTemperature(Filter_GetAverage(filter.tempBuffer)); if(HAL_GetTick() % 10000 < 2000) mode = SHOW_HUMI; break; case SHOW_HUMI: DisplayHumidity(Filter_GetAverage(filter.humiBuffer)); if(HAL_GetTick() % 10000 >= 2000) mode = SHOW_TEMP; break; } // 根据环境光线自动调节亮度 AutoAdjustBrightness(); }

4.2 动态亮度调节技术

利用TM1616的8级亮度控制功能,实现自动亮度调节:

void AutoAdjustBrightness(void) { uint16_t lightLevel = GetLightSensorLevel(); // 假设有光敏电阻 TM1616_Brightness brightness; if(lightLevel > 800) brightness = BRIGHTNESS_8; else if(lightLevel > 600) brightness = BRIGHTNESS_7; // ... 其他条件 else brightness = BRIGHTNESS_2; TM1616_SetBrightness(brightness); }

5. 进阶功能扩展

5.1 温度报警功能

当温度超过设定阈值时,让数码管闪烁提示:

void CheckTemperatureAlert(float temp) { static uint8_t alertActive = 0; static uint32_t lastBlinkTime = 0; if(temp > TEMP_ALERT_THRESHOLD) { alertActive = 1; if(HAL_GetTick() - lastBlinkTime > 500) { static uint8_t visible = 0; if(visible) { DisplayTemperature(temp); visible = 0; } else { TM1616_ClearDisplay(); visible = 1; } lastBlinkTime = HAL_GetTick(); } } else if(alertActive) { alertActive = 0; DisplayTemperature(temp); } }

5.2 低功耗模式实现

利用STM32的睡眠模式进一步降低功耗:

void EnterLowPowerMode(void) { // 配置唤醒源 EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line = EXTI_Line6; // DHT11引脚 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); // 进入停止模式 TM1616_SetPower(LED_OFF); PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); // 唤醒后重新初始化时钟 SystemInit(); TM1616_Init(); }

6. 项目外壳设计与成品展示

虽然代码是核心,但一个好的外壳能让项目更加完整。这里有几个DIY建议:

  • 3D打印外壳:使用PLA材料打印一个简约的倾斜支架
  • 亚克力激光切割:制作透明保护罩,同时展示内部结构
  • 木质底座:搭配胡桃木底座提升质感

注意:设计外壳时要考虑散热问题,避免将单片机紧贴密闭空间。

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

Element UI升级Element Plus后,el-tree全选功能踩坑与平滑迁移指南

Element UI到Element Plus迁移实战&#xff1a;el-tree全选功能深度重构指南从Vue2到Vue3的技术栈升级过程中&#xff0c;Element Plus对el-tree组件进行了多项底层重构。许多开发团队在迁移全选功能时&#xff0c;常会遇到半选状态失效、节点引用异常等问题。本文将揭示这些问…

作者头像 李华
网站建设 2026/6/11 3:02:51

Java锁膨胀机制之无锁到偏向锁源码剖析

无锁到偏向锁源码剖析前言无锁到偏向锁源码剖析核心概念&#xff1a;修正“无锁 -> 偏向锁”的常见误区一、 基石定义&#xff1a;Mark Word 内存布局与状态判定涉及文件&#xff1a;hotspot/src/share/vm/oops/markOop.hpp二、 锁初始化&#xff1a;原型请求头的确立涉及文…

作者头像 李华
网站建设 2026/6/11 2:51:04

BPMN引擎深度解析:企业级JavaScript工作流引擎架构与实战指南

BPMN引擎深度解析&#xff1a;企业级JavaScript工作流引擎架构与实战指南 【免费下载链接】bpmn-engine BPMN 2.0 execution engine. Open source javascript workflow engine. 项目地址: https://gitcode.com/gh_mirrors/bp/bpmn-engine 在当今数字化业务流程自动化领域…

作者头像 李华
网站建设 2026/6/11 2:48:00

Speechless:无需登录的微博内容PDF备份工具完整指南

Speechless&#xff1a;无需登录的微博内容PDF备份工具完整指南 【免费下载链接】Speechless 把新浪微博的内容&#xff0c;导出成 PDF 文件进行备份的 Chrome Extension。 项目地址: https://gitcode.com/gh_mirrors/sp/Speechless 在社交媒体时代&#xff0c;你的微博…

作者头像 李华
网站建设 2026/6/11 2:48:00

YOLOv8改进策略【卷积层】| CVPR2025 GBConv轻量门控瓶颈卷积 低秩瓶颈降参 + 门控聚焦形态,强效捕捉纤细目标

一、本文介绍 本文记录的是利用GBC门控瓶颈卷积模块改进 YOLOv8 的特征提取部分。 GBC(Gated Bottleneck Convolution)通过低秩瓶颈卷积轻量化、双分支门控加权与残差特征保留结合,在极低计算开销下实现裂缝形态特征的精准提取与背景干扰抑制。本文利用GBC模块,先通过瓶颈…

作者头像 李华