STM32环境监测系统:温湿度与雨滴传感器集成TFT显示实战
2026/9/4 10:50:57 网站建设 项目流程

简介:本资源是一套基于STM32F103RCT6的嵌入式环境监测系统完整工程,面向嵌入式初学者与课程设计者,解决温湿度及降雨状态实时采集与TFT可视化显示的核心问题,适用于气象监测、智慧农业与智能家居等实践场景。压缩包共139个文件,含37个头文件(.h)定义硬件接口与功能模块、35个源文件(.c)实现DHT11协议解析、雨滴信号判读及LCD驱动逻辑,另有编译中间文件(.o/.d/.crf)、可执行镜像(.hex/.axf)及Keil工程配置(.uvprojx/.uvoptx),整体大小为3.31MB。已有1788人学习下载。资源提供开箱即用的Keil工程结构,包含SYSTEM、CORE、HARDWARE等标准分层目录,集成stm32f10x固件库与自定义LCD显示函数,附带keilkilll.bat清理脚本,便于快速编译调试;代码注释清晰,传感器时序处理与TFT刷新机制均有典型实现,是掌握STM32外设协同开发的优质实操范例。

1. 项目概述与核心价值

最近在整理手头的几个嵌入式小项目,翻到了一个挺有意思的旧作——“温湿度+雨滴检测——TFT液晶显示”。这个项目名字听起来就挺“全活儿”的,集成了环境感知、数据显示和用户交互,是很多物联网终端设备或者智能家居传感器的经典雏形。说白了,它就是做一个能实时监测周围温湿度、判断是否下雨,并且把所有信息直观地显示在一块彩色屏幕上的小装置。

你可能觉得,温湿度传感器(比如DHT11、DHT22)和雨滴传感器满大街都是,教程一抓一大把,做个显示也没什么稀奇。确实,单个模块的驱动网上资料很多,但真正把多个传感器、显示模块和主控芯片有机整合,形成一个稳定、可靠、美观且便于二次开发的系统,这里面的门道就多了。比如,如何安排有限的主控资源(IO口、定时器、ADC)?多个传感器数据采集如何避免相互干扰?TFT屏刷新数据时怎样避免屏幕闪烁?这些都是在实际动手时才会遇到的“坑”。

这个项目的核心价值,在于它提供了一个完整的、可复现的嵌入式系统集成案例。它不仅仅教你如何点亮一块屏或者读取一个传感器,更重要的是展示了如何架构一个多任务、实时性要求不高的嵌入式应用软件框架。无论你是刚学完STM32基础,想找个综合项目练手,还是工作中需要快速搭建一个环境监测终端原型,这个项目都能给你提供清晰的思路和可直接借鉴的代码。接下来,我就把这个项目的设计思路、硬件选型、软件架构以及调试过程中积累的经验,毫无保留地拆解一遍。

2. 硬件系统设计与核心器件选型

做一个项目,硬件是骨架,选型决定了项目的成本、复杂度和最终性能的上限。这个项目硬件结构清晰,主要包含四大部分:主控制器、环境传感器、雨滴传感器和人机交互界面(TFT屏)。我的设计原则是在满足功能、保证稳定性的前提下,尽量选择常见、易获取、资料丰富的模块,降低学习和复现的门槛。

2.1 主控芯片:为何选择STM32系列

主控是整个系统的大脑,负责协调所有外设、执行逻辑、处理数据。在这个项目中,我选择了STM32F103C8T6,也就是大家常说的“蓝色小药丸”或者“最小系统板”的核心。选择它基于以下几点考量:

  1. 性能与资源足够:基于Cortex-M3内核,主频72MHz,对于读取传感器(毫秒级)、驱动SPI接口的TFT屏(MHz级)以及运行一些简单的逻辑判断和UI刷新绰绰有余。它拥有足够的GPIO、多个SPI/I2C接口、ADC和定时器,能轻松应对本项目的多外设需求。
  2. 生态与社区强大:STM32的生态在国内是首屈一指的。无论是标准外设库(Standard Peripheral Library)、硬件抽象层库(HAL库)还是Low-Layer库,都有完善的文档和丰富的示例。遇到任何问题,几乎都能在论坛、博客中找到解决方案。这对于学习和快速开发至关重要。
  3. 成本与易用性平衡:STM32F103系列价格亲民,开发板(核心板)种类繁多,自带调试器(如ST-Link)或兼容性强(支持J-Link、DAP-Link等),调试非常方便。相比一些更简单的8位单片机,它提供了更现代的开发体验(如基于Keil MDK或STM32CubeIDE的工程管理、调试);相比更高端的M4/M7芯片,它又避免了资源过剩和成本上升。

注意:如果你手头有ESP32之类的Wi-Fi/蓝牙芯片,当然也可以做,并且能轻松添加联网功能。但本项目聚焦于本地传感与显示的集成,STM32在纯粹的实时控制、低功耗管理(虽然本项目未深入)和硬件接口驱动的稳定性上,依然有其优势。选择STM32能让代码更专注于业务逻辑,而非网络协议栈。

2.2 传感器模块:稳定与精度的取舍

温湿度传感器:DHT11我选择了DHT11,原因就两个字:够用、简单。它的测量范围(湿度20-90%RH,温度0-50℃)和精度(湿度±5%RH,温度±2℃)对于室内环境监测或者一般的天气预报应用是完全足够的。其单总线通信协议,只需要一个GPIO口就能读取数据,极大地节省了主控资源。虽然DHT22(AM2302)精度更高、范围更广,但对于大多数入门和中等要求的应用,DHT11的性价比更高,且驱动程序几乎通用。

雨滴传感器:模拟量输出模块雨滴检测模块通常是一个带有裸露平行导线的印刷电路板。其原理是,当雨滴落在板子上,会改变导线间的电阻,从而影响其输出的电压。我选择的是输出模拟电压信号的模块(通常还有数字开关量输出版本)。模拟输出可以更细腻地反映“雨量”的大小(虽然很粗略),而不仅仅是“有雨”或“无雨”的二元判断。模块一般会有一个电位器,用于调节灵敏度(即比较器阈值)。在本项目中,我们使用STM32的ADC来读取这个模拟电压值。

2.3 显示模块:TFT液晶屏的选择与驱动

显示部分是本项目的亮点,也是调试的重点。我选择了一块1.44寸或1.8寸的SPI接口TFT彩屏,驱动芯片通常是ST7735S或ILI9341(具体看屏的型号)。

为什么是SPI接口的TFT?

  • 节省IO口:相对于并口屏(需要8位或16位数据线+若干控制线),SPI屏通常只需要4根线(SCK, MOSI, DC, CS,复位RST和背光BL可单独控制),这对IO紧张的主控非常友好。
  • 驱动简单:SPI通信协议标准,有成熟的硬件SPI外设支持,软件模拟SPI也容易。市面上针对ST7735/ILI9341的驱动代码(如Adafruit GFX库的移植版)非常丰富。
  • 性能足够:对于显示温湿度数值、简单的图标和进度条(比如表示雨量),SPI接口的刷新率完全够用,不会感到明显卡顿。

关键点:屏幕的初始化与驱动库不同的屏幕,即使驱动芯片相同,其初始化序列(一堆配置命令)也可能有细微差别。这部分代码通常由屏幕厂商提供,或者可以从开源社区找到匹配的驱动。我们需要一个基本的图形库来画点、线、矩形、显示字符和图片。通常我们会移植一个轻量级的库,比如u8g2(但更常用于OLED)或者针对特定屏优化的TFT_eSPI(来自Arduino社区,但可以移植到STM32),或者自己编写最基础的画点函数,然后构建显示字符的功能。

3. 软件架构与核心逻辑设计

硬件连接好后,软件才是让整个系统“活”起来的关键。一个好的软件架构能让代码清晰、易于维护和扩展。本项目虽然不复杂,但我依然采用了模块化、分层的思想来组织代码。

3.1 系统工作流程与任务划分

整个系统的工作流程可以看作一个简单的超级循环(Super Loop),配合定时中断来实现准实时的数据采集和显示更新。

  1. 上电初始化:配置系统时钟、GPIO、SPI、ADC、定时器等硬件外设。初始化TFT屏幕(发送初始化命令序列,清屏,设置显示方向等)。初始化传感器(对于DHT11,就是设置好GPIO模式)。
  2. 主循环(Main Loop)
    • 定时触发:利用一个硬件定时器,产生一个固定的中断(例如,每2秒一次)。在中断服务函数中设置一个标志位,如data_update_flag = 1
    • 数据采集:在主循环中不断检查data_update_flag。当标志位为1时,依次执行: a. 读取DHT11的温湿度数据。 b. 读取雨滴传感器的ADC值。 c. 清除data_update_flag
    • 数据处理与判断:将ADC原始值转换为电压,再根据实验标定,映射为“无雨”、“小雨”、“中雨”、“大雨”等状态或一个0-100%的雨量强度值。对DHT11的数据进行校验。
    • 用户界面更新:将处理好的温湿度数值、雨量状态/值,通过图形函数绘制到TFT屏幕上。为了优化体验,可以采用局部刷新策略,只更新数值变化的区域,而不是全屏刷新。
  3. 异常处理:在主循环中加入对传感器通信失败、数据校验错误的处理,比如在屏幕上显示“传感器错误”或使用上一次的有效数据。

这种架构简单有效,避免了使用实时操作系统(RTOS)的复杂性,同时通过定时中断保证了数据采集的周期性。

3.2 关键驱动代码解析

DHT11驱动要点DHT11的通信时序要求比较严格,微秒级的延时必须准确。通常我们会用定时器或精准的空循环来实现延时。通信流程是:主机(STM32)拉低总线至少18ms(启动信号)→ 释放总线等待DHT11响应 → DHT11拉低80us后拉高80us作为应答 → 随后连续输出40位数据(湿度整数、湿度小数、温度整数、温度小数、校验和)。每一位数据都以50us的低电平开始,高电平的持续时间决定是0(26-28us)还是1(70us)。代码的关键在于高电平持续时间的测量,通常使用输入捕获功能或精确查询GPIO电平。

实操心得:很多初学者读取DHT11失败,问题就出在延时函数不准确上。在STM32中,直接使用for循环做微秒延时受编译器优化和系统时钟影响很大。推荐的做法是使用系统滴答定时器(SysTick)来实现微秒延时函数,或者使用一个基本定时器来产生精确的延时。另一个常见问题是,读取数据后没有检查校验和,导致显示乱码。务必在代码中加入校验和判断。

ADC读取雨滴传感器这部分相对简单。配置一个ADC通道(例如ADC1的通道0),设置为单次转换模式。需要读取时,启动转换,等待转换完成,读取数据寄存器(DR)的值。这个值是一个0-4095(12位ADC)的数字,对应0-3.3V的电压。

关键计算

电压值 (V) = (ADC原始值 / 4095) * 3.3V

然后,你需要根据传感器特性来解读这个电压。干燥时,传感器输出可能接近3.3V(或VCC);雨滴越多,导电性越好,输出电压越低。你需要通过实验来标定:记录完全干燥时的ADC值(ADC_dry)和洒上水(模拟下雨)后的ADC值(ADC_wet)。然后可以计算一个粗略的“湿度”或“雨量”百分比:

雨量百分比 = [(ADC_dry - ADC当前值) / (ADC_dry - ADC_wet)] * 100%

将这个百分比限制在0%~100%之间。你也可以设置几个阈值来划分等级。

TFT显示驱动与GUI这是代码量较大的部分。首先需要实现底层的SPI_SendByte()函数(硬件SPI或软件模拟)。然后实现针对屏幕驱动芯片(如ST7735S)的写命令(Write_Cmd)和写数据(Write_Data)函数。接着是屏幕初始化函数,里面包含一长串厂家提供的初始化命令序列。

在此基础上,实现最基础的DrawPixel(x, y, color)画点函数。有了画点,就可以构建出画线、画矩形、画圆等函数。对于显示文字,通常我们会使用字模提取工具,将需要的汉字和ASCII字符生成一个数组(字库),然后编写一个ShowString(x, y, *str, font, color, bg_color)函数,该函数根据字符编码从字库中取出点阵数据,调用画点函数逐个像素绘制。

注意事项:TFT屏幕的坐标系原点(0,0)可能在不同旋转方向下位于屏幕的不同角落(左上、右上、左下、右下)。在初始化时通过MADCTL命令设置好显示方向后,你的所有绘图函数逻辑都必须基于这个设定的坐标系。否则会出现上下颠倒、左右颠倒的情况。在编写图形函数时,务必考虑边界检查,避免画到屏幕外面去。

4. 系统集成与调试过程实录

把各个模块的代码单独调通只是第一步,把它们整合在一起稳定工作,才是真正的挑战。下面记录几个关键的集成与调试环节。

4.1 硬件连接与电源管理

接线清单(示例)

  • STM32F103C8T6<->TFT屏 (SPI):
    • PA5->SCK(时钟)
    • PA7->MOSI(主出从入)
    • PA4->CS(片选,低电平有效)
    • PA2->DC(数据/命令选择,高电平为数据,低电平为命令)
    • PA1->RST(复位,低电平复位)
    • 3.3V->VCC
    • GND->GND
    • PA0->BL(背光控制,可通过PWM调光)
  • STM32<->DHT11:
    • PB0->DATA(单总线,需接上拉电阻,如4.7KΩ到3.3V)
    • 3.3V->VCC
    • GND->GND
  • STM32<->雨滴传感器:
    • PA3->AO(模拟输出,接STM32的ADC引脚,如ADC1_IN3)
    • 3.3V5V->VCC(注意模块工作电压)
    • GND->GND

重要提示:务必确认所有模块的供电电压一致。DHT11和很多TFT屏是3.3V逻辑电平,雨滴传感器模块可能兼容5V。如果STM32是3.3V系统,建议所有模块都使用3.3V供电,避免电平不匹配损坏IO口。如果雨滴传感器必须5V供电,其模拟输出AO可能也是5V范围,则不能直接接入STM32的ADC(承受电压通常为3.3V),中间需要分压电路。

4.2 软件模块整合与资源冲突规避

当所有驱动函数就绪,在main.c中整合时,要注意资源冲突和时序问题。

  1. SPI与GPIO配置:确保SPI引脚(SCK, MOSI)的复用功能已正确映射和使能。TFT的DCCS引脚配置为推挽输出。DHT11的数据引脚配置为开漏输出模式(在发送起始信号时)和浮空输入模式(在接收数据时),并且硬件上要有上拉电阻。
  2. ADC配置:配置为单次转换,对齐方式为右对齐。注意ADC的时钟分频,确保其不超过芯片允许的最大频率(通常14MHz)。
  3. 定时器配置:配置一个基本定时器(如TIM2)用于产生2秒的中断。在中断服务例程(ISR)中,只做最简单的事情——设置标志位。绝对不要在ISR中进行复杂计算、调用printf或执行冗长的屏幕操作。
  4. 主循环逻辑优化:数据采集(DHT11、ADC)和屏幕刷新是相对耗时的操作。尤其是DHT11,一次完整的读取过程需要几十毫秒。如果屏幕刷新也是全屏刷新,时间更长。因此,必须确保这些操作不会阻塞系统太久。我的策略是:
    • 在定时中断中只设标志。
    • 主循环检测到标志后,先读取传感器数据(这个过程是必须的,且耗时固定)。
    • 屏幕刷新采用“脏矩形”技术。即,在内存中维护一个“上一帧”的显示缓冲区(可以是简化的重要数据),只有当新数据与旧数据不同时,才调用绘图函数去更新屏幕上对应的那一小块区域。例如,温度从“25.1”变成“25.2”,只重绘最后一位数字的区域。这能极大减少屏幕刷新时间,避免闪烁。

4.3 界面布局与用户体验设计

一个直观的UI能极大提升项目质感。我在1.44寸屏上做了如下布局:

  • 顶部区域:显示项目标题,如“Env Monitor”,静态显示。
  • 中部左侧:用一个大字体显示温度值(如“25.3℃”),下方用较小字体显示“Temperature”。
  • 中部右侧:同样用大字体显示湿度值(如“60.5%”),下方显示“Humidity”。
  • 底部区域:用于显示雨量信息。可以设计一个进度条,长度随雨量百分比变化,旁边用文字标注状态(“Dry”, “Light Rain”, “Heavy Rain”)或具体百分比。

绘制这些元素需要用到画线、填充矩形、显示字符串等函数。注意颜色搭配,确保在屏幕上有良好的对比度。可以定义一些颜色常量,如BLACK,WHITE,RED,GREEN,BLUE,YELLOW等。

5. 常见问题排查与深度优化技巧

在实际制作和调试过程中,我遇到了不少典型问题,这里总结出来,希望能帮你绕过这些坑。

5.1 传感器数据读取异常

问题1:DHT11始终读取失败,返回全是0或255。

  • 检查接线:确认DATA线连接正确,上拉电阻(4.7KΩ-10KΩ)已接上。
  • 检查时序:这是最常见的原因。用逻辑分析仪或示波器抓取DATA线上的波形,与DHT11数据手册的时序图对比。重点检查起始信号的低电平时间(>18ms)、等待响应的时间、以及每一位数据中高电平的持续时间。确保你的微秒延时函数是准确的。如果使用查询方式,在等待DHT11拉高或拉低时,一定要设置超时机制,避免程序死等。
  • 电源问题:DHT11对电源纹波比较敏感。确保供电稳定,可以在VCC和GND之间加一个0.1uF的滤波电容。
  • 代码逻辑:确保在读取数据前,已将GPIO模式从输出切换到输入。读取完40位后,务必校验数据和(前4个字节之和的低8位等于校验和字节)。

问题2:雨滴传感器ADC值不稳定,跳动很大。

  • 电源噪声:模拟电路对电源噪声非常敏感。确保给传感器模块的供电是干净的。可以使用线性稳压器(如AMS1117-3.3)单独供电,并在模块的VCC和GND之间并联一个10uF的电解电容和一个0.1uF的陶瓷电容。
  • 信号滤波:在软件上对ADC采样值进行滤波。最简单的是多次采样取平均值(例如连续采样10次,去掉最大最小值后求平均)。更高级的可以用一阶低通滤波(软件实现):filtered_value = α * current_adc + (1-α) * filtered_value,其中α是滤波系数(0<α<1),值越小,滤波效果越强,响应越慢。
  • 参考电压:确保STM32的ADC参考电压(通常是VDDA,连接到3.3V)稳定。如果系统中有大功率器件(如电机、继电器)频繁开关,可能会引起电源波动,影响ADC精度。

5.2 TFT显示相关问题

问题1:屏幕白屏、花屏或显示错乱。

  • 初始化序列错误:这是首要怀疑对象。不同厂家、不同批次的屏幕,初始化命令序列可能有细微差别。务必使用卖家提供的或经过验证的针对你手中这块屏的初始化代码。初始化命令的顺序、参数都不能错。
  • SPI时序问题:检查SPI的时钟极性(CPOL)和相位(CPHA)设置。ST7735S通常模式是CPOL=0, CPHA=0。如果不对,数据就无法正确锁存。可以尝试另外三种模式组合。
  • 速度问题:SPI时钟速度太快可能导致屏幕驱动芯片无法响应。尝试降低SPI的波特率分频(如从PCLK/2降到PCLK/8)。
  • 复位与电源:确保上电时序正确。有些屏幕要求复位信号(RST)在电源稳定后保持一段时间的低电平。检查背光(BL)是否使能。

问题2:屏幕刷新慢,有闪烁感。

  • 全屏刷新:这是导致闪烁的根本原因。每次更新数据都清屏重画全部内容,在刷新过程中屏幕会呈现撕裂或闪烁状态。
  • 解决方案:实施局部刷新。如前所述,只更新数据变化的区域。例如,温度数字有4位,从“25.1”变到“25.2”,只有最后一位变了。那么就在绘制新数字“2”之前,先用背景色把旧数字“1”的区域覆盖掉(画一个实心矩形),再画上新数字“2”。这样操作只影响屏幕上很小一块区域,速度极快,人眼几乎感知不到。
  • 双缓冲:对于更复杂的图形界面,可以考虑双缓冲技术。即在内存中开辟一块和屏幕分辨率一样大的缓冲区(Frame Buffer),所有的绘图操作都在这个缓冲区中进行。完成一帧的绘制后,一次性将整个缓冲区的内容通过SPI发送到屏幕。这能完全消除撕裂,但需要大量内存(对于130x130的16位色屏幕,需要至少33.8KB的RAM),STM32F103C8T6只有20KB RAM,可能无法承受。因此,局部刷新是本项目更可行的优化方案。

5.3 系统稳定性与抗干扰

问题:系统运行一段时间后死机或数据明显异常。

  • 看门狗:启用独立看门狗(IWDG)或窗口看门狗(WWDG)。在主循环中定期“喂狗”。如果程序跑飞或陷入死循环,看门狗会在超时后复位系统,提高设备的自恢复能力。
  • 中断冲突:检查是否有中断服务程序执行时间过长,或者中断嵌套导致栈溢出。确保中断优先级设置合理,关键时序中断(如SysTick用于延时)的优先级最高。
  • 电源完整性:使用示波器观察3.3V电源轨,在系统运行时(尤其是屏幕刷新瞬间)是否有大的毛刺或跌落。如有必要,增加电源部分的电容容值。

6. 项目扩展与进阶思路

这个基础项目就像一个乐高底座,可以在上面添加很多有趣的模块,演变成功能更丰富的设备。

  1. 添加实时时钟(RTC):接入DS1302或DS3231模块,在屏幕上显示当前时间、日期,并可以实现数据定时记录的功能。
  2. 增加数据存储:加入SPI Flash(如W25Q64)或SD卡模块,将历史温湿度、雨量数据以文件形式存储,便于后续分析。
  3. 实现无线传输:这是最热门的扩展方向。可以替换或增加一个ESP8266/ESP32模块,通过Wi-Fi将数据上传到云平台(如阿里云、腾讯云IoT、Home Assistant)或者发送到手机APP。这样你就可以远程监控环境了。
  4. 添加更多传感器:例如,接入大气压强传感器(BMP280)、空气质量传感器(PMS5003)、光照强度传感器等,打造一个多功能环境监测站。
  5. 优化人机交互:增加一个旋转编码器或按键,配合TFT屏幕实现菜单系统,可以切换显示页面、设置报警阈值、查看历史数据等。
  6. 低功耗设计:如果采用电池供电,就需要考虑低功耗。可以让MCU大部分时间处于睡眠模式(Stop或Standby),定时被RTC闹钟或外部中断(如雨滴传感器达到阈值)唤醒,采集一次数据并刷新屏幕,然后继续睡眠。这能极大地延长续航时间。

在实现这些扩展时,软件架构可能需要升级。例如,引入一个简单的状态机来管理不同的显示页面,或者使用一个轻量级的RTOS(如FreeRTOS)来管理传感器读取、数据显示、网络通信等多个任务。但无论如何,当前这个项目的实践,为你打下了坚实的硬件驱动和系统集成基础。

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

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

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

立即咨询