ESP32环境下基于SD卡与FTP实现温湿度数据采集与存储

news/2024/9/24 9:19:59/

本篇文章将介绍如何利用ESP32开发板结合SD卡与FTP服务器功能,实现温湿度数据的实时采集、存储与远程访问。项目代码基于Arduino IDE平台编写,主要依赖于以下库:

  • SPI
  • DHT
  • WiFi
  • time.h
  • ESP-FTP-Server-Lib
  • SD
  • SPIFFS
  • FS

1. 硬件连接与配置

1.1 所需要的硬件

  1. ESP32开发板在这里插入图片描述

  2. DHT22传感器模块

  3. SD卡模块

1.2 SD卡接口

ESP32通过SPI总线与SD卡进行通信,各引脚连接如下:

  • CS:GPIO 23
  • MOSI:GPIO 17
  • MISO:GPIO 2
  • SCK:GPIO 16

1.3 DHT22温湿度传感器

DHT22传感器连接至ESP32的GPIO 13引脚。

1.4 Wi-Fi模块

ESP32内置Wi-Fi模块,用于接入无线网络。此处设定的Wi-Fi信息如下:

  • SSIDxxx
  • Passwordxxx

1.5 NTP服务器与时区设置

为了获取准确的本地时间,通过NTP协议从阿里云NTP服务器同步时间,并设定时区为中国标准时间(UTC+8):

  • NTP Serverntp1.aliyun.com
  • GMT Offset8 * 3600
  • Daylight Offset0

1.6 FTP服务器配置

创建一个FTP服务器,供远程设备访问存储在ESP32上的温湿度数据。FTP登录信息如下:

  • Usernameftp
  • Passwordftp

2. 代码详解

2.1 引入库与定义常量

#include <Arduino.h>
/*sd Card Interface code for ESP32SPI Pins of ESP32 sd card as follows:CS    = 23;MOSI  = 17;MISO  = 2;SCK   = 16;
*/#include <SPI.h>
#include <DHT.h>
#include <WiFi.h>
#include <time.h>
#include <ESP-FTP-Server-Lib.h>
#include <SD.h>
#include <SPIFFS.h>
#include <FS.h>#define DHTPIN 13
#define DHTTYPE DHT22DHT dht(DHTPIN, DHTTYPE);
static float h = 0;
static float t = 0;File myFile;FTPServer ftp;
// 设置SPI Pins
const int CS = 23;
const int MOSI_PIN = 17;
const int MISO_PIN = 2;
const int SCK_PIN = 16;SPIClass CustomSPI;// 设置wifi信息,更换为你的wifi设置
const char *ssid = "xxx";
const char *password = "xxx";// NTP相关参数,设置NTP服务器为阿里NTP服务器
const char *ntpServer = "ntp1.aliyun.com";
const long gmtOffset_sec = 8 * 3600;
const int daylightOffset_sec = 0;char timeStr_bj[9];
char dateStr_bj[11];
char timeStr_gmt[9];// FTP服务器配置
#define FTP_USER "ftp"
#define FTP_PASSWORD "ftp"// 上一次执行的时间,初始化为0
unsigned long previousExecutionTime = 0;
// 执行间隔时间,单位为毫秒,这里设置为60000毫秒,即1分钟
const unsigned long INTERVAL_MS = 60000;String printLocalTime()
{struct tm timeinfo;if (!getLocalTime(&timeinfo)){Serial.println("Failed to obtain time");return "";}char formattedTimeBuffer[30];                                                                // 为格式化的时间字符串分配足够的缓冲区strftime(formattedTimeBuffer, sizeof(formattedTimeBuffer), "%Y-%B-%d  %H:%M:%S", &timeinfo); // 使用 strftime 将 timeinfo 转换为格式化的字符串String formattedTime = formattedTimeBuffer; // 将格式化后的字符串复制到 String 对象中return formattedTime;
}/*** 将温度和湿度数据写入指定路径的CSV文件中。* * @param path 指定的CSV文件路径。* @param timeStr 记录的时间字符串。* @param humidity 湿度值。* @param temperature 温度值。* * 函数首先尝试打开文件以追加模式写入。如果文件成功打开,将依次写入时间字符串、湿度和温度值,* 每个数据项之间用逗号分隔,并在温度值后换行。写入完成后,关闭文件并打印完成信息。* 如果打开文件时出现错误,将打印错误信息和文件路径。*/
void WriteCSVRecord(const char *path, const char *timeStr, float humidity, float temperature)
{myFile = SD.open(path, FILE_APPEND);if (myFile){Serial.printf("Writing to %s ", path);myFile.print(timeStr);myFile.print(",");myFile.print(humidity, 2);myFile.print(",");myFile.println(temperature, 2);myFile.close();Serial.println("completed.");}else{Serial.println("error opening file ");Serial.println(path);}
}void ReadFile(const char *path)
{myFile = SD.open(path);if (myFile){Serial.printf("Reading file from %s\n", path);while (myFile.available()){// Serial.write(myFile.read());Serial.println("Read succeded");}myFile.close();}else{char error_msg[64];sprintf(error_msg, "error opening %s", path);Serial.println(error_msg);}
}void environment()
{h = dht.readHumidity();t = dht.readTemperature();Serial.printf("Humidity: %f \n", h);Serial.printf("Temperature: %f \n", t);
}
void setup()
{Serial.begin(9600);delay(500);dht.begin();WiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED){delay(500);Serial.print(".");}Serial.println("WiFi connected");Serial.println("IP address: ");Serial.println(WiFi.localIP()); // 记下运行时生成的IP地址,后面会用到configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);SPIFFS.begin(true);CustomSPI.begin(SCK_PIN, MISO_PIN, MOSI_PIN, CS);while (!Serial){;}Serial.println("Initializing sd card...");if (!SD.begin(CS, CustomSPI, 1000000)){Serial.println("initialization failed!");return;}else{Serial.println("SD card initialization succeeded.");}// // 配置FTPftp.addUser(FTP_USER, FTP_PASSWORD); // 添加FTP用户ftp.addFilesystem("SD", &SD); // 注册SD卡文件系统
ftp.addFilesystem("SPIFFS", &SPIFFS); // 注册SPIFFS文件系统ftp.begin(); // 启动FTP服务Serial.println("FTP server started"); // 打印启动信息}void loop()
{unsigned long currentMillis = millis(); // 获取当前毫秒时间戳// 检查是否已过去一分钟if (currentMillis - previousExecutionTime >= INTERVAL_MS){previousExecutionTime = currentMillis; // 更新上一次执行的时间戳environment(); // 执行环境相关操作String localTimeStr = printLocalTime(); // 获取本地时间字符串// 如果温度和湿度都不为零,则写入CSV文件if (h != 0 && t != 0){WriteCSVRecord("/record.csv", localTimeStr.c_str(), h, t);}}// 处理FTP请求ftp.handle();
}

2.2 如果你是使用的PlatfromIO IDE可以把以下内容复制到你的platformio.ini里

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 9600
lib_deps = adafruit/DHT sensor library@^1.4.6adafruit/Adafruit Unified Sensor@^1.1.14peterus/ESP-FTP-Server-Lib@^0.14.0

3. FTP命令行操作

3.1 步骤说明

  1. 打开命令提示符(Windows)或终端(macOS/Linux)。

  2. 输入以下命令连接到 FTP 服务器(请将 IP 地址替换为实际 FTP 服务器的 IP 地址):

  3. 输入用户名(默认为 “ftp”)和密码(默认为 “ftp”)。

  4. 输入 “ls” 或 “dir” 查看文件列表。

  5. 输入 “cd” 命令切换目录,例如 “cd /SD” 进入 “/SD” 目录。

  6. 输入 “lcd” 命令切换本地目录,例如 “lcd E:\temp” 进入 “E:\temp” 目录。

  7. 使用 “get” 或 “recv” 命令从 FTP 服务器下载文件,例如 “get record.csv” 下载 “record.csv” 文件。

  8. 使用 “put” 或 “send” 命令将文件上传到 FTP 服务器,例如 “put local_file.txt” 上传 “local_file.txt” 文件。

  9. 输入 “bye” 或 “quit” 命令退出 FTP 客户端。
    10.更多命令直接输入"help"来了解

3.2 我用如下步骤下载了SD卡中的record.csv到电脑上:

C:\Users\User>ftp 192.168.55.203
连接到 192.168.55.203。
220--- Welcome to FTP Server for ESP32 ---
220---        By Peter Buchegger       ---
220 --           Version 0.1           ---
200 Ok
用户(192.168.55.203:(none)): ftp
331 OK. Password required
密码:
230 OK.
ftp> cd SD
250 Ok. Current directory is /SD
ftp> lcd "E:\temp"
目前的本地目录 E:\temp。
ftp> dir
200 PORT command successful
150 Accepted data connection
drwxr-xr-x 1 owner group             0 Jan 01  1970 System Volume Information
-rw-r--r-- 1 owner group            16 Jan 01  1970 test.txt
-rw-r--r-- 1 owner group        113466 Jan 01  1970 record.csv
226 3 matches total
ftp: 收到 208 字节,用时 0.0120.80千字节/秒。
ftp> recv record.csv
200 PORT command successful
150 Accepted data connection
226 File successfully transferred
ftp: 收到 113466 字节,用时 1.1796.81千字节/秒。
ftp>

http://www.ppmy.cn/news/1433802.html

相关文章

数学专题1 - 素数筛(2)

C素数练习目录 1. 素数基础 1.1 了解什么是素数及其基本性质 素数(质数)是指在大于1的自然数中,除了1和它本身以外,不能被其他自然数整除的数。换句话说,如果一个数 n n n 只有两个因数:1和 n n n 本身,那么 n n n 就是一个素数。 素数有以下基本性质: 2是最小的素数,也…

Python构建学生信息管理系统:需求分析与规划

构建学生信息管理系统&#xff1a;需求分析与规划 在软件开发的初期&#xff0c;进行需求分析与规划是至关重要的一步。它不仅帮助开发者明确项目目标&#xff0c;还能确保最终产品能够满足用户的需求。本文将介绍如何使用Python语言&#xff0c;结合常规网络框架、RESTful技术…

vue实现弹窗的动态导入(:is=“dialogName“)

组件的动态挂载 弹窗aaa.vue <template><el-dialogwidth"700px "v-dialog-outdestroy-on-closev-if"dialogVisible":title"title":visible"dialogVisible":before-close"hideDialog":close-on-click-modal"…

Web入门-Tomcat

黑马程序员JavaWeb开发教程 文章目录 一、简介1、Web服务器2、Tomcat 二、基本使用三、入门程序解析 一、简介 1、Web服务器 对HTTP协议操作进行封装&#xff0c;简化web程序开发部署Web项目&#xff0c;对外提供网上信息浏览服务 2、Tomcat 概念&#xff1a;Tomcat是Apach…

【AI写作】未来科技趋势:揭秘DreamFusion的革新力量

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

新技术前沿-2024-大型语言模型LLM的本地化部署

参考快速入门LLM 参考究竟什么是神经网络 1 深度学习 1.1 神经网络和深度学习 神经网络是一种模拟人脑神经元工作方式的机器学习算法,也是深度学习算法的基本构成块。神经网络由多个相互连接的节点(也称为神经元或人工神经元)组成,这些节点被组织成层次结构。通过训练,…

idea 的使用和安装 以及简介

Java开发工具 大家刚才写代码的时候都是用记事本写的&#xff0c;但是有没有觉得记事本写代码不太方便啊&#xff01;记事本写代码单词写错了没有提示&#xff0c;格式也不好调整&#xff0c;写代码之后还需要我们到命令行使用javac命令手动编译&#xff0c;然后运行。 有没有一…

springboot的坑

问题&#xff1a;使用Autowired注入一个service&#xff0c;然后写了两个接口&#xff0c;第一个接口与请求时显示注入的service为空一直报错&#xff0c;但是第二个接口请求时service竟然不是空&#xff1f;在这里插入图片描述 凶手找到了&#xff0c;是private修饰。果然没仔…