准备设计arduino uno r3为主控的环境监测系统,通过传感器采集TVOC(总挥发性有机物)、HCHO(甲醛)和eCO2(等效二氧化碳)数据,并显示在LCD屏幕上,同时支持数据记录到SD卡,以及通过旋转编码器进行交互。

最终呈现效果:

结合RTC时间戳将数据记录至SD卡,并通过LCD显示屏和旋转编码器实现用户交互。系统具备三屏数据显示智能SD卡管理时间设置数据记录控制等核心功能。


代码结构分析:

  1. 包含的库:Wire(I2C通信)、LiquidCrystal_I2C(I2C LCD控制)、SoftwareSerial(软串口,用于与传感器通信)、SdFat(SD卡操作)、RTClib(实时时钟)。
  2. 引脚定义:TVOC传感器使用软串口(RX, TX)、SD卡片选、旋转编码器(CLK, DT, SW)、记录按钮、LED。
  3. 全局对象:软串口对象、LCD对象、SD卡对象、RTC对象。
  4. 全局变量:用于数据解析、传感器数据存储、显示控制、编码器状态、记录状态、硬件状态标志等。
  5. 函数:
    • setup():初始化系统,包括串口、LCD、RTC、传感器、SD卡、编码器、记录按钮等。
    • initLCD():初始化LCD,尝试多个I2C地址。
    • initSDCard():初始化SD卡,并检查其功能。
    • checkSDFunctional():检查SD卡功能(写一个测试文件并读取验证)。
    • ensureDataFile():确保数据文件存在,并写入表头。
    • loop():主循环,包括硬件状态检查、接收数据、处理编码器和按钮、更新显示、定期检查SD卡状态。
    • checkHardwareStatus():检查硬件状态(RTC、SD卡)。
    • checkSDStatus():检查SD卡状态(物理存在和功能)。
    • updateTimeDisplay():更新当前时间显示。
    • handleRecordButton():处理记录按钮的按下事件(切换记录状态)。
    • handleEncoder():处理旋转编码器的旋转和按钮事件(切换屏幕、进入时间设置模式)。
    • enterSetMode():进入时间设置模式。
    • exitTimeSetMode():退出时间设置模式,更新RTC时间。
    • receiveData():从TVOC传感器接收数据。
    • processData():处理接收到的传感器数据,验证校验和,并存储到结构体。
    • logSensorData():将传感器数据记录到SD卡。
    • loadLastRecord():从SD卡加载最后一条记录。
    • parseLastRecord():解析最后一条记录。
    • displaySDStatus():在LCD上显示SD卡状态(使用自定义字符)。
    • updateDisplay():根据当前屏幕索引更新显示内容。
    • displayTVOCHCHO():显示TVOC和HCHO数据。
    • displayECO2():显示eCO2数据。
    • displayLastRecord():显示最后记录的数据和记录状态。
    • displaySetItem():在设置模式下显示当前设置项。
    • handleSetMode():处理设置模式下的编码器旋转事件。
    • adjustTimeValue():调整时间值(根据设置项)。
    • daysInMonth():计算某年某月的天数。

功能概述:


该设备通过软串口与TVOC传感器通信,获取TVOC、HCHO和eCO2数据。这些数据会显示在LCD屏幕上,用户可以通过旋转编码器切换显示屏幕(三个屏幕:TVOC+HCHO、eCO2、最后记录)。同时,设备支持将数据记录到SD卡(记录状态由记录按钮控制)。设备还包含一个实时时钟(RTC)用于时间戳。旋转编码器长按可以进入时间设置模式,调整年、月、日、时、分、秒。

详细分析:

  1. 初始化(setup):

    • 初始化串口(用于调试)。
    • 初始化板载LED(用于指示状态)。
    • 初始化LCD(尝试多个I2C地址)。
    • 初始化RTC(如果失败则显示错误,如果RTC未运行则使用编译时间设置)。
    • 初始化TVOC传感器的软串口。
    • 初始化SD卡(并确保数据文件存在)。
    • 初始化编码器引脚(上拉输入)。
    • 初始化记录按钮引脚(上拉输入)。
    • 创建自定义字符(SD卡图标)。
    • 显示初始化完成信息。
  2. 主循环(loop):

    • 检查硬件状态(每5秒检查一次RTC和SD卡)。
    • 接收传感器数据(通过软串口,按照特定帧格式解析)。
    • 处理编码器事件(旋转和按钮,包括短按切换屏幕,长按进入时间设置模式)。
    • 处理记录按钮(按下切换记录状态,并切换到记录状态屏幕)。
    • 每500ms更新显示(包括时间和传感器数据)。
    • 每3秒检查SD卡状态(物理存在和功能状态)。
  3. 数据记录:

    • 当记录使能(recordingEnabled为true)且传感器数据有效且RTC可用时,将数据写入SD卡。
    • 数据文件为CSV格式,包含UNIX时间戳、日期时间、TVOC、HCHO、CO2。
    • 每次记录后更新最后一条记录(lastRecord结构体)。
  4. 显示:

    • 三个屏幕:
      Screen0: TVOC和HCHO的数值(第一行TVOC,第二行HCHO)。
      Screen1: eCO2的数值和日期时间(第一行eCO2,第二行日期和时间)。
      Screen2: 最后记录的数据(包括TVOC、eCO2、记录状态、SD卡状态)。
    • 在LCD右上角显示SD卡状态(自定义图标:正常为SD图标,物理存在但功能异常为'!',不存在为'X')。
  5. 时间设置模式:

    • 长按编码器按钮进入时间设置模式。
    • 通过旋转编码器调整当前设置项(年、月、日、时、分、秒)。
    • 每按一次按钮切换一个设置项,设置完所有项后退出设置模式并更新RTC时间。
  6. SD卡状态管理:

    • 定期检查SD卡物理存在(通过尝试初始化)和功能状态(通过读写测试)。
    • 状态变化时更新显示。
  7. 错误处理:

    • 初始化失败时在串口输出错误信息,并在LCD上显示(如RTC错误)。
    • SD卡写入失败时标记为功能异常,并点亮LED指示错误。

修复和增强:

代码中有一些修复和增强,例如SD卡状态检测、时间设置等。

需要单独考虑:

  • 使用条件判断来确保硬件可用性(如lcdInitialized, rtcAvailable等)。
  • 使用volatile关键字修饰编码器相关变量(因为它们在中断服务函数中修改,但本代码中并未使用中断,而是在主循环中查询,所以实际上可以不用volatile,但保留也无妨)。
  • 使用状态机思想处理编码器旋转和按钮事件。
  • 记录按钮和编码器按钮都做了防抖处理。
  • 在记录数据时,如果打开文件失败,会将sdCardFunctional置为false,然后在下一次检查时尝试恢复。

代码实现 


🛠️ ​硬件架构
  1. 核心控制器​:Arduino开发板
  2. 传感器模块​:TVOC传感器(软串口通信)
  3. 存储模块​:SD卡(SPI接口)
  4. 显示模块​:I2C LCD1602液晶屏
  5. 用户输入​:旋转编码器(CLK/DT/SW引脚) + 记录按钮
  6. 时间模块​:DS1307 RTC时钟
  7. 状态指示​:LED指示灯

🧩 ​代码结构分析
🔌 ​1. 初始化设置(setup())​
void setup() {// 串口调试初始化Serial.begin(9600); // 硬件初始化链initLCD();       // LCD显示初始化[11](@ref)initRTC();       // 实时时钟初始化[6](@ref)initSDCard();    // SD卡系统初始化[10](@ref)initSensors();   // 传感器通信初始化// 用户输入设备初始化pinMode(ENC_CLK, INPUT_PULLUP);  // 编码器CLK引脚[9](@ref)pinMode(RECORD_BTN, INPUT_PULLUP); // 记录按钮// 自定义字符创建(SD图标)lcd.createChar(0, sdIcon);  // 创建SD卡图标[11](@ref)
}

关键点​:

  • 采用模块化初始化策略,各硬件独立初始化
  • LCD支持多地址自动探测​(0x27/0x3F)
  • RTC首次启动时自动注入编译时间
🔁 ​2. 主循环逻辑(loop())​
void loop() {checkHardwareStatus();    // 硬件健康监测(5秒间隔)receiveData();            // 传感器数据采集handleEncoder();          // 编码器事件处理[9](@ref)handleRecordButton();     // 记录按钮逻辑if(needDisplayUpdate()) { // 500ms显示刷新updateTimeDisplay();    // 更新时间显示[6](@ref)updateDisplay();        // 刷新LCD内容}checkSDStatus();          // SD卡状态监测(3秒间隔)[10](@ref)
}

核心机制​:

  • 分层式任务调度​:硬件监控、数据采集、用户交互分离
  • 节流机制​:显示刷新(500ms)、SD检测(3s)避免资源争用
  • 状态机驱动​:通过currentScreen管理三屏显示
📡 ​3. 传感器数据处理
void processData() {byte checksum = 0;for(int i=0; i<8; i++) checksum += rawData[i];if(checksum != rawData[8]) { // 校验和验证Serial.println("TVOC checksum error!");return;}// 数据解析(大端序)currentData.tvoc = (rawData[2] << 8) | rawData[3]; currentData.hcho = (rawData[4] << 8) | rawData[5];currentData.eco2 = (rawData[6] << 8) | rawData[7];logSensorData(); // 有效数据记录
}

协议特性​:

  • 帧结构​:0x2C头 + 8字节数据 + 1字节校验和
  • 错误处理​:校验失败自动丢弃数据包
  • 数据映射​:TVOC/HCHO单位µg/m³,eCO₂单位ppm
💾 ​4. SD卡高级管理
void checkSDStatus() {// 物理存在检测bool physicalPresent = SD.begin(SD_CS_PIN); if(physicalPresent != sdCardPresent) { // 状态变化检测if(sdCardPresent) {sdCardFunctional = checkSDFunctional(); // 功能测试if(sdCardFunctional) ensureDataFile();  // 文件系统验证[10](@ref)}}// 自动恢复机制if(sdCardPresent && !sdCardFunctional) {sdCardFunctional = checkSDFunctional(); // 定期重试}
}

创新设计​:

  • 双状态检测​:物理存在(sdCardPresent) + 功能状态(sdCardFunctional)
  • 智能恢复​:定期尝试重新挂载失效SD卡
  • 文件保障​:自动创建CSV文件并写入表头
  • 图标化显示​:自定义SD状态字符(正常/异常/缺失)
⏰ ​5. 时间管理系统
void handleSetMode() {if(encTurned) {int delta = (digitalRead(ENC_DT) != lastClkState) ? -1 : 1;adjustTimeValue(delta); // 时间值调整switch(setIndex) { // 多级设置菜单[9](@ref)case 0: newTime = DateTime(newTime.year()+delta, ...); break;case 1: // 月份(带天数边界检查)uint8_t newMonth = constrain(month+delta, 1, 12);uint8_t newDay = min(day, daysInMonth(newMonth, year));...}}
}

交互特性​:

  • 长按触发​:编码器按钮长按>1秒进入设置模式
  • 循环设置​:年→月→日→时→分→秒→保存
  • 智能边界​:自动计算每月天数(含闰年)
📊 ​6. 数据显示系统
void updateDisplay() {switch(currentScreen) {case 0: // TVOC+HCHO同屏显示lcd.print("TVOC:"); lcd.print(currentData.tvoc); lcd.print("HCHO:"); lcd.print(currentData.hcho);break;case 1: // eCO2与日期时间lcd.print("eCO2:"); lcd.print(currentData.eco2);snprintf(dateBuffer, "%02d%02d%02d", now.year%100, now.month, now.day);break;case 2: // 最后记录与状态lcd.print("TV:"); lcd.print(lastRecord.tvoc);lcd.print("CO2:"); lcd.print(lastRecord.eco2);lcd.print(recordingEnabled ? "ON" : "OFF");displaySDStatus(); // 右下角状态图标[11](@ref)}
}

显示优化​:

  • 多屏切换​:编码器短按循环切换三个界面
  • 动态更新​:时间显示每秒刷新,数据每500ms更新
  • 状态集成​:SD图标(0)/警告(!)/缺失(X)直观指示

⚙️ ​系统创新设计
  1. SD卡智能恢复系统

    • 实现物理检测→功能验证→自动恢复的全链路管理
    • 采用双状态机模型(prevSdCardPresent/sdCardPresent)
    • 文件操作增加写后验证(创建测试文件校验完整性)
  2. 时间设置容错机制

    void adjustTimeValue(int delta) {case 1: // 月份调整uint8_t newDay = min(day, daysInMonth(newMonth, year));
    • 自动计算当月最大天数(含闰年判断)
    • 防止设置无效日期(如2月30日)
  3. 数据记录优化

    void logSensorData() {if(!recordingEnabled || !sdCardFunctional) return;File dataFile = SD.open("sensor.csv", FILE_WRITE);dataFile.print(unixTime); // UNIX时间戳[6](@ref)dataFile.print(currentData.tvoc); ...
    • 双时间戳存储:人类可读时间+UNIX时间戳
    • CSV格式标准化:兼容Excel/LibreOffice分析
  4. LCD显示优化

    • 自定义字符​:8×5像素SD图标设计
    • 空间复用​:15×0位置显示状态图标
    • 多屏布局​:科学分配16×2显示空间

📝 ​改进建议
  1. 增加传感器异常处理

    // 在processData()中增加:
    if(currentData.tvoc > 30000) { // 异常值判定Serial.println("Sensor out of range!");runSelfTest(); // 触发自检
    }
  2. 实现数据缓存机制

    • SD卡不可用时启用RAM缓存
    • 恢复后自动写入缓存数据
  3. 添加低功耗模式

    void enterSleepMode() {if(noInteraction(5 * 60 * 1000)) { // 5分钟无操作lcd.noBacklight();setCpuFrequency(10); // ESP32特有节能}
    }
  4. 优化时间设置

    // 在displaySetItem()中:
    lcd.print("▲▼"); // 增加操作提示

🔍 ​关键引用说明
  • LCD初始化​:支持I2C地址自动探测
  • RTC时间设置​:编译时间注入机制
  • SD卡操作​:CSV文件创建与表头写入
  • 编码器控制​:旋转检测与按钮处理
  • 数据显示​:多屏切换与自定义字符

该设计实现了环境数据的采集→处理→存储→显示全链路管理,通过创新性的状态管理和错误恢复机制,显著提升了系统的可靠性和用户体验。

代码修正1

时间设置功能的设计存在以下问题,导致LCD显示内容在时间设置期间会被覆盖:

  1. 主显示循环冲突​:updateDisplay()函数每500毫秒运行一次,而该函数并不检查timeSetMode状态。因此即使在时间设置模式下,它仍会根据当前屏幕设置(0/1/2)覆盖显示内容。

  2. 显示刷新逻辑​:displaySetItem()仅在旋转编码器时才被调用(通过handleSetMode()),没有独立的周期性刷新机制。当没有编码器操作时,主显示循环会覆盖时间设置界面。

解决方案

updateDisplay()函数开头添加时间设置模式的专属显示逻辑:

void updateDisplay() {if (!lcdInitialized) return;// ============ 添加的代码 - 时间设置模式优先 ============if (timeSetMode) {displaySetItem();return;  // 进入设置模式后跳过常规显示}// =================================================// ... 其余原有代码保持不变 ...
}

具体修改说明

  1. 优先级控制​:

    if (timeSetMode) {displaySetItem();return;
    }
    • 首先检查是否处于时间设置模式
    • timeSetMode=true时立即显示设置界面
    • return语句确保退出函数,防止常规内容覆盖设置界面

完整测试代码

https://download.csdn.net/download/Medlar_CN/91477067

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/90440.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/90440.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/90440.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ITIL 4:云计算与微服务对组织架构的影响

这几年&#xff0c;很多组织在推进数字化转型时遇到一个共同的问题&#xff1a;业务节奏越来越快&#xff0c;但内部协作的“架构”却越来越跟不上节奏。技术架构的变革&#xff0c;必须同步推动组织架构的重塑。特别是随着云计算和微服务架构的广泛应用&#xff0c;这种影响愈…

【Android】xml和Java两种方式实现发送邮件页面

三三要成为安卓糕手 一&#xff1a;xml中LinearLayout布局参数的使用 1&#xff1a;xml代码 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http:/…

美林数据用大模型重构电能质量评估,让隐蔽合规问题无所遁形

在“双碳”目标驱动下&#xff0c;电网企业正加速推进数字化转型&#xff0c;电能质量评估作为电力系统安全运行的核心环节&#xff0c;其合规性与效率直接影响着电网智能化水平。然而&#xff0c;传统人工审核模式已难以应对海量报告与复杂标准——单份报告需20-30人天核对、关…

前端基础 JS Vue3 Ajax

一、JSalert( .... ) //弹出框console.log( ....... ) //输出到控制台浏览器JS引入方式&#xff1a;1、内部脚本&#xff1a;将JS代码定义在HTML页面中位于<script></script>标签之间2、外部脚本&#xff1a;将JS代码写在外部JS文件中&#xff0c;在HTML页面中使用…

如何解决pip安装报错ModuleNotFoundError: No module named ‘notebook’问题

【Python系列Bug修复PyCharm控制台pip install报错】如何解决pip安装报错ModuleNotFoundError: No module named ‘notebook’问题 一、摘要 在使用 PyCharm 进行 Python 开发时&#xff0c;常常需要通过 pip install 安装第三方包。但有时即便已经安装成功&#xff0c;运行代…

一、Vue概述以及快速入门

什么是VueVue的快速入门代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Vue快速入门</title><script src"js/vue.js"></script> </head> <bod…

模型的存储、加载和部署

定义损失函数并以此训练和评估模型 存储模型可以只存储state_dict或模型参数&#xff0c;每当需要部署经过训练的模型时&#xff0c;创建模型的对象并从文件中加载参数&#xff0c;这是 Pytorch 创建者推荐的方法。 目录 模型的存储、加载 模型的部署 模型的存储、加载 承接…

Java学习第七十部分——微服务架构

目录 一、前言提要 二、核心优势 三、核心技术栈 四、构建步骤 五、困难挑战 六、总结归纳 一、前言提要 Java 微服务架构是一种使用 Java 技术栈构建分布式系统的方法论&#xff0c;它将单一的大型应用程序分解为一组小型、独立、松耦合、可独立部署和扩展的服务。每个服…

六边形滚动机器人cad【7张】三维图+设计书明说

摘 要 机械制造业是国家的重要产业,随着时代的发展,智能化越来越在生活中变得普遍,工业的发展深深的影响着一个国家的经济发展。全球经济的发展带领着机械工业在不断的进步。随着国外先进技术在我国的传播,也影响着我国技术的发展,在全球经济的大环境的推动下,大型四边形…

人形机器人加快先进AI机器人开发

物理AI的新时代通用人形机器人专为快速适应现有的以人类为中心的城市和工业工作空间而构建&#xff0c;用以承担枯燥、重复性或对体力要求高的工作任务。这些机器人正在从工厂车间走向医疗健康机构&#xff0c;通过自动化帮助人类工作&#xff0c;缓解劳动力短缺问题。但是&…

AI 驱动开发效能跃升:企业级智能开发全流程优化方案​

企业软件开发正面临 “三高困境”&#xff1a;需求变更频率高、人力成本占比高、线上故障风险高。破解这些难题的核心在于构建 AI 驱动的全流程智能开发体系&#xff0c;通过系统化效能优化实现开发能力升级。​ 需求分析作为开发起点&#xff0c;常因理解偏差导致后期返工。A…

时序数据库 TDengine × Ontop:三步构建你的时序知识图谱

在做设备预测性维护或能源管理分析时&#xff0c;你是否也曾思考过&#xff1a;如何才能让机器“理解”我们收集的大量时序数据&#xff1f;工业现场的数据是结构化的&#xff0c;而语义分析、知识推理却往往需要 RDF 等图谱格式。换句话说&#xff0c;“会说话”的数据更聪明&…

Android启动图不拉伸且宽占满屏幕

Android启动图不拉伸且宽占满屏幕 一般启动图的做法&#xff1a; start_app_bg.xml <?xml version"1.0" encoding"utf-8"?> <layer-list xmlns:android"http://schemas.android.com/apk/res/android"><item><shape>&l…

rust-方法语法

方法语法 方法类似于函数&#xff1a;我们用 fn 关键字和一个名称来声明它们&#xff0c;它们可以有参数和返回值&#xff0c;并且包含一些在从其他地方调用该方法时运行的代码。与函数不同&#xff0c;方法是在结构体&#xff08;或枚举、trait 对象&#xff0c;分别在第6章和…

【C++】C++ 的入门语法知识1

本文主要讲解C语言的入门知识&#xff0c;包括命名空间、C的输入与输出、缺省参数以及函数重载。 目录 1 C的第一个程序 2 命名空间 1&#xff09; 命名空间存在的意义 2&#xff09; 命名空间的定义 3&#xff09; 命名空间的使用 3 C的输出与输入 1&#xff09; C中…

SpringBoot6-10(黑马)

JWT令牌简介&#xff1a;1.JWT全称:JSON Web Token(https://iwt.io/)定义了一种简洁的、自包含的格式&#xff0c;用于通信双方以json数据格式安全的传输信息。2.组成: >第一部分:Header(头)&#xff0c;记录令牌类型、签名算法等。例如:("alg":“HS256",“t…

智能制造场景195个术语的16个分类

说明&#xff1a;《智能制造典型场景参考指引&#xff08;2025年版&#xff09;》日前&#xff0c;由工信部办公厅正式发布&#xff0c;将成为众多制造型企业的工作纲领 1. 工厂数字化规划设计&#xff08;1.1&#xff09;&#xff1a;在电脑上用专业软件设计工厂布局、规划生产…

[论文阅读] 人工智能 + 软件工程 | 微信闭源代码库中的RAG代码补全:揭秘工业级场景下的检索增强生成技术

微信闭源代码库中的RAG代码补全&#xff1a;揭秘工业级场景下的检索增强生成技术 论文标题&#xff1a;A Deep Dive into Retrieval-Augmented Generation for Code Completion: Experience on WeChatarXiv:2507.18515 A Deep Dive into Retrieval-Augmented Generation for Co…

RabbitMQ—仲裁队列

上篇文章&#xff1a; RabbitMQ集群搭建https://blog.csdn.net/sniper_fandc/article/details/149312481?fromshareblogdetail&sharetypeblogdetail&sharerId149312481&sharereferPC&sharesourcesniper_fandc&sharefromfrom_link 目录 1 Raft一致性算法…

[2025CVPR-目标检测方向] CorrBEV:多视图3D物体检测

1. ​研究背景与动机​ 论文关注自动驾驶中相机仅有的多视图3D物体检测&#xff08;camera-only multi-view 3D object detection&#xff09;问题。尽管基于鸟瞰图&#xff08;BEV&#xff09;的建模近年来取得显著进展&#xff08;如BEVFormer和SparseBEV等基准模型&#xf…