当前位置: 首页 > news >正文

零知IDE——基于STM32F407VET6和雨滴传感器的多界面TFT降雨监测显示系统 - 详解

   ✔零知IDE 是一个真正属于国人自己的开源软件平台,在开发效率上超越了Arduino平台并且更加容易上手,大大降低了开发难度。零知开源在软件方面提供了完整的学习教程和丰富示例代码,让不懂程序的工程师也能非常轻而易举的搭建电路来创作产品,测试产品。快来动手试试吧!

✔访问零知实验室,获取更多实战项目和教程资源吧!

www.lingzhilab.com

目录

一、硬件连接部分

1.1 硬件清单

1.2 接线方案表

1.3 具体接线图

1.4 连接实物图

二、核心代码解析

2.1 初始化设置

2.2 数据读取与映射

2.3 防闪烁更新机制

2.4 条形图表绘制

2.5 完整代码

三、项目结果演示

3.1 操作流程

3.2 界面展示

3.3 视频演示

四、雨滴传感器工作原理

4.1 基本原理

4.2 工作过程

4.3 模数转换原理

五、常见问题解答

Q1: 为什么雨量百分比显示不正确?

Q2: 如何调整报警阈值?

Q3: 历史数据图表不更新怎么办?


(1)项目概述

        本项目基于STM32F407VET6主控芯片,结合雨滴传感器和240×240分辨率ST7789 TFT显示屏,开发了一套智能降雨监测系统。系统能够实时监测降雨情况,通过三种不同的UI界面展示数据,具备数据可视化、历史趋势分析和报警功能。

(2)项目功能及亮点

       功能描述:数据映射关系处理,实时雨量百分比监测与显示

系统亮点:正确处理雨滴传感器的电阻特性,实现从模拟值到百分比的合理映射

一、硬件连接部分

1.1 硬件清单

组件规格数量
主控板STM32F407VET61
雨滴传感器模拟输出型1
TFT显示屏ST7789 240×2401
报警LED5mm LED1
连接线杜邦线若干

1.2 接线方案表

根据代码定义的引脚分配:

组件引脚功能零知增强板引脚
雨滴传感器模拟输入A1
报警LED数字输出9
ST7789片选信号53
ST7789复位信号6
ST7789数据/命令7
ST7789SPI时钟52
ST7789SPI数据51

1.3 具体接线图

1.4 连接实物图

二、核心代码解析

2.1 初始化设置

void setup() {pinMode(RAIN_SENSOR, INPUT);pinMode(ALERT, OUTPUT);Serial.begin(9600);// 初始化显示屏tft.init(240, 240);tft.setRotation(1);tft.fillScreen(BACKGROUND_COLOR);tft.setTextWrap(false);// 显示启动画面showStartupScreen();delay(2500);// 绘制初始界面drawCurrentPage();Serial.println("Rain Sensor with TFT Display Started");}

        tft.setRotation(1)设置屏幕方向为横屏、tft.setTextWrap(false)禁止文本自动换行

2.2 数据读取与映射

void readSensorData() {rawValue = analogRead(RAIN_SENSOR) / 4; // 适配4096的模拟值// 反转映射关系:无雨时电阻大,模拟值大,我们希望无雨时百分比小sensorValue = map(rawValue, 0, 1023, 100, 0); // 反转映射// 保存历史数据historyValues[historyIndex] = sensorValue;historyIndex = (historyIndex + 1) % 15;// 设置报警状态(阈值可调整)alertState = (sensorValue > 70); // 大于70%认为有雨(因为映射已反转)}

        模拟值除以4适配4096分辨率ADC、使用map()函数实现数值范围映射

2.3 防闪烁更新机制

void updateCurrentPage() {// 只有在数据变化时才更新显示,避免闪烁if (sensorValue != lastSensorValue || alertState != lastAlertState || rawValue != lastRawValue) {switch(currentPage) {case 0: updatePage1(); break;case 1: updatePage2(); break;case 2: updatePage3(); break;}// 更新上一次的值lastSensorValue = sensorValue;lastAlertState = alertState;lastRawValue = rawValue;}// 页面2(图表页面)需要持续更新if (currentPage == 1 && millis() - lastChartUpdate > 1000) {updatePage2Chart();lastChartUpdate = millis();}
}

        数据变化检测避免不必要刷新、图表页面单独处理,保证实时性、时间戳控制刷新频率

2.4 条形图表绘制

void updatePage2Chart() {// 计算条形图参数(居中显示,增加间隔)int barCount = 12;int barWidth = 10;int barSpacing = 6;int totalWidth = barCount * barWidth + (barCount - 1) * barSpacing;int startX = 130 - totalWidth / 2; // 居中计算// 绘制条形图for (int i = 0; i < barCount; i++) {int valueIndex = (historyIndex - barCount + i + barCount) % barCount;int barHeight = map(historyValues[valueIndex], 0, 100, 0, chartHeight);// 选择颜色 - 使用渐变效果uint16_t barColor;if (historyValues[valueIndex] > 70) {barColor = WARNING_COLOR; // 红色报警} else if (historyValues[valueIndex] > 40) {barColor = ST77XX_ORANGE; // 橙色警告} else {barColor = BAR_COLOR; // 蓝色正常}tft.fillRect(x, y, barWidth, barHeight, barColor);}
}

        渐变颜色指示不同状态、时间轴标签显示

2.5 完整代码

  #include #include #include // 引脚定义#define ST77XX_DARKGREY 0x7453#define RAIN_SENSOR A1#define ALERT 9#define TFT_CS   53#define TFT_RST   6#define TFT_DC    7// 创建显示屏对象Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);// 变量定义int sensorValue = 0;int rawValue = 0;bool alertState = false;unsigned long lastDisplayUpdate = 0;unsigned long lastSensorRead = 0;unsigned long lastChartUpdate = 0;int currentPage = 0;const int TOTAL_PAGES = 3;const int PAGE_DURATION = 10000; // 页面切换时间8秒// 颜色定义#define BACKGROUND_COLOR ST77XX_BLACK#define TEXT_COLOR ST77XX_WHITE#define WARNING_COLOR ST77XX_RED#define NORMAL_COLOR ST77XX_GREEN#define BAR_COLOR ST77XX_BLUE#define ACCENT_COLOR ST77XX_CYAN#define GRID_COLOR 0x4208 // 深灰色// 页面切换动画相关int animationOffset = 0;bool isAnimating = false;unsigned long animationStartTime = 0;// 历史数据记录int historyValues[15] = {0};int historyIndex = 0;// 防止闪烁的变量int lastSensorValue = -1;bool lastAlertState = false;int lastRawValue = -1;void setup() {pinMode(RAIN_SENSOR, INPUT);pinMode(ALERT, OUTPUT);Serial.begin(9600);// 初始化显示屏tft.init(240, 240);tft.setRotation(1);tft.fillScreen(BACKGROUND_COLOR);tft.setTextWrap(false);// 显示启动画面showStartupScreen();delay(2500);// 绘制初始界面drawCurrentPage();Serial.println("Rain Sensor with TFT Display Started");}void loop() {unsigned long currentTime = millis();// 每800ms读取一次传感器数据if (currentTime - lastSensorRead >= 800) {readSensorData();lastSensorRead = currentTime;}// 每8秒切换页面if (currentTime - lastDisplayUpdate >= PAGE_DURATION) {switchToNextPage();lastDisplayUpdate = currentTime;}// 处理页面切换动画if (isAnimating) {handlePageAnimation();} else {// 更新当前页面数据(局部刷新)updateCurrentPage();}// 控制报警LEDdigitalWrite(ALERT, alertState ? HIGH : LOW);}void readSensorData() {rawValue = analogRead(RAIN_SENSOR) / 4; // 适配4096的模拟值// 反转映射关系:无雨时电阻大,模拟值大,我们希望无雨时百分比小sensorValue = map(rawValue, 0, 1023, 100, 0); // 反转映射// 保存历史数据historyValues[historyIndex] = sensorValue;historyIndex = (historyIndex + 1) % 15;// 设置报警状态(阈值可调整)alertState = (sensorValue > 70); // 大于70%认为有雨(因为映射已反转)Serial.print("Raw: ");Serial.print(rawValue);Serial.print(" - Rain Level: ");Serial.print(sensorValue);Serial.print("% - Alert: ");Serial.println(alertState ? "ON" : "OFF");}void switchToNextPage() {currentPage = (currentPage + 1) % TOTAL_PAGES;isAnimating = true;animationOffset = 240; // 从右侧开始animationStartTime = millis();// 重置上一次的值,确保新页面完全绘制lastSensorValue = -1;lastAlertState = !alertState;lastRawValue = -1;}void handlePageAnimation() {unsigned long currentTime = millis();unsigned long elapsed = currentTime - animationStartTime;// 动画持续时间400msif (elapsed < 400) {// 计算动画偏移量(缓动效果)float progress = (float)elapsed / 400.0;animationOffset = 240 - (int)(240 * easeOutCubic(progress));// 绘制动画帧drawPageAnimation();} else {isAnimating = false;animationOffset = 0;drawCurrentPage(); // 最终绘制完整页面}}float easeOutCubic(float x) {return 1 - pow(1 - x, 3);}void drawPageAnimation() {tft.fillScreen(BACKGROUND_COLOR);// 绘制新页面(带偏移)switch(currentPage) {case 0: drawPage1(animationOffset); break;case 1: drawPage2(animationOffset); break;case 2: drawPage3(animationOffset); break;}}void drawCurrentPage() {switch(currentPage) {case 0: drawPage1(0); break;case 1: drawPage2(0); break;case 2: drawPage3(0); break;}}void updateCurrentPage() {// 只有在数据变化时才更新显示,避免闪烁if (sensorValue != lastSensorValue || alertState != lastAlertState || rawValue != lastRawValue) {switch(currentPage) {case 0: updatePage1(); break;case 1: updatePage2(); break;case 2: updatePage3(); break;}// 更新上一次的值lastSensorValue = sensorValue;lastAlertState = alertState;lastRawValue = rawValue;}// 页面2(图表页面)需要持续更新if (currentPage == 1 && millis() - lastChartUpdate > 1000) {updatePage2Chart();lastChartUpdate = millis();}}void showStartupScreen() {tft.fillScreen(ST77XX_BLACK);// 主标题tft.setTextColor(ST77XX_GREEN);tft.setTextSize(3);tft.setCursor(25, 80);tft.println("RAIN SENSOR");// 副标题tft.setTextColor(ST77XX_WHITE);tft.setTextSize(2);tft.setCursor(85, 120);tft.println("SYSTEM");// 进度条 - 粗进度条tft.drawRoundRect(40, 160, 160, 20, 10, ST77XX_WHITE);for(int i = 0; i <= 160; i += 8) {tft.fillRoundRect(40, 160, i, 20, 10, ST77XX_BLUE);delay(30);}}// 页面1: 简洁数据展示void drawPage1(int offset) {tft.fillScreen(BACKGROUND_COLOR);// 标题 - 左上角tft.setTextColor(ACCENT_COLOR);tft.setTextSize(2);tft.setCursor(10 + offset, 10);tft.println("RAIN LEVEL");// 分隔线tft.drawFastHLine(10 + offset, 35, 220, GRID_COLOR);// 绘制静态内容drawPage1Static(offset);}void drawPage1Static(int offset) {// 状态指示标签tft.setTextColor(TEXT_COLOR);tft.setTextSize(2);tft.setCursor(20 + offset, 160);tft.print("Raw: ");// 页面指示tft.setCursor(80 + offset, 220);tft.print("Page 1/");tft.print(TOTAL_PAGES);}void updatePage1() {// 清除数据区域tft.fillRect(10, 50, 220, 100, BACKGROUND_COLOR);// 大字体显示百分比tft.setTextColor(sensorValue > 70 ? WARNING_COLOR : TEXT_COLOR);tft.setTextSize(4);tft.setCursor(85, 70);tft.print(sensorValue);tft.setTextSize(2);tft.println("%");// 状态指示tft.setTextSize(2);tft.setCursor(75, 120);if (sensorValue > 70) {tft.setTextColor(WARNING_COLOR);tft.println("RAINING!");} else if (sensorValue > 30) {tft.setTextColor(ST77XX_YELLOW);tft.println("CLOUDY");} else {tft.setTextColor(NORMAL_COLOR);tft.println("CLEAR");}// 原始值显示tft.setTextColor(ACCENT_COLOR);tft.fillRect(50, 150, 100, 30, BACKGROUND_COLOR);tft.setTextSize(2);tft.setCursor(20, 160);tft.print("Raw: ");tft.print(rawValue);}// 页面2: 现代化图表展示void drawPage2(int offset) {tft.fillScreen(BACKGROUND_COLOR);// 标题 - 左上角tft.setTextColor(ACCENT_COLOR);tft.setTextSize(2);tft.setCursor(10 + offset, 10);tft.println("RAIN HISTORY");// 分隔线tft.drawFastHLine(10 + offset, 35, 220, GRID_COLOR);// 绘制图表框架drawChartFrame(offset);// 绘制静态标签tft.setTextColor(TEXT_COLOR);tft.setTextSize(1);tft.setCursor(10 + offset, 200);tft.print("Time");// 页面指示tft.setTextSize(2);tft.setCursor(80 + offset, 220);tft.print("Page 2/");tft.print(TOTAL_PAGES);}void drawChartFrame(int offset) {// 绘制坐标轴tft.drawFastVLine(30 + offset, 50, 140, TEXT_COLOR); // Y轴tft.drawFastHLine(30 + offset, 190, 190, TEXT_COLOR); // X轴// Y轴标签tft.setTextColor(TEXT_COLOR);tft.setTextSize(1);tft.setCursor(5 + offset, 45);tft.print("100%");tft.setCursor(10 + offset, 90);tft.print("75%");tft.setCursor(10 + offset, 135);tft.print("50%");tft.setCursor(10 + offset, 180);tft.print("25%");// X轴箭头tft.drawLine(220 + offset, 190, 215 + offset, 185, TEXT_COLOR);tft.drawLine(220 + offset, 190, 215 + offset, 195, TEXT_COLOR);// Y轴箭头tft.drawLine(30 + offset, 50, 25 + offset, 55, TEXT_COLOR);tft.drawLine(30 + offset, 50, 35 + offset, 55, TEXT_COLOR);}void updatePage2() {// 更新当前值显示tft.fillRect(120, 205, 100, 12, BACKGROUND_COLOR);tft.setTextColor(ACCENT_COLOR);tft.setTextSize(1);tft.setCursor(120, 205);tft.print("Now: ");tft.print(sensorValue);tft.print("%");}void updatePage2Chart() {// 计算条形图参数(居中显示,增加间隔)int barCount = 12;int barWidth = 10;int barSpacing = 6;int totalWidth = barCount * barWidth + (barCount - 1) * barSpacing;int startX = 130 - totalWidth / 2; // 居中计算int chartBottom = 190;int chartHeight = 130;// 清除图表区域(只清除条形区域,保留坐标轴)tft.fillRect(startX, 60, totalWidth + 5, chartHeight, BACKGROUND_COLOR);// 绘制条形图for (int i = 0; i < barCount; i++) {int valueIndex = (historyIndex - barCount + i + barCount) % barCount;int barHeight = map(historyValues[valueIndex], 0, 100, 0, chartHeight);int x = startX + i * (barWidth + barSpacing);int y = chartBottom - barHeight;// 选择颜色 - 使用渐变效果uint16_t barColor;if (historyValues[valueIndex] > 70) {barColor = WARNING_COLOR;} else if (historyValues[valueIndex] > 40) {barColor = ST77XX_ORANGE;} else {barColor = BAR_COLOR;}// 绘制条形(带阴影效果)tft.fillRect(x, y, barWidth, barHeight, barColor);// 条形顶部边框tft.drawFastHLine(x, y, barWidth, TEXT_COLOR);// 数值标签(只显示较高的条形)if (barHeight > 20) {tft.setTextColor(TEXT_COLOR);tft.setTextSize(1);tft.setCursor(x + 1, y - 10);tft.print(historyValues[valueIndex]);}// 时间标签(底部)if (i % 3 == 0) {tft.setTextColor(GRID_COLOR);tft.setTextSize(1);tft.setCursor(x - 3, chartBottom + 5);tft.print("-");tft.print(barCount - i);}}}// 页面3: 详细信息void drawPage3(int offset) {tft.fillScreen(BACKGROUND_COLOR);// 标题 - 左上角tft.setTextColor(ACCENT_COLOR);tft.setTextSize(2);tft.setCursor(10 + offset, 10);tft.println("SENSOR INFO");// 分隔线tft.drawFastHLine(10 + offset, 35, 220, GRID_COLOR);// 绘制静态内容drawPage3Static(offset);}void drawPage3Static(int offset) {// 静态标签tft.setTextColor(TEXT_COLOR);tft.setTextSize(2);tft.setCursor(5 + offset, 60);tft.print("Rain Level");tft.setCursor(5 + offset, 90);tft.print("Raw Value: ");tft.setCursor(5 + offset, 120);tft.print("Alert: ");tft.setCursor(5 + offset, 150);tft.print("Threshold: ");// 映射说明tft.setTextColor(GRID_COLOR);tft.setTextSize(1);tft.setCursor(5 + offset, 180);tft.println("Dry=Low%, Wet=High%");// 页面指示tft.setTextColor(ACCENT_COLOR);tft.setTextSize(2);tft.setCursor(80 + offset, 220);tft.print("Page 3/");tft.print(TOTAL_PAGES);}void updatePage3() {// 更新雨量百分比tft.fillRect(130, 60, 80, 20, BACKGROUND_COLOR);tft.setTextColor(sensorValue > 70 ? WARNING_COLOR : NORMAL_COLOR);tft.setTextSize(2);tft.setCursor(130, 60);tft.print(sensorValue);tft.println("%");// 更新原始值tft.fillRect(130, 90, 100, 20, BACKGROUND_COLOR);tft.setTextColor(ACCENT_COLOR);tft.setCursor(130, 90);tft.print(rawValue);tft.println("/1023");// 更新报警状态tft.fillRect(130, 120, 100, 20, BACKGROUND_COLOR);if (alertState) {tft.setTextColor(WARNING_COLOR);tft.setCursor(130, 120);tft.println("ACTIVE");} else {tft.setTextColor(NORMAL_COLOR);tft.setCursor(130, 120);tft.println("INACTIVE");}// 更新阈值信息tft.fillRect(130, 150, 80, 20, BACKGROUND_COLOR);tft.setTextColor(TEXT_COLOR);tft.setCursor(130, 150);tft.println(">70%");}

数据展示思维导图

三、项目结果演示

3.1 操作流程

①系统启动显示启动界面
②自动进入主监测界面(页面1)
③每10秒自动切换至下一页面

        历史雨量数据柱状统计图模拟界面设计,根据时间戳显示雨量大小

④页面1: 实时雨量百分比显示、页面2: 历史数据趋势图表、页面3: 详细传感器信息

⑤零知IDE串口打印输出

串口输出示例:        

        Rain Sensor with TFT Display Started
        Raw: 245 - Rain Level: 76% - Alert: ON

3.2 界面展示

页面1: 大字体显示当前雨量百分比和状态指示

页面2: 条形柱状图展示历史数据趋势

页面3: 详细的传感器参数和报警状态

3.3 视频演示

雨滴传感器的多界面TFT降雨监测显示系统

系统从启动到运行的完整流程,包括三种界面的自动切换、模拟降雨检测、报警触发等关键功能

四、雨滴传感器工作原理

4.1 基本原理

        雨滴传感器基于电阻变化原理工作。传感器表面有交错排列的导电线,当雨水落到表面时,水分的导电性会在导线之间形成电阻通路

        模拟电压输出特性:模拟雨量增大之后,导通电阻降低,输出电压下降

4.2 工作过程

(1)干燥状态: 导线间电阻极大(兆欧级),输出高电压

(2)湿润状态: 水分形成导电通路,电阻显著降低,输出电压下降

(3)雨量检测: 通过ADC读取电压值,映射为雨量百分比,雨量阈值超过70%亮红灯报警

4.3 模数转换原理

        零知增强板的STM32F407VET6主控芯片内置12位ADC,将0-3.3V模拟电压转换为0-4095数字值:

五、常见问题解答

Q1: 为什么雨量百分比显示不正确?

A: 检查雨滴传感器的接线:

        确保模拟输入引脚正确。调整map()函数的参数以适应具体传感器特性

Q2: 如何调整报警阈值?

A: 修改代码:

        调整alertState = (sensorValue > 70);的阈值数值,根据实际需求设置合适的报警点

Q3: 历史数据图表不更新怎么办?

A: 检查historyValues数组的索引管理:

        确保新数据正确覆盖旧数据。验证updatePage2Chart()函数的调用频率

http://www.zskr.cn/news/28200.html

相关文章:

  • 深入解析:本机网速会影响到云手机的运行吗
  • 交互的脉络:小程序事件平台详解
  • 基于MATLAB的Copula函数实现
  • 2025年国产助听器品牌推荐榜:聚焦专业适配,杭州爱听科技引领国产助听新体验​
  • 2025 年PPR家装管厂家最新推荐榜:聚焦企业专利技术、品质管控及知名客户合作案例的权威解析
  • 2025 年废气处理设备厂家最新推荐榜:聚焦企业专利技术、品质管控及知名客户合作案例的权威解析
  • 2025 年连接器厂家最新推荐榜单:聚焦电子 / Type-C / 板对板等品类,精选领军企业助力下游企业精准选型
  • 2025 年干燥机厂家最新推荐排行榜:聚焦闪蒸 / 气流 / 沸腾 / 闭路循环等多类型设备,精选优质企业深度解析
  • 2025 年北京订制旅游 / 精品旅游 / 旅游包车 / 精品小包团旅游旅行社推荐,北京汇通清源国际旅游公司专业服务解析
  • 具有柔性关节的机械臂MATLAB仿真
  • Linux的基本操作值vi操作对与文件
  • 2025 年最新推荐!滑石粉厂家实力排行榜,超细 / 塑料级 / 涂料级 / 造纸级 / 工业级等多类型产品优质企业全解析
  • 实用指南:题解:AT_abc401_c [ABC401C] K-bonacci
  • session cookie token的区别
  • uniapp h5内嵌h5重复进入css动画卡顿的问题
  • 2025 年青岛金属材料检测公司最新推荐榜:聚焦企业专利技术、品质管控及知名客户合作案例的权威解析
  • 2025 年苏州机械设备EAC认证公司最新推荐榜:聚焦企业专利技术、品质管控及知名客户合作案例的权威解析
  • 从普通用户到影视后期都能用!Topaz Video AI 7.0.0 靠 AI 搞定视频修复与质量升级
  • 高通QCS8550部署YOLO-NAS模型与性能测试
  • 2025年10月北京全过程工程咨询公司推荐榜:权威评测五强对比
  • 2025年10月肤色暗沉产品评测榜:五款温和亮肤方案
  • 2025年10月熬夜急救产品推荐榜:实测五款修护亮肤精华对比
  • 自动化组件库AdvLibSuite.CCUnified发布
  • 10.23 Session、Cookie、Token的核心区别;Cookie和缓存(Cache)的区别
  • 扩展域并查集
  • 2025年10月留香沐浴露对比榜:蓝蕨等五款留香力实测
  • 2025年10月留香沐浴露推荐:五强口碑榜对比评测
  • 2025年10月浦东装修公司推荐榜:五强排名深度评测 2025年10月浦东装修公司榜:五强对比与选择指南
  • 北京房产纠纷律师服务口碑榜:专业能力与胜诉案例深度评估
  • 【高录用、见刊快】2025年教育技术与管理信息系统国际学术会议(ETMIS 2025)