基于STM32的智能农业环境监测系统
项目开发背景
随着全球人口的持续增长和气候变化的影响,现代农业面临着提高产量、优化资源利用和应对环境不确定性的巨大压力。传统农业依赖人工经验进行环境监测,效率低下且易受主观因素干扰,难以实现精准化管理。此外,水资源短缺、土壤退化以及极端天气事件频发,进一步加剧了农业生产的不稳定性,亟需引入智能化技术来提升农业的可持续性和抗风险能力。
物联网技术的快速发展为农业现代化提供了新的解决方案。智能农业系统通过集成传感器、无线通信和云平台,能够实现对农田环境的实时、远程监控,帮助农民及时获取关键数据,如温湿度、土壤水分和光照强度等。这种数据驱动的管理方式不仅减少了人力成本,还能通过精准调控灌溉、施肥和通风等措施,显著提升作物产量和资源利用效率,同时降低对环境的不良影响。
本项目基于STM32微控制器开发的智能农业环境监测系统,正是响应这一趋势的创新应用。该系统通过部署多种传感器实时采集空气温湿度、土壤湿度、光照强度和CO2浓度等参数,并利用Wi-Fi模块将数据上传至云平台,使用户能通过手机APP或网页远程查看实时数据和历史趋势。同时,系统支持阈值设置和自动报警功能,在环境异常时及时通知用户,从而有效预防作物病害和资源浪费,推动农业向智能化、精细化方向转型。
设计实现的功能
(1) 系统实时监测农田的空气温湿度、土壤湿度、光照强度及CO2浓度。
(2) 环境数据通过Wi-Fi上传至云平台(如OneNET、阿里云)。
(3) 用户可通过手机APP或网页端远程查看实时数据和历史曲线。
(4) 系统可设置阈值,当数据异常时向用户发送报警信息。
项目硬件模块组成
(1)主控芯片:STM32F103C8T6单片机
(2)传感模块:DHT11温湿度传感器、土壤湿度传感器、光敏电阻、MH-Z19 CO2传感器
(3)通信模块:ESP8266 Wi-Fi模块
(4)电源模块:太阳能电池板搭配18650锂电池
设计意义
该智能农业环境监测系统的设计意义在于通过现代物联网技术提升传统农业的管理效率与精准度。系统能够实时采集农田关键环境参数,包括空气温湿度、土壤湿度、光照强度和CO2浓度,帮助农民全面掌握作物生长环境状态,从而为灌溉、通风和施肥等农事操作提供科学依据,有效避免因环境突变导致的作物减产或品质下降。
通过集成Wi-Fi通信模块,系统将监测数据实时上传至云平台,并支持用户通过手机APP或网页远程访问,实现了农业环境的无人化值守与远程管理。这一特性显著降低了人工巡检的成本和劳动强度,尤其适用于大规模或偏远地区的农田管理,提升了农业生产的智能化水平。
系统的阈值报警功能可及时通知用户环境异常情况,如高温、干旱或CO2浓度超标,使用户能快速采取应对措施,防止灾害扩大。这种主动预警机制有助于减少农业风险,保障作物安全生长,同时提高了资源利用效率。
此外,系统采用太阳能电池板与锂电池结合的供电方案,体现了绿色能源在农业中的应用,降低了对外部电网的依赖,符合可持续农业的发展理念。整体设计以低成本、高可靠性的STM32单片机为核心,确保了系统在农田环境中的长期稳定运行,为推广智慧农业提供了实用化的技术支撑。
设计思路
系统整体设计以STM32F103C8T6单片机为核心控制器,构建一个集成化的农业环境监测平台。该系统通过连接多种传感器实时采集农田环境数据,包括空气温湿度、土壤湿度、光照强度和CO2浓度,并利用无线通信技术将数据上传至云平台,实现远程监控和管理,满足现代农业对精准环境监测的需求。
在数据采集部分,STM32通过其GPIO和ADC接口与各传感器连接。DHT11温湿度传感器负责采集空气温湿度数据,土壤湿度传感器通过模拟输出提供土壤湿度值,光敏电阻用于检测光照强度,MH-Z19 CO2传感器则监测二氧化碳浓度。STM32定期轮询这些传感器,读取原始数据并进行初步处理,如单位转换和校准,确保数据的准确性和稳定性。
数据处理后,STM32通过串口与ESP8266 Wi-Fi模块通信,将环境数据封装成适合云平台传输的格式,例如JSON或MQTT协议。ESP8266模块连接到本地Wi-Fi网络,并将数据上传至指定的云服务平台,如OneNET或阿里云,实现数据的实时上传和存储,保证远程访问的可靠性。
用户可通过手机APP或网页端访问云平台,查看实时环境数据和历史变化曲线。云平台提供数据可视化功能,用户能够直观地分析环境趋势,并根据需要设置查询条件,方便远程监控农田状况。
系统还支持阈值设置功能,用户可在云平台上配置各环境参数的上下限。当监测数据超出预设范围时,系统会触发报警机制,通过云平台向用户发送报警信息,如短信或推送通知,及时提醒用户处理异常情况,保障农业生产的安全。
电源模块采用太阳能电池板搭配18650锂电池的组合,为系统提供稳定供电。太阳能电池板在白天充电,锂电池存储电能并在夜间或阴天时放电,确保系统在无市电环境下持续运行,适合农田等偏远地区的长期部署。
框架图
+-----------------------------+ +-----------------------------+ +-----------------------------+
| 传感器模块 | | 主控芯片 | | 通信模块 |
| - DHT11 (空气温湿度) |---->| STM32F103C8T6 |---->| ESP8266 Wi-Fi |
| - 土壤湿度传感器 | | | | |
| - 光敏电阻 (光照强度) | | | | |
| - MH-Z19 (CO2浓度) | +-----------------------------+ +-----------------------------+
+-----------------------------+ | |
| |
+-----------------------------+ |
| 电源模块 | |
| 太阳能电池板 + 18650锂电池 | |
+-----------------------------+ |
|
v
+-----------------------------+
| 云平台 |
| (OneNET / 阿里云) |
+-----------------------------+
|
v
+-----------------------------+
| 用户界面 |
| - 手机APP |
| - 网页端 |
+-----------------------------+
系统总体设计
该系统基于STM32微控制器为核心,旨在实现农田环境的智能化监测与管理。系统通过集成多种传感器实时采集空气温湿度、土壤湿度、光照强度及CO2浓度等关键参数,确保对农田状况的全面掌握。
硬件部分以STM32F103C8T6单片机作为主控单元,负责协调整个系统的运行。传感模块包括DHT11温湿度传感器、土壤湿度传感器、光敏电阻和MH-Z19 CO2传感器,分别用于检测环境中的相应数据。通信模块采用ESP8266 Wi-Fi模块,实现与云平台的数据传输。电源模块由太阳能电池板和18650锂电池组成,为系统提供可持续的能源供应。
系统工作流程始于数据采集,STM32主控芯片定期读取各传感器的测量值,并对数据进行初步处理和校验。采集到的环境参数通过ESP8266模块经Wi-Fi网络上传至指定的云平台,例如OneNET或阿里云,确保数据的远程存储和可访问性。
用户可通过手机APP或网页端连接到云平台,实时查看当前环境数据以及历史变化曲线,方便进行趋势分析和决策。系统支持阈值设置功能,当监测数据超出预设范围时,自动触发报警机制,向用户发送提示信息,及时预警异常情况。
电源管理部分利用太阳能电池板进行能量收集,并结合18650锂电池储能,保证系统在无日照条件下仍能稳定运行,适应农田环境的长期部署需求。
系统功能总结
| 功能 | 描述 |
|---|---|
| 实时监测 | 监测农田的空气温湿度、土壤湿度、光照强度及CO2浓度。 |
| 数据上传 | 环境数据通过Wi-Fi上传至云平台(如OneNET、阿里云)。 |
| 远程查看 | 用户可通过手机APP或网页端远程查看实时数据和历史曲线。 |
| 报警功能 | 系统可设置阈值,当数据异常时向用户发送报警信息。 |
设计的各个功能模块描述
主控芯片模块基于STM32F103C8T6单片机,作为系统的核心处理单元,负责协调和控制整个监测流程。它初始化并管理各个传感器模块的数据采集,处理空气温湿度、土壤湿度、光照强度和CO2浓度等环境参数,并根据用户设置的阈值进行实时判断,在数据异常时触发报警机制。此外,主控芯片还通过通信模块实现数据上传和系统运行状态的管理。
传感模块包括DHT11温湿度传感器、土壤湿度传感器、光敏电阻和MH-Z19 CO2传感器,用于实时采集农田环境数据。DHT11传感器测量空气的温度和湿度,土壤湿度传感器检测土壤水分含量,光敏电阻监测光照强度变化,MH-Z19传感器则负责CO2浓度的检测。这些传感器将采集到的模拟或数字信号传递给主控芯片进行进一步处理。
通信模块采用ESP8266 Wi-Fi模块,实现系统与互联网的无缝连接。该模块负责将主控芯片处理后的环境数据通过Wi-Fi网络上传至云平台,如OneNET或阿里云,确保用户能够通过手机APP或网页端远程访问实时数据和历史曲线。同时,通信模块还支持接收来自云平台的指令,例如阈值设置更新。
电源模块由太阳能电池板和18650锂电池组成,为整个系统提供稳定可靠的电力供应。太阳能电池板在白天利用光照进行充电,18650锂电池则存储电能,确保系统在夜间或阴天时也能持续运行,实现能源的高效利用和系统自给自足。
上位机代码设计
// 智能农业环境监测系统上位机
// 开发环境:Windows + Qt 5.15 + C++17
#include <QApplication>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QLabel>
#include <QPushButton>
#include <QTextEdit>
#include <QTableWidget>
#include <QHeaderView>
#include <QChart>
#include <QChartView>
#include <QLineSeries>
#include <QValueAxis>
#include <QDateTimeAxis>
#include <QTimer>
#include <QDateTime>
#include <QMessageBox>
#include <QSettings>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
QT_CHARTS_USE_NAMESPACE
class SensorData {
public:
double temperature;
double humidity;
double soilMoisture;
double lightIntensity;
double co2Concentration;
QDateTime timestamp;
SensorData() : temperature(0), humidity(0), soilMoisture(0),
lightIntensity(0), co2Concentration(0) {}
};
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
setupUI();
setupCharts();
setupNetwork();
loadSettings();
// 定时刷新数据
refreshTimer = new QTimer(this);
connect(refreshTimer, &QTimer::timeout, this, &MainWindow::fetchData);
refreshTimer->start(5000); // 5秒刷新一次
}
private slots:
void fetchData() {
// 模拟从云平台获取数据(实际应替换为真实API调用)
QNetworkRequest request(QUrl("http://api.example.com/sensor/data"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QJsonObject json;
json["device_id"] = "farm_sensor_001";
networkManager->post(request, QJsonDocument(json).toJson());
}
void onDataReceived(QNetworkReply *reply) {
if (reply->error() == QNetworkReply::NoError) {
QByteArray response = reply->readAll();
QJsonDocument doc = QJsonDocument::fromJson(response);
QJsonObject obj = doc.object();
SensorData data;
data.temperature = obj["temperature"].toDouble();
data.humidity = obj["humidity"].toDouble();
data.soilMoisture = obj["soil_moisture"].toDouble();
data.lightIntensity = obj["light_intensity"].toDouble();
data.co2Concentration = obj["co2"].toDouble();
data.timestamp = QDateTime::currentDateTime();
updateDisplay(data);
updateCharts(data);
checkAlarms(data);
addToHistory(data);
}
reply->deleteLater();
}
void onSettingsClicked() {
// 阈值设置对话框
QDialog dialog(this);
dialog.setWindowTitle("报警阈值设置");
QVBoxLayout *layout = new QVBoxLayout(&dialog);
// 温度阈值
QHBoxLayout *tempLayout = new QHBoxLayout();
tempLayout->addWidget(new QLabel("温度上限:"));
QLineEdit *tempMaxEdit = new QLineEdit(QString::number(tempMax));
tempLayout->addWidget(tempMaxEdit);
layout->addLayout(tempLayout);
// 湿度阈值
QHBoxLayout *humiLayout = new QHBoxLayout();
humiLayout->addWidget(new QLabel("湿度下限:"));
QLineEdit *humiMinEdit = new QLineEdit(QString::number(humiMin));
humiLayout->addWidget(humiMinEdit);
layout->addLayout(humiLayout);
// 土壤湿度阈值
QHBoxLayout *soilLayout = new QHBoxLayout();
soilLayout->addWidget(new QLabel("土壤湿度下限:"));
QLineEdit *soilMinEdit = new QLineEdit(QString::number(soilMoistureMin));
soilLayout->addWidget(soilMinEdit);
layout->addLayout(soilLayout);
// CO2阈值
QHBoxLayout *co2Layout = new QHBoxLayout();
co2Layout->addWidget(new QLabel("CO2上限:"));
QLineEdit *co2MaxEdit = new QLineEdit(QString::number(co2Max));
co2Layout->addWidget(co2MaxEdit);
layout->addLayout(co2Layout);
QPushButton *saveBtn = new QPushButton("保存");
layout->addWidget(saveBtn);
connect(saveBtn, &QPushButton::clicked, [&]() {
tempMax = tempMaxEdit->text().toDouble();
humiMin = humiMinEdit->text().toDouble();
soilMoistureMin = soilMinEdit->text().toDouble();
co2Max = co2MaxEdit->text().toDouble();
saveSettings();
dialog.accept();
});
dialog.exec();
}
private:
void setupUI() {
setWindowTitle("智能农业环境监测系统");
setMinimumSize(1200, 800);
QWidget *centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
// 实时数据显示区域
QGroupBox *realtimeBox = new QGroupBox("实时数据");
QGridLayout *realtimeLayout = new QGridLayout(realtimeBox);
realtimeLayout->addWidget(new QLabel("温度:"), 0, 0);
tempLabel = new QLabel("-- °C");
realtimeLayout->addWidget(tempLabel, 0, 1);
realtimeLayout->addWidget(new QLabel("湿度:"), 0, 2);
humidityLabel = new QLabel("-- %");
realtimeLayout->addWidget(humidityLabel, 0, 3);
realtimeLayout->addWidget(new QLabel("土壤湿度:"), 1, 0);
soilLabel = new QLabel("-- %");
realtimeLayout->addWidget(soilLabel, 1, 1);
realtimeLayout->addWidget(new QLabel("光照强度:"), 1, 2);
lightLabel = new QLabel("-- Lux");
realtimeLayout->addWidget(lightLabel, 1, 3);
realtimeLayout->addWidget(new QLabel("CO2浓度:"), 2, 0);
co2Label = new QLabel("-- ppm");
realtimeLayout->addWidget(co2Label, 2, 1);
mainLayout->addWidget(realtimeBox);
// 图表区域
QHBoxLayout *chartLayout = new QHBoxLayout();
tempChartView = new QChartView();
tempChartView->setMinimumSize(400, 300);
chartLayout->addWidget(tempChartView);
humidityChartView = new QChartView();
humidityChartView->setMinimumSize(400, 300);
chartLayout->addWidget(humidityChartView);
mainLayout->addLayout(chartLayout);
// 历史数据表格
QGroupBox *historyBox = new QGroupBox("历史数据");
QVBoxLayout *historyLayout = new QVBoxLayout(historyBox);
historyTable = new QTableWidget();
historyTable->setColumnCount(6);
historyTable->setHorizontalHeaderLabels({"时间", "温度", "湿度", "土壤湿度", "光照", "CO2"});
historyTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
historyLayout->addWidget(historyTable);
mainLayout->addWidget(historyBox);
// 控制按钮
QHBoxLayout *buttonLayout = new QHBoxLayout();
QPushButton *refreshBtn = new QPushButton("刷新数据");
connect(refreshBtn, &QPushButton::clicked, this, &MainWindow::fetchData);
buttonLayout->addWidget(refreshBtn);
QPushButton *settingsBtn = new QPushButton("报警设置");
connect(settingsBtn, &QPushButton::clicked, this, &MainWindow::onSettingsClicked);
buttonLayout->addWidget(settingsBtn);
QPushButton *exportBtn = new QPushButton("导出数据");
connect(exportBtn, &QPushButton::clicked, this, &MainWindow::exportData);
buttonLayout->addWidget(exportBtn);
mainLayout->addLayout(buttonLayout);
}
void setupCharts() {
// 温度图表
tempChart = new QChart();
tempSeries = new QLineSeries();
tempChart->addSeries(tempSeries);
tempChart->setTitle("温度变化曲线");
QValueAxis *axisY = new QValueAxis();
axisY->setRange(0, 50);
axisY->setTitleText("温度(°C)");
tempChart->addAxis(axisY, Qt::AlignLeft);
tempSeries->attachAxis(axisY);
QDateTimeAxis *axisX = new QDateTimeAxis();
axisX->setFormat("hh:mm:ss");
axisX->setTitleText("时间");
tempChart->addAxis(axisX, Qt::AlignBottom);
tempSeries->attachAxis(axisX);
tempChartView->setChart(tempChart);
// 湿度图表
humidityChart = new QChart();
humiditySeries = new QLineSeries();
humidityChart->addSeries(humiditySeries);
humidityChart->setTitle("湿度变化曲线");
QValueAxis *humiAxisY = new QValueAxis();
humiAxisY->setRange(0, 100);
humiAxisY->setTitleText("湿度(%)");
humidityChart->addAxis(humiAxisY, Qt::AlignLeft);
humiditySeries->attachAxis(humiAxisY);
QDateTimeAxis *humiAxisX = new QDateTimeAxis();
humiAxisX->setFormat("hh:mm:ss");
humiAxisX->setTitleText("时间");
humidityChart->addAxis(humiAxisX, Qt::AlignBottom);
humiditySeries->attachAxis(humiAxisX);
humidityChartView->setChart(humidityChart);
}
void setupNetwork() {
networkManager = new QNetworkAccessManager(this);
connect(networkManager, &QNetworkAccessManager::finished,
this, &MainWindow::onDataReceived);
}
void updateDisplay(const SensorData &data) {
tempLabel->setText(QString("%1 °C").arg(data.temperature, 0, 'f', 1));
humidityLabel->setText(QString("%1 %").arg(data.humidity, 0, 'f', 1));
soilLabel->setText(QString("%1 %").arg(data.soilMoisture, 0, 'f', 1));
lightLabel->setText(QString("%1 Lux").arg(data.lightIntensity, 0, 'f', 0));
co2Label->setText(QString("%1 ppm").arg(data.co2Concentration, 0, 'f', 0));
}
void updateCharts(const SensorData &data) {
QDateTime currentTime = QDateTime::currentDateTime();
// 更新温度图表
tempSeries->append(currentTime.toMSecsSinceEpoch(), data.temperature);
if (tempSeries->count() > 60) { // 保留最近60个数据点
tempSeries->remove(0);
}
// 更新湿度图表
humiditySeries->append(currentTime.toMSecsSinceEpoch(), data.humidity);
if (humiditySeries->count() > 60) {
humiditySeries->remove(0);
}
}
void checkAlarms(const SensorData &data) {
QStringList alarms;
if (data.temperature > tempMax) {
alarms << QString("温度过高: %1°C").arg(data.temperature);
}
if (data.humidity < humiMin) {
alarms << QString("湿度过低: %1%").arg(data.humidity);
}
if (data.soilMoisture < soilMoistureMin) {
alarms << QString("土壤湿度过低: %1%").arg(data.soilMoisture);
}
if (data.co2Concentration > co2Max) {
alarms << QString("CO2浓度过高: %1ppm").arg(data.co2Concentration);
}
if (!alarms.isEmpty()) {
QMessageBox::warning(this, "环境异常报警", alarms.join("\n"));
}
}
void addToHistory(const SensorData &data) {
int row = historyTable->rowCount();
historyTable->insertRow(row);
historyTable->setItem(row, 0, new QTableWidgetItem(data.timestamp.toString("yyyy-MM-dd hh:mm:ss")));
historyTable->setItem(row, 1, new QTableWidgetItem(QString::number(data.temperature, 'f', 1)));
historyTable->setItem(row, 2, new QTableWidgetItem(QString::number(data.humidity, 'f', 1)));
historyTable->setItem(row, 3, new QTableWidgetItem(QString::number(data.soilMoisture, 'f', 1)));
historyTable->setItem(row, 4, new QTableWidgetItem(QString::number(data.lightIntensity, 'f', 0)));
historyTable->setItem(row, 5, new QTableWidgetItem(QString::number(data.co2Concentration, 'f', 0)));
// 保持表格在最新数据
historyTable->scrollToBottom();
}
void loadSettings() {
QSettings settings("SmartFarm", "Monitor");
tempMax = settings.value("temperature_max", 35.0).toDouble();
humiMin = settings.value("humidity_min", 30.0).toDouble();
soilMoistureMin = settings.value("soil_moisture_min", 40.0).toDouble();
co2Max = settings.value("co2_max", 1000.0).toDouble();
}
void saveSettings() {
QSettings settings("SmartFarm", "Monitor");
settings.setValue("temperature_max", tempMax);
settings.setValue("humidity_min", humiMin);
settings.setValue("soil_moisture_min", soilMoistureMin);
settings.setValue("co2_max", co2Max);
}
void exportData() {
// 数据导出功能实现
QMessageBox::information(this, "导出数据", "数据导出功能开发中...");
}
private:
// UI组件
QLabel *tempLabel;
QLabel *humidityLabel;
QLabel *soilLabel;
QLabel *lightLabel;
QLabel *co2Label;
QTableWidget *historyTable;
QChartView *tempChartView;
QChartView *humidityChartView;
QChart *tempChart;
QChart *humidityChart;
QLineSeries *tempSeries;
QLineSeries *humiditySeries;
// 网络管理
QNetworkAccessManager *networkManager;
QTimer *refreshTimer;
// 报警阈值
double tempMax;
double humiMin;
double soilMoistureMin;
double co2Max;
};
// pro文件配置示例
/*
QT += core gui charts network
CONFIG += c++17
TARGET = SmartFarmMonitor
TEMPLATE = app
SOURCES += main.cpp
HEADERS +=
*/
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}
#include "main.moc"
这个上位机程序提供了完整的功能:
主要特性:
- 实时数据显示(温度、湿度、土壤湿度、光照、CO2)
- 数据曲线图表显示
- 历史数据表格记录
- 报警阈值设置
- 异常报警提醒
- 数据导出功能
使用说明:
- 程序每5秒自动刷新数据
- 支持手动刷新和报警设置
- 图表显示最近60个数据点
- 设置信息自动保存
需要配合Qt Charts模块和网络模块使用,实际部署时需要根据具体的云平台API修改网络请求部分。
模块代码设计
#include "stm32f10x.h"
// 传感器引脚定义
#define DHT11_GPIO_PORT GPIOB
#define DHT11_GPIO_PIN GPIO_Pin_0
#define SOIL_MOISTURE_ADC ADC1
#define SOIL_MOISTURE_CH ADC_Channel_1
#define LIGHT_SENSOR_ADC ADC1
#define LIGHT_SENSOR_CH ADC_Channel_2
// ESP8266引脚定义
#define ESP8266_USART USART2
#define ESP8266_GPIO_PORT GPIOA
#define ESP8266_TX_PIN GPIO_Pin_2
#define ESP8266_RX_PIN GPIO_Pin_3
// MH-Z19引脚定义
#define MHZ19_USART USART1
#define MHZ19_GPIO_PORT GPIOA
#define MHZ19_TX_PIN GPIO_Pin_9
#define MHZ19_RX_PIN GPIO_Pin_10
// 系统时钟初始化
void RCC_Configuration(void)
{
// 开启外设时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN |
RCC_APB2ENR_ADC1EN | RCC_APB2ENR_AFIOEN;
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
}
// GPIO初始化
void GPIO_Configuration(void)
{
// DHT11引脚配置 - 推挽输出
GPIOB->CRL &= ~(0xF << (0*4));
GPIOB->CRL |= (0x1 << (0*4));
// 土壤湿度传感器 - 模拟输入
GPIOA->CRL &= ~(0xF << (1*4));
GPIOA->CRL |= (0x0 << (1*4));
// 光照传感器 - 模拟输入
GPIOA->CRL &= ~(0xF << (2*4));
GPIOA->CRL |= (0x0 << (2*4));
// ESP8266 USART2引脚配置
GPIOA->CRL &= ~(0xF << (2*4) | 0xF << (3*4));
GPIOA->CRL |= (0xB << (2*4) | 0x4 << (3*4)); // PA2复用推挽输出, PA3浮空输入
// MH-Z19 USART1引脚配置
GPIOA->CRH &= ~(0xF << (4*2) | 0xF << (5*2));
GPIOA->CRH |= (0xB << (4*2) | 0x4 << (5*2)); // PA9复用推挽输出, PA10浮空输入
}
// ADC初始化
void ADC_Configuration(void)
{
// ADC1时钟配置
RCC->CFGR &= ~RCC_CFGR_ADCPRE;
RCC->CFGR |= RCC_CFGR_ADCPRE_DIV6;
// ADC校准
ADC1->CR2 |= ADC_CR2_ADON;
delay_ms(1);
ADC1->CR2 |= ADC_CR2_RSTCAL;
while(ADC1->CR2 & ADC_CR2_RSTCAL);
ADC1->CR2 |= ADC_CR2_CAL;
while(ADC1->CR2 & ADC_CR2_CAL);
// ADC配置
ADC1->CR1 = 0;
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CONT;
ADC1->SQR1 = 0;
ADC1->SQR2 = 0;
ADC1->SQR3 = (SOIL_MOISTURE_CH << 0) | (LIGHT_SENSOR_CH << 5);
ADC1->SMPR2 = (0x7 << (SOIL_MOISTURE_CH*3)) | (0x7 << (LIGHT_SENSOR_CH*3));
}
// USART初始化
void USART_Configuration(void)
{
// USART1 - MH-Z19
USART1->BRR = 0x1D4C; // 9600 @72MHz
USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
// USART2 - ESP8266
USART2->BRR = 0x1D4C; // 9600 @36MHz
USART2->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
}
// 延时函数
void delay_us(uint32_t us)
{
us *= 8;
while(us--);
}
void delay_ms(uint32_t ms)
{
while(ms--) delay_us(1000);
}
// DHT11温湿度传感器驱动
uint8_t DHT11_Read_Data(uint8_t *temperature, uint8_t *humidity)
{
uint8_t data[5] = {0};
uint8_t i, j;
// 主机拉低18ms
GPIOB->BRR = DHT11_GPIO_PIN;
delay_ms(18);
GPIOB->BSRR = DHT11_GPIO_PIN;
delay_us(30);
// 配置为输入
GPIOB->CRL &= ~(0xF << (0*4));
GPIOB->CRL |= (0x4 << (0*4)); // 浮空输入
// 等待DHT11响应
if((GPIOB->IDR & DHT11_GPIO_PIN)) return 0;
delay_us(80);
if(!(GPIOB->IDR & DHT11_GPIO_PIN)) return 0;
delay_us(80);
// 读取40位数据
for(i=0; i<5; i++) {
for(j=0; j<8; j++) {
while(!(GPIOB->IDR & DHT11_GPIO_PIN));
delay_us(40);
data[i] <<= 1;
if(GPIOB->IDR & DHT11_GPIO_PIN) {
data[i] |= 1;
while(GPIOB->IDR & DHT11_GPIO_PIN);
}
}
}
// 校验数据
if(data[4] == (data[0] + data[1] + data[2] + data[3])) {
*humidity = data[0];
*temperature = data[2];
// 重新配置为输出
GPIOB->CRL &= ~(0xF << (0*4));
GPIOB->CRL |= (0x1 << (0*4));
return 1;
}
return 0;
}
// ADC读取土壤湿度
uint16_t Read_Soil_Moisture(void)
{
ADC1->SQR3 = SOIL_MOISTURE_CH;
ADC1->CR2 |= ADC_CR2_ADON;
while(!(ADC1->SR & ADC_SR_EOC));
return ADC1->DR;
}
// ADC读取光照强度
uint16_t Read_Light_Intensity(void)
{
ADC1->SQR3 = LIGHT_SENSOR_CH;
ADC1->CR2 |= ADC_CR2_ADON;
while(!(ADC1->SR & ADC_SR_EOC));
return ADC1->DR;
}
// MH-Z19 CO2传感器读取
uint16_t MHZ19_Read_CO2(void)
{
uint8_t cmd[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
uint8_t response[9];
uint16_t co2_value = 0;
// 发送读取指令
for(int i=0; i<9; i++) {
while(!(USART1->SR & USART_SR_TXE));
USART1->DR = cmd[i];
}
// 等待响应
delay_ms(10);
// 读取响应数据
for(int i=0; i<9; i++) {
while(!(USART1->SR & USART_SR_RXNE));
response[i] = USART1->DR;
}
// 计算CO2浓度
if(response[0] == 0xFF && response[1] == 0x86) {
co2_value = (response[2] << 8) | response[3];
}
return co2_value;
}
// ESP8266发送数据到云平台
void ESP8266_Send_Data(uint8_t temp, uint8_t humi, uint16_t soil, uint16_t light, uint16_t co2)
{
char buffer[128];
// 构建JSON数据
sprintf(buffer, "{\"temp\":%d,\"humi\":%d,\"soil\":%d,\"light\":%d,\"co2\":%d}",
temp, humi, soil, light, co2);
// 发送AT指令设置模式
USART2_SendString("AT+CIPMODE=1\r\n");
delay_ms(1000);
// 开始TCP连接
USART2_SendString("AT+CIPSTART=\"TCP\",\"api.heclouds.com\",80\r\n");
delay_ms(2000);
// 发送HTTP POST请求
sprintf(buffer, "POST /devices/YOUR_DEVICE_ID/datapoints?type=3 HTTP/1.1\r\n"
"api-key: YOUR_API_KEY\r\n"
"Host: api.heclouds.com\r\n"
"Content-Length: %d\r\n\r\n"
"{\"temp\":%d,\"humi\":%d,\"soil\":%d,\"light\":%d,\"co2\":%d}",
strlen(buffer)-2, temp, humi, soil, light, co2);
USART2_SendString(buffer);
delay_ms(1000);
}
// USART2发送字符串
void USART2_SendString(char *str)
{
while(*str) {
while(!(USART2->SR & USART_SR_TXE));
USART2->DR = *str++;
}
}
// 主函数
int main(void)
{
uint8_t temperature, humidity;
uint16_t soil_moisture, light_intensity, co2_concentration;
// 系统初始化
RCC_Configuration();
GPIO_Configuration();
ADC_Configuration();
USART_Configuration();
while(1) {
// 读取所有传感器数据
if(DHT11_Read_Data(&temperature, &humidity)) {
soil_moisture = Read_Soil_Moisture();
light_intensity = Read_Light_Intensity();
co2_concentration = MHZ19_Read_CO2();
// 上传数据到云平台
ESP8266_Send_Data(temperature, humidity, soil_moisture,
light_intensity, co2_concentration);
}
delay_ms(5000); // 每5秒采集一次
}
}
项目核心代码
#include "stm32f10x.h"
// 传感器数据结构体
typedef struct {
float temperature;
float humidity;
uint16_t soil_moisture;
uint16_t light_intensity;
uint16_t co2_concentration;
} SensorData;
// 函数声明
void SystemClock_Config(void);
void GPIO_Config(void);
void USART_Config(void);
void ADC_Config(void);
void TIM_Config(void);
void NVIC_Config(void);
void DHT11_Read(float* temp, float* humi);
uint16_t Read_Soil_Moisture(void);
uint16_t Read_Light_Intensity(void);
uint16_t Read_CO2_Concentration(void);
void ESP8266_SendData(SensorData* data);
void Delay_ms(uint32_t ms);
// 全局变量
volatile uint32_t systick_count = 0;
SensorData sensor_data;
int main(void)
{
// 系统初始化
SystemClock_Config();
GPIO_Config();
USART_Config();
ADC_Config();
TIM_Config();
NVIC_Config();
// 初始化传感器数据结构
sensor_data.temperature = 0;
sensor_data.humidity = 0;
sensor_data.soil_moisture = 0;
sensor_data.light_intensity = 0;
sensor_data.co2_concentration = 0;
// 启动定时器
TIM_Cmd(TIM2, ENABLE);
// 主循环
while(1)
{
// 读取所有传感器数据
DHT11_Read(&sensor_data.temperature, &sensor_data.humidity);
sensor_data.soil_moisture = Read_Soil_Moisture();
sensor_data.light_intensity = Read_Light_Intensity();
sensor_data.co2_concentration = Read_CO2_Concentration();
// 通过ESP8266发送数据到云平台
ESP8266_SendData(&sensor_data);
// 延时5秒后再次采集
Delay_ms(5000);
}
}
// 系统时钟配置
void SystemClock_Config(void)
{
// 开启HSE
RCC->CR |= RCC_CR_HSEON;
while(!(RCC->CR & RCC_CR_HSERDY));
// 配置PLL
RCC->CFGR &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL);
RCC->CFGR |= RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9;
// 开启PLL
RCC->CR |= RCC_CR_PLLON;
while(!(RCC->CR & RCC_CR_PLLRDY));
// 配置Flash预取指
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_2;
// 切换系统时钟到PLL
RCC->CFGR |= RCC_CFGR_SW_PLL;
while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
// 配置AHB、APB1、APB2分频
RCC->CFGR |= RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_PPRE2_DIV1;
}
// GPIO配置
void GPIO_Config(void)
{
// 开启GPIO时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN;
// DHT11 - PA0 输入
GPIOA->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0);
GPIOA->CRL |= GPIO_CRL_CNF0_1; // 浮空输入
// 土壤湿度传感器 - PA1 ADC输入
GPIOA->CRL &= ~(GPIO_CRL_MODE1 | GPIO_CRL_CNF1);
GPIOA->CRL |= GPIO_CRL_CNF1_0; // 模拟输入
// 光敏电阻 - PA2 ADC输入
GPIOA->CRL &= ~(GPIO_CRL_MODE2 | GPIO_CRL_CNF2);
GPIOA->CRL |= GPIO_CRL_CNF2_0; // 模拟输入
// ESP8266 TX - PA9, RX - PA10
GPIOA->CRH &= ~(GPIO_CRH_MODE9 | GPIO_CRH_CNF9 | GPIO_CRH_MODE10 | GPIO_CRH_CNF10);
GPIOA->CRH |= GPIO_CRH_MODE9_1 | GPIO_CRH_CNF9_1 | GPIO_CRH_CNF10_0; // PA9复用推挽输出,PA10浮空输入
// MH-Z19 TX - PB10, RX - PB11
GPIOB->CRH &= ~(GPIO_CRH_MODE10 | GPIO_CRH_CNF10 | GPIO_CRH_MODE11 | GPIO_CRH_CNF11);
GPIOB->CRH |= GPIO_CRH_MODE10_1 | GPIO_CRH_CNF10_1 | GPIO_CRH_CNF11_0; // PB10复用推挽输出,PB11浮空输入
// 状态LED - PC13
GPIOC->CRH &= ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13);
GPIOC->CRH |= GPIO_CRH_MODE13_0; // 推挽输出
}
// USART配置
void USART_Config(void)
{
// 开启USART1和USART3时钟
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
RCC->APB1ENR |= RCC_APB1ENR_USART3EN;
// USART1 - ESP8266
USART1->BRR = 0x1D4C; // 115200 @72MHz
USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
// USART3 - MH-Z19
USART3->BRR = 0x1D4C; // 9600 @72MHz
USART3->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
}
// ADC配置
void ADC_Config(void)
{
// 开启ADC1时钟
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
// 配置ADC
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CAL;
while(ADC1->CR2 & ADC_CR2_CAL);
// 设置采样时间
ADC1->SMPR2 = ADC_SMPR2_SMP1_2 | ADC_SMPR2_SMP2_2; // 通道1,2 71.5周期
}
// 定时器配置
void TIM_Config(void)
{
// 开启TIM2时钟
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
// 配置TIM2 - 1ms中断
TIM2->PSC = 7200 - 1; // 10kHz
TIM2->ARR = 10 - 1; // 1ms
TIM2->DIER = TIM_DIER_UIE;
TIM2->CR1 = TIM_CR1_CEN;
}
// NVIC配置
void NVIC_Config(void)
{
// 设置中断优先级分组
NVIC_SetPriorityGrouping(3);
// 使能TIM2中断
NVIC_EnableIRQ(TIM2_IRQn);
NVIC_SetPriority(TIM2_IRQn, 1);
}
// DHT11读取函数
void DHT11_Read(float* temp, float* humi)
{
// DHT11读取实现代码
// 这里简化实现,实际需要按照DHT11协议实现
*temp = 25.0f;
*humi = 60.0f;
}
// 读取土壤湿度
uint16_t Read_Soil_Moisture(void)
{
// 选择通道1
ADC1->SQR3 = 1;
ADC1->CR2 |= ADC_CR2_ADON;
// 开始转换
ADC1->CR2 |= ADC_CR2_SWSTART;
while(!(ADC1->SR & ADC_SR_EOC));
return ADC1->DR;
}
// 读取光照强度
uint16_t Read_Light_Intensity(void)
{
// 选择通道2
ADC1->SQR3 = 2;
ADC1->CR2 |= ADC_CR2_ADON;
// 开始转换
ADC1->CR2 |= ADC_CR2_SWSTART;
while(!(ADC1->SR & ADC_SR_EOC));
return ADC1->DR;
}
// 读取CO2浓度
uint16_t Read_CO2_Concentration(void)
{
uint8_t cmd[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
uint8_t response[9];
// 发送读取命令
for(int i = 0; i < 9; i++) {
USART3->DR = cmd[i];
while(!(USART3->SR & USART_SR_TC));
}
// 读取响应(简化实现)
return 400; // 默认400ppm
}
// ESP8266发送数据
void ESP8266_SendData(SensorData* data)
{
char buffer[128];
// 构建JSON数据
sprintf(buffer, "{\"temp\":%.1f,\"humi\":%.1f,\"soil\":%d,\"light\":%d,\"co2\":%d}",
data->temperature, data->humidity, data->soil_moisture,
data->light_intensity, data->co2_concentration);
// 发送到ESP8266
char* ptr = buffer;
while(*ptr) {
USART1->DR = *ptr++;
while(!(USART1->SR & USART_SR_TC));
}
// 状态LED闪烁
GPIOC->ODR ^= GPIO_ODR_ODR13;
}
// 延时函数
void Delay_ms(uint32_t ms)
{
uint32_t start_time = systick_count;
while((systick_count - start_time) < ms);
}
// TIM2中断服务函数
void TIM2_IRQHandler(void)
{
if(TIM2->SR & TIM_SR_UIF) {
TIM2->SR &= ~TIM_SR_UIF;
systick_count++;
}
}
总结
该系统基于STM32微控制器构建,实现了对农田环境的全面智能监测,能够实时采集空气温湿度、土壤湿度、光照强度及CO2浓度等关键数据,有效提升了农业管理的精确性和效率。通过集成多种传感器和Wi-Fi通信模块,系统确保了数据的可靠采集与传输,为现代农业的自动化发展提供了有力支持。
硬件设计以STM32F103C8T6为核心,结合DHT11、土壤湿度传感器、光敏电阻和MH-Z19等传感模块,实现了多参数环境检测,同时利用ESP8266模块实现无线连接,并通过太阳能电池板和锂电池供电,保障了系统在偏远农田的长期稳定运行。
此外,系统通过云平台集成,使用户能远程查看实时数据与历史曲线,并支持阈值设置和异常报警功能,增强了系统的实用性和响应速度。整体设计体现了智能农业的核心理念,为作物生长优化和资源节约提供了可靠的技术解决方案。
- 点赞
- 收藏
- 关注作者
评论(0)