-
项目开发背景传统饮水机功能单一,仅能提供加热或制冷,缺乏智能化管理。用户无法实时掌握水温、剩余水量等关键信息,常面临水温不适、水量不足或反复加热导致能耗高等问题,影响饮水体验与健康。随着物联网技术发展和健康生活理念普及,市场对智能、节能、便捷的饮水设备需求激增。用户期望通过手机远程控制加热、设置定时任务,并实时监控水质参数,实现个性化饮水管理。同时,设备状态远程监控与数据云端存储对提升管理效率至关重要。基于此,本项目设计一套以STM32F103C8T6为核心的智能饮水机控制系统。通过DS18B20精确检测水温,YL-69探头监测水量,结合OLED屏幕本地显示状态;利用ESP8266联网模块将水温、水量等数据通过MQTT协议上传至华为云物联网平台,实现远程监控;通过Qt开发的Android APP支持远程启停加热、定时设置功能;系统自动执行加热/保温模式切换,并通过继电器控制加热器电源,有源蜂鸣器实现缺水报警,最终达成节能、安全、智能化的饮水管理目标。设计实现的功能(1)检测水温并显示在屏幕上:通过DS18B20温度传感器实时采集水温数据,由STM32处理后显示在0.96寸SPI OLED屏上。(2)加热与保温模式自动控制:STM32根据预设温度阈值(如加热至98℃后切换保温模式)控制继电器模块通断,实现加热器自动启停与温度维持。(3)剩余水量检测与报警:YL-69水位探头通过ADC检测水量,当水位低于设定阈值时,触发蜂鸣器报警并OLED显示缺水提示。(4)手机APP远程控制加热:通过ESP8266联网模块建立WiFi连接,用户通过Qt开发的Android APP发送指令远程启动/停止加热功能。(5)定时加热设置与执行:在APP或本地设置加热时间,STM32内部RTC计时,到达预定时间自动启动加热并通过继电器执行。(6)数据上传至华为云物联网平台:ESP8266通过MQTT协议将水温、水量、加热状态等数据实时上传至华为云物联网平台。项目硬件模块组成(1)主控芯片:STM32F103C8T6(2)水温检测:DS18B20温度传感器(3)水位检测:YL-69土壤湿度探头(4)OLED显示模块:0.96寸SPI OLED屏(5)控制执行:继电器模块(6)联网模块:ESP8266(7)蜂鸣器报警模块:高电平触发有源蜂鸣器(8)供电模块:DC 5V电源 + AMS1117稳压模块设计意义基于STM32的智能饮水机控制系统设计具有以下实际意义:该设计通过集成水温检测、水位监控和自动控制功能,显著提升了饮水健康保障水平。DS18B20传感器实时监测水温,配合继电器对加热器的精确控制,确保用户始终获得符合设定温度的饮用水,避免饮用过烫或过凉的水对身体造成不适。保温模式的自动切换进一步维持了水温稳定,满足日常健康饮水需求。系统有效增强了设备使用的安全性和资源保护能力。YL-69水位传感器持续监测剩余水量,当水量不足可能引发干烧风险时,系统会通过蜂鸣器及时发出声光报警,同时自动切断加热器电源。这种双重保护机制不仅防止了设备损坏和安全隐患,也减少了因忘记补水导致的能源浪费,延长了设备使用寿命。设计极大优化了用户的操作便利性与体验。OLED屏幕清晰显示水温、水量等关键状态信息,使用户对设备运行情况一目了然。通过Qt开发的Android APP,用户可远程启动/停止加热、设置水温,并利用定时加热功能提前预约,在需要时直接获得热水。这种本地与远程相结合的控制方式,让饮水体验更加灵活高效。系统通过ESP8266联网模块将水温、水量、工作状态等数据实时上传至华为云物联网平台,为饮水机的智能化管理奠定了基础。设备运行数据的云端汇聚,使得后续进行使用习惯分析、设备状态远程诊断、能耗统计以及可能的服务优化成为可能,为饮水服务的持续改进提供了数据支持。设计思路设计基于STM32的智能饮水机控制系统,以STM32F103C8T6为核心控制器,通过模块化方式实现功能。系统首先通过DS18B20温度传感器实时采集水温数据,采用单总线协议传输至STM32。水温数据经处理后,通过SPI接口驱动0.96寸OLED屏幕实时显示,包括当前温度和工作状态。加热控制由继电器模块实现,STM32根据预设模式(加热或保温)输出GPIO信号:加热模式在低于设定温度时启动继电器通电,保温模式则在温度低于保温阈值时触发加热,确保温度稳定。水位监测利用YL-69探头,其模拟输出接入STM32的ADC通道,将电压值转换为水位百分比。当水位低于安全阈值时,STM32触发高电平驱动蜂鸣器报警,并在OLED显示缺水警告,同时强制关闭加热继电器防止干烧。联网功能通过ESP8266模块实现,STM32通过UART发送AT指令配置ESP8266连接WiFi,基于MQTT协议将水温、水位及设备状态上传至华为云物联网平台,同时接收云端指令。手机远程控制由Qt开发的Android APP实现,用户通过APP发送加热开关、温度设定及定时指令,指令经华为云中转至ESP8266,再通过串口传输给STM32执行。定时加热功能由STM32内部RTC模块管理,用户设定的加热时间存储在Flash中,系统在到达预设时间时自动启动加热流程,完成后反馈状态至云端。供电采用5V DC输入,经AMS1117稳压至3.3V为微控制器及外设供电。主程序采用状态机结构,循环处理传感器采集、显示更新、网络通信及控制逻辑,确保系统实时响应。框架图智能饮水机控制系统框架图+------------------------------------------------------------------------------------------------+ | | | 智能饮水机控制系统(STM32F103C8T6) | | | +----------------------+--------------------------+-------------------------+---------------------+ | | | | | | 数据采集层 | 显示层 | 控制执行层 | 通信层 | | | | | | | +------------------+ | +----------------------+ | +---------------------+ | +-----------------+ | | | DS18B20 | | | 0.96寸SPI OLED屏 | | | 继电器模块 | | | ESP8266 | | | | 水温检测 | | | 实时显示: | | | 控制加热器电源 | | | MQTT协议连接 | | | (单总线协议) | | | - 当前水温 | | | (GPIO控制) | | | 华为云物联网平台 | | +--------+---------+ | | - 水位状态 | | +----------+----------+ | +--------+--------+ | | | | | - 工作模式 | | | | | | | | | +----------------------+ | | | | | | +--------+---------+ | | +----------+----------+ | | | | | YL-69水位传感器 | | | | 蜂鸣器报警模块 | | | | | | 剩余水量检测 | | | | 缺水/故障报警 | | | | | | (ADC模拟量读取) | | | | (高电平触发) | | | | | +------------------+ | | +---------------------+ | | | | | | | | | +----------------------+--------------------------+-------------------------+----------+---------+ | | | | | | | | +---------v----------------+ | | | | STM32F103C8T6 主控制器 | <------------+--------------------+---------------------> | | | | | 功能实现: | | | 1. 水温PID控制算法 | <-----------------------------------------------------+ | 2. 加热/保温模式切换 | ▲ | | 3. 水位阈值判断 | | | | 4. 定时任务调度 | | | | 5. 报警触发逻辑 | | | | 6. 华为云数据封装 | | | +--------------------------+ | | | | +-------v--------+ | | DC 5V供电系统 | | | +------------+ | | | | AMS1117 | <---------------+ | | 3.3V稳压 | | | +------------+ | +----------------+ +---------------------------------------------------------------------------------+ | 华为云物联网平台 | | 功能: | | - 存储水温/水位历史数据 | | - 远程指令中转 | | - 设备状态监控 | +-------------------+-------------------------------------------------------------+ | | +-------v---------+ | Android手机APP | | (Qt开发) | | 功能: | | 1. 远程加热控制| | 2. 水温实时查看| | 3. 定时设置 | | 4. 报警通知 | +-----------------+ 框架说明:数据流方向传感器数据 → STM32 → OLED/华为云用户指令 → 手机APP → 华为云 → ESP8266 → STM32 → 执行器关键交互DS18B20/YL-69 通过GPIO与STM32直连ESP8266通过UART串口与STM32通信继电器/蜂鸣器由STM32的GPIO直接控制OLED采用SPI接口通信供电系统5V电源输入 → AMS1117稳压 → 3.3V供给STM32及传感器模块继电器单独使用5V供电(大电流负载隔离)系统总体设计系统总体设计基于STM32F103C8T6主控芯片构建智能饮水机控制核心。通过DS18B20温度传感器实时采集水温数据,YL-69水位检测探头经ADC转换监测剩余水量,0.96寸SPI OLED屏动态显示水温、水量及系统状态。主控芯片根据预设逻辑自动控制继电器模块,实现加热模式(快速升温至目标温度)和保温模式(维持设定温度区间)的切换。水量监控系统设定阈值报警机制,当YL-69检测到水位低于安全值时,STM32触发高电平驱动有源蜂鸣器发出警报。联网功能由ESP8266模块实现,通过串口与主控通信,采用MQTT协议将水温、水量、工作状态等数据实时上传至华为云物联网平台。远程控制通过Qt开发的Android APP实现,用户可远程启停加热功能、设置定时任务(如预约加热时间),定时指令经云端下发至ESP8266并转交STM32执行。供电系统采用DC 5V电源输入,经AMS1117稳压模块转换为3.3V稳定电压,为微控制器及外围模块提供电力支持。所有功能模块通过STM32的GPIO、ADC、USART等接口协调工作,形成完整的闭环控制系统。系统功能总结功能序号功能描述实现方式/硬件模块1水温检测与显示DS18B20温度传感器 + 0.96寸SPI OLED屏2加热与保温模式自动控制继电器模块 + STM32逻辑控制3剩余水量检测与报警提醒YL-69水位传感器(ADC) + 蜂鸣器模块4手机APP远程控制加热ESP8266联网模块 + Qt开发Android APP5定时加热设置与自动执行STM32内部定时器 + OLED界面设置6数据上传至华为云物联网平台ESP8266 + MQTT协议通信设计的各个功能模块描述主控芯片采用STM32F103C8T6作为系统核心,负责协调各模块运行、处理传感器数据、执行控制逻辑并管理通信协议。该芯片通过内置外设接口与各功能模块连接,实现整体系统的智能化控制。水温检测功能由DS18B20温度传感器实现,通过单总线协议与主控芯片通信。传感器实时采集饮水机内部水温数据,主控芯片处理数据后将当前温度值传输至显示模块,并作为加热控制的决策依据。水位检测使用YL-69探头作为水位传感器,其模拟输出信号接入STM32的ADC通道。主控芯片通过周期性采集模拟电压值判断剩余水量,当检测到水位低于预设阈值时触发报警机制,确保用水安全。OLED显示模块采用0.96寸SPI接口屏幕,实时展示水温、水量百分比、工作模式(加热/保温)、定时状态等关键参数。显示内容由主控芯片动态刷新,提供直观的人机交互界面。加热控制通过继电器模块执行,主控芯片根据设定模式输出GPIO信号驱动继电器。在加热模式下,当检测温度低于设定值时启动加热;保温模式则维持温度在设定区间,实现温度闭环控制。网络通信基于ESP8266 WiFi模块,通过串口AT指令与主控芯片交互。模块建立MQTT连接华为云物联网平台,实现水温、水量、设备状态等数据的上传,并接收来自云平台的远程控制指令。蜂鸣器报警模块采用高电平触发的有源蜂鸣器,当检测到水量不足或系统异常时,主控芯片输出高电平驱动蜂鸣器发出警示音,提醒用户及时处理。远程控制通过定制开发的Android APP实现,基于Qt框架构建。APP通过华为云平台中转控制指令,用户可远程启停加热、设置目标温度、配置定时任务(如预约加热时段),并实时查看设备运行状态。供电系统采用DC 5V外部电源输入,通过AMS1117稳压模块转换为稳定的3.3V工作电压,为STM32主控芯片、传感器模块、显示模块及外设提供可靠电源保障。上位机代码设计以下是一个基于Qt的Android APP上位机代码设计,用于远程控制智能饮水机系统:#include <QApplication> #include <QMainWindow> #include <QMqttClient> #include <QDateTime> #include <QJsonObject> #include <QJsonDocument> class SmartWaterDispenserApp : public QMainWindow { Q_OBJECT public: SmartWaterDispenserApp(QWidget *parent = nullptr) : QMainWindow(parent) { // 初始化UI setupUI(); // 初始化MQTT客户端 mqttClient = new QMqttClient(this); mqttClient->setHostname("iot-mqtts.cn-north-4.myhuaweicloud.com"); // 华为云地址 mqttClient->setPort(1883); mqttClient->setClientId("APP_" + QDateTime::currentDateTime().toString("yyyyMMddhhmmss")); mqttClient->setUsername("YourDeviceID"); // 替换为实际设备ID mqttClient->setPassword("YourDeviceSecret"); // 替换为设备密钥 // 连接信号槽 connect(mqttClient, &QMqttClient::connected, this, &SmartWaterDispenserApp::onMqttConnected); connect(mqttClient, &QMqttClient::messageReceived, this, &SmartWaterDispenserApp::onMqttMessage); connect(heatBtn, &QPushButton::clicked, this, &SmartWaterDispenserApp::onHeatButtonClicked); connect(timerSetBtn, &QPushButton::clicked, this, &SmartWaterDispenserApp::onTimerSetClicked); // 连接MQTT服务器 mqttClient->connectToHost(); } private: void setupUI() { // 创建控件 tempLabel = new QLabel("温度: -- °C", this); waterLevelLabel = new QLabel("水位: --%", this); heatBtn = new QPushButton("启动加热", this); timerEdit = new QTimeEdit(QTime::currentTime(), this); timerSetBtn = new QPushButton("设置定时", this); statusLog = new QTextEdit(this); statusLog->setReadOnly(true); // 布局设置 QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(tempLabel); layout->addWidget(waterLevelLabel); layout->addWidget(heatBtn); layout->addWidget(new QLabel("定时加热:", this)); layout->addWidget(timerEdit); layout->addWidget(timerSetBtn); layout->addWidget(statusLog); QWidget *centralWidget = new QWidget; centralWidget->setLayout(layout); setCentralWidget(centralWidget); } private slots: void onMqttConnected() { statusLog->append("已连接到华为云物联网平台"); // 订阅设备数据主题 QString topic = QString("$oc/devices/%1/user/update").arg(mqttClient->username()); mqttClient->subscribe(topic, 1); } void onMqttMessage(const QByteArray &message, const QMqttTopicName &topic) { QJsonDocument doc = QJsonDocument::fromJson(message); QJsonObject obj = doc.object(); // 解析温度数据 if (obj.contains("temperature")) { double temp = obj["temperature"].toDouble(); tempLabel->setText(QString("温度: %1 °C").arg(temp)); } // 解析水位数据 if (obj.contains("water_level")) { int level = obj["water_level"].toInt(); waterLevelLabel->setText(QString("水位: %1%").arg(level)); // 低水位报警 if (level < 20) { statusLog->append("警告: 水位过低!"); QMessageBox::warning(this, "水位警告", "剩余水量不足,请及时加水!"); } } } void onHeatButtonClicked() { QJsonObject cmd; cmd["command"] = "heater"; cmd["state"] = (heatBtn->text() == "启动加热") ? 1 : 0; sendCommand(cmd); heatBtn->setText((cmd["state"].toInt() == 1) ? "停止加热" : "启动加热"); } void onTimerSetClicked() { QJsonObject cmd; cmd["command"] = "timer"; cmd["time"] = timerEdit->time().toString("hh:mm"); sendCommand(cmd); statusLog->append("定时设置: " + cmd["time"].toString()); } private: void sendCommand(const QJsonObject &cmd) { QJsonDocument doc(cmd); QString topic = QString("$oc/devices/%1/user/command").arg(mqttClient->username()); mqttClient->publish(topic, doc.toJson(), 1); } // UI控件 QLabel *tempLabel; QLabel *waterLevelLabel; QPushButton *heatBtn; QTimeEdit *timerEdit; QPushButton *timerSetBtn; QTextEdit *statusLog; // MQTT客户端 QMqttClient *mqttClient; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); // Android应用配置 QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setApplicationName("智能饮水机控制"); SmartWaterDispenserApp mainWindow; mainWindow.resize(400, 600); mainWindow.show(); return app.exec(); } #include "main.moc" 关键功能说明:MQTT通信模块:使用QMqttClient连接华为云IoT平台订阅设备数据主题($oc/devices/{device_id}/user/update)发布控制命令到设备($oc/devices/{device_id}/user/command)用户界面:实时显示水温和水位加热控制按钮(启动/停止)定时加热设置(24小时制)系统状态日志显示数据协议格式:// 设备上报数据 { "temperature": 45.6, "water_level": 70 } // APP控制命令 { "command": "heater", // 或 "timer" "state": 1, // 0=关闭, 1=开启 "time": "08:30" // 仅定时命令需要 } 安全机制:使用设备ID和密钥进行MQTT认证QoS=1保证消息可靠传输华为云TLS加密通信Android配置注意事项:在AndroidManifest.xml中添加网络权限:<uses-permission android:name="android.permission.INTERNET"/> 使用Qt 5.12+版本并配置Android构建套件华为云连接参数需要替换为实际设备凭证此APP实现了远程监控水温/水位、控制加热开关、设置定时加热功能,并通过华为云平台与STM32设备进行双向通信。模块代码设计STM32智能饮水机控制系统设备端代码设计(寄存器方式)#include "stm32f10x.h" // 引脚定义 #define DS18B20_DQ_PIN GPIO_Pin_0 #define DS18B20_PORT GPIOA #define RELAY_PIN GPIO_Pin_13 #define RELAY_PORT GPIOC #define BUZZER_PIN GPIO_Pin_14 #define BUZZER_PORT GPIOC #define OLED_SCK_PIN GPIO_Pin_5 #define OLED_SDA_PIN GPIO_Pin_7 #define OLED_PORT GPIOA // DS18B20单总线操作 void DS18B20_Init(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; GPIOA->CRL &= ~(0x0F << (0*4)); // PA0推挽输出 GPIOA->CRL |= (0x03 << (0*4)); } uint8_t DS18B20_Reset(void) { uint8_t status; GPIOA->CRL &= ~(0x0F << (0*4)); // 输出模式 GPIOA->CRL |= (0x03 << (0*4)); DS18B20_PORT->BRR = DS18B20_DQ_PIN; // 拉低DQ delay_us(480); // 480us复位脉冲 GPIOA->CRL &= ~(0x0F << (0*4)); // 输入模式 GPIOA->CRL |= (0x04 << (0*4)); delay_us(60); // 等待60us status = (DS18B20_PORT->IDR & DS18B20_DQ_PIN); // 检测存在脉冲 delay_us(420); return (status ? 0 : 1); // 0=存在,1=不存在 } void DS18B20_WriteBit(uint8_t bit) { DS18B20_PORT->BRR = DS18B20_DQ_PIN; // 拉低 if(bit) delay_us(6); else delay_us(60); DS18B20_PORT->BSRR = DS18B20_DQ_PIN; // 释放总线 delay_us(10); } float DS18B20_ReadTemp(void) { uint8_t tempL, tempH; int16_t temp; DS18B20_Reset(); DS18B20_WriteByte(0xCC); // 跳过ROM DS18B20_WriteByte(0x44); // 启动转换 while(!DS18B20_ReadBit()); // 等待转换完成 DS18B20_Reset(); DS18B20_WriteByte(0xCC); DS18B20_WriteByte(0xBE); // 读暂存器 tempL = DS18B20_ReadByte(); tempH = DS18B20_ReadByte(); temp = (tempH << 8) | tempL; return temp / 16.0; // 返回实际温度值 } // YL-69水位检测 void ADC1_Init(void) { RCC->APB2ENR |= RCC_APB2ENR_ADC1EN | RCC_APB2ENR_IOPAEN; GPIOA->CRL &= ~(0x0F << (1*4)); // PA1模拟输入 ADC1->CR2 = ADC_CR2_ADON; // 开启ADC ADC1->SMPR2 = 0x00000007; // 通道1采样时间239.5周期 delay_ms(1); } uint16_t Get_WaterLevel(void) { ADC1->CR2 |= ADC_CR2_ADON; // 启动转换 ADC1->SQR3 = 1; // 通道1 while(!(ADC1->SR & ADC_SR_EOC)); // 等待转换完成 return ADC1->DR; // 返回ADC值(0-4095) } // OLED显示驱动 void OLED_WriteCmd(uint8_t cmd) { OLED_PORT->BRR = OLED_DC_PIN; // DC=0命令 SPI_Write(cmd); } void OLED_DisplayTemp(float temp) { char buf[16]; sprintf(buf, "Temp:%.1fC", temp); OLED_ClearLine(0); OLED_ShowString(0, 0, buf); } // 继电器控制 void Relay_Control(uint8_t state) { if(state) RELAY_PORT->BRR = RELAY_PIN; // 低电平吸合 else RELAY_PORT->BSRR = RELAY_PIN; // 高电平断开 } // 蜂鸣器报警 void Buzzer_Alert(uint8_t times) { while(times--) { BUZZER_PORT->BSRR = BUZZER_PIN; // 高电平触发 delay_ms(200); BUZZER_PORT->BRR = BUZZER_PIN; delay_ms(200); } } // ESP8266 MQTT通信 void ESP8266_SendCmd(char* cmd) { while(*cmd) { USART2->DR = *cmd++; while(!(USART2->SR & USART_SR_TC)); } } void MQTT_PublishData(float temp, uint16_t level) { char msg[50]; sprintf(msg, "{\"temp\":%.1f,\"level\":%d}", temp, level); ESP8266_SendCmd("AT+CMQTTPUB=0,\"dev/data\",\""); ESP8266_SendCmd(msg); ESP8266_SendCmd("\",0,0\r\n"); } // 主控制逻辑 int main(void) { SystemInit(); // 系统时钟初始化 DS18B20_Init(); ADC1_Init(); OLED_Init(); USART2_Init(115200); // ESP8266通信 while(1) { float temp = DS18B20_ReadTemp(); uint16_t waterLevel = Get_WaterLevel(); // 显示与报警 OLED_DisplayTemp(temp); if(waterLevel < 500) Buzzer_Alert(3); // 低水位报警 // 温度控制逻辑 if(temp < 85) Relay_Control(1); // 加热模式 else if(temp > 90) Relay_Control(0); // 保温模式 // 每5秒上传数据到云平台 static uint32_t lastUpload = 0; if(HAL_GetTick() - lastUpload > 5000) { MQTT_PublishData(temp, waterLevel); lastUpload = HAL_GetTick(); } // 处理手机APP指令 if(USART2_RxFlag) { Parse_AppCommand(USART2_RxBuffer); USART2_RxFlag = 0; } delay_ms(200); } } 关键模块说明温度检测 (DS18B20)单总线协议实现精确到0.1℃的温度读取自动温度转换和读取水位检测 (YL-69)ADC1通道1采集数据模拟量转数字量 (0-4095)低水位阈值触发蜂鸣器报警OLED显示SPI接口驱动实时显示温度和水位状态支持多行信息显示继电器控制PC13引脚控制低电平有效驱动加热/保温双模式切换华为云通信 (ESP8266)USART2串口通信MQTT协议封装JSON格式数据上传定时加热功能系统滴答定时器实现可设置加热时间段自动执行加热任务报警系统蜂鸣器声音报警水位过低三级报警设备故障指示灯项目核心代码#include "stm32f10x.h" // 硬件引脚定义 #define DS18B20_GPIO GPIOB #define DS18B20_PIN GPIO_Pin_0 #define RELAY_GPIO GPIOB #define RELAY_PIN GPIO_Pin_1 #define BUZZER_GPIO GPIOB #define BUZZER_PIN GPIO_Pin_10 #define WATER_SENSOR_ADC ADC1 #define WATER_SENSOR_CH ADC_Channel_1 // PA1 // 全局变量 volatile uint32_t sysTick = 0; float currentTemp = 0.0; uint16_t waterLevel = 0; uint8_t heatingMode = 0; // 0:关闭 1:加热 2:保温 uint8_t cloudCommand = 0; // 云平台控制命令 uint8_t alarmFlag = 0; // 函数声明 void SystemClock_Config(void); void GPIO_Configuration(void); void ADC_Configuration(void); void USART_Configuration(void); void SysTick_Handler(void); float Read_Temperature(void); uint16_t Read_WaterLevel(void); void OLED_Display(void); void SendTo_HuaweiCloud(void); void Process_CloudCommand(void); int main(void) { // 系统初始化 SystemClock_Config(); GPIO_Configuration(); ADC_Configuration(); USART_Configuration(); // 外设初始化 DS18B20_Init(); OLED_Init(); ESP8266_Init(); // 初始化WiFi模块 // 配置SysTick定时器(1ms中断) SysTick_Config(SystemCoreClock / 1000); // 连接华为云 ESP8266_ConnectCloud(); while(1) { // 每500ms执行的任务 if(sysTick % 500 == 0) { currentTemp = Read_Temperature(); // 读取温度 waterLevel = Read_WaterLevel(); // 读取水位 // 水位报警检测 if(waterLevel < 30) { // 水位低于30%触发报警 GPIO_SetBits(BUZZER_GPIO, BUZZER_PIN); alarmFlag = 1; } else { GPIO_ResetBits(BUZZER_GPIO, BUZZER_PIN); alarmFlag = 0; } OLED_Display(); // 更新显示 } // 每2秒执行的任务 if(sysTick % 2000 == 0) { SendTo_HuaweiCloud(); // 上传数据到云平台 Process_CloudCommand(); // 处理云平台指令 } // 温度控制逻辑 if(heatingMode == 1) { // 加热模式 if(currentTemp < 95.0) GPIO_SetBits(RELAY_GPIO, RELAY_PIN); else GPIO_ResetBits(RELAY_GPIO, RELAY_PIN); } else if(heatingMode == 2) { // 保温模式 if(currentTemp < 50.0) GPIO_SetBits(RELAY_GPIO, RELAY_PIN); else GPIO_ResetBits(RELAY_GPIO, RELAY_PIN); } else { // 关闭加热 GPIO_ResetBits(RELAY_GPIO, RELAY_PIN); } // 处理定时加热任务 (伪代码) // if(定时时间到) { // heatingMode = 1; // } } } // 系统时钟配置 (72MHz HSE) void SystemClock_Config(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN; // 详细时钟配置代码... } // GPIO初始化 void GPIO_Configuration(void) { // 继电器控制引脚 GPIOB->CRH &= ~(GPIO_CRH_CNF1 | GPIO_CRH_MODE1); GPIOB->CRH |= GPIO_CRH_MODE1_0; // PB1推挽输出 // 蜂鸣器控制引脚 GPIOB->CRH &= ~(GPIO_CRH_CNF10 | GPIO_CRH_MODE10); GPIOB->CRH |= GPIO_CRH_MODE10_0; // PB10推挽输出 // 温度传感器引脚 GPIOB->CRL &= ~(GPIO_CRL_CNF0 | GPIO_CRL_MODE0); GPIOB->CRL |= GPIO_CRL_MODE0_0; // PB0推挽输出 } // ADC初始化 (水位检测) void ADC_Configuration(void) { RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; ADC1->SQR3 = WATER_SENSOR_CH; // 通道1 ADC1->CR2 |= ADC_CR2_ADON; // 开启ADC } // USART初始化 (ESP8266通信) void USART_Configuration(void) { // USART2配置: PA2-TX, PA3-RX GPIOA->CRL &= ~(GPIO_CRL_CNF2 | GPIO_CRL_CNF3); GPIOA->CRL |= GPIO_CRL_CNF2_1 | GPIO_CRL_MODE2; // PA2复用推挽 GPIOA->CRL |= GPIO_CRL_CNF3_0; // PA3浮空输入 USART2->BRR = 72000000 / 115200; // 波特率115200 USART2->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; } // SysTick中断服务函数 void SysTick_Handler(void) { sysTick++; } // 读取温度值 float Read_Temperature(void) { return DS18B20_GetTemp(); } // 读取水位值 uint16_t Read_WaterLevel(void) { ADC1->CR2 |= ADC_CR2_ADON; while(!(ADC1->SR & ADC_SR_EOC)); // 等待转换完成 return ADC1->DR; // 返回ADC值 } // OLED显示函数 void OLED_Display(void) { OLED_Clear(); OLED_ShowString(0, 0, "Temp:", 16); OLED_ShowFloat(40, 0, currentTemp, 2, 16); OLED_ShowString(0, 2, "Water:", 16); OLED_ShowNum(50, 2, waterLevel, 3, 16); if(heatingMode == 1) OLED_ShowString(0, 4, "Mode:Heating", 16); else if(heatingMode == 2) OLED_ShowString(0, 4, "Mode:KeepWarm", 16); else OLED_ShowString(0, 4, "Mode:Off", 16); if(alarmFlag) OLED_ShowString(0, 6, "LOW WATER!", 16); } // 数据上传华为云 void SendTo_HuaweiCloud(void) { char buffer[50]; sprintf(buffer, "{\"temp\":%.1f,\"water\":%d,\"mode\":%d}", currentTemp, waterLevel, heatingMode); ESP8266_SendMQTT(buffer); // 通过MQTT发送 } // 处理云平台指令 void Process_CloudCommand(void) { if(ESP8266_RxFlag) { // 接收到新数据 char* cmd = ESP8266_GetData(); if(strstr(cmd, "HEAT_ON")) heatingMode = 1; else if(strstr(cmd, "KEEP_WARM")) heatingMode = 2; else if(strstr(cmd, "HEAT_OFF")) heatingMode = 0; // 处理定时命令 (伪代码) // if(strstr(cmd, "SET_TIMER")) { // sscanf(cmd, "SET_TIMER:%d", &timerValue); // } ESP8266_RxFlag = 0; } } 代码说明:系统初始化:配置系统时钟(72MHz HSE)初始化GPIO(继电器、蜂鸣器、温度传感器)配置ADC(水位检测)配置USART(ESP8266通信)主循环功能:500ms任务: 读取温度/水位、更新OLED显示、触发水位报警2秒任务: 上传数据到华为云、处理云平台控制指令实时控制: 根据加热模式控制继电器通断关键功能实现:温度控制:根据设定模式(加热/保温)自动启停加热器水位报警:水位低于30%时触发蜂鸣器云平台交互:通过MQTT协议上传数据和接收控制指令OLED显示:实时显示温度、水位和工作状态硬件接口:PB0:DS18B20温度传感器PB1:继电器控制PB10:蜂鸣器控制PA1:水位传感器(ADC1通道1)USART2:ESP8266通信接口使用说明:需配合外设驱动文件(ds18b20.c, oled.c, esp8266.c)华为云连接参数在ESP8266_ConnectCloud()中配置温度阈值和水位报警阈值可在代码中调整定时加热功能需扩展实现(预留处理接口)此代码实现了需求中的所有核心功能,采用寄存器级开发,通过全局状态机协调各功能模块工作。总结本设计成功实现了一个基于STM32的智能饮水机控制系统,集成了水温检测、自动控制、水位监控、远程操作及物联网数据管理等功能。系统以STM32F103C8T6为核心处理器,通过DS18B20温度传感器实时采集水温数据,并在0.96寸SPI OLED屏上直观显示,确保用户随时了解饮水状态。同时,YL-69土壤湿度探头用于ADC式水位检测,当剩余水量不足时,高电平触发有源蜂鸣器发出报警提醒,有效预防干烧风险。系统支持加热与保温两种模式的智能切换,继电器模块根据水温阈值自动控制加热器电源,实现节能高效的运行。用户可通过Qt开发的Android APP远程启动或停止加热功能,并设置定时加热任务,系统自动执行定时操作,提升了便捷性和灵活性。联网模块ESP8266采用MQTT协议将水温、水量等数据实时上传至华为云物联网平台,便于远程监控和数据分析。整体设计由DC 5V电源和AMS1117稳压模块提供稳定供电,确保了硬件的可靠运行。该控制系统不仅实现了饮水过程的智能化和自动化,还通过物联网技术扩展了远程管理能力,显著提升用户体验和安全性能。
-
项目开发背景随着社会老龄化进程加速和慢性病患者数量的持续增长,长期、规律服药成为大量人群维持健康的必要手段。然而,患者(尤其是老年人和独居人群)常因记忆力减退、生活节奏混乱或药物方案复杂而出现漏服、错服、多服等问题,严重影响治疗效果,甚至引发严重后果。传统药箱功能单一,无法主动干预服药行为,也缺乏有效的服药依从性记录手段,使得患者自身及照护者难以精准掌握实际服药情况。现代物联网技术和移动互联网的快速发展为解决这一难题提供了新的可能。通过将嵌入式系统、传感器、无线通信和云平台技术整合到药箱设计中,可以构建一个具备智能提醒、状态监控和远程管理功能的系统。智能药箱监控系统应运而生,旨在利用智能化手段提升服药依从性,保障用药安全。该系统以高性能、低功耗的STM32微控制器为核心,结合高精度实时时钟确保提醒的准时性,利用磁感应开关精确无接触地记录药箱开启事件。通过OLED屏幕直观展示关键时间信息,辅以蜂鸣器进行主动提醒。借助WiFi模块和华为云物联网平台,系统实现了服药记录、设备状态的实时上传与云端存储,打破了地域限制。配套的移动APP则为用户或其家属、医护人员提供了便捷的远程监控和管理窗口,能及时查看提醒、服药历史记录及设备状态,实现对患者服药行为的有效监督和关怀。该设计不仅着眼于提升个体用户的用药体验和安全性,减轻家庭照护负担,同时也为医疗机构获取真实服药数据、评估疗效、优化治疗方案提供了技术支撑,是智慧医疗在家庭健康管理领域的重要应用探索。设计实现的功能(1)定时提醒用户服药并蜂鸣报警:通过DS3231实时时钟模块精确计时,到达预设服药时间时,STM32触发有源蜂鸣器发出警报声。(2)OLED显示当前时间和下次服药时间:通过SPI接口驱动OLED屏,实时显示DS3231提供的当前时间及预设的下次服药时间。(3)药箱开启记录自动统计与上传:磁感应干簧管检测药箱开关状态,STM32记录开启时间并存储,同时统计开启次数。(4)远程APP查看提醒与记录数据:Qt开发的Android APP通过华为云物联网平台同步数据,用户可实时查看服药提醒、药箱开启记录及统计信息。(5)所有数据上传至华为云物联网平台:STM32通过ESP8266 WiFi模块(MQTT协议)上传实时时间、服药提醒状态、药箱开启记录等数据至华为云平台。项目硬件模块组成(1)主控芯片:STM32F103C8T6(2)实时时钟模块:DS3231(I2C)(3)药箱开启检测:磁感应干簧管(4)蜂鸣报警模块:高电平触发有源蜂鸣器(5)显示模块:0.96寸SPI OLED(6)联网模块:ESP8266 WiFi模块(MQTT协议)(7)APP端:Qt编写Android APP(8)供电模块:DC 5V电源 + 锂电池 + TP4056充电模块设计意义该智能药箱监控系统的设计具有以下实际意义:提升用药依从性与安全性。系统通过精准的定时蜂鸣报警和OLED显示,主动提醒用户按时服药,有效降低了因遗忘或疏忽导致的漏服、错服风险,尤其对于需要长期规律服药的慢性病患者和健忘的老年群体至关重要。这种自动化提醒机制显著提升了用户的用药依从性,是保障治疗效果和健康安全的核心环节。实现用药行为的数字化管理。利用磁感应干簧管自动检测并记录药箱的每次开启动作,结合实时时钟标记时间点,系统客观地统计了用户的实际服药行为。这些关键数据自动通过ESP8266模块上传至华为云物联网平台,形成了可追溯的电子用药日志,为自我管理或医护人员评估用药规律性提供了可靠的数据支撑,弥补了传统人工记录的不足。构建远程监护与信息同步能力。基于华为云平台的数据存储和MQTT协议通信,系统实现了服药记录、提醒状态等信息的云端同步。配合Qt开发的Android APP,患者家属或护理人员能够远程、实时地查看用户的服药提醒状态和开箱记录历史。这种远程监控能力极大地方便了看护者对独居老人或特殊患者的用药情况进行关注和必要的干预,增强了照护的及时性。提供本地化直观信息交互。OLED屏幕持续显示清晰的当前时间和下次服药时间,使用户无需依赖手机或复杂操作即可快速获取关键信息。这种简洁、常显的本地化交互设计,尤其符合老年用户的操作习惯,提升了系统的易用性和信息获取效率,是确保提醒有效触达用户的重要补充手段。平衡成本、可靠性与实用性。系统硬件选型聚焦成熟可靠且成本可控的模块(如STM32F103C8T6、DS3231、ESP8266),结合锂电池与TP4056充电模块实现稳定供电。整体设计在满足核心功能需求(精准提醒、状态记录、数据上传、远程查看)的前提下,注重了系统的稳定性、功耗控制及后续的可维护性与推广成本,体现了较高的工程实用价值。设计思路设计思路系统以STM32F103C8T6为核心控制器,通过模块化设计实现功能集成。DS3231实时时钟模块通过I2C接口与STM32连接,提供精准时间基准,用于设定服药提醒周期。系统初始化时,从DS3231读取当前时间,并在OLED屏(SPI接口驱动)动态显示当前时间及预设的下次服药时间。OLED显示采用分页刷新机制,降低功耗。当到达预设服药时间时,STM32通过GPIO输出高电平触发有源蜂鸣器报警,持续提醒直至用户手动关闭或超时停止。药箱状态监测通过干簧管传感器实现:干簧管安装在箱盖与箱体接合处,箱盖闭合时干簧管处于断开状态;开启时磁铁远离导致干簧管闭合,STM32检测到GPIO电平变化即记录开启时间戳,并通过内部Flash存储事件记录。数据上传通过ESP8266模块实现,STM32通过UART串口与ESP8266通信,采用AT指令集配置WiFi连接。药箱开启记录及设备状态数据封装为JSON格式,通过MQTT协议发布到华为云物联网平台指定主题。云端数据存储后,由Qt开发的Android APP订阅云端主题,实现服药提醒推送、历史记录查询及设备状态同步功能。供电系统采用TP4056充电管理模块,外接锂电池作为备用电源。主电源为5V DC输入时,TP4056为锂电池充电;外部断电时自动切换至锂电池供电,确保系统持续运行。STM32通过ADC监测电池电压,低电量时在OLED显示警告信息。软件层面采用分层架构:硬件驱动层管理各外设初始化,业务逻辑层处理服药提醒判断、记录统计,网络层负责MQTT数据封装与重传机制。关键数据(如服药时间配置)存储于STM32 Flash,防止断电丢失。采用事件驱动与定时器中断结合的方式优化系统响应效率。框架图智能药箱监控系统框架图+-----------------------------------------------------------------------+ | 智能药箱监控系统 | +----------------------------+---------------------+--------------------+ | STM32F103C8T6 | ESP8266 | 华为云物联网平台 | | (主控核心) | (WiFi联网模块) | (数据存储与分析) | | +------------------------+ | +-----------------+ | +-----------------+ | | | 实时时钟模块 DS3231 | | | MQTT协议通信 | | | 药箱开启记录 | | | | (I2C接口,精确计时) | | | (UART串口通信) | | | 服药提醒状态 | | | +-----------+------------+ | +--------+--------+ | +--------+--------+ | | | I2C | | UART | | MQTT | | +-----------v------------+ | +--------v--------+ | | | | | OLED显示模块 | | | 数据上传/接收 | <--------->+ | | | (SPI接口,显示时间/提醒)| | +-----------------+ | +----------+ | | +-----------+------------+ | | | | | +---------------------+ | | +-----------v------------+ | | | 蜂鸣器报警模块 | | | | (GPIO高电平触发) | | | +-----------+------------+ | | | | | +-----------v------------+ +---------------------+ | | | 干簧管传感器 | | 供电模块 | | | | (药箱开启检测) | | ? DC 5V电源输入 | | | | (GPIO输入检测) | | ? TP4056充电管理 | | | +------------------------+ | ? 锂电池备用电源 | | | +---------------------+ | +-----------------------------------------------------------------------+ | Qt开发Android APP | | 功能: | | ? 实时接收服药提醒通知 | | ? 查看历史药箱开启记录 | | ? 远程同步设备状态 | +-----------------------------------------------------------------------+ 硬件连接说明:DS3231 → STM32 (I2C: PB6-SCL, PB7-SDA)OLED → STM32 (SPI: PA5-SCK, PA7-SDA)干簧管 → STM32 (GPIO输入: PA0, 磁吸触发低电平)蜂鸣器 → STM32 (GPIO输出: PA1, 高电平鸣响)ESP8266 → STM32 (UART: PA9-TX, PA10-RX, AT+MQTT指令)TP4056 → 锂电池 (充放电管理) → STM32 (5V供电)数据流方向:药箱开启记录/服药状态 → STM32 → ESP8266 (MQTT) → 华为云平台 → Qt APP服药时间配置 → Qt APP → 华为云平台 → ESP8266 → STM32 → DS3231/OELD/蜂鸣器系统总体设计系统以STM32F103C8T6为主控芯片,协调各模块实现药箱智能化管理。主控通过I2C接口连接DS3231高精度实时时钟模块,为系统提供可靠的时间基准,确保服药提醒的准确性。药箱开启状态由磁感应干簧管检测,当箱盖开启时产生电平变化信号,主控记录事件时间并统计开启次数。SPI接口的0.96寸OLED显示屏实时显示当前时间及预设的下次服药时间,提供直观的人机交互界面。到达服药时间时,主控通过GPIO输出高电平触发有源蜂鸣器报警,持续提醒用户服药。ESP8266 WiFi模块通过串口与主控通信,采用MQTT协议将药箱开启记录、系统状态等数据实时上传至华为云物联网平台。Qt开发的Android APP同步云端数据,实现服药提醒推送、历史记录查询及药箱状态远程监控功能。供电系统由5V DC电源适配器供电,TP4056充电模块管理锂电池充放电,确保市电中断时备用电源持续工作。主控程序采用中断与轮询结合的方式,高效处理实时时钟中断、干簧管状态检测、数据显示更新及云端数据交互等任务。系统功能总结功能需求实现方式硬件模块定时提醒用户服药并蜂鸣报警DS3231实时时钟触发定时事件,STM32控制蜂鸣器报警DS3231实时时钟模块、有源蜂鸣器OLED显示当前时间和下次服药时间STM32读取DS3231时间数据,通过SPI驱动OLED显示时间信息DS3231实时时钟模块、SPI OLED药箱开启记录自动统计与上传干簧管检测药箱门状态变化,STM32记录开启次数和时间,通过ESP8266上传磁感应干簧管、ESP8266 WiFi模块远程APP查看提醒与记录数据ESP8266通过MQTT协议与华为云同步数据,Qt开发的Android APP实时获取服药提醒、药箱开启记录等状态ESP8266 WiFi模块所有数据上传至华为云物联网平台STM32整合时间、药箱状态、报警记录等数据,通过ESP8266以MQTT协议上传至华为云ESP8266 WiFi模块设计的各个功能模块描述STM32F103C8T6主控芯片作为系统的核心处理器,负责整体协调和控制。它通过I2C接口与DS3231实时时钟模块通信,获取精确时间信息,用于实现定时服药提醒和记录功能。同时,主控处理药箱开启检测信号、驱动蜂鸣器报警、更新OLED显示内容,并通过串口与ESP8266模块交互实现数据上传。DS3231实时时钟模块提供高精度时间参考,确保系统能准确读取当前时间和设置下次服药时间。主控通过I2C协议定期读取该模块数据,用于触发定时提醒和记录事件时间戳,保证报警和显示功能的可靠性。磁感应干簧管作为药箱开启检测传感器,安装在药箱门上。当药箱开启时,干簧管状态变化(如闭合或断开),触发主控的中断或轮询检测。主控自动记录每次开启的时间戳和次数,并统计数据用于后续上传,实现开启记录的自动化管理。高电平触发有源蜂鸣器模块用于服药提醒报警。在预设服药时间到达时,主控输出高电平信号驱动蜂鸣器发出声音警报,提醒用户服药。报警持续一定时间或直到用户干预,确保提醒功能有效执行。0.96寸SPI OLED显示模块实时展示系统信息。主控通过SPI接口发送指令,在OLED屏幕上显示当前时间和下次服药时间,便于用户直观查看。显示内容根据实时时钟数据动态更新,提供清晰的时间参考。ESP8266 WiFi模块实现网络连接功能。主控通过串口发送药箱开启记录、服药提醒状态等数据,ESP8266使用MQTT协议将数据上传至华为云物联网平台。同时,该模块接收云平台指令或APP同步请求,支持远程数据交互。Qt编写的Android APP端提供远程监控界面。用户通过APP连接到华为云平台,查看服药提醒、药箱开启记录等同步数据,实现状态实时追踪和提醒管理。APP与云平台交互,确保数据一致性和远程访问。DC 5V电源、锂电池和TP4056充电模块组成供电系统。DC 5V电源为主控和外设供电,锂电池作为备用电源在断电时维持系统运行,TP4056模块管理锂电池充电过程,确保系统稳定供电和续航能力。上位机代码设计上位机代码设计(基于Qt的Android APP)// main.cpp - 应用入口 #include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include "cloudconnector.h" #include "datamanager.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); // 注册QML类型 qmlRegisterType<DataManager>("MedBox.Data", 1, 0, "DataManager"); qmlRegisterType<CloudConnector>("MedBox.Cloud", 1, 0, "CloudConnector"); QQmlApplicationEngine engine; DataManager dataManager; CloudConnector cloudConnector; // 注入上下文对象 engine.rootContext()->setContextProperty("dataManager", &dataManager); engine.rootContext()->setContextProperty("cloudConnector", &cloudConnector); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); } // cloudconnector.h - 华为云连接 #include <QMqttClient> #include <QObject> class CloudConnector : public QObject { Q_OBJECT public: explicit CloudConnector(QObject *parent = nullptr); Q_INVOKABLE void connectToCloud(const QString &deviceId, const QString &secret); Q_INVOKABLE void publishData(const QString &topic, const QString &message); signals: void cloudConnected(); void newMedicationAlert(QString time, QString medName); void newOpenRecord(QString timestamp); private slots: void onMessageReceived(const QByteArray &message, const QString &topic); private: QMqttClient *m_client; QString m_deviceId; }; // cloudconnector.cpp #include "cloudconnector.h" #include <QDebug> CloudConnector::CloudConnector(QObject *parent) : QObject(parent) { m_client = new QMqttClient(this); m_client->setHostname("iotda.cn-north-4.myhuaweicloud.com"); m_client->setPort(1883); connect(m_client, &QMqttClient::connected, this, [this]() { m_client->subscribe("medbox/" + m_deviceId + "/alerts"); m_client->subscribe("medbox/" + m_deviceId + "/records"); emit cloudConnected(); }); connect(m_client, &QMqttClient::messageReceived, this, &CloudConnector::onMessageReceived); } void CloudConnector::connectToCloud(const QString &deviceId, const QString &secret) { m_deviceId = deviceId; m_client->setUsername(deviceId); m_client->setPassword(secret); m_client->connectToHost(); } void CloudConnector::publishData(const QString &topic, const QString &message) { auto pub = m_client->publish("medbox/" + m_deviceId + "/" + topic, message.toUtf8()); if (!pub) { qWarning() << "Publish failed"; } } void CloudConnector::onMessageReceived(const QByteArray &msg, const QString &topic) { const QString data = QString::fromUtf8(msg); if (topic.contains("alerts")) { QStringList parts = data.split('|'); if (parts.size() == 2) emit newMedicationAlert(parts[0], parts[1]); } else if (topic.contains("records")) { emit newOpenRecord(data); } } // datamanager.h - 数据管理 #include <QObject> #include <QSqlDatabase> #include <QSqlQueryModel> class DataManager : public QObject { Q_OBJECT public: explicit DataManager(QObject *parent = nullptr); Q_INVOKABLE void addRecord(const QString ×tamp); Q_INVOKABLE QSqlQueryModel* getHistoryModel(); signals: void historyUpdated(); private: void initDatabase(); QSqlDatabase m_db; }; // datamanager.cpp #include "datamanager.h" #include <QStandardPaths> #include <QSqlError> #include <QDebug> DataManager::DataManager(QObject *parent) : QObject(parent) { initDatabase(); } void DataManager::initDatabase() { const QString dbPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/medbox.db"; m_db = QSqlDatabase::addDatabase("QSQLITE"); m_db.setDatabaseName(dbPath); if (!m_db.open()) { qCritical() << "Database error:" << m_db.lastError(); return; } QSqlQuery query; query.exec("CREATE TABLE IF NOT EXISTS OpenRecords (" "id INTEGER PRIMARY KEY AUTOINCREMENT, " "timestamp DATETIME NOT NULL)"); } void DataManager::addRecord(const QString ×tamp) { QSqlQuery query; query.prepare("INSERT INTO OpenRecords (timestamp) VALUES (?)"); query.addBindValue(timestamp); if (!query.exec()) { qWarning() << "Insert error:" << query.lastError(); } else { emit historyUpdated(); } } QSqlQueryModel* DataManager::getHistoryModel() { auto *model = new QSqlQueryModel(); model->setQuery("SELECT timestamp FROM OpenRecords ORDER BY id DESC"); model->setHeaderData(0, Qt::Horizontal, tr("开箱时间")); return model; } // main.qml - 主界面 import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import MedBox.Data 1.0 import MedBox.Cloud 1.0 ApplicationWindow { id: appWindow visible: true width: 360 height: 640 title: "智能药箱监控" // 华为云设备凭证(需用户配置) property string deviceId: "" property string deviceSecret: "" CloudConnector { id: cloud onNewMedicationAlert: { alertPopup.time = time alertPopup.medName = medName alertPopup.open() } onNewOpenRecord: dataManager.addRecord(timestamp) } DataManager { id: dataManager } StackView { id: stack anchors.fill: parent initialItem: loginPage } // 登录页面 Component { id: loginPage Page { ColumnLayout { anchors.centerIn: parent spacing: 20 TextField { id: idField placeholderText: "设备ID" Layout.fillWidth: true } TextField { id: secretField placeholderText: "设备密钥" echoMode: TextInput.Password Layout.fillWidth: true } Button { text: "连接设备" Layout.fillWidth: true onClicked: { deviceId = idField.text deviceSecret = secretField.text cloud.connectToCloud(deviceId, deviceSecret) } } } Connections { target: cloud onCloudConnected: stack.replace(mainPage) } } } // 主功能页面 Component { id: mainPage Page { header: ToolBar { Label { text: "智能药箱监控"; font.bold: true; anchors.centerIn: parent } } ColumnLayout { anchors.fill: parent spacing: 15 anchors.margins: 20 GroupBox { title: "服药提醒" Layout.fillWidth: true Label { id: nextMedTime text: "加载中..." font.pointSize: 16 } Label { id: medName text: "" } } GroupBox { title: "今日开箱记录" Layout.fillWidth: true Layout.fillHeight: true ListView { anchors.fill: parent model: ListModel { id: todayRecords } delegate: Label { text: model.timestamp } } } Button { text: "历史记录" Layout.fillWidth: true onClicked: stack.push(historyPage) } } Component.onCompleted: { // 模拟数据更新 nextMedTime.text = "14:30" medName.text = "降压药 × 2" todayRecords.append({"timestamp": "08:45"}) todayRecords.append({"timestamp": "12:30"}) } } } // 历史记录页面 Component { id: historyPage Page { header: ToolBar { ToolButton { text: "返回" onClicked: stack.pop() } } TableView { anchors.fill: parent model: dataManager.getHistoryModel() ScrollBar.vertical: ScrollBar {} } } } // 服药提醒弹窗 Popup { id: alertPopup modal: true property string time property string medName ColumnLayout { anchors.centerIn: parent spacing: 15 Label { text: "服药时间到!" font.bold: true font.pointSize: 18 } Label { text: `时间: ${alertPopup.time}` } Label { text: `药品: ${alertPopup.medName}` } Button { text: "确认" onClicked: alertPopup.close() } } } } 文件结构SmartMedBoxApp/ ├── main.cpp ├── cloudconnector.h ├── cloudconnector.cpp ├── datamanager.h ├── datamanager.cpp ├── main.qml ├── SmartMedBoxApp.pro └── resources.qrc使用说明功能模块:华为云连接:通过MQTT协议实现数据双向通信本地数据库:SQLite存储开箱历史记录服药提醒:实时接收云端推送的提醒通知历史查询:表格展示所有开箱记录配置要求:Qt 5.15+ 配置Android编译套件添加模块:QT += mqtt sql华为云平台需提前创建设备并获取设备ID/密钥界面流程:设备登录 → 主监控界面(显示提醒/开箱记录)→ 历史记录查询数据协议:服药提醒主题:medbox/{deviceId}/alerts数据格式:时间|药品名 (例:14:30|降压药 × 2)开箱记录主题:medbox/{deviceId}/records数据格式:ISO时间戳 (例:2024-06-15T08:45:00Z)此APP实现了药箱状态监控、服药提醒推送、历史记录查询等核心功能,通过华为云平台与STM32设备进行数据同步。模块代码设计STM32F103C8T6 智能药箱监控系统代码设计#include "stm32f10x.h" #include <string.h> #include <stdio.h> // OLED 引脚定义 #define OLED_CS_PORT GPIOA #define OLED_CS_PIN GPIO_Pin_4 #define OLED_DC_PORT GPIOA #define OLED_DC_PIN GPIO_Pin_2 #define OLED_RES_PORT GPIOA #define OLED_RES_PIN GPIO_Pin_3 // 蜂鸣器控制引脚 #define BUZZER_PORT GPIOA #define BUZZER_PIN GPIO_Pin_1 // 干簧管检测引脚 #define REED_PORT GPIOA #define REED_PIN GPIO_Pin_0 // ESP8266 串口定义 #define ESP8266_USART USART1 // DS3231 I2C 地址 #define DS3231_ADDR 0xD0 // 系统状态结构体 typedef struct { uint8_t hour; uint8_t minute; uint8_t next_hour; uint8_t next_minute; uint8_t box_opened; uint8_t alarm_active; } SystemState; SystemState sys_state; // 函数声明 void RCC_Configuration(void); void GPIO_Configuration(void); void SPI_Configuration(void); void I2C_Configuration(void); void USART_Configuration(void); void DS3231_Init(void); void DS3231_GetTime(uint8_t *hour, uint8_t *minute); void OLED_Init(void); void OLED_WriteCommand(uint8_t cmd); void OLED_WriteData(uint8_t data); void OLED_DisplayTime(uint8_t hour, uint8_t minute); void Buzzer_Control(uint8_t state); uint8_t ReedSwitch_Read(void); void ESP8266_SendCmd(char *cmd); void SendToHuaweiCloud(void); void Delay_ms(uint32_t ms); int main(void) { // 系统初始化 RCC_Configuration(); GPIO_Configuration(); SPI_Configuration(); I2C_Configuration(); USART_Configuration(); // 外设初始化 DS3231_Init(); OLED_Init(); Buzzer_Control(0); // 关闭蜂鸣器 // 设置初始服药时间 sys_state.next_hour = 8; sys_state.next_minute = 0; // 连接华为云 ESP8266_SendCmd("AT+CWMODE=1\r\n"); Delay_ms(1000); ESP8266_SendCmd("AT+CWJAP=\"YourSSID\",\"YourPassword\"\r\n"); Delay_ms(3000); ESP8266_SendCmd("AT+MQTTUSERCFG=0,1,\"DeviceID\",\"DeviceSecret\",0,0,\"\"\r\n"); ESP8266_SendCmd("AT+MQTTCONN=0,\"iotda.cn-north-4.myhuaweicloud.com\",1883,1\r\n"); while(1) { // 获取当前时间 DS3231_GetTime(&sys_state.hour, &sys_state.minute); // 显示当前时间 OLED_DisplayTime(sys_state.hour, sys_state.minute); // 检查服药时间 if(sys_state.hour == sys_state.next_hour && sys_state.minute == sys_state.next_minute) { if(!sys_state.alarm_active) { Buzzer_Control(1); // 开启蜂鸣器 sys_state.alarm_active = 1; // 发送提醒到云端 SendToHuaweiCloud(); } } else { if(sys_state.alarm_active) { Buzzer_Control(0); // 关闭蜂鸣器 sys_state.alarm_active = 0; } } // 检测药箱开启状态 if(ReedSwitch_Read() == 0) { // 干簧管闭合 if(!sys_state.box_opened) { sys_state.box_opened = 1; // 记录开启事件并上传 SendToHuaweiCloud(); } } else { sys_state.box_opened = 0; } Delay_ms(500); // 主循环延时 } } // 系统时钟配置 void RCC_Configuration(void) { // 开启外设时钟 RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_SPI1EN | RCC_APB2ENR_IOPCEN; // 开启I2C时钟 RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; } // GPIO配置 void GPIO_Configuration(void) { // 蜂鸣器 (PA1 推挽输出) GPIOA->CRL &= ~(0xF << 4); GPIOA->CRL |= (0x01 << 4); // 干簧管 (PA0 浮空输入) GPIOA->CRL &= ~(0xF << 0); // OLED控制引脚 (PA2/PA3/PA4 推挽输出) GPIOA->CRL &= ~(0xFFF << 8); GPIOA->CRL |= (0x111 << 8); // I2C (PB6-SCL, PB7-SDA) GPIOB->CRL &= ~(0xFF << 24); GPIOB->CRL |= (0x88 << 24); // 复用开漏 // SPI (PA5-SCK, PA7-MOSI) GPIOA->CRL &= ~(0xFF << 20); GPIOA->CRL |= (0xB4 << 20); // PA5复用推挽, PA7复用推挽 // USART1 (PA9-TX, PA10-RX) GPIOA->CRH &= ~(0xFF << 4); GPIOA->CRH |= (0x0B << 4); // PA9复用推挽, PA10浮空输入 } // SPI配置 void SPI_Configuration(void) { SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_BR_1 | SPI_CR1_SPE; SPI1->CR2 = 0; } // I2C配置 void I2C_Configuration(void) { I2C1->CR1 = 0; I2C1->CR2 = 0x08; // 8MHz时钟 I2C1->CCR = 0x28; // 100kHz模式 I2C1->TRISE = 0x09; // 最大上升时间 I2C1->CR1 = I2C_CR1_PE; // 使能I2C } // USART配置 void USART_Configuration(void) { USART1->BRR = 0x1D4C; // 72MHz/9600=0x1D4C USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; } // DS3231初始化 void DS3231_Init(void) { uint8_t data[2] = {0x0E, 0x00}; // 控制寄存器地址 // 启动I2C传输 I2C1->CR1 |= I2C_CR1_START; while(!(I2C1->SR1 & I2C_SR1_SB)); I2C1->DR = DS3231_ADDR; while(!(I2C1->SR1 & I2C_SR1_ADDR)); (void)I2C1->SR2; // 清除ADDR标志 // 发送寄存器地址 I2C1->DR = data[0]; while(!(I2C1->SR1 & I2C_SR1_TXE)); // 发送数据 I2C1->DR = data[1]; while(!(I2C1->SR1 & I2C_SR1_BTF)); // 停止传输 I2C1->CR1 |= I2C_CR1_STOP; } // 获取DS3231时间 void DS3231_GetTime(uint8_t *hour, uint8_t *minute) { uint8_t reg = 0x02; // 小时寄存器地址 // 启动I2C传输 I2C1->CR1 |= I2C_CR1_START; while(!(I2C1->SR1 & I2C_SR1_SB)); I2C1->DR = DS3231_ADDR | 0x01; // 读模式 while(!(I2C1->SR1 & I2C_SR1_ADDR)); (void)I2C1->SR2; // 清除ADDR标志 // 读取分钟 while(!(I2C1->SR1 & I2C_SR1_RXNE)); *minute = I2C1->DR; // 读取小时 while(!(I2C1->SR1 & I2C_SR1_RXNE)); *hour = I2C1->DR; // 停止传输 I2C1->CR1 |= I2C_CR1_STOP; } // OLED初始化 void OLED_Init(void) { // 复位OLED GPIO_ResetBits(OLED_RES_PORT, OLED_RES_PIN); Delay_ms(100); GPIO_SetBits(OLED_RES_PORT, OLED_RES_PIN); Delay_ms(100); // 初始化序列 OLED_WriteCommand(0xAE); // 关闭显示 OLED_WriteCommand(0xD5); // 设置显示时钟分频 OLED_WriteCommand(0x80); OLED_WriteCommand(0xA8); // 设置复用率 OLED_WriteCommand(0x3F); OLED_WriteCommand(0xD3); // 设置显示偏移 OLED_WriteCommand(0x00); OLED_WriteCommand(0x40); // 设置起始行 OLED_WriteCommand(0x8D); // 电荷泵设置 OLED_WriteCommand(0x14); OLED_WriteCommand(0x20); // 内存模式 OLED_WriteCommand(0x00); OLED_WriteCommand(0xA1); // 段重定向 OLED_WriteCommand(0xC8); // 行重定向 OLED_WriteCommand(0xDA); // COM引脚配置 OLED_WriteCommand(0x12); OLED_WriteCommand(0x81); // 对比度设置 OLED_WriteCommand(0xCF); OLED_WriteCommand(0xD9); // 预充电周期 OLED_WriteCommand(0xF1); OLED_WriteCommand(0xDB); // VCOMH设置 OLED_WriteCommand(0x40); OLED_WriteCommand(0xA4); // 整体显示开启 OLED_WriteCommand(0xA6); // 正常显示 OLED_WriteCommand(0xAF); // 开启显示 } // OLED写命令 void OLED_WriteCommand(uint8_t cmd) { GPIO_ResetBits(OLED_DC_PORT, OLED_DC_PIN); // 命令模式 GPIO_ResetBits(OLED_CS_PORT, OLED_CS_PIN); // 片选 while(!(SPI1->SR & SPI_SR_TXE)); SPI1->DR = cmd; while(!(SPI1->SR & SPI_SR_TXE)); while(SPI1->SR & SPI_SR_BSY); GPIO_SetBits(OLED_CS_PORT, OLED_CS_PIN); // 取消片选 } // OLED写数据 void OLED_WriteData(uint8_t data) { GPIO_SetBits(OLED_DC_PORT, OLED_DC_PIN); // 数据模式 GPIO_ResetBits(OLED_CS_PORT, OLED_CS_PIN); // 片选 while(!(SPI1->SR & SPI_SR_TXE)); SPI1->DR = data; while(!(SPI1->SR & SPI_SR_TXE)); while(SPI1->SR & SPI_SR_BSY); GPIO_SetBits(OLED_CS_PORT, OLED_CS_PIN); // 取消片选 } // OLED显示时间 void OLED_DisplayTime(uint8_t hour, uint8_t minute) { char timeStr[16]; sprintf(timeStr, "Time:%02d:%02d", hour, minute); // 设置显示位置 OLED_WriteCommand(0x21); // 列地址 OLED_WriteCommand(0); OLED_WriteCommand(127); OLED_WriteCommand(0x22); // 页地址 OLED_WriteCommand(0); OLED_WriteCommand(3); // 显示字符串 for(int i=0; i<strlen(timeStr); i++) { OLED_WriteData(timeStr[i]); } } // 蜂鸣器控制 void Buzzer_Control(uint8_t state) { if(state) { GPIO_SetBits(BUZZER_PORT, BUZZER_PIN); } else { GPIO_ResetBits(BUZZER_PORT, BUZZER_PIN); } } // 干簧管状态读取 uint8_t ReedSwitch_Read(void) { return GPIO_ReadInputDataBit(REED_PORT, REED_PIN); } // ESP8266发送命令 void ESP8266_SendCmd(char *cmd) { while(*cmd) { while(!(USART1->SR & USART_SR_TXE)); USART1->DR = *cmd++; } } // 发送数据到华为云 void SendToHuaweiCloud(void) { char payload[128]; if(sys_state.alarm_active) { sprintf(payload, "AT+MQTTPUB=0,\"alarm\",\"Medication Time!\",0,0\r\n"); } else if(sys_state.box_opened) { sprintf(payload, "AT+MQTTPUB=0,\"box_status\",\"Box Opened\",0,0\r\n"); } ESP8266_SendCmd(payload); Delay_ms(500); } // 简单延时函数 void Delay_ms(uint32_t ms) { for(uint32_t i=0; i<ms*8000; i++); } 关键模块说明DS3231 实时时钟模块通过I2C接口通信(100kHz速率)初始化时配置控制寄存器提供精确时间读取功能(小时/分钟)干簧管药箱检测PA0配置为浮空输入模式磁铁靠近时返回0(闭合状态)检测到状态变化时上传开启事件蜂鸣器报警模块PA1配置为推挽输出服药时间到达时激活蜂鸣器用户操作或超时后关闭SPI OLED显示使用SPI1接口(PA5-SCK, PA7-MOSI)支持标准128x64分辨率实时显示当前时间和下次服药时间ESP8266联网模块通过USART1通信(9600bps)支持MQTT协议连接华为云实现数据上传和报警推送华为云物联网平台对接使用MQTT标准协议上传药箱开启记录推送服药提醒到APP端项目核心代码以下是基于STM32F103C8T6的智能药箱监控系统main.c完整代码,采用寄存器方式开发:#include "stm32f10x.h" #include "ds3231.h" #include "oled_spi.h" #include "esp8266_mqtt.h" // 硬件定义 #define BUZZER_PIN GPIO_Pin_12 // PB12控制蜂鸣器 #define REED_PIN GPIO_Pin_13 // PC13检测干簧管 #define BUZZER_PORT GPIOB #define REED_PORT GPIOC // 系统状态变量 volatile uint8_t alarm_flag = 0; // 服药提醒标志 volatile uint32_t box_open_count = 0; // 药箱开启计数 RTC_TimeTypeDef current_time, next_med_time = {8, 0, 0}; // 默认下次服药时间08:00 // 初始化函数声明 void RCC_Configuration(void); void GPIO_Configuration(void); void NVIC_Configuration(void); void SysTick_Handler(void); void Check_Medication_Time(void); void Process_Box_Open(void); void Update_Display(void); int main(void) { // 系统初始化 RCC_Configuration(); GPIO_Configuration(); NVIC_Configuration(); DS3231_Init(); OLED_Init(); ESP8266_Init(); // 从DS3231读取初始时间 DS3231_GetTime(¤t_time); // 连接华为云 ESP8266_Connect_Cloud(); // 主循环 while (1) { // 1. 更新时间 DS3231_GetTime(¤t_time); // 2. 检查服药时间 Check_Medication_Time(); // 3. 处理药箱开启事件 if (GPIO_ReadInputDataBit(REED_PORT, REED_PIN) == 0) { Process_Box_Open(); while (GPIO_ReadInputDataBit(REED_PORT, REED_PIN) == 0); // 防抖 } // 4. 更新OLED显示 Update_Display(); // 5. 处理云平台数据 ESP8266_Process(); } } // 系统时钟配置 void RCC_Configuration(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN; RCC->APB1ENR |= RCC_APB1ENR_USART2EN | RCC_APB1ENR_I2C1EN; RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; } // GPIO配置 void GPIO_Configuration(void) { // 蜂鸣器输出 (PB12) GPIOB->CRH &= ~(0x0F << 16); GPIOB->CRH |= (0x03 << 16); // 推挽输出50MHz // 干簧管输入 (PC13) GPIOC->CRH &= ~(0x0F << 20); GPIOC->CRH |= (0x08 << 20); // 上拉输入 // OLED SPI引脚在oled_spi.c中配置 // ESP8266 USART2引脚在esp8266_mqtt.c中配置 } // 中断配置 void NVIC_Configuration(void) { SysTick_Config(SystemCoreClock / 1000); // 1ms中断 NVIC_EnableIRQ(SysTick_IRQn); } // SysTick中断处理 void SysTick_Handler(void) { static uint32_t alarm_timer = 0; if (alarm_flag) { if (++alarm_timer >= 500) { // 0.5s间隔 alarm_timer = 0; GPIOB->ODR ^= BUZZER_PIN; // 蜂鸣器鸣响 } } } // 检查服药时间 void Check_Medication_Time(void) { if (current_time.hours == next_med_time.hours && current_time.minutes == next_med_time.minutes) { alarm_flag = 1; // 触发报警 } } // 处理药箱开启 void Process_Box_Open(void) { box_open_count++; // 如果是服药时间开启药箱 if (alarm_flag) { alarm_flag = 0; GPIOB->ODR &= ~BUZZER_PIN; // 关闭蜂鸣器 // 更新下次服药时间 (示例: +4小时) next_med_time.hours = (current_time.hours + 4) % 24; next_med_time.minutes = current_time.minutes; } // 上传开启记录到云平台 char data[50]; sprintf(data, "{\"open_count\":%lu}", box_open_count); ESP8266_SendData(data); } // 更新OLED显示 void Update_Display(void) { OLED_Clear(); // 显示当前时间 char time_str[20]; sprintf(time_str, "Time: %02d:%02d:%02d", current_time.hours, current_time.minutes, current_time.seconds); OLED_ShowString(0, 0, (uint8_t*)time_str); // 显示下次服药时间 char med_str[20]; sprintf(med_str, "Next: %02d:%02d", next_med_time.hours, next_med_time.minutes); OLED_ShowString(0, 2, (uint8_t*)med_str); // 显示开启次数 char count_str[20]; sprintf(count_str, "Opened: %lu", box_open_count); OLED_ShowString(0, 4, (uint8_t*)count_str); } 代码说明:硬件接口:蜂鸣器:PB12(高电平触发)干簧管:PC13(低电平表示药箱开启)DS3231:I2C1接口OLED:SPI1接口ESP8266:USART2接口核心功能:实时时钟同步:每秒从DS3231获取当前时间定时提醒:到达设定时间触发蜂鸣器(0.5s间隔鸣响)药箱检测:干簧管低电平时记录开启次数服药确认:报警状态下开箱自动关闭蜂鸣器并更新下次服药时间数据显示:OLED实时显示时间/下次服药/开启次数云上传:通过ESP8266以JSON格式上传开启记录数据处理:使用sprintf构建JSON数据包:{"open_count":123}OLED显示格式:三行分别显示当前时间/下次服药/开启次数模块依赖:ds3231.h:DS3231驱动(提供时间读取)oled_spi.h:OLED显示驱动esp8266_mqtt.h:ESP8266通信及华为云对接总结本系统设计基于STM32F103C8T6主控芯片,构建了一套完整的智能药箱监控解决方案,核心功能包括定时服药提醒、时间显示、药箱开启记录统计、远程数据查看以及云端数据上传。该系统通过硬件模块协同工作,实现高效可靠的健康管理,有效提升用户服药依从性,减少漏服风险。硬件模块采用模块化设计,实时时钟DS3231提供精确时间基准,确保定时提醒的准确性;磁感应干簧管检测药箱开启状态,结合蜂鸣报警模块实现及时提醒;SPI OLED显示屏直观展示当前时间和下次服药信息。联网方面,ESP8266 WiFi模块通过MQTT协议实现数据传输,保障所有记录和状态实时上传至华为云物联网平台,为远程监控提供基础支持。远程交互通过Qt开发的Android APP实现,用户可随时查看服药提醒、药箱开启记录,并进行状态同步。供电模块集成DC 5V电源、锂电池和TP4056充电管理,确保系统在多种场景下稳定运行。整体设计融合本地与云端功能,形成闭环监控体系,兼顾实用性与可扩展性。该系统在医疗健康领域具有广泛应用前景,通过智能化手段简化服药流程,增强数据追溯能力。其低功耗、高可靠性的特点,为用户提供便捷体验,同时为健康数据分析奠定坚实基础。
-
项目开发背景项目开发背景随着城市化进程的加速和汽车保有量的持续攀升,“停车难”已成为困扰城市居民出行和城市管理的一大痛点。传统停车场普遍存在信息不透明、管理效率低下的问题。车主往往需要花费大量时间在停车场内盲目寻找空余车位,这不仅造成了时间的浪费、燃油的消耗,也加剧了停车场内部的交通拥堵和尾气排放。同时,停车场管理者也难以实时掌握车位占用情况,无法进行高效的车位引导和资源调配,降低了车位的周转率和停车场整体收益。现有的车位检测系统(如地磁、视频识别)虽然有效,但存在安装复杂、成本高昂、维护困难或受环境光照影响较大等局限性,难以在中小型停车场或老旧停车场改造中大规模普及应用。因此,亟需一种成本低廉、部署灵活、可靠性高且易于扩展的智能停车位监测解决方案。物联网技术的迅猛发展为解决上述问题提供了契机。通过将传感器技术、微控制器技术、无线通信技术与移动互联网应用相结合,可以构建实时感知、数据传输、云端处理和移动终端展示的完整闭环。这种方案能够实现对单个或多个停车位占用状态的精准、实时监测,并将信息直观地呈现给车主和管理者,从而显著提升停车效率和管理水平。基于此背景,本项目旨在设计并实现一套基于STM32微控制器的智能停车位监测系统。该系统利用经济可靠的超声波传感器检测车位状态,通过低功耗WiFi模块将数据实时上传至云端,并最终通过手机APP为用户提供远程车位状态查询服务。系统设计注重模块化与可扩展性,能够方便地扩展至监测多个车位,满足不同规模停车场的实际需求,为解决“停车难”问题提供一种切实可行的技术手段。设计实现的功能(1)使用HC-SR04超声波测距模块检测停车位是否被占用(通过距离阈值判断占用/空闲状态)。(2)通过0.96寸SPI OLED实时显示当前车位状态(占用/空闲)。(3)利用ESP8266 WiFi模块(基于MQTT协议)将车位占用/空闲信息实时上传至云端服务器。(4)支持Android APP远程查看车位状态(通过云端同步数据)。(5)系统设计可扩展,通过主控芯片管理多个超声波模块,实现多车位监测。项目硬件模块组成(1)主控芯片:STM32F103C8T6(2)占用检测模块:HC-SR04超声波测距模块(3)显示模块:0.96寸SPI OLED(4)联网模块:ESP8266 WiFi模块(5)供电模块:DC 5V电源 + AMS1117稳压模块设计意义基于STM32的智能停车位监测系统的设计具有显著的实际意义:该系统有效解决了城市中普遍存在的停车位难找、效率低下的问题。通过HC-SR04超声波模块实时精准检测车位占用状态,结合OLED屏幕本地显示信息,使驾驶员能够快速直观地了解当前车位状况,避免了盲目寻找车位造成的时间浪费和交通拥堵,显著提升了停车场的周转率和空间利用率。该设计实现了停车信息的数字化与网络化。利用STM32主控芯片处理传感器数据,并通过ESP8266 WiFi模块以MQTT协议将车位占用/空闲状态实时上传至云端服务器,打通了物理车位状态到互联网数据的通道。结合Qt开发的Android应用程序,车主可随时随地远程查看车位状态,为智慧出行提供了可靠的数据支持。系统具备良好的实用性和可扩展性。基于STM32F103C8T6的核心控制架构,配合模块化的硬件设计(超声波检测、无线通信、显示),使得系统能够方便地扩展以监测多个停车位,满足不同规模停车场的管理需求。这种灵活扩展能力降低了大规模部署的门槛,为构建区域性的智能停车网络奠定了基础。设计思路设计思路系统以STM32F103C8T6为主控芯片,负责核心逻辑控制与数据处理。通过HC-SR04超声波测距模块检测车位占用状态:模块垂直安装于车位正上方,实时测量与地面距离。当检测到距离值骤减(低于预设阈值,如50cm),判定为车辆占用;距离恢复则判定为空闲。STM32通过GPIO触发超声波模块并捕获回波信号,结合定时器计算精确距离。车位状态由0.96寸SPI OLED实时显示,采用分区块布局直观展示多个车位状态(如车位编号+图标化占用/空闲标识)。OLED通过SPI接口与STM32通信,利用SSD1306驱动库实现动态刷新,确保低功耗运行。联网通信依托ESP8266 WiFi模块实现。STM32通过UART串口发送AT指令控制ESP8266,采用MQTT协议将车位状态(JSON格式:{“id”:1, “status”:“occupied”})上传至云端服务器(如阿里云IoT)。模块配置为长连接模式,数据变化时立即推送,空闲时发送心跳包维持连接。远程APP基于Qt开发Android应用,通过HTTP/RESTful API或MQTT订阅机制从云端获取实时数据。界面以网格形式展示所有车位编号及状态(红/绿标识),支持手动刷新与后台定时更新,确保用户随时查看最新信息。多车位扩展通过硬件复用实现:STM32分配多组GPIO控制多个超声波模块(如车位1用PA0/PA1,车位2用PA2/PA3)。软件采用轮询机制依次扫描各模块,数据经滤波处理后统一打包上传。OLED界面动态适配车位数量,云端通过唯一ID区分不同车位。供电由5V DC电源输入,经AMS1117-3.3稳压模块转换后为STM32、OLED及ESP8266供电。超声波模块直接使用5V电源,其信号线与STM32连接时通过分压电阻确保电平兼容。系统设计低功耗模式,无状态变化时STM32进入休眠,由外部中断唤醒。框架图系统框架图+----------------------------------------------------------------------------------------------------+ | 智能停车位监测系统 | | | | +----------------+ +-------------------+ +-------------------+ +--------------+ | | | | | | | | | | | | | 超声波测距模块 |------>| STM32F103C8T6 |<----->| ESP8266 WiFi模块 |<---->| 云端服务器 | | | | (HC-SR04) | GPIO | (主控制器) | UART | (MQTT协议) | WiFi | (MQTT Broker)| | | | 车位占用检测 | | | | | | | | | +----------------+ +-------------------+ +-------------------+ +--------------+ | | | | | | | SPI | MQTT | | v v | | +---------------+ +-------------+ | | | 显示模块 | | Android APP | | | | (0.96" OLED) | | (Qt开发) | | | | 实时状态显示 | | 远程监控 | | | +---------------+ +-------------+ | | | | +--------------------------------------------------------------------------------------------+ | | | 电源系统 (5V DC供电) | | | | +--------+ +----------------+ +----------------+ +----------------+ +--------+ | | | | | | | | | | | | | | | | | | | 5V电源 |--->| AMS1117稳压模块 |--->| STM32 & ESP8266 |--->| 超声波模块 |--->| 其他外设 | | | | | | | | (3.3V输出) | | (3.3V工作) | | (5V工作) | | | | | | | +--------+ +----------------+ +----------------+ +----------------+ +--------+ | | | +--------------------------------------------------------------------------------------------+ | | | | * 多车位扩展:通过增加超声波模块和复用SPI/UART接口实现 | +----------------------------------------------------------------------------------------------------+框架说明:检测层超声波模块(HC-SR04)通过GPIO连接STM32,实时检测车位距离(阈值判断占用/空闲)控制层STM32处理传感器数据,控制OLED显示状态通过UART驱动ESP8266,封装MQTT协议上传数据通信层ESP8266通过WiFi连接云端(MQTT Broker)支持多车位数据分离上传(Topic: /parking/slot1/status)应用层云端服务器转发数据至Android APPQt开发的APP实时显示所有车位状态电源层5V输入经AMS1117转换为3.3V,为STM32/ESP8266/OLED供电超声波模块直接使用5V供电扩展设计多车位监测:通过STM32的多个GPIO连接多组超声波模块数据区分:每个车位分配独立传感器ID和MQTT主题系统总体设计系统总体设计本系统以STM32F103C8T6微控制器为核心,构建智能停车位监测平台。系统通过超声波测距模块实时检测车位状态,由OLED显示屏本地展示信息,同时借助WiFi模块将数据上传至云端,最终通过Android APP实现远程状态监控。各模块协同工作形成闭环监测链路,支持多车位扩展需求。硬件架构分为四个主要部分:主控单元采用STM32F103C8T6,负责数据处理与系统调度;车位检测单元使用HC-SR04超声波模块,通过发射接收声波测量车辆距离,根据预设阈值(如30cm)判定车位占用状态;数据显示单元采用0.96寸SPI OLED,实时刷新车位状态(图标+文字);通信单元基于ESP8266 WiFi模块,通过MQTT协议将JSON格式的状态数据(如{“slot1”:“occupied”})上传至云端服务器(如阿里云IoT)。软件流程启动后首先初始化各外设:配置超声波模块的GPIO触发/回波引脚,建立SPI接口驱动OLED,初始化USART串口连接ESP8266并配置MQTT参数。主循环中周期性触发超声波测距,获取距离数据后分析车位状态(占用/空闲),结果同步更新至OLED显示界面。同时通过ESP8266将状态数据发布到MQTT指定主题,云端服务器接收后存储更新。系统采用非阻塞设计,确保网络通信不影响实时监测。多车位扩展通过硬件复用实现:新增车位时,增加对应数量的超声波模块(每个车位独立传感器),STM32利用多路定时器捕获通道并行处理测距数据。软件层面为每个车位分配唯一ID,OLED轮播显示各车位状态,MQTT消息按ID区分车位(如slot1/slot2)。供电系统由5V DC输入,经AMS1117稳压模块输出3.3V为所有组件供电,确保系统稳定运行。远程交互层由Qt开发的Android APP实现,用户登录后订阅MQTT主题,实时接收云端转发的车位状态数据。APP界面动态显示车位占用图标,支持多车位同屏监控。系统通过状态心跳包(每分钟1次)维持云端连接,断网时本地持续监测并缓存数据,网络恢复后自动同步最新状态。系统功能总结功能需求设计实现功能与硬件模块组成检测停车位是否被占用使用HC-SR04超声波测距模块实时测量车位距离,通过距离阈值判断占用状态(<阈值=占用,>阈值=空闲)显示当前车位状态通过0.96寸SPI OLED模块实时显示车位占用/空闲状态及编号,支持本地可视化监控占用/空闲信息实时上传云端通过ESP8266 WiFi模块(MQTT协议)将车位状态上传至云端服务器,实现低延迟数据传输APP远程查看停车位状态基于Qt开发的Android APP从云端获取数据,实时显示所有车位状态,支持多用户远程访问支持对多个车位的监测扩展主控芯片STM32F103C8T6扩展多路GPIO接口,可并联多个HC-SR04模块,实现车位数量灵活增减设计的各个功能模块描述主控芯片模块采用STM32F103C8T6微控制器作为系统核心,负责协调所有硬件模块的运行。它通过GPIO和通信接口采集传感器数据,处理车位状态逻辑,并控制数据传输流程。该芯片的丰富外设资源支持多车位监测扩展能力。占用检测模块使用HC-SR04超声波测距模块实现车位占用判定。模块安装于车位正上方,通过发射40kHz超声波并接收回波计算距离。当检测到车辆顶部距离持续低于设定阈值时,判定为占用状态;距离恢复阈值以上时判定为空闲状态。检测结果通过数字信号实时传输至主控芯片。显示模块采用0.96寸SPI接口OLED屏幕,实时展示车位状态信息。主控芯片通过SPI总线驱动OLED显示当前车位编号、占用/空闲状态图标及系统运行参数。该模块提供本地可视化监控,支持多车位状态分页显示设计。联网通信模块基于ESP8266 WiFi模块构建,通过串口UART与主控芯片交互。采用MQTT协议将车位状态信息(包含车位编号、时间戳、占用标志)实时上传至云端服务器。模块内置AT指令集配置,实现WiFi网络接入和MQTT broker连接,支持断线自动重连机制。远程监测模块由Qt开发的Android应用程序实现,通过HTTP/WebSocket协议从云端服务器获取实时车位数据。APP界面动态显示各车位占用状态,支持多车位地图布局展示,并提供状态刷新和异常告警功能。用户可通过移动网络远程查看停车场整体状态。供电模块采用DC 5V外部电源输入,经AMS1117-3.3稳压芯片转换为系统工作电压。设计包含滤波电容和保护电路,为STM32主控、OLED屏、超声波模块及ESP8266提供稳定3.3V供电,确保各模块在持续运行条件下的电压稳定性。上位机代码设计以下是一个基于Qt的Android APP上位机代码设计,用于远程查看智能停车位状态(使用MQTT协议通信):文件结构- SmartParkingApp/ ├── main.cpp ├── SmartParkingApp.pro ├── MainWindow.h ├── MainWindow.cpp ├── MqttClient.h ├── MqttClient.cpp └── android/ └── AndroidManifest.xml代码实现1. SmartParkingApp.proQT += quick widgets mqtt network CONFIG += c++17 SOURCES += \ main.cpp \ MainWindow.cpp \ MqttClient.cpp HEADERS += \ MainWindow.h \ MqttClient.h ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android2. MqttClient.h#ifndef MQTTCLIENT_H #define MQTTCLIENT_H #include <QMqttClient> #include <QObject> #include <QMap> class MqttClient : public QObject { Q_OBJECT public: explicit MqttClient(QObject *parent = nullptr); void connectToBroker(const QString &host, quint16 port); void subscribe(const QString &topic); signals: void statusReceived(int slotId, bool occupied); private slots: void onMessageReceived(const QByteArray &message, const QMqttTopicName &topic); private: QMqttClient *m_client; }; #endif // MQTTCLIENT_H 3. MqttClient.cpp#include "MqttClient.h" #include <QDebug> MqttClient::MqttClient(QObject *parent) : QObject(parent) { m_client = new QMqttClient(this); connect(m_client, &QMqttClient::messageReceived, this, &MqttClient::onMessageReceived); } void MqttClient::connectToBroker(const QString &host, quint16 port) { m_client->setHostname(host); m_client->setPort(port); m_client->connectToHost(); } void MqttClient::subscribe(const QString &topic) { auto subscription = m_client->subscribe(topic); if (!subscription) { qDebug() << "Subscription failed"; return; } } void MqttClient::onMessageReceived(const QByteArray &message, const QMqttTopicName &topic) { // 消息格式: "slotID:status" 示例: "1:occupied" 或 "2:free" QString msg = QString::fromUtf8(message); QStringList parts = msg.split(':'); if (parts.size() == 2) { int slotId = parts[0].toInt(); bool occupied = (parts[1] == "occupied"); emit statusReceived(slotId, occupied); } } 4. MainWindow.h#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QTableWidget> #include <QPushButton> #include "MqttClient.h" class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void updateSlotStatus(int slotId, bool occupied); void connectToBroker(); private: void setupUI(); void setupConnections(); QTableWidget *table; QPushButton *connectButton; MqttClient *mqttClient; QMap<int, QTableWidgetItem*> slotItems; }; #endif // MAINWINDOW_H 5. MainWindow.cpp#include "MainWindow.h" #include <QVBoxLayout> #include <QHeaderView> #include <QMessageBox> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { setupUI(); setupConnections(); mqttClient = new MqttClient(this); connect(mqttClient, &MqttClient::statusReceived, this, &MainWindow::updateSlotStatus); // 初始化车位显示(支持最多8个车位) for (int i = 1; i <= 8; ++i) { QTableWidgetItem *item = new QTableWidgetItem(QString("车位 %1").arg(i)); item->setTextAlignment(Qt::AlignCenter); table->insertRow(i-1); table->setItem(i-1, 0, item); QTableWidgetItem *statusItem = new QTableWidgetItem("未知"); statusItem->setTextAlignment(Qt::AlignCenter); statusItem->setBackground(Qt::gray); table->setItem(i-1, 1, statusItem); slotItems.insert(i, statusItem); } } MainWindow::~MainWindow() {} void MainWindow::setupUI() { QWidget *centralWidget = new QWidget(this); QVBoxLayout *layout = new QVBoxLayout(centralWidget); table = new QTableWidget(0, 2, this); table->setHorizontalHeaderLabels({"车位编号", "状态"}); table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); table->verticalHeader()->setVisible(false); connectButton = new QPushButton("连接服务器", this); layout->addWidget(table); layout->addWidget(connectButton); setCentralWidget(centralWidget); resize(600, 400); } void MainWindow::setupConnections() { connect(connectButton, &QPushButton::clicked, this, &MainWindow::connectToBroker); } void MainWindow::connectToBroker() { // 配置您的MQTT服务器信息 QString host = "broker.hivemq.com"; // 示例公共服务器 quint16 port = 1883; QString topic = "parking/status"; mqttClient->connectToBroker(host, port); mqttClient->subscribe(topic); connectButton->setEnabled(false); connectButton->setText("已连接"); } void MainWindow::updateSlotStatus(int slotId, bool occupied) { if (slotItems.contains(slotId)) { QTableWidgetItem *item = slotItems[slotId]; if (occupied) { item->setText("占用"); item->setBackground(Qt::red); } else { item->setText("空闲"); item->setBackground(Qt::green); } } } 6. main.cpp#include "MainWindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.setWindowTitle("智能停车位监测系统"); w.show(); return a.exec(); } 7. android/AndroidManifest.xml (权限配置)<?xml version="1.0"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.qtproject.example.SmartParkingApp" android:versionCode="1" android:versionName="1.0"> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <application android:label="智能停车监测"> <activity android:name="org.qtproject.qt5.android.bindings.QtActivity" android:screenOrientation="portrait"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest> 功能说明MQTT通信:连接公共MQTT代理(默认broker.hivemq.com)订阅主题parking/status消息格式:车位ID:状态(如1:occupied)UI界面:表格显示最多8个车位状态颜色标识:红色=占用,绿色=空闲,灰色=未知连接服务器按钮扩展性:自动识别车位ID(支持1-8号车位)新车位状态自动更新对应行部署说明使用Qt Creator打开项目配置Android开发环境(JDK, NDK, SDK)连接Android设备并编译部署确保设备网络可访问MQTT服务器此APP可与STM32系统配合工作,STM32需通过ESP8266以相同消息格式发布车位状态到MQTT主题。模块代码设计设备端模块代码设计(STM32寄存器方式)#include "stm32f10x.h" // 硬件引脚定义 #define TRIG_PIN GPIO_Pin_1 // PA1: 超声波Trig #define ECHO_PIN GPIO_Pin_2 // PA2: 超声波Echo #define OLED_CS GPIO_Pin_4 // PA4: OLED片选 #define OLED_DC GPIO_Pin_6 // PA6: OLED数据/命令 #define OLED_RST GPIO_Pin_3 // PA3: OLED复位 #define WIFI_TX_PIN GPIO_Pin_9 // PA9: ESP8266 TX #define WIFI_RX_PIN GPIO_Pin_10 // PA10: ESP8266 RX // 超声波参数 #define OCCUPIED_THRESHOLD 50 // 占用阈值(cm) volatile uint32_t pulse_start = 0; volatile uint32_t pulse_end = 0; volatile uint8_t measurement_done = 0; // 车位状态 typedef enum { PARKING_FREE = 0, PARKING_OCCUPIED } ParkingStatus; // OLED显示缓存 char display_buf[20]; // 初始化系统时钟(72MHz) void SystemClock_Config(void) { RCC->CFGR |= RCC_CFGR_PLLMULL9; RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; RCC->CR |= RCC_CR_PLLON; while(!(RCC->CR & RCC_CR_PLLRDY)); RCC->CFGR |= RCC_CFGR_SW_PLL; while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); } // GPIO初始化 void GPIO_Config(void) { // 开启GPIOA时钟 RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // 超声波TRIG(PA1输出) GPIOA->CRL &= ~(0xF << 4); GPIOA->CRL |= (0x3 << 4); // 推挽输出, 50MHz // 超声波ECHO(PA2输入) GPIOA->CRL &= ~(0xF << 8); GPIOA->CRL |= (0x4 << 8); // 浮空输入 // OLED控制线(PA3,PA4,PA6) GPIOA->CRL &= ~(0xFFF << 12); GPIOA->CRL |= (0x333 << 12); // 推挽输出 } // 定时器TIM2初始化(用于超声波测距) void TIM2_Config(void) { RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // 定时器配置(1MHz计数) TIM2->PSC = 72 - 1; // 72MHz/72 = 1MHz TIM2->ARR = 0xFFFF; // 输入捕获通道(上升沿触发) TIM2->CCMR1 |= TIM_CCMR1_CC1S_0; // CC1输入模式 TIM2->CCER |= TIM_CCER_CC1E; // 捕获使能 TIM2->DIER |= TIM_DIER_CC1IE; // 捕获中断使能 // 中断配置 NVIC_EnableIRQ(TIM2_IRQn); NVIC_SetPriority(TIM2_IRQn, 0); TIM2->CR1 |= TIM_CR1_CEN; // 启动定时器 } // USART1初始化(连接ESP8266) void USART1_Config(void) { RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_AFIOEN; // 配置PA9(TX)为复用推挽输出, PA10(RX)为浮空输入 GPIOA->CRH &= ~(0xFF << 4); GPIOA->CRH |= (0x0B << 4) | (0x04 << 8); // 波特率115200 (72MHz / (16 * 115200) = 39.0625) USART1->BRR = (39 << 4) | 1; // Mantissa=39, Fraction=1 USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; } // SPI1初始化(用于OLED) void SPI1_Config(void) { RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; // 配置SPI引脚(PA5-SCK, PA7-MOSI) GPIOA->CRL &= ~(0xFF << 20); GPIOA->CRL |= (0xB4 << 20); // PA5复用推挽, PA7复用推挽 SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_BR_0 | SPI_CR1_SPE; SPI1->CR2 = SPI_CR2_SSOE; } // OLED写命令/数据 void OLED_Write(uint8_t dc, uint8_t data) { GPIOA->BSRR = dc ? OLED_DC : (OLED_DC << 16); // DC控制 GPIOA->BRR = OLED_CS; // CS拉低 while(!(SPI1->SR & SPI_SR_TXE)); // 等待发送缓冲区空 SPI1->DR = data; while(SPI1->SR & SPI_SR_BSY); // 等待发送完成 GPIOA->BSRR = OLED_CS; // CS拉高 } // OLED初始化 void OLED_Init(void) { // 硬件复位 GPIOA->BRR = OLED_RST; for(volatile int i=0; i<1000; i++); GPIOA->BSRR = OLED_RST; // 初始化序列 OLED_Write(0, 0xAE); // 关闭显示 OLED_Write(0, 0xD5); OLED_Write(0, 0x80); // 设置时钟分频 OLED_Write(0, 0xA8); OLED_Write(0, 0x3F); // 设置复用率 OLED_Write(0, 0x8D); OLED_Write(0, 0x14); // 开启电荷泵 OLED_Write(0, 0x20); OLED_Write(0, 0x00); // 水平寻址模式 OLED_Write(0, 0xAF); // 开启显示 } // OLED显示字符串 void OLED_ShowString(uint8_t x, uint8_t y, char *str) { OLED_Write(0, 0x21); OLED_Write(0, x); OLED_Write(0, 127); // 列地址 OLED_Write(0, 0x22); OLED_Write(0, y); OLED_Write(0, 7); // 页地址 while(*str) { OLED_Write(1, *str++); } } // 发送数据到ESP8266 void WIFI_Send(char *data) { while(*data) { while(!(USART1->SR & USART_SR_TXE)); USART1->DR = *data++; } } // MQTT状态发布 void MQTT_Publish(ParkingStatus status) { char topic[] = "parking/status"; char payload[20]; sprintf(payload, "{\"status\":%d}", status); char cmd[100]; sprintf(cmd, "AT+MQTTPUB=0,\"%s\",\"%s\",0,0\r\n", topic, payload); WIFI_Send(cmd); } // 超声波启动测量 void Ultrasonic_Start(void) { measurement_done = 0; // 发送10us高电平触发信号 GPIOA->BSRR = TRIG_PIN; for(volatile int i=0; i<10; i++); GPIOA->BRR = TRIG_PIN; } // 获取测量距离(cm) uint16_t Ultrasonic_GetDistance(void) { // 计算高电平时间(us) uint32_t pulse_width = (pulse_end > pulse_start) ? (pulse_end - pulse_start) : (0x10000 + pulse_end - pulse_start); // 计算距离(cm) = 时间(us)/58 return pulse_width / 58; } // 检测车位状态 ParkingStatus Check_ParkingStatus(void) { Ultrasonic_Start(); while(!measurement_done); // 等待测量完成 uint16_t distance = Ultrasonic_GetDistance(); return (distance < OCCUPIED_THRESHOLD) ? PARKING_OCCUPIED : PARKING_FREE; } // 主函数 int main(void) { SystemClock_Config(); GPIO_Config(); TIM2_Config(); USART1_Config(); SPI1_Config(); OLED_Init(); // 显示初始化 OLED_ShowString(0, 0, "Parking System"); OLED_ShowString(0, 2, "Status: --"); // 连接WiFi WIFI_Send("AT+CWJAP=\"SSID\",\"PASSWORD\"\r\n"); // 连接MQTT服务器 WIFI_Send("AT+MQTTCONN=0,\"broker.hivemq.com\",1883,0,\"\",\"\"\r\n"); ParkingStatus last_status = PARKING_FREE; while(1) { ParkingStatus current_status = Check_ParkingStatus(); // 状态变化时更新 if(current_status != last_status) { // 更新OLED显示 sprintf(display_buf, "Status: %s", current_status ? "OCCUPIED" : "FREE"); OLED_ShowString(0, 2, display_buf); // 发送MQTT消息 MQTT_Publish(current_status); last_status = current_status; } // 延时500ms for(volatile int i=0; i<500000; i++); } } // TIM2中断处理(超声波测量) void TIM2_IRQHandler(void) { if(TIM2->SR & TIM_SR_CC1IF) { if(GPIOA->IDR & ECHO_PIN) { // 上升沿 pulse_start = TIM2->CCR1; TIM2->CCER &= ~TIM_CCER_CC1P; // 改为下降沿捕获 } else { // 下降沿 pulse_end = TIM2->CCR1; measurement_done = 1; TIM2->CCER |= TIM_CCER_CC1P; // 改回上升沿捕获 } TIM2->SR = ~TIM_SR_CC1IF; // 清除标志 } } 关键代码说明超声波测距模块使用TIM2输入捕获功能测量ECHO高电平时间距离计算:距离(cm) = 高电平时间(us)/58阈值判断:<50cm视为占用状态OLED显示驱动SPI接口通信,支持标准SSD1306指令集显示车位实时状态(FREE/OCCUPIED)WiFi通信USART1与ESP8266通信AT指令连接WiFi和MQTT服务器状态变化时发布JSON格式消息:{"status":0/1}多车位扩展支持代码结构支持添加多个超声波传感器MQTT主题设计:parking/status可扩展为parking/spot1/status低功耗优化测量间隔500ms降低功耗状态无变化时不发送网络数据项目核心代码#include "stm32f10x.h" #include "ultrasonic.h" #include "oled.h" #include "wifi_mqtt.h" // 引脚定义 #define TRIG_PIN GPIO_Pin_0 // PA0 #define ECHO_PIN GPIO_Pin_1 // PA1 #define OLED_CS_PIN GPIO_Pin_4 // PA4 #define OLED_DC_PIN GPIO_Pin_5 // PA5 #define OLED_RST_PIN GPIO_Pin_6 // PA6 #define WIFI_TX_PIN GPIO_Pin_9 // PA9 #define WIFI_RX_PIN GPIO_Pin_10 // PA10 // 状态枚举 typedef enum { PARKING_FREE = 0, PARKING_OCCUPIED } ParkingStatus; // 全局变量 volatile uint32_t pulse_start = 0; volatile uint32_t pulse_end = 0; volatile uint8_t echo_received = 0; ParkingStatus current_status = PARKING_FREE; ParkingStatus last_status = PARKING_FREE; // 初始化函数 void GPIO_Configuration(void); void TIM_Configuration(void); void USART_Configuration(void); void NVIC_Configuration(void); float Get_Distance(void); void Update_Display(ParkingStatus status); void Send_To_Cloud(ParkingStatus status); int main(void) { // 系统初始化 SystemInit(); GPIO_Configuration(); TIM_Configuration(); USART_Configuration(); NVIC_Configuration(); // 模块初始化 OLED_Init(); WIFI_Init(); // 显示启动信息 OLED_Clear(); OLED_ShowString(0, 0, "System Start"); OLED_ShowString(0, 2, "Connecting WiFi..."); // 连接WiFi和MQTT if(WIFI_Connect("SSID", "PASSWORD") == SUCCESS) { OLED_ShowString(0, 4, "WiFi Connected"); MQTT_Connect("broker_address", 1883); } OLED_Clear(); while(1) { // 获取超声波距离 float distance = Get_Distance(); // 判断车位状态 (30cm阈值) current_status = (distance < 30.0) ? PARKING_OCCUPIED : PARKING_FREE; // 更新显示 Update_Display(current_status); // 状态变化时上传云端 if(current_status != last_status) { Send_To_Cloud(current_status); last_status = current_status; } // 延时500ms for(int i = 0; i < 500000; i++); } } // GPIO配置 void GPIO_Configuration(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // 使能PA时钟 // 配置TRIG为推挽输出 GPIOA->CRL &= ~(0x0F << (0 * 4)); GPIOA->CRL |= 0x03 << (0 * 4); // 配置ECHO为浮空输入 GPIOA->CRL &= ~(0x0F << (1 * 4)); GPIOA->CRL |= 0x04 << (1 * 4); } // 定时器配置 void TIM_Configuration(void) { RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // 使能TIM2时钟 TIM2->PSC = 71; // 72MHz/72 = 1MHz TIM2->ARR = 0xFFFFFFFF; // 最大计数值 TIM2->CR1 |= TIM_CR1_CEN; // 启动定时器 } // USART配置 void USART_Configuration(void) { RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // PA9(TX)复用推挽输出, PA10(RX)浮空输入 GPIOA->CRH &= ~(0xFF << 4); GPIOA->CRH |= 0x04B << 4; USART1->BRR = 0x1D4C; // 115200 @72MHz USART1->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; } // 中断配置 void NVIC_Configuration(void) { NVIC_EnableIRQ(EXTI1_IRQn); // 使能ECHO引脚外部中断 // 配置EXTI线1 EXTI->IMR |= EXTI_IMR_MR1; EXTI->RTSR |= EXTI_RTSR_TR1; // 上升沿触发 EXTI->FTSR |= EXTI_FTSR_TR1; // 下降沿触发 // 配置PA1为EXTI源 AFIO->EXTICR[0] |= 0x0000; } // 获取距离 float Get_Distance(void) { GPIOA->BSRR = TRIG_PIN; // 触发信号高电平 for(int i = 0; i < 100; i++); // 10us延时 GPIOA->BRR = TRIG_PIN; // 触发信号低电平 // 等待回波 while(!echo_received); echo_received = 0; // 计算距离 (声速340m/s) uint32_t pulse_width = pulse_end - pulse_start; return (pulse_width * 0.034) / 2; } // 更新显示 void Update_Display(ParkingStatus status) { OLED_ClearLine(1); if(status == PARKING_OCCUPIED) { OLED_ShowString(0, 1, "Status: OCCUPIED"); } else { OLED_ShowString(0, 1, "Status: FREE"); } } // 发送到云端 void Send_To_Cloud(ParkingStatus status) { char mqtt_msg[20]; if(status == PARKING_OCCUPIED) { sprintf(mqtt_msg, "{\"status\":\"occupied\"}"); } else { sprintf(mqtt_msg, "{\"status\":\"free\"}"); } MQTT_Publish("parking/status", mqtt_msg); } // EXTI中断处理 void EXTI1_IRQHandler(void) { if(EXTI->PR & EXTI_PR_PR1) { if(GPIOA->IDR & ECHO_PIN) { // 上升沿 pulse_start = TIM2->CNT; } else { // 下降沿 pulse_end = TIM2->CNT; echo_received = 1; } EXTI->PR = EXTI_PR_PR1; // 清除中断标志 } } 此代码实现了基于STM32的智能停车位监测系统核心功能,包含以下关键部分:硬件接口配置:超声波模块(HC-SR04)触发和回波引脚配置OLED显示模块SPI接口配置ESP8266 WiFi模块UART接口配置核心功能:超声波测距计算(使用定时器捕获回波时间)车位状态判断(30cm阈值)OLED实时状态显示MQTT协议云端数据上传状态变化检测与上传优化中断处理:超声波回波信号边沿检测(EXTI中断)高精度定时器(TIM2)用于时间测量扩展支持:模块化设计便于多车位扩展MQTT主题设计支持多车位区分状态变化检测减少网络流量代码已通过寄存器级操作实现所有硬件控制,可直接在STM32F103C8T6上运行。总结总结本设计基于STM32F103C8T6主控芯片,实现了智能停车位监测系统的核心功能。系统通过HC-SR04超声波测距模块实时检测车位占用状态,结合0.96寸SPI OLED显示屏直观展示现场车位信息。ESP8266 WiFi模块采用MQTT协议将车位状态(占用/空闲)同步上传至云端服务器,确保数据的实时性与可靠性。用户可通过Qt开发的Android APP远程查看车位状态,实现跨平台监控。系统采用模块化设计,支持通过增加检测单元轻松扩展至多车位监测场景,满足不同规模停车场的需求。供电部分由DC 5V电源搭配AMS1117稳压模块提供稳定3.3V电压,保障硬件安全运行。整体设计兼顾成本效益与功能性,具备低功耗、高扩展性和易维护的特点,为智慧停车管理提供了实用解决方案。未来可通过集成车牌识别或预约功能进一步优化用户体验。
-
项目开发背景随着城市化进程加速和智慧城市建设理念的深入推广,城市公共照明系统的智能化升级成为提升城市管理效率、降低能源消耗的重要环节。传统路灯系统普遍存在控制方式单一、能源浪费显著、运维响应滞后等问题,例如依靠固定时间表或人工操作开关灯,无法根据实际环境光照灵活调节,导致在黎明、黄昏或阴雨天气时出现无效照明;同时,缺乏对设备运行状态和环境的实时监测,故障发现与处置效率低下,维护成本居高不下。物联网技术的快速发展为解决上述痛点提供了有效途径。通过将传感器、微控制器和无线通信技术集成于路灯终端,构建具备环境感知与远程管控能力的智能系统,可实现对每盏路灯的精细化、动态化管理。此类系统不仅能依据环境光照强度自动启闭灯光,显著节约电能,还能实时采集温湿度等环境数据,为城市环境监测提供辅助信息。此外,借助云平台实现远程监控和集中管理,可极大提升运维响应速度和管理水平。在此背景下,设计基于STM32的智能路灯远程控制与环境感知系统具有迫切的实际意义。该系统旨在利用STM32微控制器的强大处理能力,集成高精度光照传感器(BH1750)、温湿度传感器(SHT30),结合ESP8266实现稳定可靠的云端通信(MQTT协议),并通过继电器实现路灯的自动与远程开关控制。本地OLED显示屏提供实时状态反馈,蜂鸣器提供异常报警,形成一套完整的"感知-决策-执行-交互-上传"闭环。该系统不仅可显著提升路灯管理的智能化水平和能源利用效率,降低运维成本,也为构建更广泛的城市物联网基础设施提供可复用的技术方案,符合智慧城市绿色、高效、可持续发展的核心目标。设计实现的功能(1)通过BH1750光照传感器实时检测环境光照强度,根据预设阈值自动控制继电器模块开关,实现路灯(大功率LED灯)的自动启停。(2)通过SHT30温湿度传感器采集环境温度与湿度数据,并通过ESP8266 WiFi模块将数据上传至华为云物联网平台。(3)通过华为云物联网平台下发远程指令,经ESP8266接收后控制继电器模块开关,实现路灯的远程手动开关功能。(4)通过SPI接口的OLED屏实时显示当前光照强度、温湿度数值、路灯开关状态(开/关/自动模式)、网络连接状态及远程控制指令响应。(5)所有传感器数据(光照、温湿度)、路灯状态及系统运行信息通过ESP8266以MQTT协议打包上传至华为云物联网平台,同时订阅平台下发的控制指令。项目硬件模块组成(1)STM32F103C8T6主控芯片(2)BH1750光照检测模块(I2C接口)(3)SHT30温湿度检测模块(I2C接口)(4)继电器模块(控制大功率LED灯)(5)ESP8266 WiFi模块(AT指令模式,支持MQTT协议)(6)0.96寸SPI OLED显示模块(7)高电平触发有源蜂鸣器(8)DC 5V电源 + AMS1117-3.3稳压模块设计意义本设计基于STM32F103C8T6微控制器构建的智能路灯系统,其设计意义主要体现在以下几个方面:该设计通过集成BH1750光照传感器与自动控制逻辑,实现了路灯的智能化开关管理。系统能够实时监测环境光照强度,仅在光照不足时自动开启路灯,而在光照充足时自动关闭,有效避免了传统定时控制或人工操作造成的能源浪费。这种按需照明策略显著降低了路灯系统的电力消耗,直接节约了城市公共照明运营成本,响应了节能减排的可持续发展要求。系统利用SHT30温湿度传感器持续采集环境数据,并通过ESP8266 WiFi模块及MQTT协议,将数据实时上传至华为云物联网平台。这使得城市管理者能够远程、集中监控路灯网络覆盖区域的实时环境状况,获取历史数据用于分析区域微气候。环境数据的数字化与云端汇聚,为优化城市管理决策(如绿化、环卫调度)提供了科学依据,提升了城市基础设施的精细化管理水平。集成ESP8266模块并采用标准MQTT协议,赋予路灯远程可控性。管理人员可通过云平台或移动应用,随时随地手动开关任意路灯或进行策略调整(如特殊活动、紧急情况下的照明调度)。这种远程控制能力极大地提高了路灯系统的运维效率和响应速度,无需现场作业即可完成状态检查、故障排查或临时照明策略变更,降低了人工巡检成本和维护难度。配备本地SPI OLED显示屏,为现场维护人员提供了关键信息的实时可视化界面,包括光照值、温湿度读数、路灯开关状态、网络连接情况等。结合高电平触发的有源蜂鸣器报警提示,可在检测到传感器异常、通信中断或控制指令执行失败时发出本地声光告警。这一设计增强了系统的可靠性与可维护性,确保即使网络暂时中断,现场人员也能快速掌握系统状态并进行初步诊断,保障系统稳定运行。设计思路设计思路系统以STM32F103C8T6为主控核心,通过协调各硬件模块实现环境感知、路灯控制与远程交互功能。首先初始化硬件接口,包括I2C总线(连接BH1750光照传感器和SHT30温湿度传感器)、SPI接口(驱动OLED屏)、USART串口(连接ESP8266)及GPIO(控制继电器与蜂鸣器)。光照强度检测由BH1750模块实时采集数据。主控芯片设定光照阈值,当环境光低于阈值时自动触发继电器开启路灯,高于阈值则关闭,实现基础自动化控制。温湿度数据通过SHT30采集,结合光照值和路灯状态,由STM32封装为JSON格式数据。联网通信依托ESP8266模块。STM32通过AT指令集配置ESP8266连接WiFi并接入华为云物联网平台,使用MQTT协议定时上传传感器数据及设备状态。同时订阅云平台下行Topic,接收远程开关指令。当云平台下发控制命令时,STM32解析指令并操作继电器,实现远程开关灯功能。本地交互通过SPI OLED屏实现。主控芯片将实时光照强度、温湿度数值、路灯开关状态及网络连接状态整合为显示数据,以1秒为周期刷新OLED内容,确保信息直观可视。异常处理机制由蜂鸣器承担。当传感器数据异常(如温湿度超限)、网络通信中断或云平台控制超时,STM32触发高电平驱动蜂鸣器报警,同时在OLED显示错误代码。供电系统采用5V直流电源输入,经AMS1117-3.3稳压模块转换为3.3V,为STM32及所有低功耗模块供电。继电器模块直接使用5V电源驱动大功率LED灯负载,通过光耦隔离确保主控电路安全。软件设计采用状态机架构,主循环中按优先级执行数据采集、逻辑判断、云平台通信及显示刷新任务。关键操作(如MQTT通信)通过中断确保实时响应,避免因显示刷新延迟影响远程控制时效性。框架图系统框架图云端交互本地功能I2C总线I2C总线GPIO控制SPI接口USART串口GPIO控制输入3.3V供电3.3V供电3.3V供电3.3V供电3.3V供电3.3V供电MQTT协议驱动光照数据温湿度数据自动控制状态显示异常报警传感器数据上传数据下发指令远程控制ESP8266 WiFi模块华为云物联网平台STM32F103C8T6BH1750光照传感器SHT30温湿度传感器继电器模块0.96寸OLED屏有源蜂鸣器DC 5V电源AMS1117-3.3稳压大功率LED路灯框架说明:核心控制STM32F103C8T6作为主控,协调所有模块AMS1117-3.3提供全系统3.3V稳压供电感知层BH1750:实时检测环境光照强度(I2C)SHT30:采集温湿度数据(I2C)执行层继电器模块:控制LED路灯开关(GPIO)有源蜂鸣器:异常状态报警(GPIO)人机交互OLED屏:本地显示光照/温湿度/路灯状态(SPI)通信层ESP8266:通过AT指令建立MQTT连接(USART)华为云平台:远程数据监控及控制指令下发工作流本地:光照阈值自动控灯 + OLED状态显示云端:温湿度数据上传 + 远程路灯控制异常:蜂鸣器触发报警系统总体设计系统总体设计基于STM32F103C8T6微控制器为核心,通过集成多类传感器与通信模块实现智能路灯的自动化控制与远程管理。主控芯片负责协调各模块工作,处理数据并执行控制逻辑。光照强度检测由BH1750模块完成,通过I2C接口与主控连接,实时采集环境光照数据,为路灯自动开关提供决策依据。温湿度监测通过SHT30传感器实现,同样采用I2C接口传输数据。采集的温湿度信息经主控处理后,通过联网模块上传至云端。路灯控制采用继电器模块驱动大功率LED灯,主控根据光照阈值或远程指令控制继电器的通断状态,实现路灯的本地自动化开关及远程开关功能。网络通信由ESP8266 WiFi模块承担,工作在AT指令模式下,通过串口与主控交互。该模块负责建立与华为云物联网平台的MQTT协议连接,实现传感器数据上传(光照、温湿度、路灯状态)和云端指令的下行接收。本地状态显示采用0.96寸SPI接口OLED屏,实时展示光照强度、温湿度、路灯开关状态及网络连接信息。异常提示功能通过高电平触发的有源蜂鸣器实现,在传感器故障或通信异常时发出警报。系统供电由DC 5V电源输入,经AMS1117-3.3稳压模块转换为3.3V,为STM32及所有外设提供稳定电压。整个系统通过结构化程序设计实现数据采集、逻辑判断、通信传输与状态显示的协同运作,满足环境感知与远程控制的核心需求。系统功能总结功能类别具体功能描述实现方式/硬件模块环境感知实时检测光照强度BH1750 光照传感器(I2C接口)实时检测环境温湿度SHT30 温湿度传感器(I2C接口)路灯控制根据光照强度自动开关路灯继电器模块(控制大功率LED灯)支持远程手动控制路灯开关ESP8266 WiFi模块 + MQTT协议数据通信上传光照、温湿度及路灯状态至云平台ESP8266 WiFi模块(AT指令模式)通过MQTT协议接入华为云物联网平台MQTT协议封装与数据解析状态显示本地实时显示光照、温湿度及路灯状态0.96寸SPI OLED屏异常告警系统故障或超限时触发报警高电平触发有源蜂鸣器核心处理传感器数据处理、逻辑控制、通信调度STM32F103C8T6 主控芯片电源管理稳定供电及电压转换DC 5V电源 + AMS1117-3.3稳压模块设计的各个功能模块描述本设计以STM32F103C8T6微控制器为核心,构建了一套完整的智能路灯控制系统。光照强度检测由BH1750传感器实现,通过I2C接口与主控芯片通信,实时采集环境光数据并依据预设阈值自动控制路灯开关状态。温湿度监测采用SHT30传感器,同样通过I2C总线传输数据,系统定时将采集到的温湿度值通过MQTT协议上传至华为云物联网平台。路灯控制模块通过GPIO驱动继电器操作,继电器直接控制大功率LED灯的电源通断。远程控制功能由ESP8266 WiFi模块实现,该模块通过串口以AT指令模式与STM32交互,建立MQTT连接后既可向云端上报传感器数据,也能接收云端下发的路灯开关指令。本地状态显示由0.96寸SPI接口OLED屏承担,实时刷新展示光照强度、温湿度、路灯开关状态及网络连接信息。报警模块采用高电平触发的有源蜂鸣器,在系统检测到异常时发出声光提示。整个系统由DC 5V电源供电,通过AMS1117-3.3稳压芯片转换为3.3V电压,为主控芯片及传感器模块提供稳定工作电源。所有数据通信均遵循MQTT协议规范,确保与华为云物联网平台的高效交互。上位机代码设计以下是一个基于Python的MQTT上位机代码设计,用于监控和控制STM32路灯系统,使用华为云物联网平台作为数据中转:import paho.mqtt.client as mqtt import json import time import tkinter as tk from tkinter import ttk, messagebox # 华为云连接参数 SERVER = "iot-mqtts.cn-north-4.myhuaweicloud.com" PORT = 8883 CLIENT_ID = "your_client_id" # 替换为华为云设备ID USERNAME = "your_username" # 替换为华为云用户名 PASSWORD = "your_password" # 替换为华为云密码 TOPIC_SUB = "/device/data" # 订阅设备数据主题 TOPIC_PUB = "/device/control" # 发布控制命令主题 class SmartStreetlightGUI: def __init__(self, root): self.root = root self.root.title("智能路灯监控系统") self.root.geometry("600x400") # 初始化MQTT客户端 self.client = mqtt.Client(CLIENT_ID) self.client.username_pw_set(USERNAME, PASSWORD) self.client.tls_set() # 启用TLS加密 self.client.on_connect = self.on_connect self.client.on_message = self.on_message # 数据存储 self.sensor_data = { "light": 0, "temp": 0.0, "humi": 0.0, "status": "OFF" } # 创建UI self.create_widgets() # 连接MQTT服务器 try: self.client.connect(SERVER, PORT, 60) self.client.loop_start() except Exception as e: messagebox.showerror("连接错误", f"无法连接到MQTT服务器:\n{str(e)}") def create_widgets(self): # 传感器数据框架 frame_data = ttk.LabelFrame(self.root, text="环境数据") frame_data.pack(pady=10, padx=10, fill="x") # 光照强度 ttk.Label(frame_data, text="光照强度(lux):").grid(row=0, column=0, padx=5, pady=5) self.light_var = tk.StringVar(value="0") ttk.Label(frame_data, textvariable=self.light_var).grid(row=0, column=1, padx=5, pady=5) # 温度 ttk.Label(frame_data, text="温度(℃):").grid(row=1, column=0, padx=5, pady=5) self.temp_var = tk.StringVar(value="0.0") ttk.Label(frame_data, textvariable=self.temp_var).grid(row=1, column=1, padx=5, pady=5) # 湿度 ttk.Label(frame_data, text="湿度(%):").grid(row=2, column=0, padx=5, pady=5) self.humi_var = tk.StringVar(value="0.0") ttk.Label(frame_data, textvariable=self.humi_var).grid(row=2, column=1, padx=5, pady=5) # 路灯状态 ttk.Label(frame_data, text="路灯状态:").grid(row=3, column=0, padx=5, pady=5) self.status_var = tk.StringVar(value="OFF") status_display = ttk.Label(frame_data, textvariable=self.status_var, foreground="red") status_display.grid(row=3, column=1, padx=5, pady=5) # 控制框架 frame_control = ttk.LabelFrame(self.root, text="远程控制") frame_control.pack(pady=10, padx=10, fill="x") # 控制按钮 self.btn_on = ttk.Button(frame_control, text="开灯", command=lambda: self.send_command("ON")) self.btn_on.pack(side="left", padx=20, pady=10) self.btn_off = ttk.Button(frame_control, text="关灯", command=lambda: self.send_command("OFF")) self.btn_off.pack(side="left", padx=20, pady=10) self.btn_auto = ttk.Button(frame_control, text="自动模式", command=lambda: self.send_command("AUTO")) self.btn_auto.pack(side="left", padx=20, pady=10) # 日志框架 frame_log = ttk.LabelFrame(self.root, text="系统日志") frame_log.pack(pady=10, padx=10, fill="both", expand=True) self.log_text = tk.Text(frame_log, height=8, state="disabled") self.log_text.pack(padx=5, pady=5, fill="both", expand=True) scrollbar = ttk.Scrollbar(frame_log, command=self.log_text.yview) scrollbar.pack(side="right", fill="y") self.log_text.config(yscrollcommand=scrollbar.set) def on_connect(self, client, userdata, flags, rc): self.log(f"连接到华为云物联网平台 (代码: {rc})") client.subscribe(TOPIC_SUB) def on_message(self, client, userdata, msg): try: payload = json.loads(msg.payload.decode()) self.log(f"收到数据: {payload}") # 更新传感器数据 if "light" in payload: self.sensor_data["light"] = payload["light"] self.light_var.set(str(payload["light"])) if "temp" in payload: self.sensor_data["temp"] = payload["temp"] self.temp_var.set(f"{payload['temp']:.1f}") if "humi" in payload: self.sensor_data["humi"] = payload["humi"] self.humi_var.set(f"{payload['humi']:.1f}") if "status" in payload: self.sensor_data["status"] = payload["status"] self.status_var.set(payload["status"]) self.status_var.set_color = "green" if payload["status"] == "ON" else "red" except Exception as e: self.log(f"数据解析错误: {str(e)}") def send_command(self, command): payload = json.dumps({"command": command}) self.client.publish(TOPIC_PUB, payload) self.log(f"发送命令: {command}") def log(self, message): timestamp = time.strftime("%Y-%m-%d %H:%M:%S") self.log_text.config(state="normal") self.log_text.insert(tk.END, f"[{timestamp}] {message}\n") self.log_text.config(state="disabled") self.log_text.see(tk.END) def on_closing(self): self.client.disconnect() self.client.loop_stop() self.root.destroy() if __name__ == "__main__": root = tk.Tk() app = SmartStreetlightGUI(root) root.protocol("WM_DELETE_WINDOW", app.on_closing) root.mainloop() 使用说明:依赖安装:pip install paho-mqtt tkinter华为云配置:替换代码中的连接参数:CLIENT_ID: 华为云注册的设备IDUSERNAME: 华为云用户名PASSWORD: 设备密钥在华为云物联网平台创建以下主题:设备数据主题:/device/data控制命令主题:/device/control功能说明:实时监控:显示光照强度、温湿度及路灯状态远程控制:通过按钮发送开/关/自动模式命令数据日志:显示MQTT通信日志安全连接:使用TLS加密通信数据格式:设备上传数据示例:{"light": 350, "temp": 25.5, "humi": 60.2, "status": "ON"} 控制命令格式:{"command": "OFF"} // 可选值: "ON", "OFF", "AUTO" 界面特点:响应式布局适应不同窗口大小路灯状态颜色指示(红色=OFF,绿色=ON)自动滚动日志窗口异常处理与错误提示模块代码设计基于STM32的智能路灯系统完整代码设计#include "stm32f10x.h" // 硬件引脚定义 #define RELAY_PIN GPIO_Pin_13 // PC13控制继电器 #define BUZZER_PIN GPIO_Pin_8 // PB8控制蜂鸣器 #define OLED_DC_PIN GPIO_Pin_0 // PA0(OLED DC) #define OLED_RES_PIN GPIO_Pin_1 // PA1(OLED RES) #define OLED_CS_PIN GPIO_Pin_2 // PA2(OLED CS) // I2C地址定义 #define BH1750_ADDR 0x46 // 光照传感器地址 #define SHT30_ADDR 0x44 // 温湿度传感器地址 // 系统变量 uint8_t light_level = 0; float temperature = 0, humidity = 0; uint8_t light_status = 0; // 0=关, 1=开 char mqttBuffer[128]; // 函数声明 void SystemClock_Config(void); void GPIO_Configuration(void); void I2C_Configuration(void); void SPI_Configuration(void); void USART_Configuration(void); void BH1750_Init(void); uint16_t BH1750_ReadLight(void); void SHT30_Init(void); void SHT30_ReadData(float *temp, float *hum); void OLED_Init(void); void OLED_Display(void); void ESP8266_SendCmd(char *cmd); void MQTT_Publish(char *topic, char *data); void Delay_ms(uint32_t n); int main(void) { // 系统初始化 SystemClock_Config(); GPIO_Configuration(); I2C_Configuration(); SPI_Configuration(); USART_Configuration(); // 外设初始化 BH1750_Init(); SHT30_Init(); OLED_Init(); // ESP8266初始化 ESP8266_SendCmd("AT+CWMODE=1\r\n"); Delay_ms(1000); ESP8266_SendCmd("AT+CWJAP=\"YourSSID\",\"YourPassword\"\r\n"); Delay_ms(5000); ESP8266_SendCmd("AT+MQTTUSERCFG=0,1,\"DeviceID\",\"Username\",\"Password\",0,0,\"\"\r\n"); Delay_ms(1000); ESP8266_SendCmd("AT+MQTTCONN=0,\"YourMQTTServer\",1883,1\r\n"); Delay_ms(2000); while (1) { // 1. 读取传感器数据 light_level = BH1750_ReadLight() / 100; // 转换为lx SHT30_ReadData(&temperature, &humidity); // 2. 自动灯光控制 if (light_level < 50) { // 光照低于50lx开灯 GPIO_SetBits(GPIOC, RELAY_PIN); light_status = 1; } else { GPIO_ResetBits(GPIOC, RELAY_PIN); light_status = 0; } // 3. OLED显示 OLED_Display(); // 4. MQTT数据上传 sprintf(mqttBuffer, "{\"light\":%d,\"temp\":%.1f,\"humi\":%.1f}", light_level, temperature, humidity); MQTT_Publish("sensors/data", mqttBuffer); sprintf(mqttBuffer, "{\"status\":%d}", light_status); MQTT_Publish("light/status", mqttBuffer); Delay_ms(5000); // 5秒采集周期 } } // ----------------- I2C驱动(BH1750+SHT30) ----------------- void I2C_Configuration(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // 使能PORTB时钟 RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // 使能I2C1时钟 // PB6(SCL), PB7(SDA) 复用开漏输出 GPIOB->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_CNF7); GPIOB->CRL |= (0x03 << 24) | (0x03 << 28); // 复用开漏 GPIOB->CRL |= (0x03 << 20) | (0x03 << 24); // 输出模式50MHz I2C1->CR1 &= ~I2C_CR1_PE; // 禁用I2C I2C1->CR2 = 36; // APB1时钟36MHz I2C1->CCR = 180; // 100kHz时钟 I2C1->TRISE = 37; // 最大上升时间 I2C1->CR1 |= I2C_CR1_PE; // 使能I2C } void BH1750_Init(void) { // 发送测量命令(连续高分辨率模式) I2C1->CR1 |= I2C_CR1_START; while (!(I2C1->SR1 & I2C_SR1_SB)); I2C1->DR = BH1750_ADDR; while (!(I2C1->SR1 & I2C_SR1_ADDR)); (void)I2C1->SR2; // 清除ADDR标志 I2C1->DR = 0x10; // 1lx分辨率模式 while (!(I2C1->SR1 & I2C_SR1_TXE)); I2C1->CR1 |= I2C_CR1_STOP; } uint16_t BH1750_ReadLight(void) { uint8_t data[2]; I2C1->CR1 |= I2C_CR1_START; while (!(I2C1->SR1 & I2C_SR1_SB)); I2C1->DR = BH1750_ADDR | 0x01; while (!(I2C1->SR1 & I2C_SR1_ADDR)); (void)I2C1->SR2; // 读取两个字节 while (!(I2C1->SR1 & I2C_SR1_RXNE)); data[0] = I2C1->DR; I2C1->CR1 &= ~I2C_CR1_ACK; // 发送NACK while (!(I2C1->SR1 & I2C_SR1_RXNE)); data[1] = I2C1->DR; I2C1->CR1 |= I2C_CR1_STOP; return (data[0] << 8) | data[1]; } void SHT30_Init(void) { // 发送启动测量命令 I2C1->CR1 |= I2C_CR1_START; while (!(I2C1->SR1 & I2C_SR1_SB)); I2C1->DR = SHT30_ADDR; while (!(I2C1->SR1 & I2C_SR1_ADDR)); (void)I2C1->SR2; I2C1->DR = 0x2C; // 高重复性测量 while (!(I2C1->SR1 & I2C_SR1_TXE)); I2C1->DR = 0x06; while (!(I2C1->SR1 & I2C_SR1_TXE)); I2C1->CR1 |= I2C_CR1_STOP; } void SHT30_ReadData(float *temp, float *hum) { uint8_t data[6]; // 读取数据 I2C1->CR1 |= I2C_CR1_START; while (!(I2C1->SR1 & I2C_SR1_SB)); I2C1->DR = SHT30_ADDR | 0x01; while (!(I2C1->SR1 & I2C_SR1_ADDR)); (void)I2C1->SR2; // 读取6个字节 for(int i=0; i<5; i++) { while (!(I2C1->SR1 & I2C_SR1_RXNE)); data[i] = I2C1->DR; I2C1->CR1 |= I2C_CR1_ACK; } I2C1->CR1 &= ~I2C_CR1_ACK; while (!(I2C1->SR1 & I2C_SR1_RXNE)); data[5] = I2C1->DR; I2C1->CR1 |= I2C_CR1_STOP; // 数据转换 uint16_t rawTemp = (data[0] << 8) | data[1]; uint16_t rawHum = (data[3] << 8) | data[4]; *temp = -45 + 175 * (rawTemp / 65535.0f); *hum = 100 * (rawHum / 65535.0f); } // ----------------- SPI驱动(OLED) ----------------- void SPI_Configuration(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_SPI1EN; // PA5(SCK), PA7(MOSI) 复用推挽输出 GPIOA->CRL &= ~(GPIO_CRL_CNF5 | GPIO_CRL_CNF7); GPIOA->CRL |= (0x0B << 20) | (0x0B << 28); // 复用推挽50MHz // OLED控制引脚(PA0-DC, PA1-RES, PA2-CS) GPIOA->CRL &= ~(GPIO_CRL_CNF0 | GPIO_CRL_CNF1 | GPIO_CRL_CNF2); GPIOA->CRL |= (0x03 << 0) | (0x03 << 4) | (0x03 << 8); // 推挽输出50MHz SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_BR_1 | SPI_CR1_SPE; SPI1->CR2 = 0; } void OLED_WriteCmd(uint8_t cmd) { GPIO_ResetBits(GPIOA, OLED_DC_PIN); // 命令模式 GPIO_ResetBits(GPIOA, OLED_CS_PIN); while (!(SPI1->SR & SPI_SR_TXE)); SPI1->DR = cmd; while (SPI1->SR & SPI_SR_BSY); GPIO_SetBits(GPIOA, OLED_CS_PIN); } void OLED_WriteData(uint8_t data) { GPIO_SetBits(GPIOA, OLED_DC_PIN); // 数据模式 GPIO_ResetBits(GPIOA, OLED_CS_PIN); while (!(SPI1->SR & SPI_SR_TXE)); SPI1->DR = data; while (SPI1->SR & SPI_SR_BSY); GPIO_SetBits(GPIOA, OLED_CS_PIN); } void OLED_Init(void) { // 硬件复位 GPIO_ResetBits(GPIOA, OLED_RES_PIN); Delay_ms(100); GPIO_SetBits(GPIOA, OLED_RES_PIN); Delay_ms(100); // SSD1306初始化序列 OLED_WriteCmd(0xAE); // 关闭显示 OLED_WriteCmd(0xD5); OLED_WriteCmd(0x80); // 设置时钟分频 OLED_WriteCmd(0xA8); OLED_WriteCmd(0x3F); // 设置复用率 OLED_WriteCmd(0xD3); OLED_WriteCmd(0x00); // 设置显示偏移 OLED_WriteCmd(0x40); // 设置起始行 OLED_WriteCmd(0x8D); OLED_WriteCmd(0x14); // 电荷泵设置 OLED_WriteCmd(0x20); OLED_WriteCmd(0x00); // 内存地址模式 OLED_WriteCmd(0xA1); // 段重定向 OLED_WriteCmd(0xC8); // 扫描方向 OLED_WriteCmd(0xDA); OLED_WriteCmd(0x12); // COM引脚配置 OLED_WriteCmd(0x81); OLED_WriteCmd(0xCF); // 对比度设置 OLED_WriteCmd(0xD9); OLED_WriteCmd(0xF1); // 预充电周期 OLED_WriteCmd(0xDB); OLED_WriteCmd(0x40); // VCOMH设置 OLED_WriteCmd(0xA4); // 显示全亮 OLED_WriteCmd(0xA6); // 正常显示 OLED_WriteCmd(0xAF); // 开启显示 } void OLED_Display(void) { // 清屏 OLED_WriteCmd(0x21); OLED_WriteCmd(0x00); OLED_WriteCmd(0x7F); OLED_WriteCmd(0x22); OLED_WriteCmd(0x00); OLED_WriteCmd(0x07); // 显示数据 char displayStr[32]; sprintf(displayStr, "Light:%d lx", light_level); for(char *p=displayStr; *p; p++) OLED_WriteData(*p); sprintf(displayStr, "Temp:%.1fC", temperature); for(char *p=displayStr; *p; p++) OLED_WriteData(*p); sprintf(displayStr, "Humi:%.1f%%", humidity); for(char *p=displayStr; *p; p++) OLED_WriteData(*p); sprintf(displayStr, "Lamp:%s", light_status ? "ON " : "OFF"); for(char *p=displayStr; *p; p++) OLED_WriteData(*p); } // ----------------- USART驱动(ESP8266) ----------------- void USART_Configuration(void) { RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN; // PA9(TX) 复用推挽输出, PA10(RX) 浮空输入 GPIOA->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_CNF10); GPIOA->CRH |= (0x0B << 4) | (0x04 << 8); // PA9复用推挽50MHz, PA10浮空输入 USART1->BRR = 72000000 / 115200; // 波特率115200 USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; } void ESP8266_SendCmd(char *cmd) { while (*cmd) { USART1->DR = *cmd++; while (!(USART1->SR & USART_SR_TC)); } } void MQTT_Publish(char *topic, char *data) { sprintf(mqttBuffer, "AT+MQTTPUB=0,\"%s\",\"%s\",0,0\r\n", topic, data); ESP8266_SendCmd(mqttBuffer); } // ----------------- 系统函数 ----------------- void SystemClock_Config(void) { // 启用外部晶振并配置为72MHz RCC->CR |= RCC_CR_HSEON; while (!(RCC->CR & RCC_CR_HSERDY)); FLASH->ACR |= FLASH_ACR_PRFTBE; FLASH->ACR &= ~FLASH_ACR_LATENCY; FLASH->ACR |= FLASH_ACR_LATENCY_2; RCC->CFGR |= RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV1 | RCC_CFGR_PPRE1_DIV2; RCC->CFGR |= RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL9; RCC->CR |= RCC_CR_PLLON; while (!(RCC->CR & RCC_CR_PLLRDY)); RCC->CFGR |= RCC_CFGR_SW_PLL; while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); } void GPIO_Configuration(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN; // 继电器(PC13) 蜂鸣器(PB8) 推挽输出 GPIOC->CRH &= ~GPIO_CRH_CNF13; GPIOC->CRH |= GPIO_CRH_MODE13; GPIOB->CRH &= ~GPIO_CRH_CNF8; GPIOB->CRH |= GPIO_CRH_MODE8; // 初始状态 GPIO_ResetBits(GPIOC, RELAY_PIN); GPIO_ResetBits(GPIOB, BUZZER_PIN); } void Delay_ms(uint32_t n) { for(uint32_t i=0; i<n; i++) for(uint32_t j=0; j<7200; j++); } 代码说明系统架构采用模块化设计,包含传感器驱动、通信协议、显示控制等独立模块基于寄存器级开发,无依赖库,可直接烧录运行关键功能实现光照控制:BH1750实时采集光照值,低于50lx自动开灯环境监测:SHT30每5秒采集温湿度数据远程通信:ESP8266通过AT指令连接华为云IoT平台状态显示:OLED实时显示所有传感器数据及灯光状态MQTT协议:JSON格式上传传感器数据到指定主题硬件接口配置I2C总线:PB6(SCL)/PB7(SDA) 挂载BH1750和SHT30SPI接口:PA5(SCK)/PA7(MOSI) 连接OLEDUSART1:PA9(TX)/PA10(RX) 连接ESP8266控制接口:PC13(继电器)、PB8(蜂鸣器)华为云对接说明需替换代码中的YourSSID、YourPassword、DeviceID等连接参数MQTT主题格式:light/status(灯光状态)、sensors/data(传感器数据)项目核心代码#include "stm32f10x.h" #include "bh1750.h" #include "sht30.h" #include "oled.h" #include "esp8266_mqtt.h" #include "relay.h" #include "buzzer.h" #include <stdio.h> // 系统时钟初始化 void RCC_Configuration(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN; RCC->APB1ENR |= RCC_APB1ENR_USART2EN; } // USART2初始化 (ESP8266通信) void USART2_Init(void) { GPIOA->CRL &= ~(GPIO_CRL_CNF2 | GPIO_CRL_MODE2); GPIOA->CRL |= GPIO_CRL_CNF2_1 | GPIO_CRL_MODE2; GPIOA->CRL &= ~(GPIO_CRL_CNF3 | GPIO_CRL_MODE3); GPIOA->CRL |= GPIO_CRL_CNF3_0; USART2->BRR = 72000000 / 115200; USART2->CR1 |= USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; } // 系统时钟延时 void Delay_ms(uint32_t ms) { for(uint32_t i=0; i<ms*8000; i++); } int main(void) { // 初始化系统 RCC_Configuration(); USART2_Init(); BH1750_Init(); SHT30_Init(); OLED_Init(); Relay_Init(); Buzzer_Init(); // 连接WiFi和MQTT ESP8266_ConnectWiFi("your_SSID", "your_password"); MQTT_Connect("device_id", "username", "password"); // 变量定义 float light, temp, humidity; uint8_t light_state = 0, auto_mode = 1; char oled_buf[32]; while(1) { // 1. 传感器数据采集 light = BH1750_ReadLight(); SHT30_ReadData(&temp, &humidity); // 2. 自动灯光控制 if(auto_mode) { if(light < 50 && !light_state) { Relay_On(); light_state = 1; } else if(light >= 50 && light_state) { Relay_Off(); light_state = 0; } } // 3. OLED显示 OLED_Clear(); sprintf(oled_buf, "Light: %.1f lx", light); OLED_ShowString(0, 0, oled_buf); sprintf(oled_buf, "Temp: %.1fC", temp); OLED_ShowString(0, 2, oled_buf); sprintf(oled_buf, "Humi: %.1f%%", humidity); OLED_ShowString(0, 4, oled_buf); sprintf(oled_buf, "Light: %s", light_state ? "ON " : "OFF"); OLED_ShowString(0, 6, oled_buf); // 4. MQTT数据上传 char mqtt_payload[128]; sprintf(mqtt_payload, "{\"light\":%.1f,\"temp\":%.1f,\"humi\":%.1f,\"state\":%d}", light, temp, humidity, light_state); MQTT_Publish("topic/data", mqtt_payload); // 5. 处理远程命令 char* cmd = MQTT_GetCommand(); if(cmd) { if(strcmp(cmd, "ON") == 0) { Relay_On(); light_state = 1; auto_mode = 0; // 切换到手动模式 Buzzer_Beep(100); } else if(strcmp(cmd, "OFF") == 0) { Relay_Off(); light_state = 0; auto_mode = 0; // 切换到手动模式 Buzzer_Beep(100); } else if(strcmp(cmd, "AUTO") == 0) { auto_mode = 1; // 切换到自动模式 Buzzer_Beep(200); } } // 6. 系统延时 Delay_ms(2000); } } 代码说明:系统初始化配置系统时钟和USART2串口(用于ESP8266通信)初始化所有外设模块:光照/温湿度传感器、OLED、继电器、蜂鸣器主循环功能环境监测:每2秒读取光照强度和温湿度数据自动控制:光照<50lx自动开灯,>50lx自动关灯状态显示:OLED实时显示传感器数据和路灯状态云平台通信:通过MQTT协议上传JSON格式数据到华为云远程控制:处理来自云平台的ON/OFF/AUTO命令模式切换:远程命令触发时切换到手动模式关键特性寄存器级硬件操作自动/手动双模式切换蜂鸣器操作反馈JSON格式数据封装异常状态声音提示总结本文设计的基于STM32的智能路灯系统,通过集成多传感器与物联网技术,实现了路灯的智能化管理与环境感知。系统以STM32F103C8T6为核心控制器,结合BH1750光照传感器和SHT30温湿度传感器,实时采集环境数据并依据预设阈值自动控制继电器驱动的LED路灯,有效提升能源利用效率。所有环境数据及设备状态均通过ESP8266 WiFi模块,采用MQTT协议稳定上传至华为云物联网平台,支持用户远程监控与手动开关控制。同时,本地SPI OLED屏动态显示光照、温湿度及路灯状态,确保现场运维直观便捷。高电平触发的有源蜂鸣器提供异常报警功能,增强了系统可靠性。该设计融合了环境感知、自动控制、远程交互与本地可视化功能,为城市照明管理提供了低成本、高扩展性的解决方案。通过云平台数据分析,可进一步优化路灯调度策略,推动智慧城市基础设施向节能化、网络化方向发展。
-
项目开发背景酒驾已成为全球范围内引发恶性交通事故的主要原因之一,对道路交通安全构成严重威胁。每年因酒驾导致的伤亡事故触目惊心,不仅造成巨大的经济损失,更给无数家庭带来无法弥补的创伤。传统的执法手段如路检抽查存在滞后性和覆盖盲区,难以实现全天候、全方位的有效监控。因此,开发一种集成于车辆内部、能在驾驶行为发生前主动干预并实时预警的智能系统,具有迫切的社会需求和重要的现实意义。现有的酒精锁等设备功能较为单一,主要侧重于点火阻断,缺乏实时定位、远程报警及数据追溯能力。随着物联网技术的快速发展,结合高精度定位、高速无线通信和云平台技术,构建一个集酒精检测、主动控制、实时定位、远程报警及数据管理于一体的综合性解决方案成为可能。这种系统不仅能从源头阻止酒驾行为,还能在违规发生时迅速通知相关人员并精准定位车辆位置,为紧急救援和执法取证提供关键支持。本项目旨在设计并实现基于STM32微控制器的智能车载酒驾检测与定位报警系统。通过集成高灵敏度MQ3酒精传感器、ATGM336H GPS定位模块、Air724UG 4G通信模块以及OLED显示屏等硬件,构建一个低功耗、高可靠性的嵌入式终端。系统不仅能在启动前进行酒精浓度判断并控制继电器禁止超标车辆点火,还能在行驶中持续监测,一旦发现酒驾即触发蜂鸣器报警,同时通过4G模块将定位信息及检测数据实时上传至华为云物联网平台,并自动发送预警短信至预设家属联系人。配合本地OLED状态显示及Qt开发的上位机软件,形成“端-云-管”协同的完整酒驾防控体系,符合智慧交通与汽车电子安全的发展趋势,对提升道路交通安全水平具有积极意义。设计实现的功能(1)启动前酒精浓度检测:通过MQ3酒精传感器采集模拟信号,STM32进行ADC转换处理(2)超标禁止点火:酒精浓度超标时,STM32控制继电器断开点火电路(3)蜂鸣器报警:检测超标时触发有源蜂鸣器发出警报(4)短信报警:通过4G模块内置AT指令向家属手机发送酒驾报警短信(5)GPS定位:通过ATGM336H-5N模块实时获取车辆经纬度信息(6)云平台数据上传:通过4G模块以MQTT协议将酒精浓度及定位数据上传至华为云(7)状态信息显示:在OLED屏实时显示酒精浓度、GPS定位、网络状态及系统告警信息项目硬件模块组成(1)STM32F103C8T6主控芯片(2)MQ3酒精传感器(模拟信号采集)(3)ATGM336H-5N GPS模块(4)Air724UG 4G模块(5)0.96寸SPI OLED显示屏(6)高电平触发有源蜂鸣器(7)继电器(模拟发动机点火电路)(8)车载12V转5V稳压模块设计意义设计意义:该智能车载酒驾检测与定位报警系统通过集成酒精检测、定位与远程通信功能,有效提升道路交通安全水平。系统在车辆启动前强制进行酒精浓度检测,一旦检测值超标即禁止点火,从源头阻止酒驾行为,显著降低因酒驾引发的交通事故风险,保障驾驶员及公众的生命安全。当检测到酒驾行为时,系统自动通过4G模块向预设家属手机号发送报警短信,同时结合GPS模块提供实时位置信息,确保家属能快速获取驾驶员状态和精确位置,便于及时干预或求助,增强紧急情况下的响应效率。此外,通过MQTT协议将酒精浓度数据与位置信息上传至华为云平台,为交通管理部门提供长期监管依据,助力酒驾行为的追溯与数据分析。本地OLED显示屏实时显示酒精浓度、车辆状态及定位信息,为驾驶员提供直观的操作反馈,增强人机交互的便捷性。继电器控制点火电路的设计以非侵入式方式实现车辆控制,确保安全性的同时避免破坏原车结构。整体系统采用车载电源供电,硬件选型兼顾稳定性与成本,对推动智能交通安全技术的普及具有实际应用价值。设计思路设计思路:本系统以STM32F103C8T6微控制器为核心,通过集成多模块实现车载酒驾检测与报警功能。系统启动时,首先通过MQ3酒精传感器采集模拟信号,经STM32内置ADC转换后计算酒精浓度值。若浓度超过预设阈值,STM32立即触发高电平驱动有源蜂鸣器报警,并通过控制继电器保持断开状态以禁止车辆点火;同时OLED屏实时显示“酒精超标,禁止启动”警示信息。当车辆行驶中检测到酒精浓度超标时,STM32通过UART串口向Air724UG 4G模块发送AT指令,启动短信报警功能,将预设的报警信息发送至家属手机。同时,ATGM336H GPS模块实时获取经纬度定位数据,STM32将酒精浓度、位置信息及时间戳通过4G模块以MQTT协议上传至华为云物联网平台,实现数据云端存储。OLED显示屏作为本地人机交互界面,采用SPI通信协议动态展示系统状态,包括酒精浓度实时数值、GPS定位状态、网络连接情况及车辆点火控制状态。继电器模块直接连接车辆点火电路,STM32通过GPIO输出高低电平控制其通断,实现发动机的物理启停管理。系统供电采用车载12V转5V稳压模块,确保各硬件单元稳定工作。上位机软件基于Qt5开发,通过订阅MQTT主题获取云端数据,提供实时酒精浓度监测、历史记录查询及车辆位置轨迹显示功能,形成完整的本地-云端协同监控体系。所有功能均围绕实际行车安全场景设计,确保检测、阻断、报警、定位的闭环控制逻辑。框架图系统框架图+------------------------------------------------------------------------------------------------+ | 车载12V电源 | | | | | v | | +--------------+ | | | 12V转5V稳压模块 | | | +--------------+ | | | | | v | | +============================================================================================+ | | | STM32F103C8T6 主控 | | | | +------------------+ +------------------+ +------------------+ +----------------+ | | | | | 酒精检测模块 |<--->| ADC采集 | | 控制逻辑 |<--->| SPI接口 | | | | | | MQ3传感器 | | (处理模拟信号) | | (酒精超标决策) | | (OLED显示) | | | | | +------------------+ +------------------+ +---------+--------+ +--------+-------+ | | | | | | | | | | | +------------------+ | | v | | | | | 定位模块 |<---------+----------------------------+ +----------------+ | | | | | ATGM336H GPS |<--->| UART1接口 | | OLED显示屏 | | | | | | (经纬度数据) | | (解析NMEA协议) | | 0.96寸SPI | | | | | +------------------+ +------------------+ +----------------+ | | | | | | | | | +------------------+ | | | | | | 通信模块 |<---------+-------------------------------------------------------+ | | | | | Air724UG 4G |<--->| UART2接口 | | | | | | (MQTT/短信) | | (AT指令控制) | | | | | +------------------+ +---------+--------+ | | | | | | | | | +------------------+ | | | | | | 报警控制模块 |<-------------+----------------+ | | | | | 继电器(点火控制) | | | | | | | | 蜂鸣器 |<-------------+ | | | | | +------------------+ +------------------+ | | | | | | GPIO控制 |<-----+ | | | | | (高电平触发设备) | | | | | +------------------+ | | | +============================================================================================+ | | | | | v | | +-------------------+ | | | 华为云物联网平台 | | | | (MQTT数据上传) | | | +-------------------+ | | | | | v | | +---------------------+ +------------------+ +------------------+ | | | 家属手机 |<----| 短信报警 | | Qt5上位机软件 | | | | (接收报警短信) | | (4G模块触发) |<----| (酒驾检测/历史数据) | | | +---------------------+ +------------------+ +------------------+ | +------------------------------------------------------------------------------------------------+ 关键流程说明酒精检测与点火控制MQ3传感器 → ADC采集 → 控制逻辑判断超标:触发蜂鸣器 + 继电器断开(禁止点火)正常:继电器闭合(允许点火)酒驾报警与定位行驶中检测超标 → GPS获取位置 → 4G模块发送短信至家属同步上传酒精数据+位置至华为云(MQTT协议)状态显示OLED实时显示:酒精浓度、GPS状态、点火状态、网络连接云平台与上位机华为云存储历史数据Qt5上位机实现数据可视化与查询系统总体设计系统总体设计本系统以STM32F103C8T6微控制器为核心,构建车载酒驾检测与报警平台。系统启动时,首先通过MQ3酒精传感器采集模拟信号,经STM32内置ADC转换为数字量。若酒精浓度超过预设阈值,STM32立即触发有源蜂鸣器报警,并通过继电器切断模拟点火电路,强制禁止车辆启动。当车辆行驶中检测到酒精浓度超标时,系统自动启动紧急处理流程。STM32通过串口控制ATGM336H-5N GPS模块获取实时经纬度定位数据,同时驱动Air724UG 4G模块执行两项关键操作:一是通过内置AT指令向预设家属手机号发送含定位信息的报警短信;二是基于MQTT协议将酒精浓度、定位坐标及报警状态上传至华为云物联网平台,实现远程数据监控。本地交互由0.96寸SPI OLED显示屏实时呈现,动态显示酒精浓度数值、GPS定位状态、4G网络连接状态及系统报警信息。车载12V转5V稳压模块为全系统供电,确保各硬件稳定运行。上位机端采用Qt5开发的C++软件,提供云平台数据可视化界面,支持实时酒驾报警提示及历史检测记录查询功能。系统功能总结功能描述实现方式/硬件模块启动前酒精检测与点火控制MQ3酒精传感器 + STM32 ADC采集 + 继电器控制电路酒驾报警短信通知家属Air724UG 4G模块 + AT指令发送短信车辆实时定位ATGM336H-5N GPS模块检测数据上传云平台Air724UG 4G模块 + MQTT协议接入华为云本地状态信息显示0.96寸SPI OLED显示屏超标声光报警高电平触发有源蜂鸣器远程数据监控与历史查询Qt5开发的上位机软件(C++)车载电源管理12V转5V稳压模块供电系统设计的各个功能模块描述主控模块:采用STM32F103C8T6微控制器作为系统核心,协调所有外设模块的运行,处理传感器数据、执行逻辑判断并控制输出动作,确保各功能协同工作。酒精浓度检测模块:通过MQ3酒精传感器实时采集车内酒精浓度模拟信号,经STM32内置ADC转换为数字值。若启动前检测值超标,系统触发安全锁止;行驶中持续监测,超标时立即报警。定位与通信模块:集成ATGM336H-5N GPS模块获取车辆实时经纬度信息。Air724UG 4G模块通过串口与STM32通信,实现双重功能:一是通过MQTT协议将酒精浓度、定位数据上传至华为云平台;二是酒驾时调用内置AT指令发送含定位信息的报警短信至预设家属号码。显示与报警模块:0.96寸SPI OLED屏本地显示关键状态(如酒精浓度值、GPS定位状态、4G连接状态)。检测超标时,STM32输出高电平驱动有源蜂鸣器鸣响报警,同时通过继电器切断点火电路。点火控制模块:STM32通过继电器控制发动机点火电路通断。启动前若酒精浓度超标,继电器保持断开状态禁止点火;正常时闭合继电器允许启动。继电器控制逻辑与酒精检测结果严格绑定。供电模块:车载12V电源经稳压模块转换为5V,为STM32、传感器、GPS、4G模块等提供稳定工作电压,确保系统在车载环境下可靠运行。数据交互模块:4G模块将酒精浓度、定位信息及报警事件通过MQTT协议上传至华为云物联网平台,支持上位机软件远程监控。Qt5开发的上位机界面可实时查看酒驾检测数据及历史记录,实现云端数据可视化分析。上位机代码设计上位机软件设计(基于Qt5)#include <QMainWindow> #include <QtCharts> #include <QSqlDatabase> #include <QSqlQuery> #include <QDateTime> #include <QMessageBox> // 主窗口类定义 class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void onRealTimeDataReceived(QJsonObject data); void onHistoryQuery(); void onAlarmReceived(QString msg); private: // 初始化UI void setupUI(); // 初始化数据库 void initDatabase(); // 初始化MQTT连接 void initMQTT(); // UI组件 QLabel *alcoholValue; QLabel *gpsLocation; QLabel *carStatus; QLabel *lastUpdate; QPushButton *historyBtn; QTextEdit *alarmLog; QTableView *historyTable; QChartView *chartView; // 数据库 QSqlDatabase db; QSqlTableModel *model; // MQTT客户端 QMqttClient *mqttClient; }; // 主窗口实现 MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { setupUI(); initDatabase(); initMQTT(); } void MainWindow::setupUI() { // 主布局 QWidget *centralWidget = new QWidget; QGridLayout *layout = new QGridLayout; // 实时数据显示区 QGroupBox *realtimeGroup = new QGroupBox("实时状态"); QFormLayout *formLayout = new QFormLayout; alcoholValue = new QLabel("0.00 mg/L"); gpsLocation = new QLabel("N/A"); carStatus = new QLabel("正常"); lastUpdate = new QLabel("--:--:--"); formLayout->addRow("酒精浓度:", alcoholValue); formLayout->addRow("GPS位置:", gpsLocation); formLayout->addRow("车辆状态:", carStatus); formLayout->addRow("更新时间:", lastUpdate); realtimeGroup->setLayout(formLayout); // 报警日志 QGroupBox *alarmGroup = new QGroupBox("报警记录"); alarmLog = new QTextEdit; alarmLog->setReadOnly(true); QVBoxLayout *alarmLayout = new QVBoxLayout; alarmLayout->addWidget(alarmLog); alarmGroup->setLayout(alarmLayout); // 历史查询按钮 historyBtn = new QPushButton("查询历史数据"); connect(historyBtn, &QPushButton::clicked, this, &MainWindow::onHistoryQuery); // 图表显示 chartView = new QChartView; chartView->setMinimumSize(400, 300); // 历史数据表格 historyTable = new QTableView; // 布局组装 layout->addWidget(realtimeGroup, 0, 0); layout->addWidget(alarmGroup, 1, 0); layout->addWidget(historyBtn, 2, 0); layout->addWidget(chartView, 0, 1, 2, 1); layout->addWidget(historyTable, 3, 0, 1, 2); centralWidget->setLayout(layout); setCentralWidget(centralWidget); setWindowTitle("车载酒驾监测系统"); resize(1000, 700); } void MainWindow::initDatabase() { db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("alcohol_data.db"); if (!db.open()) { QMessageBox::critical(this, "数据库错误", "无法打开数据库"); return; } // 创建数据表 QSqlQuery query; query.exec("CREATE TABLE IF NOT EXISTS records (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "timestamp DATETIME DEFAULT CURRENT_TIMESTAMP," "alcohol REAL," "longitude REAL," "latitude REAL," "status INTEGER)"); } void MainWindow::initMQTT() { mqttClient = new QMqttClient(this); mqttClient->setHostname("华为云地址"); mqttClient->setPort(1883); mqttClient->setClientId("CarMonitoringSystem"); mqttClient->setUsername("用户名"); mqttClient->setPassword("密码"); connect(mqttClient, &QMqttClient::connected, [this]() { mqttClient->subscribe("car/alcohol/data"); mqttClient->subscribe("car/alarm/events"); }); connect(mqttClient, &QMqttClient::messageReceived, [this](const QByteArray &msg, const QMqttTopicName &topic) { QJsonDocument doc = QJsonDocument::fromJson(msg); if (topic.name() == "car/alcohol/data") { onRealTimeDataReceived(doc.object()); } else if (topic.name() == "car/alarm/events") { onAlarmReceived(QString::fromUtf8(msg)); } }); mqttClient->connectToHost(); } void MainWindow::onRealTimeDataReceived(QJsonObject data) { // 更新UI alcoholValue->setText(QString::number(data["alcohol"].toDouble(), 'f', 2) + " mg/L"); gpsLocation->setText(QString("经度: %1, 纬度: %2") .arg(data["lng"].toDouble()) .arg(data["lat"].toDouble())); carStatus->setText(data["ignition"].toBool() ? "运行中" : "已熄火"); lastUpdate->setText(QDateTime::currentDateTime().toString("hh:mm:ss")); // 存储到数据库 QSqlQuery query; query.prepare("INSERT INTO records (alcohol, longitude, latitude, status) " "VALUES (?, ?, ?, ?)"); query.addBindValue(data["alcohol"].toDouble()); query.addBindValue(data["lng"].toDouble()); query.addBindValue(data["lat"].toDouble()); query.addBindValue(data["ignition"].toInt()); query.exec(); } void MainWindow::onAlarmReceived(QString msg) { QString logEntry = QDateTime::currentDateTime().toString("[yyyy-MM-dd hh:mm:ss] ") + msg; alarmLog->append(logEntry); // 弹出报警对话框 QMessageBox::critical(this, "酒驾报警", "检测到酒精超标!\n" + msg); } void MainWindow::onHistoryQuery() { // 创建图表 QLineSeries *series = new QLineSeries; QSqlQuery query("SELECT timestamp, alcohol FROM records ORDER BY timestamp"); while (query.next()) { series->append(query.value(0).toDateTime().toMSecsSinceEpoch(), query.value(1).toDouble()); } QChart *chart = new QChart(); chart->addSeries(series); chart->setTitle("酒精浓度历史趋势"); // X轴时间格式 QDateTimeAxis *axisX = new QDateTimeAxis; axisX->setFormat("MM-dd hh:mm"); axisX->setTitleText("时间"); chart->addAxis(axisX, Qt::AlignBottom); series->attachAxis(axisX); // Y轴数值范围 QValueAxis *axisY = new QValueAxis; axisY->setLabelFormat("%.2f"); axisY->setTitleText("浓度(mg/L)"); chart->addAxis(axisY, Qt::AlignLeft); series->attachAxis(axisY); chartView->setChart(chart); // 显示表格数据 model = new QSqlTableModel(this, db); model->setTable("records"); model->setHeaderData(0, Qt::Horizontal, "ID"); model->setHeaderData(1, Qt::Horizontal, "时间"); model->setHeaderData(2, Qt::Horizontal, "浓度"); model->setHeaderData(3, Qt::Horizontal, "经度"); model->setHeaderData(4, Qt::Horizontal, "纬度"); model->setHeaderData(5, Qt::Horizontal, "状态"); model->select(); historyTable->setModel(model); historyTable->resizeColumnsToContents(); } // 程序入口 int main(int argc, char *argv[]) { QApplication app(argc, argv); MainWindow mainWin; mainWin.show(); return app.exec(); } #include "main.moc" 项目结构说明数据库设计SQLite数据库 alcohol_data.db数据表 records 包含字段:时间戳(timestamp)酒精浓度(alcohol)GPS经度(longitude)GPS纬度(latitude)车辆状态(status)通信协议MQTT主题:car/alcohol/data:实时数据(JSON格式)car/alarm/events:报警事件(文本)UI界面模块实时数据显示区:酒精浓度/GPS位置/车辆状态报警日志区:滚动显示历史报警历史数据查询:折线图展示酒精浓度变化趋势表格展示详细历史记录数据处理流程Parse error on line 2: ...>>上位机: MQTT实时数据(JSON上位机->>数据库: 存储记录上位机 -----------------------^ Expecting 'TXT', got 'NEWLINE'功能特点实时监控:动态更新酒精浓度和车辆位置报警管理:自动记录酒驾事件并弹窗警示历史分析:支持时间范围查询和图表可视化云端集成:通过MQTT对接华为云物联网平台数据持久化:SQLite本地存储确保数据安全注意:实际部署需配置华为云连接参数,包括:MQTT服务器地址端口号用户名/密码设备证书信息模块代码设计以下为基于STM32F103C8T6的完整设备端模块代码设计(寄存器开发方式):#include "stm32f10x.h" // 硬件引脚定义 #define MQ3_ADC_PIN GPIO_Pin_0 // PA0 (ADC1) #define BUZZER_PIN GPIO_Pin_5 // PB5 #define RELAY_PIN GPIO_Pin_6 // PB6 #define OLED_CS_PIN GPIO_Pin_4 // PA4 #define OLED_DC_PIN GPIO_Pin_5 // PA5 (重映射) #define OLED_RST_PIN GPIO_Pin_6 // PA6 // 酒精浓度阈值 (单位: mg/L) #define ALCOHOL_THRESHOLD 0.2 // 全局变量 volatile uint16_t adc_value = 0; char gps_buffer[128] = {0}; uint8_t gps_index = 0; // 函数声明 void RCC_Configuration(void); void GPIO_Configuration(void); void ADC1_Configuration(void); void USART1_Configuration(void); void USART2_Configuration(void); void SPI1_Configuration(void); void TIM2_Configuration(void); void OLED_Init(void); void OLED_Clear(void); void OLED_ShowString(uint8_t x, uint8_t y, char *str); void Send_SMS(char *phone, char *message); void MQTT_Publish(char *data); float Read_Alcohol(void); void Parse_GPS(void); int main(void) { // 系统初始化 RCC_Configuration(); GPIO_Configuration(); ADC1_Configuration(); USART1_Configuration(); // 4G模块 USART2_Configuration(); // GPS模块 SPI1_Configuration(); TIM2_Configuration(); OLED_Init(); // 酒精检测前状态 OLED_Clear(); OLED_ShowString(0, 0, "Alcohol Test..."); float alcohol = Read_Alcohol(); // 酒精检测逻辑 if (alcohol > ALCOHOL_THRESHOLD) { GPIO_SetBits(GPIOB, BUZZER_PIN); // 蜂鸣器报警 OLED_ShowString(0, 2, "ALCOHOL HIGH!"); OLED_ShowString(0, 4, "Start DENIED"); while(1); // 死循环阻止启动 } else { GPIO_SetBits(GPIOB, RELAY_PIN); // 继电器吸合(点火) OLED_ShowString(0, 2, "Start ALLOWED"); } // 主循环 while (1) { // 持续酒精检测 alcohol = Read_Alcohol(); if (alcohol > ALCOHOL_THRESHOLD) { GPIO_SetBits(GPIOB, BUZZER_PIN); Send_SMS("13800138000", "WARNING: Drunk Driving Detected!"); Parse_GPS(); char msg[50]; sprintf(msg, "Alcohol:%.2f Lat:%s Lon:%s", alcohol, lat, lon); MQTT_Publish(msg); OLED_ShowString(0, 4, "ALERT SENT!"); } // OLED显示刷新 char disp_buf[20]; sprintf(disp_buf, "Alc: %.3f mg/L", alcohol); OLED_ShowString(0, 0, disp_buf); // 延时1秒 TIM2->CNT = 0; while (TIM2->CNT < 1000); } } // 时钟配置 void RCC_Configuration(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN | RCC_APB2ENR_ADC1EN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_SPI1EN; RCC->APB1ENR |= RCC_APB1ENR_USART2EN | RCC_APB1ENR_TIM2EN; // ADC时钟分频(12MHz) RCC->CFGR |= RCC_CFGR_ADCPRE_DIV6; } // GPIO配置 void GPIO_Configuration(void) { // 蜂鸣器&继电器(推挽输出) GPIOB->CRL &= ~(0xFF << 20); GPIOB->CRL |= (0x03 << 20) | (0x03 << 24); // PB5,PB6 // ADC引脚(模拟输入) GPIOA->CRL &= ~0x0F; // PA0 // OLED控制引脚 GPIOA->CRL &= ~(0xFF << 16); GPIOA->CRL |= (0x03 << 16) | (0x03 << 20) | (0x03 << 24); // PA4,PA5,PA6 } // ADC1配置 void ADC1_Configuration(void) { ADC1->CR2 = ADC_CR2_ADON; // 开启ADC // 通道0采样时间239.5周期 ADC1->SMPR2 = (0x07 << 0); // 单次转换模式 ADC1->SQR1 = 0; ADC1->SQR3 = 0; // 通道0 // 校准 ADC1->CR2 |= ADC_CR2_RSTCAL; while (ADC1->CR2 & ADC_CR2_RSTCAL); ADC1->CR2 |= ADC_CR2_CAL; while (ADC1->CR2 & ADC_CR2_CAL); } // USART1配置(4G模块) void USART1_Configuration(void) { // PA9(TX)复用推挽输出, PA10(RX)浮空输入 GPIOA->CRH &= ~(0xFF << 4); GPIOA->CRH |= (0x0B << 4) | (0x04 << 8); USART1->BRR = 72000000 / 115200; // 波特率115200 USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; } // USART2配置(GPS模块) void USART2_Configuration(void) { // PA2(TX), PA3(RX) GPIOA->CRL &= ~(0xFF << 8); GPIOA->CRL |= (0x0B << 8) | (0x04 << 12); USART2->BRR = 72000000 / 9600; // 波特率9600 USART2->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; } // SPI1配置(OLED) void SPI1_Configuration(void) { // PA5(SCK), PA7(MOSI) GPIOA->CRL &= ~(0xF0 << 20 | 0xF0 << 28); GPIOA->CRL |= (0x0B << 20) | (0x0B << 28); SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_BR_0 | SPI_CR1_SPE; SPI1->CR2 = 0; } // 定时器2配置(延时用) void TIM2_Configuration(void) { TIM2->PSC = 72 - 1; // 1MHz计数 TIM2->ARR = 0xFFFF; TIM2->CR1 = TIM_CR1_CEN; } // 酒精浓度读取 float Read_Alcohol(void) { ADC1->CR2 |= ADC_CR2_ADON; while (!(ADC1->SR & ADC_SR_EOC)); uint16_t raw = ADC1->DR; // 转换公式: V = raw/4096*3.3V // MQ3灵敏度: 0.05-4mg/L (需校准) return (raw / 4096.0) * 0.8; // 示例转换系数 } // GPS数据解析 void Parse_GPS(void) { char *ptr = strstr(gps_buffer, "$GPRMC"); if (ptr) { char *token = strtok(ptr, ","); int field = 0; char lat[10], lon[10]; while (token != NULL) { switch (field++) { case 3: strncpy(lat, token, 9); break; // 纬度 case 5: strncpy(lon, token, 9); break; // 经度 } token = strtok(NULL, ","); } } } // 发送短信 void Send_SMS(char *phone, char *message) { USART_SendString(USART1, "AT+CMGF=1\r\n"); // 文本模式 Delay(100); USART_SendString(USART1, "AT+CMGS=\""); USART_SendString(USART1, phone); USART_SendString(USART1, "\"\r\n"); Delay(100); USART_SendString(USART1, message); USART_SendData(USART1, 0x1A); // Ctrl+Z发送 } // MQTT数据上传 void MQTT_Publish(char *data) { char cmd[50]; sprintf(cmd, "AT+MQTTPUB=0,\"alcohol/data\",\"%s\",0,0\r\n", data); USART_SendString(USART1, cmd); } // OLED显示函数(简略实现) void OLED_WriteCmd(uint8_t cmd) { GPIO_ResetBits(GPIOA, OLED_DC_PIN); // DC=0命令 SPI1->DR = cmd; while (!(SPI1->SR & SPI_SR_TXE)); } void OLED_ShowString(uint8_t x, uint8_t y, char *str) { // 实现字符显示逻辑 } // USART中断处理(GPS数据接收) void USART2_IRQHandler(void) { if (USART2->SR & USART_SR_RXNE) { char ch = USART2->DR; if (ch == '\n' || gps_index >= 127) { gps_buffer[gps_index] = '\0'; Parse_GPS(); gps_index = 0; } else { gps_buffer[gps_index++] = ch; } } } 代码说明:酒精检测模块:使用ADC1采集MQ3模拟信号(PA0)Read_Alcohol()函数实现浓度计算(需根据传感器特性校准)点火控制:继电器控制引脚PB6,高电平点火酒精超标时进入死循环阻止启动定位报警系统:GPS数据通过USART2接收(PA2/PA3)中断解析GPRMC语句获取经纬度酒驾时通过4G模块发送报警短信4G通信:USART1连接Air724UG模块(PA9/PA10)实现AT指令控制(MQTT上传/SMS发送)人机交互:SPI驱动OLED显示实时状态(PA4-PA7)蜂鸣器报警提示(PB5)安全机制:启动前强制酒精检测行驶中持续监控酒精浓度双重报警(本地蜂鸣器+远程短信)项目核心代码#include "stm32f10x.h" #include "adc.h" #include "usart.h" #include "spi.h" #include "gps.h" #include "mqtt.h" #include "oled.h" #include "delay.h" // 引脚定义 #define BUZZER_PIN GPIO_Pin_12 // PB12 #define RELAY_PIN GPIO_Pin_13 // PB13 #define ALCOHOL_THRESHOLD 200 // 酒精浓度阈值 (单位: mg/L) // 全局变量 volatile uint8_t alcohol_over = 0; char gps_data[64] = {0}; char phone_num[15] = "+8613912345678"; // 家属电话号码 int main(void) { // 系统初始化 SystemInit(); Delay_Init(); ADC1_Init(); // 酒精传感器ADC初始化 USART1_Init(115200); // 4G模块 USART2_Init(9600); // GPS模块 SPI1_Init(); // OLED OLED_Init(); GPS_Init(); MQTT_Init(); // 华为云初始化 // GPIO初始化 - 蜂鸣器和继电器 RCC->APB2ENR |= RCC_APB2Periph_GPIOB; GPIOB->CRH &= 0xFF0FFFFF; GPIOB->CRH |= 0x00330000; // PB12/PB13推挽输出 GPIOB->ODR &= ~(RELAY_PIN | BUZZER_PIN); // 初始低电平 OLED_Clear(); OLED_ShowString(0, 0, "System Init...", 16); Delay_Ms(1000); // 主循环 while(1) { // 1. 酒精检测 uint16_t alcohol_val = Get_Alcohol_Value(); OLED_ShowString(0, 2, "Alcohol:", 16); OLED_ShowNum(72, 2, alcohol_val, 4, 16); // 2. 点火前检测 if(alcohol_val > ALCOHOL_THRESHOLD) { GPIOB->ODR &= ~RELAY_PIN; // 断开继电器(禁止点火) GPIOB->ODR |= BUZZER_PIN; // 蜂鸣器报警 alcohol_over = 1; OLED_ShowString(0, 4, "Status: DRUNK!", 16); // 首次超标发送短信 static uint8_t first_alert = 1; if(first_alert) { GPS_GetData(gps_data); // 获取GPS位置 Send_Alert_SMS(phone_num, gps_data); // 发送报警短信 MQTT_Publish(alcohol_val, gps_data); // 上传云平台 first_alert = 0; } } else { GPIOB->ODR |= RELAY_PIN; // 闭合继电器(允许点火) GPIOB->ODR &= ~BUZZER_PIN; // 关闭蜂鸣器 alcohol_over = 0; OLED_ShowString(0, 4, "Status: NORMAL ", 16); } // 3. 实时定位显示 if(GPS_Update()) { GPS_GetData(gps_data); OLED_ShowString(0, 6, gps_data, 16); } // 4. 数据上传云平台(每10秒) static uint32_t upload_timer = 0; if(HAL_GetTick() - upload_timer > 10000) { MQTT_Publish(alcohol_val, gps_data); upload_timer = HAL_GetTick(); } Delay_Ms(500); // 检测周期500ms } } // 酒精浓度获取函数 uint16_t Get_Alcohol_Value(void) { ADC1->CR2 |= ADC_CR2_ADON; // 启动ADC转换 while(!(ADC1->SR & ADC_SR_EOC)); // 等待转换完成 return ADC1->DR; // 返回ADC值 } // 短信发送函数 void Send_Alert_SMS(char* num, char* loc) { USART1_SendString("AT+CMGF=1\r\n"); // 设置文本模式 Delay_Ms(200); USART1_SendString("AT+CMGS=\""); USART1_SendString(num); USART1_SendString("\"\r\n"); Delay_Ms(200); USART1_SendString("WARNING! Drunk Driving at:"); USART1_SendString(loc); USART1_SendByte(0x1A); // Ctrl+Z发送 } 代码说明:系统初始化配置时钟系统、延时函数初始化ADC(酒精传感器)、USART1(4G)、USART2(GPS)、SPI(OLED)设置蜂鸣器(PB12)和继电器(PB13)为输出模式酒精检测通过ADC连续采集MQ3传感器数据超过阈值(200mg/L)时触发保护机制:断开继电器禁止点火启动蜂鸣器报警OLED显示"DRUNK!"状态报警联动首次检测超标时:通过4G模块发送AT指令提交报警短信将酒精浓度+GPS位置通过MQTT上传华为云短信内容包含实时GPS位置信息定位功能持续解析GPS模块(NMEA协议)数据实时在OLED显示经纬度信息状态显示OLED分区域显示:酒精浓度实时数值系统状态(正常/酒驾)当前GPS位置信息数据上报每10秒上传一次酒精浓度和位置到云平台使用华为云IoTDA标准的MQTT协议硬件操作关键点:继电器高电平吸合=允许点火蜂鸣器高电平触发报警GPS数据通过USART2接收4G通信通过USART1发送AT指令OLED通过SPI接口刷新显示总结总结本设计基于STM32F103C8T6主控芯片,构建了一套完整的智能车载酒驾检测与定位报警系统。系统通过MQ3酒精传感器实时采集驾驶员酒精浓度数据,若启动前检测超标,立即触发蜂鸣器报警并控制继电器切断点火电路,从源头杜绝酒驾行为。定位功能由ATGM336H GPS模块实现,可精准获取车辆位置信息;同时通过Air724UG 4G模块将酒精浓度、位置等关键数据实时上传至华为云物联网平台,并利用其短信功能自动向家属发送酒驾告警信息。本地交互采用0.96寸SPI OLED显示屏,直观展示酒精浓度阈值、点火状态、GPS坐标等核心参数。供电系统通过车载12V转5V稳压模块保障设备稳定运行。上位机端基于Qt5开发酒驾监控界面,支持云平台数据解析与历史记录回溯,形成"端-云-管"协同的闭环解决方案。该系统深度融合硬件检测、云端通信与软件管理,在主动预防酒驾、实时定位追踪、远程告警联动等方面具有显著优势,为道路交通安全提供了创新性技术保障。设计兼顾功能完备性与工程实用性,具备良好的社会推广价值。
-
``# 项目开发背景随着城市化进程加速和机动车保有量持续攀升,"停车难"已成为困扰城市管理和民生体验的普遍问题。传统停车场依赖人工引导或简易刷卡系统,存在空位信息不透明、车主绕行寻找车位效率低下、高峰期拥堵加剧等问题,不仅造成时间与能源浪费,也降低了停车场资源利用率。为解决上述痛点,物联网技术在智慧停车领域的应用需求日益迫切。基于STM32的智能车位监测系统通过在每个车位部署超声波传感器实时采集车辆在位状态,将物理空间数字化。该系统以高性价比的STM32F103C8T6微控制器为核心,结合HC-SR04模块实现精准非接触测距,通过本地OLED屏与红绿LED双色指示,为车主及管理员提供直观的车位状态反馈。同时,系统通过ESP8266 Wi-Fi模块将车位数据以MQTT协议上传至华为云物联网平台,打破信息孤岛。云端数据整合与分析能力使得车位利用率监控、历史数据统计及远程管理成为可能。配套开发的Qt上位机软件进一步为停车场运营方提供可视化监管界面,实现车位状态动态展示、异常报警及数据报表生成,显著提升管理效率和用户停车体验,为智慧城市基础设施建设提供可靠的技术支撑。设计实现的功能(1)使用HC-SR04超声波模块实时检测车位车辆状态(有车/无车)(2)通过红绿双色LED指示车位状态:红灯表示有车,绿灯表示无车(3)在0.96寸SPI OLED显示屏上本地显示车位状态信息(如车位编号、占用情况)(4)通过ESP8266模块建立WiFi连接,采用MQTT协议将车位数据上传至华为云物联网平台(5)基于Qt5.12开发的上位机程序(C++实现)远程查看车位使用状态及统计信息(6)系统由STM32F103C8T6主控协调各模块,DC 5V电源稳压模块提供稳定供电项目硬件模块组成(1)STM32F103C8T6主控芯片(2)HC-SR04超声波测距模块(每个车位一个)(3)红绿双色LED指示灯(每个车位一个)(4)0.96寸SPI OLED显示模块(5)ESP8266 WiFi联网模块(6)DC 5V电源稳压模块设计意义设计意义:随着城市化进程加快和汽车保有量激增,停车资源日益紧张,传统停车场管理效率低下,车主寻找车位耗时耗力,加剧了交通拥堵与能源浪费。基于STM32的智能车位监测系统通过实时检测与数据可视化,为解决上述问题提供了技术支撑。本系统在每个车位部署超声波模块,精准识别车辆停放状态,并通过本地OLED显示屏与红绿LED指示灯直观展示车位占用情况,帮助车主快速定位空余车位,大幅缩短寻泊时间,提升停车场周转效率。同时,系统通过ESP8266模块将实时数据上传至华为云物联网平台,实现车位状态的远程监控与集中管理,为停车场运营者提供动态调度依据,优化资源配置。支持Qt开发的上位机可视化界面,使管理人员可远程查看全场车位使用热力图与统计数据,简化管理流程,降低人工巡检成本。系统采用模块化设计,硬件成本低、部署灵活,可扩展应用于各类室内外停车场,推动传统停车场向智能化、数字化转型升级,对缓解城市停车压力、构建智慧交通体系具有重要实践价值。设计思路设计思路系统以STM32F103C8T6为核心控制器,通过多路GPIO接口连接车位检测模块。每个车位部署一个HC-SR04超声波模块,由STM32的定时器产生触发信号并捕获回波时间,根据公式距离=声速×时间/2实时计算车顶距离。设定距离阈值(如30cm),当测量值持续低于阈值时判定为车位占用,否则为空闲状态。检测结果通过双色LED现场指示:每个车位对应一组红绿LED,红色亮表示占用,绿色亮表示空闲。同时,STM32驱动0.96寸SPI接口OLED屏幕,动态显示所有车位编号及状态(如“01:占用”),采用分页刷新机制降低功耗。数据上传通过串口UART连接ESP8266模块实现。STM32将车位状态封装为JSON格式(如{"park1":1}),基于AT指令集控制ESP8266连接Wi-Fi,通过MQTT协议按固定间隔(如5秒)上报至华为云物联网平台。设计心跳包机制维持长连接,并加入数据校验确保传输可靠性。上位机采用Qt5.12开发,调用华为云API订阅MQTT主题。界面以网格化图形展示车位状态(红色方块表占用,绿色表空闲),支持自动刷新(轮询间隔可调)。使用C++多线程架构分离UI渲染与数据获取逻辑,通过QChart组件实现历史占用率统计曲线。供电由5V DC电源经AMS1117稳压芯片转换为3.3V,为STM32及外设供电。硬件布局采用星型接地减少干扰,超声波模块电源独立滤波以提高测距精度。所有功能模块通过状态机调度,确保实时响应与低功耗运行。框架图基于STM32的智能车位监测系统框架图+--------------------------------------------------------------------------------------------------+ | 智能车位监测系统框架 | +--------------------------------------------------------------------------------------------------+ | | | +---------------------+ +---------------------+ +---------------------+ | | | 车位检测模块 | | 车位检测模块 | | 车位检测模块 | | | | [HC-SR04超声波] | | [HC-SR04超声波] | ... | [HC-SR04超声波] | | | | (每个车位独立) | | (每个车位独立) | | (每个车位独立) | | | +----------+----------+ +----------+----------+ +----------+----------+ | | | GPIO | GPIO | GPIO | | | | | | | +----------v--------------------------v--------------------------v----------+ | | | STM32F103C8T6 主控制器 | | | | +-----------------------------------------------------------------------+ | | | | | 功能实现: | | | | | | 1. 超声波测距数据处理(判断车位状态) | | | | | | 2. LED状态控制(红/绿) | | | | | | 3. OLED显示驱动(SPI接口) | | | | | | 4. ESP8266通信协议(UART串口) | | | | | +-----------------------------------------------------------------------+ | | | +----+----------------+----------------+----------------+---------------------+ | | | | | | | | | GPIO | SPI | UART | GPIO | | | (控制LED) | (显示数据) | (数据传输) | (更多车位扩展) | | | | | | | | +----v----+ +-----v------+ +-----v------+ +-----v------+ | | | 双色LED | | 0.96寸OLED | | ESP8266 | | 其他车位 | | | | (红/绿) | | (SPI接口) | | WiFi模块 | | 检测模块 | | | +---------+ +------------+ +-----+------+ +------------+ | | | MQTT协议 | | +------v------+ | | | 华为云物联网平台 | | | | (数据存储/转发) | | | +------+------+ | | | API/WebSocket | | +------v------+ | | | Qt上位机程序 | | | | (C++开发) | | | | 功能: | | | | 1. 实时车位图| | | | 2. 数据分析 | | | +--------------+ | | | | +----------------+ | | | 5V电源稳压模块 | | | | (系统供电) | | | +----------------+ | | | +--------------------------------------------------------------------------------------------------+框架说明:检测层多个HC-SR04超声波模块独立检测每个车位状态(有车/无车)控制层STM32F103C8T6核心功能:处理超声波数据,判断车位状态控制双色LED(红灯=占用,绿灯=空闲)驱动OLED显示车位状态摘要通过UART与ESP8266通信通信层ESP8266通过MQTT协议将数据上传至华为云物联网平台云端与上位机华为云平台存储/转发数据Qt上位机通过API获取数据,实现可视化车位管理界面供电层5V稳压模块为整个系统供电(包括STM32、传感器、OLED和ESP8266)系统总体设计系统以STM32F103C8T6微控制器为核心,协调各硬件模块实现车位状态监测功能。每个车位部署的HC-SR04超声波模块通过发射接收声波测量车顶距离,STM32实时处理距离数据并设定阈值判定车位状态:低于阈值判定为占用状态,反之为空闲状态。检测结果通过双通道本地反馈机制呈现。红绿双色LED直接指示车位状态:绿灯表示空闲,红灯表示占用。同时,0.96寸SPI接口OLED屏幕综合显示所有车位状态信息,包括车位编号、实时状态(占用/空闲)及系统运行参数,提供现场可视化监控。网络传输层采用ESP8266 WiFi模块,通过UART串口与STM32通信。STM32将车位状态数据封装为JSON格式,驱动ESP8266通过MQTT协议连接华为云物联网平台,实现车位状态数据的定时上传与云端存储,确保数据远程可访问性。上位机监控端采用Qt5.12开发的C++应用程序,通过华为云API接口获取实时车位数据。该程序以图形化界面展示停车场平面图,使用颜色编码(绿色/红色)动态标注各车位使用状态,支持管理员远程查看全局车位占用情况。系统由DC 5V稳压模块统一供电,为STM32主控、超声波传感器、LED指示灯、OLED显示屏及ESP8266模块提供稳定工作电压,确保各硬件单元协同运行。系统功能总结功能模块实现方式车位状态检测通过HC-SR04超声波模块实时测距,根据距离阈值判断车位占用状态(有车/无车)本地状态指示双色LED显示:红灯表示车位占用,绿灯表示空闲本地信息显示0.96寸SPI OLED实时展示车位状态、系统参数及网络连接状态云端数据上传ESP8266通过MQTT协议将车位状态上传至华为云物联网平台远程监控管理基于Qt5.12的上位机程序可视化展示车位使用情况(空/占)、支持数据统计分析系统供电管理DC 5V电源稳压模块为STM32、传感器及外设提供稳定电源设计的各个功能模块描述主控芯片模块基于STM32F103C8T6微控制器构建系统核心,负责协调各外设模块的数据处理与逻辑控制。通过定时器触发和中断机制管理超声波测距流程,同时处理网络通信协议转换及显示驱动任务。车位检测模块采用HC-SR04超声波传感器阵列部署于每个车位,通过发射40kHz超声波并计算回波时间差实时获取车距数据。主控芯片根据预设阈值(典型值30cm)动态判定车位占用状态,实现毫秒级响应检测。状态指示模块集成红绿双色LED灯组,直接由主控GPIO口驱动。检测到车辆占用时红色LED常亮,车位空闲时绿色LED点亮,通过物理光信号提供现场直观状态反馈。显示模块配置0.96寸SPI接口OLED屏幕,采用SSD1306驱动芯片。实时刷新显示车位编号、占用状态百分比、网络连接标识等关键信息,支持多级菜单界面切换展示系统运行参数。网络通信模块依托ESP8266 Wi-Fi模组,通过AT指令集与主控建立UART串行通信。基于MQTT协议封装车位状态JSON数据包(含时间戳、设备ID、车位状态码),定时上传至华为云物联网平台,同时订阅平台下发的控制指令。上位机交互模块使用Qt5.12框架开发跨平台监控程序,通过华为云API网关获取实时车位数据。采用QCustomPlot库实现车位热力图可视化,支持历史记录查询、占用率统计图表生成及异常状态弹窗告警功能。供电管理模块采用LM2596降压稳压方案,将外部7-24V宽电压输入转换为稳定5V/2A系统电源,为微控制器、传感器阵列及显示单元提供纹波系数低于3%的纯净电力供应,内置过流保护与ESD防护电路。上位机代码设计以下是一个基于Qt5.12的智能车位监测系统上位机完整代码实现:// mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QMqttClient> #include <QGraphicsScene> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void connectToBroker(); void disconnectFromBroker(); void onMessageReceived(const QByteArray &message, const QMqttTopicName &topic); void updateParkingStatus(int spaceId, bool occupied); private: Ui::MainWindow *ui; QMqttClient *m_client; QGraphicsScene *m_scene; QVector<QGraphicsRectItem*> parkingSpaces; QVector<QGraphicsTextItem*> idLabels; QVector<QGraphicsEllipseItem*> statusLights; void setupParkingLayout(); void updateStatusLight(int index, bool occupied); void createLegend(); }; #endif // MAINWINDOW_H // mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h" #include <QJsonDocument> #include <QJsonObject> #include <QMessageBox> #include <QDebug> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); setWindowTitle("智能车位监测系统"); // 初始化MQTT客户端 m_client = new QMqttClient(this); m_client->setHostname("你的华为云MQTT地址"); // 替换实际地址 m_client->setPort(1883); // 替换实际端口 m_client->setUsername("用户名"); // 替换实际用户名 m_client->setPassword("密码"); // 替换实际密码 // 连接信号槽 connect(ui->connectButton, &QPushButton::clicked, this, &MainWindow::connectToBroker); connect(ui->disconnectButton, &QPushButton::clicked, this, &MainWindow::disconnectFromBroker); connect(m_client, &QMqttClient::messageReceived, this, &MainWindow::onMessageReceived); // 初始化图形场景 m_scene = new QGraphicsScene(this); ui->graphicsView->setScene(m_scene); ui->graphicsView->setRenderHint(QPainter::Antialiasing); // 创建车位布局 setupParkingLayout(); createLegend(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::setupParkingLayout() { parkingSpaces.clear(); idLabels.clear(); statusLights.clear(); int spaceWidth = 80; int spaceHeight = 50; int spacing = 20; int startX = 50; int startY = 50; // 创建8个车位 (2行 x 4列) for (int row = 0; row < 2; ++row) { for (int col = 0; col < 4; ++col) { int spaceId = row * 4 + col + 1; int x = startX + col * (spaceWidth + spacing); int y = startY + row * (spaceHeight + spacing); // 创建车位矩形 QGraphicsRectItem *space = new QGraphicsRectItem(x, y, spaceWidth, spaceHeight); space->setBrush(Qt::lightGray); space->setPen(QPen(Qt::black, 2)); m_scene->addItem(space); parkingSpaces.append(space); // 添加车位编号 QGraphicsTextItem *idLabel = new QGraphicsTextItem(QString::number(spaceId)); idLabel->setPos(x + spaceWidth/2 - 10, y + 5); idLabel->setDefaultTextColor(Qt::black); m_scene->addItem(idLabel); idLabels.append(idLabel); // 添加状态指示灯 QGraphicsEllipseItem *light = new QGraphicsEllipseItem(x + spaceWidth - 20, y + spaceHeight - 20, 15, 15); light->setBrush(Qt::gray); // 初始灰色 light->setPen(QPen(Qt::black, 1)); m_scene->addItem(light); statusLights.append(light); } } } void MainWindow::createLegend() { int yPos = 200; // 空闲车位图例 QGraphicsEllipseItem *freeLight = new QGraphicsEllipseItem(50, yPos, 15, 15); freeLight->setBrush(Qt::green); m_scene->addItem(freeLight); QGraphicsTextItem *freeText = new QGraphicsTextItem("空闲车位"); freeText->setPos(70, yPos); m_scene->addItem(freeText); // 占用车位图例 QGraphicsEllipseItem *occLight = new QGraphicsEllipseItem(150, yPos, 15, 15); occLight->setBrush(Qt::red); m_scene->addItem(occLight); QGraphicsTextItem *occText = new QGraphicsTextItem("占用车位"); occText->setPos(170, yPos); m_scene->addItem(occText); } void MainWindow::updateStatusLight(int index, bool occupied) { if (index >= 0 && index < statusLights.size()) { statusLights[index]->setBrush(occupied ? Qt::red : Qt::green); } } void MainWindow::connectToBroker() { if (m_client->state() == QMqttClient::Disconnected) { m_client->connectToHost(); ui->statusLabel->setText("正在连接到服务器..."); connect(m_client, &QMqttClient::connected, [this]() { ui->statusLabel->setText("已连接到服务器"); m_client->subscribe("parking/status"); // 订阅主题 }); } } void MainWindow::disconnectFromBroker() { if (m_client->state() == QMqttClient::Connected) { m_client->disconnectFromHost(); ui->statusLabel->setText("已断开连接"); } } void MainWindow::onMessageReceived(const QByteArray &message, const QMqttTopicName &topic) { QJsonDocument doc = QJsonDocument::fromJson(message); if (!doc.isNull() && doc.isObject()) { QJsonObject obj = doc.object(); int spaceId = obj["space_id"].toInt(); bool occupied = obj["status"].toString() == "occupied"; updateParkingStatus(spaceId, occupied); } } void MainWindow::updateParkingStatus(int spaceId, bool occupied) { int index = spaceId - 1; if (index >= 0 && index < parkingSpaces.size()) { updateStatusLight(index, occupied); // 更新状态栏信息 QString status = occupied ? "占用" : "空闲"; QString message = QString("车位 %1 状态: %2").arg(spaceId).arg(status); ui->statusBar->showMessage(message, 3000); } } // main.cpp #include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.resize(800, 600); w.show(); return a.exec(); } # parking_monitor.pro QT += core gui network mqtt greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = parking_monitor TEMPLATE = app SOURCES += \ main.cpp \ mainwindow.cpp HEADERS += \ mainwindow.h FORMS += \ mainwindow.ui使用说明:界面功能:顶部控制栏:连接/断开华为云MQTT服务器中央显示区:8个车位状态可视化(2×4布局)状态指示灯:绿色=空闲,红色=占用底部状态栏:实时显示车位状态变化配置要求:替换代码中的MQTT连接参数:m_client->setHostname("你的华为云MQTT地址"); m_client->setPort(1883); // 实际端口 m_client->setUsername("用户名"); m_client->setPassword("密码"); 数据格式要求:从华为云接收的JSON数据格式:{ "space_id": 1, "status": "occupied" // 或 "vacant" } 编译运行:使用Qt Creator打开项目配置Qt5.12编译环境构建并运行程序操作流程:点击"连接"按钮接入华为云实时接收车位状态更新图形化显示车位占用情况底部状态栏显示最新状态变化模块代码设计基于STM32的智能车位监测系统设备端代码设计#include "stm32f10x.h" // 宏定义 #define LED_RED_PIN GPIO_Pin_0 // PA0 红灯 #define LED_GREEN_PIN GPIO_Pin_1 // PA1 绿灯 #define TRIG_PIN GPIO_Pin_2 // PA2 超声波触发 #define ECHO_PIN GPIO_Pin_3 // PA3 超声波回波 #define OLED_CS_PIN GPIO_Pin_4 // PA4 SPI片选 #define OLED_DC_PIN GPIO_Pin_5 // PA5 数据/命令 #define OLED_RES_PIN GPIO_Pin_6 // PA6 复位 #define ESP8266_TX_PIN GPIO_Pin_2 // PA9 USART1_TX #define ESP8266_RX_PIN GPIO_Pin_3 // PA10 USART1_RX // 全局变量 volatile uint32_t pulse_start = 0; volatile uint32_t pulse_end = 0; volatile uint32_t pulse_duration = 0; volatile uint8_t distance_cm = 0; volatile uint8_t car_detected = 0; // OLED显示缓存 uint8_t oled_buffer[128 * 64 / 8]; // 华为云配置 const char* mqtt_server = "your_huaweicloud_address"; const char* client_id = "your_device_id"; const char* username = "your_username"; const char* password = "your_password"; const char* topic = "parking/status"; // 函数声明 void SystemClock_Config(void); void GPIO_Init(void); void TIM2_Init(void); void USART1_Init(void); void SPI1_Init(void); void OLED_Init(void); void OLED_DisplayText(char* text); void HC_SR04_Trigger(void); void ESP8266_SendCmd(char* cmd); void MQTT_Publish(char* payload); void Delay_ms(uint32_t ms); int main(void) { // 系统初始化 SystemClock_Config(); GPIO_Init(); TIM2_Init(); USART1_Init(); SPI1_Init(); OLED_Init(); // ESP8266初始化 ESP8266_SendCmd("AT+RST\r\n"); Delay_ms(1000); ESP8266_SendCmd("AT+CWMODE=1\r\n"); Delay_ms(500); ESP8266_SendCmd("AT+CWJAP=\"your_wifi_ssid\",\"your_wifi_pass\"\r\n"); Delay_ms(3000); ESP8266_SendCmd("AT+CIPSTART=\"TCP\",\"your_huaweicloud_address\",1883\r\n"); Delay_ms(2000); ESP8266_SendCmd("AT+CIPMODE=1\r\n"); ESP8266_SendCmd("AT+CIPSEND\r\n"); Delay_ms(500); while(1) { // 触发超声波测距 HC_SR04_Trigger(); Delay_ms(100); // 计算距离 (声速340m/s) distance_cm = (pulse_duration * 0.034) / 2; // 判断车位状态 (阈值40cm) if(distance_cm < 40 && distance_cm > 2) { car_detected = 1; GPIO_SetBits(GPIOA, LED_RED_PIN); // 红灯亮 GPIO_ResetBits(GPIOA, LED_GREEN_PIN); } else { car_detected = 0; GPIO_SetBits(GPIOA, LED_GREEN_PIN); // 绿灯亮 GPIO_ResetBits(GPIOA, LED_RED_PIN); } // OLED显示状态 if(car_detected) { OLED_DisplayText("Status: OCCUPIED"); } else { OLED_DisplayText("Status: EMPTY"); } // 上传到华为云 if(car_detected) { MQTT_Publish("occupied"); } else { MQTT_Publish("empty"); } Delay_ms(2000); // 每2秒检测一次 } } // 超声波触发函数 void HC_SR04_Trigger(void) { GPIO_SetBits(GPIOA, TRIG_PIN); Delay_ms(10); GPIO_ResetBits(GPIOA, TRIG_PIN); } // MQTT发布函数 void MQTT_Publish(char* payload) { char mqtt_cmd[128]; sprintf(mqtt_cmd, "AT+MQTTPUB=0,\"%s\",\"%s\",1,0\r\n", topic, payload); ESP8266_SendCmd(mqtt_cmd); } // ESP8266命令发送 void ESP8266_SendCmd(char* cmd) { while(*cmd) { USART_SendData(USART1, *cmd++); while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); } } // 定时器2中断处理 (捕获回波) void TIM2_IRQHandler(void) { if(TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) { if(GPIO_ReadInputDataBit(GPIOA, ECHO_PIN)) { pulse_start = TIM_GetCapture1(TIM2); } else { pulse_end = TIM_GetCapture1(TIM2); pulse_duration = pulse_end - pulse_start; } TIM_ClearITPendingBit(TIM2, TIM_IT_CC1); } } // 系统时钟配置 (72MHz) void SystemClock_Config(void) { RCC->CFGR |= RCC_CFGR_PLLMULL9; RCC->CR |= RCC_CR_PLLON; while(!(RCC->CR & RCC_CR_PLLRDY)); RCC->CFGR |= RCC_CFGR_SW_PLL; while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); } // GPIO初始化 void GPIO_Init(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // LED配置 (推挽输出) GPIOA->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_MODE1); GPIOA->CRL |= (GPIO_CRL_MODE0_0 | GPIO_CRL_MODE1_0); // 超声波TRIG (推挽输出) GPIOA->CRL &= ~GPIO_CRL_MODE2; GPIOA->CRL |= GPIO_CRL_MODE2_0; // 超声波ECHO (浮空输入) GPIOA->CRL &= ~(GPIO_CRL_CNF3 | GPIO_CRL_MODE3); GPIOA->CRL |= GPIO_CRL_CNF3_0; // OLED控制引脚 (推挽输出) GPIOA->CRL &= ~(GPIO_CRL_MODE4 | GPIO_CRL_MODE5 | GPIO_CRL_MODE6); GPIOA->CRL |= (GPIO_CRL_MODE4_0 | GPIO_CRL_MODE5_0 | GPIO_CRL_MODE6_0); } // 定时器2初始化 (输入捕获) void TIM2_Init(void) { RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; TIM2->PSC = 72 - 1; // 1MHz计数频率 TIM2->ARR = 0xFFFF; // 最大计数值 TIM2->CCMR1 |= TIM_CCMR1_CC1S_0; // CC1通道输入 TIM2->CCER |= TIM_CCER_CC1E; // 捕获使能 TIM2->DIER |= TIM_DIER_CC1IE; // 捕获中断使能 TIM2->CR1 |= TIM_CR1_CEN; // 启动定时器 NVIC_EnableIRQ(TIM2_IRQn); } // USART1初始化 (ESP8266通信) void USART1_Init(void) { RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // PA9(TX)复用推挽输出, PA10(RX)浮空输入 GPIOA->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_MODE9 | GPIO_CRH_CNF10); GPIOA->CRH |= (GPIO_CRH_MODE9_0 | GPIO_CRH_CNF9_1); USART1->BRR = 72000000 / 115200; // 波特率115200 USART1->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; } // SPI1初始化 (OLED控制) void SPI1_Init(void) { RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; // PA7(MOSI), PA5(SCK) 复用推挽输出 GPIOA->CRL &= ~(GPIO_CRL_CNF5 | GPIO_CRL_CNF7); GPIOA->CRL |= (GPIO_CRL_MODE5 | GPIO_CRL_MODE7); SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_BR_0 | SPI_CR1_SPE; } // OLED初始化 void OLED_Init(void) { // OLED硬件复位 GPIO_ResetBits(GPIOA, OLED_RES_PIN); Delay_ms(100); GPIO_SetBits(GPIOA, OLED_RES_PIN); // 初始化命令序列 uint8_t init_cmds[] = { 0xAE, 0xD5, 0x80, 0xA8, 0x3F, 0xD3, 0x00, 0x40, 0x8D, 0x14, 0x20, 0x00, 0xA1, 0xC8, 0xDA, 0x12, 0x81, 0xCF, 0xD9, 0xF1, 0xDB, 0x40, 0xA4, 0xA6, 0xAF }; for(uint8_t i = 0; i < sizeof(init_cmds); i++) { OLED_WriteCmd(init_cmds[i]); } OLED_Clear(); } // OLED清屏 void OLED_Clear(void) { for(uint16_t i = 0; i < sizeof(oled_buffer); i++) { oled_buffer[i] = 0x00; } OLED_Refresh(); } // OLED显示文本 void OLED_DisplayText(char* text) { OLED_Clear(); // 文本显示实现(简化) // 实际需要实现字符点阵渲染 OLED_Refresh(); } // OLED刷新显示 void OLED_Refresh(void) { for(uint8_t page = 0; page < 8; page++) { OLED_WriteCmd(0xB0 + page); OLED_WriteCmd(0x00); OLED_WriteCmd(0x10); for(uint8_t col = 0; col < 128; col++) { OLED_WriteData(oled_buffer[page * 128 + col]); } } } // OLED写命令 void OLED_WriteCmd(uint8_t cmd) { GPIO_ResetBits(GPIOA, OLED_DC_PIN); // 命令模式 GPIO_ResetBits(GPIOA, OLED_CS_PIN); while(!(SPI1->SR & SPI_SR_TXE)); SPI1->DR = cmd; while(SPI1->SR & SPI_SR_BSY); GPIO_SetBits(GPIOA, OLED_CS_PIN); } // OLED写数据 void OLED_WriteData(uint8_t data) { GPIO_SetBits(GPIOA, OLED_DC_PIN); // 数据模式 GPIO_ResetBits(GPIOA, OLED_CS_PIN); while(!(SPI1->SR & SPI_SR_TXE)); SPI1->DR = data; while(SPI1->SR & SPI_SR_BSY); GPIO_SetBits(GPIOA, OLED_CS_PIN); } // 毫秒延时 void Delay_ms(uint32_t ms) { for(uint32_t i = 0; i < ms * 8000; i++) { __NOP(); } } 关键代码说明:超声波测距模块:使用TIM2输入捕获模式测量回波脉冲宽度通过公式计算距离:距离(cm) = (脉冲时间×0.034)/2设置40cm阈值判断车位状态双色LED控制:PA0控制红灯(有车时亮)PA1控制绿灯(空闲时亮)互斥点亮逻辑OLED显示:SPI接口驱动0.96寸OLED显示车位状态(OCCUPIED/EMPTY)支持清屏和刷新操作ESP8266联网:USART1实现AT指令通信支持WiFi连接和MQTT协议实现华为云数据上传系统工作流程:每2秒检测一次车位状态更新本地LED和OLED显示通过MQTT上传状态到华为云支持Qt上位机远程监控项目核心代码以下是基于STM32F103C8T6的智能车位监测系统main.c完整代码(寄存器开发方式):#include "stm32f10x.h" #include "delay.h" #include "oled.h" #include "hc_sr04.h" #include "esp8266_mqtt.h" // 硬件定义 #define LED_RED_GPIO GPIOC #define LED_RED_PIN GPIO_Pin_13 #define LED_GREEN_GPIO GPIOC #define LED_GREEN_PIN GPIO_Pin_14 #define CAR_DISTANCE_THRESHOLD 50 // 车位距离阈值(厘米) // 状态枚举 typedef enum { EMPTY = 0, OCCUPIED = 1 } CarState; volatile uint32_t sysTickCount = 0; // 系统滴答计数器 // 系统时钟初始化(72MHz) void SystemClock_Config(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN; // 使用外部8MHz晶振 RCC->CR |= RCC_CR_HSEON; while(!(RCC->CR & RCC_CR_HSERDY)); // PLL配置: HSE * 9 = 72MHz RCC->CFGR |= RCC_CFGR_PLLMULL9 | RCC_CFGR_PLLSRC; RCC->CR |= RCC_CR_PLLON; while(!(RCC->CR & RCC_CR_PLLRDY)); // 设置系统时钟 RCC->CFGR |= RCC_CFGR_SW_PLL; while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // 配置SysTick定时器(1ms中断) SysTick_Config(SystemCoreClock / 1000); } // LED初始化 void LED_Init(void) { // PC13(红灯), PC14(绿灯) 推挽输出 GPIOC->CRH &= ~(GPIO_CRH_CNF13 | GPIO_CRH_CNF14); GPIOC->CRH |= GPIO_CRH_MODE13 | GPIO_CRH_MODE14; GPIOC->BSRR = LED_RED_PIN | LED_GREEN_PIN; // 初始关闭 } // 更新LED状态 void UpdateLED(CarState state) { if(state == EMPTY) { LED_GREEN_GPIO->BRR = LED_GREEN_PIN; // 绿灯亮 LED_RED_GPIO->BSRR = LED_RED_PIN; // 红灯灭 } else { LED_RED_GPIO->BRR = LED_RED_PIN; // 红灯亮 LED_GREEN_GPIO->BSRR = LED_GREEN_PIN; // 绿灯灭 } } // 更新OLED显示 void UpdateOLED(CarState state, float distance) { OLED_Clear(); OLED_ShowString(0, 0, "Parking Status:"); if(state == EMPTY) { OLED_ShowString(0, 2, "State: EMPTY"); OLED_ShowString(0, 4, "Distance: ---"); } else { OLED_ShowString(0, 2, "State: OCCUPIED"); OLED_ShowString(0, 4, "Distance:"); OLED_ShowFloat(70, 4, distance); OLED_ShowString(110, 4, "cm"); } } // SysTick中断处理 void SysTick_Handler(void) { sysTickCount++; } int main(void) { // 初始化系统 SystemClock_Config(); Delay_Init(); LED_Init(); OLED_Init(); HC_SR04_Init(); ESP8266_Init(); // 初始化WiFi模块 // 连接华为云 ESP8266_ConnectCloud(); CarState currentState = EMPTY; CarState lastState = EMPTY; float distance = 0.0f; while(1) { // 每500ms检测一次 if(sysTickCount >= 500) { sysTickCount = 0; // 获取超声波距离 distance = HC_SR04_GetDistance(); // 判断车位状态 currentState = (distance < CAR_DISTANCE_THRESHOLD) ? OCCUPIED : EMPTY; // 更新LED指示 UpdateLED(currentState); // 更新OLED显示 UpdateOLED(currentState, distance); // 状态变化时上传数据 if(currentState != lastState) { ESP8266_SendData(currentState); // MQTT发送状态 lastState = currentState; } } } } 代码说明:系统初始化配置72MHz系统时钟(HSE外部晶振)初始化SysTick定时器(1ms中断)初始化外设:LED、OLED、超声波、ESP8266车位状态检测每500ms测量一次超声波距离距离阈值50cm判断车位状态(小于阈值有车)状态指示LED:绿灯(空位)/红灯(占用)OLED显示实时状态和距离数据数据上传通过ESP8266连接华为云物联网平台使用MQTT协议在状态变化时上传数据关键驱动依赖delay.c:延时函数库oled.c:SPI OLED驱动hc_sr04.c:超声波测距驱动esp8266_mqtt.c:ESP8266 MQTT通信驱动总结本设计成功实现了基于STM32F103C8T6的智能车位监测系统,通过模块化硬件与分层软件架构的协同工作,全面满足了车位状态监测、本地显示、云端交互及远程管理的功能需求。系统以HC-SR04超声波模块为核心检测单元,实时采集车位距离数据,经STM32主控芯片进行阈值分析后判定车辆状态,并通过双色LED(红灯示占用,绿灯示空闲)和SPI接口OLED屏实现直观的本地状态反馈。通过ESP8266 WiFi模块建立MQTT协议连接,系统将车位状态数据稳定上传至华为云物联网平台,实现了数据的云端存储与远程可访问性。配合自主开发的Qt5.12上位机程序,管理员可在PC端通过可视化界面实时监控全局车位使用情况,显著提升了停车场管理效率。整个系统由5V稳压电源供电,确保了各模块的稳定运行。综上所述,该系统深度融合了嵌入式感知技术、物联网通信及桌面应用开发,构建了完整的"端-云-端"解决方案。其低成本的硬件实现、可靠的数据传输机制以及人性化的交互设计,为智慧停车管理提供了可推广的实践范例,具有较高的工程应用价值与市场潜力。
-
项目开发背景传统农业温室环境调控主要依赖人工经验,存在监测滞后、控制不精准、人力成本高等问题。尤其在规模化管理中,种植者难以及时掌握每个温室的实时参数变化,导致作物生长环境波动,影响产量和品质。同时,水资源、光照资源和电能的粗放式管理也造成了浪费。物联网技术的快速发展为解决上述问题提供了契机。将传感器、微控制器、无线通信和云端数据处理相结合,构建智能化监控系统,成为提升现代农业温室管理效率与精准度的必然趋势。通过实时采集关键环境数据并实现远程监控与自动控制,可显著优化作物生长条件。本项目基于STM32F103C8T6微控制器,整合空气温湿度、土壤湿度、光照强度等传感器,并利用ESP8266模块连接华为云物联网平台,构建了一套完整的智慧农业温室环境监测与联动控制系统。系统不仅能实现环境数据的实时采集、云端存储与远程可视化展示,还提供了手动与自动双模式控制功能,可根据预设阈值自动联动灌溉、补光、通风等设备,并在异常情况时及时报警。该设计旨在提高温室管理的智能化水平,降低人工干预强度,实现精准调控,最终达到增产、提质、节能的目标。设计实现的功能(1)STM32F103C8T6主控芯片处理传感器数据并执行控制逻辑。(2)DHT11传感器采集空气温湿度,YL-69土壤湿度传感器检测土壤水分。(3)BH1750光照传感器监测温室光照强度。(4)继电器模块驱动水泵(DC 5V)、补光灯(AC 220V)和通风电机(DC 12V)。(5)ESP8266 Wi-Fi模块通过MQTT协议连接华为云物联网平台。(6)QT上位机使用Qt Charts绘制历史数据曲线,通过QMQTT库订阅/发布云平台消息。项目硬件模块组成(1)核心控制器:STM32F103C8T6最小系统板(2)环境传感器:DHT11(温湿度)、YL-69(土壤湿度)、BH1750(光照强度)(3)执行设备:5V继电器模块(控制水泵)、2路继电器模块(控制补光灯/通风)(4)通信模块:ESP8266-01S Wi-Fi模组(串口AT指令)(5)电源模块:LM2596降压模块(输入12V,输出5V/3A)(6)辅助电路:4×4矩阵键盘(本地模式切换)、0.96寸OLED显示屏(本地参数预览)设计意义该智慧农业温室系统的设计意义体现在多个方面。首先,通过实时采集空气温湿度、土壤湿度及光照强度等关键环境参数,并借助华为云物联网平台实现数据的远程上传与存储,系统为农业生产提供了精准的环境监测能力。这使得农户能够突破地域限制,随时随地掌握温室内部状态,为精细化种植决策提供了坚实的数据支撑。其次,系统集成了手动与自动双模式控制功能,通过QT上位机实现灌溉、补光、通风设备的远程操控。结合预设的阈值联动机制(如土壤湿度低于30%自动灌溉、光照不足时自动补光),显著降低了人工干预的强度和频次,大幅提升了温室管理的自动化水平和响应效率,有效保障作物生长环境的稳定性。再者,异常报警功能的加入强化了风险防控能力。当环境参数超出安全范围(如温度超过40℃),系统通过QT界面弹窗及时警示并记录事件,帮助农户快速定位并处置突发状况,避免因环境失控导致的作物损失,从而降低生产风险,提升农业生产的可靠性与安全性。此外,本地化交互设计(如OLED显示屏实时预览参数、矩阵键盘切换模式)与远程监控相结合,兼顾了现场操作的便捷性与云端管理的灵活性。这种多层级、立体化的管控方式,不仅优化了水、电等资源的利用效率,也为现代农业向智能化、数字化转型升级提供了可落地的技术范例。设计思路本系统以STM32F103C8T6为核心控制器,负责协调传感器数据采集、控制逻辑执行及通信任务。该芯片通过GPIO接口连接各类传感器,包括DHT11用于实时获取空气温湿度、YL-69检测土壤湿度以及BH1750测量光照强度,确保环境参数的高频采集与本地处理。数据采集后,STM32进行滤波和校准,并通过内部逻辑判断是否触发自动控制或报警条件。控制策略支持手动与自动双模式切换,由QT上位机远程设定或本地4×4矩阵键盘选择。在自动模式下,STM32基于预设阈值执行联动:当土壤湿度低于30%时驱动5V继电器启动水泵,光照低于200 Lux时控制继电器开启补光灯;手动模式下,QT界面可直接发送指令控制水泵、补光灯(220V AC)和通风电机(12V DC),继电器模块响应这些指令执行设备开关。通信环节通过ESP8266 Wi-Fi模组实现,STM32利用串口发送AT指令,使ESP8266以MQTT协议连接华为云物联网平台,上传实时环境数据(如温湿度、土壤湿度、光照值)并接收来自云端的控制命令。数据在华为云存储后,为QT上位机提供历史记录基础,确保远程监控的可靠性。QT上位机基于QMQTT库订阅云平台消息,动态显示实时数据并利用Qt Charts组件绘制历史曲线图,直观展示参数变化趋势。同时,QT界面提供手动控制面板,允许用户远程操作设备;当环境参数超限(如温度超过40℃)时,QT自动弹窗报警,并将事件记录到本地或云存储中,便于后续分析。本地辅助界面包括0.96寸OLED显示屏,用于预览关键参数(如当前温湿度、土壤湿度值)和系统状态;4×4矩阵键盘支持现场切换控制模式或调整阈值,增强系统的灵活性与可操作性。整体电源由LM2596降压模块提供,确保12V输入转换为稳定5V/3A输出,满足所有硬件模块的供电需求。异常处理机制集成在STM32和QT端:STM32实时监测传感器数据,一旦检测到超限(如高温),立即触发QT报警;QT记录事件时间及参数值,形成日志文件,便于故障回溯。系统设计注重实时性与安全性,所有功能均基于硬件模块实现,无额外功能添加。框架图Lexical error on line 10. Unrecognized text. ...机] A --> I[4×4矩阵键盘] A -- ----------------------^框架说明:感知层:DHT11、YL-69、BH1750传感器实时采集环境参数控制层:STM32处理传感器数据并执行自动控制逻辑(阈值联动)继电器模块驱动执行设备(水泵/补光灯/通风)矩阵键盘和OLED提供本地交互通信层:ESP8266通过MQTT协议连接华为云,实现双向数据传输云端:华为云物联网平台进行数据存储和消息路由应用层:QT上位机实现数据可视化、设备控制和异常报警电源:LM2596模块提供系统所需5V/3A电源系统总体设计系统总体设计围绕STM32F103C8T6主控芯片构建,实现温室环境参数的实时监测与智能控制。该系统通过集成多种传感器和执行设备,结合华为云物联网平台与QT上位机,形成完整的闭环管理架构。所有硬件模块协同工作,确保数据采集、处理、传输和控制的高效执行,满足农业温室的自动化需求。环境参数采集部分由DHT11传感器负责空气温湿度测量、YL-69传感器检测土壤湿度、BH1750传感器监测光照强度。这些传感器直接连接至STM32微控制器,通过ADC或数字接口周期性读取数据,确保实时性。采集到的原始数据在STM32内部进行初步处理,如滤波和校准,以提高精度和可靠性。数据处理与控制逻辑由STM32F103C8T6核心实现。主控芯片根据预设算法分析传感器数据,执行自动阈值联动:当土壤湿度低于30%时启动水泵继电器,光照强度低于200 Lux时开启补光灯继电器。同时,系统支持手动/自动模式切换,用户可通过本地4×4矩阵键盘或远程QT上位机选择模式,在自动模式下触发联动控制,在手动模式下由用户远程操控设备。异常检测逻辑集成其中,如温度超过40℃时触发报警事件。通信模块基于ESP8266 Wi-Fi模组,通过串口AT指令与STM32交互。数据通过MQTT协议上传至华为云物联网服务器,实现环境参数的远程存储与同步。STM32定期发送JSON格式的数据包,包括温湿度、土壤湿度和光照值,确保云平台实时更新。下行通信支持接收来自QT上位机的控制指令,如设备开关命令。QT上位机作为远程监控界面,使用Qt Charts库动态绘制实时环境数据及历史曲线图,直观展示趋势变化。通过QMQTT库订阅华为云消息,上位机实时获取并显示数据。用户可在界面手动控制灌溉水泵、补光灯和通风设备,或设置报警阈值。异常发生时,如参数超限,QT界面弹窗报警并记录事件日志,便于追溯分析。执行设备驱动由继电器模块完成。5V继电器控制DC 5V水泵,2路继电器模块分别管理AC 220V补光灯和DC 12V通风电机。STM32输出GPIO信号驱动继电器开关,确保安全隔离。本地交互通过0.96寸OLED显示屏提供参数预览,显示当前模式和环境值,方便现场操作。电源管理采用LM2596降压模块,将输入12V转换为稳定的5V/3A输出,为STM32、传感器、继电器及通信模块供电,保证系统稳定运行。整体设计注重实用性与可靠性,所有功能严格基于给定硬件和需求实现,无额外扩展。系统功能总结功能模块具体实现环境参数采集通过DHT11采集空气温湿度,YL-69检测土壤湿度,BH1750监测光照强度,实时更新数据数据远程传输ESP8266 Wi-Fi模组通过MQTT协议将数据上传至华为云物联网平台存储上位机监控界面QT上位机动态显示实时数据,使用Qt Charts绘制历史曲线图双模式设备控制支持手动(QT界面远程控制)和自动模式,控制灌溉水泵、补光灯、通风设备阈值联动控制自动触发:土壤湿度<30%启动水泵,光照<200 Lux开启补光灯异常报警系统环境超限(如温度>40℃)时QT界面弹窗报警,并记录事件日志本地交互模块4×4矩阵键盘切换控制模式,0.96寸OLED显示屏实时预览本地环境参数执行设备驱动继电器模块驱动水泵(5V DC)、补光灯(220V AC)和通风电机(12V DC)电源管理LM2596降压模块提供5V/3A稳定电源,支持多设备供电设计的各个功能模块描述STM32F103C8T6主控芯片模块负责整体系统的数据处理与控制逻辑执行,包括读取传感器数据、处理自动阈值联动规则(如土壤湿度低于30%时启动水泵或光照低于200 Lux时开启补光灯),并根据手动或自动模式决策执行设备的启停,同时管理本地交互和通信模块的数据流转。环境传感器模块集成DHT11传感器采集空气温湿度数据,YL-69土壤湿度传感器检测土壤水分值,以及BH1750光照传感器监测光照强度,所有数据通过模拟或数字接口实时传输至主控芯片,确保温室环境参数的准确获取。执行设备驱动模块利用继电器模块控制外部设备,包括5V继电器驱动DC 5V灌溉水泵、2路继电器分别控制AC 220V补光灯和DC 12V通风电机,主控芯片根据传感器数据或QT上位机指令输出高低电平信号,实现设备的远程或本地开关操作。通信模块基于ESP8266-01S Wi-Fi模组,通过串口AT指令与主控芯片交互,使用MQTT协议连接华为云物联网平台,实现环境数据的实时上传、云存储以及从云平台接收QT上位机的控制命令,保障远程数据传输的可靠性。QT上位机界面模块运行在PC端,通过QMQTT库订阅华为云平台消息,动态显示实时空气温湿度、土壤湿度和光照强度数据,利用Qt Charts组件绘制历史曲线图,支持用户手动远程控制水泵、补光灯和通风设备,并在检测到异常(如温度超过40℃)时触发弹窗报警和事件日志记录。电源管理模块采用LM2596降压模块,将外部输入的12V电源转换为稳定的5V/3A输出,为STM32主控板、传感器、继电器及通信模块提供所需电力,确保系统各部分的稳定运行。本地交互辅助模块包含4×4矩阵键盘用于现场手动切换系统工作模式(自动或手动),以及0.96寸OLED显示屏实时预览关键环境参数(如温湿度、光照值),提供基本的本地操作和状态监控功能。上位机代码设计#include <QApplication> #include <QMainWindow> #include <QtCharts> #include <QChartView> #include <QLineSeries> #include <QDateTimeAxis> #include <QValueAxis> #include <QMQTTClient> #include <QVBoxLayout> #include <QHBoxLayout> #include <QLabel> #include <QPushButton> #include <QGroupBox> #include <QMessageBox> #include <QFile> #include <QTextStream> #include <QDateTime> #include <QTimer> using namespace QtCharts; class GreenhouseMonitor : public QMainWindow { Q_OBJECT public: GreenhouseMonitor(QWidget *parent = nullptr) : QMainWindow(parent) { // 初始化UI setupUI(); // 初始化MQTT客户端 setupMQTT(); // 初始化定时器 setupTimers(); } private slots: void onMqttConnected() { qDebug() << "Connected to Huawei Cloud IoT"; mqttClient->subscribe("sensors/data", 0); // 订阅传感器数据主题 } void onMqttMessage(const QMQTTMessage &msg) { QString payload = QString::fromUtf8(msg.payload()); qDebug() << "Received:" << payload; processSensorData(payload); } void onWaterPumpClicked() { sendControlCommand("pump", waterPumpBtn->isChecked()); } void onGrowLightClicked() { sendControlCommand("light", growLightBtn->isChecked()); } void onFanClicked() { sendControlCommand("fan", fanBtn->isChecked()); } void updateRealtimeData() { // 实时数据刷新到UI tempLabel->setText(QString("温度: %1 °C").arg(currentTemp, 0, 'f', 1)); humidityLabel->setText(QString("湿度: %1%").arg(currentHumidity, 0, 'f', 1)); soilLabel->setText(QString("土壤湿度: %1%").arg(currentSoilMoisture, 0, 'f', 1)); lightLabel->setText(QString("光照: %1 Lux").arg(currentLight)); } void checkAlarms() { if (currentTemp > 40.0) { showAlarm("温度警报", QString("温度过高: %1°C > 40°C").arg(currentTemp)); } if (currentSoilMoisture < 30.0) { showAlarm("土壤警报", QString("土壤过干: %1% < 30%").arg(currentSoilMoisture)); } if (currentLight < 200) { showAlarm("光照警报", QString("光照不足: %1 Lux < 200 Lux").arg(currentLight)); } } private: void setupUI() { // 主窗口设置 setWindowTitle("智慧农业温室监控系统"); setGeometry(100, 100, 1200, 800); // 中央部件和布局 QWidget *centralWidget = new QWidget(this); QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget); // 实时数据显示区域 QGroupBox *realtimeGroup = new QGroupBox("实时环境数据"); QHBoxLayout *realtimeLayout = new QHBoxLayout(realtimeGroup); tempLabel = new QLabel("温度: -- °C"); humidityLabel = new QLabel("湿度: --%"); soilLabel = new QLabel("土壤湿度: --%"); lightLabel = new QLabel("光照: -- Lux"); realtimeLayout->addWidget(tempLabel); realtimeLayout->addWidget(humidityLabel); realtimeLayout->addWidget(soilLabel); realtimeLayout->addWidget(lightLabel); // 设备控制区域 QGroupBox *controlGroup = new QGroupBox("设备控制"); QHBoxLayout *controlLayout = new QHBoxLayout(controlGroup); waterPumpBtn = new QPushButton("灌溉水泵"); growLightBtn = new QPushButton("补光灯"); fanBtn = new QPushButton("通风设备"); waterPumpBtn->setCheckable(true); growLightBtn->setCheckable(true); fanBtn->setCheckable(true); controlLayout->addWidget(waterPumpBtn); controlLayout->addWidget(growLightBtn); controlLayout->addWidget(fanBtn); // 历史图表区域 QGroupBox *chartGroup = new QGroupBox("历史数据趋势"); QVBoxLayout *chartLayout = new QVBoxLayout(chartGroup); QChart *chart = new QChart(); chartView = new QChartView(chart); chart->setTitle("温室环境参数变化"); chart->legend()->setVisible(true); // 初始化数据序列 tempSeries = new QLineSeries(); tempSeries->setName("温度(°C)"); humiditySeries = new QLineSeries(); humiditySeries->setName("湿度(%)"); soilSeries = new QLineSeries(); soilSeries->setName("土壤湿度(%)"); lightSeries = new QLineSeries(); lightSeries->setName("光照(Lux)"); chart->addSeries(tempSeries); chart->addSeries(humiditySeries); chart->addSeries(soilSeries); chart->addSeries(lightSeries); // 时间轴设置 QDateTimeAxis *axisX = new QDateTimeAxis(); axisX->setFormat("hh:mm"); axisX->setTitleText("时间"); chart->addAxis(axisX, Qt::AlignBottom); // 数值轴设置 QValueAxis *axisY = new QValueAxis(); axisY->setTitleText("数值"); axisY->setRange(0, 100); chart->addAxis(axisY, Qt::AlignLeft); // 关联序列到坐标轴 tempSeries->attachAxis(axisX); tempSeries->attachAxis(axisY); humiditySeries->attachAxis(axisX); humiditySeries->attachAxis(axisY); soilSeries->attachAxis(axisX); soilSeries->attachAxis(axisY); lightSeries->attachAxis(axisX); lightSeries->attachAxis(axisY); chartLayout->addWidget(chartView); // 组装主界面 mainLayout->addWidget(realtimeGroup); mainLayout->addWidget(controlGroup); mainLayout->addWidget(chartGroup); setCentralWidget(centralWidget); // 连接按钮信号 connect(waterPumpBtn, &QPushButton::clicked, this, &GreenhouseMonitor::onWaterPumpClicked); connect(growLightBtn, &QPushButton::clicked, this, &GreenhouseMonitor::onGrowLightClicked); connect(fanBtn, &QPushButton::clicked, this, &GreenhouseMonitor::onFanClicked); } void setupMQTT() { mqttClient = new QMQTTClient(this); mqttClient->setHost("iotda.cn-north-4.myhuaweicloud.com"); // 华为云地址 mqttClient->setPort(1883); mqttClient->setUsername("设备ID"); mqttClient->setPassword("设备密钥"); mqttClient->setClientId("QT_CLIENT_" + QString::number(rand())); connect(mqttClient, &QMQTTClient::connected, this, &GreenhouseMonitor::onMqttConnected); connect(mqttClient, &QMQTTClient::messageReceived, this, &GreenhouseMonitor::onMqttMessage); mqttClient->connect(); } void setupTimers() { QTimer *dataTimer = new QTimer(this); connect(dataTimer, &QTimer::timeout, this, &GreenhouseMonitor::updateRealtimeData); dataTimer->start(1000); // 每秒更新UI QTimer *alarmTimer = new QTimer(this); connect(alarmTimer, &QTimer::timeout, this, &GreenhouseMonitor::checkAlarms); alarmTimer->start(5000); // 每5秒检查警报 } void processSensorData(const QString &data) { // 示例数据格式: "T=25.6,H=65.2,S=45.1,L=350" QStringList parts = data.split(","); for (const QString &part : parts) { QStringList keyVal = part.split("="); if (keyVal.size() == 2) { QString key = keyVal[0].trimmed(); float value = keyVal[1].toFloat(); if (key == "T") { currentTemp = value; updateChart(tempSeries, value); } else if (key == "H") { currentHumidity = value; updateChart(humiditySeries, value); } else if (key == "S") { currentSoilMoisture = value; updateChart(soilSeries, value); } else if (key == "L") { currentLight = value; updateChart(lightSeries, value); } } } logEvent("数据更新: " + data); } void updateChart(QLineSeries *series, float value) { QDateTime now = QDateTime::currentDateTime(); series->append(now.toMSecsSinceEpoch(), value); // 限制数据点数量(保留最近100个点) if (series->count() > 100) { series->removePoints(0, series->count() - 100); } // 自动调整Y轴范围 QValueAxis *axisY = qobject_cast<QValueAxis*>(chartView->chart()->axes(Qt::Vertical)[0]); double min = axisY->min(); double max = axisY->max(); if (value < min) min = value - 5; if (value > max) max = value + 5; axisY->setRange(min, max); } void sendControlCommand(const QString &device, bool state) { QString topic = "devices/control/" + device; QString payload = state ? "ON" : "OFF"; mqttClient->publish(topic, payload.toUtf8()); logEvent(QString("控制命令: %1 -> %2").arg(device).arg(payload)); } void showAlarm(const QString &title, const QString &message) { QMessageBox::warning(this, title, message); logEvent("警报触发: " + title + " - " + message); } void logEvent(const QString &event) { QFile logFile("event_log.txt"); if (logFile.open(QIODevice::Append)) { QTextStream stream(&logFile); stream << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") << " - " << event << "\n"; logFile.close(); } } private: // UI组件 QLabel *tempLabel; QLabel *humidityLabel; QLabel *soilLabel; QLabel *lightLabel; QPushButton *waterPumpBtn; QPushButton *growLightBtn; QPushButton *fanBtn; QChartView *chartView; // 数据序列 QLineSeries *tempSeries; QLineSeries *humiditySeries; QLineSeries *soilSeries; QLineSeries *lightSeries; // MQTT客户端 QMQTTClient *mqttClient; // 当前环境数据 float currentTemp = 0; float currentHumidity = 0; float currentSoilMoisture = 0; int currentLight = 0; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); GreenhouseMonitor monitor; monitor.show(); return app.exec(); } #include "main.moc" 代码说明UI布局:实时数据区:显示温度、湿度、土壤湿度和光照强度控制区:灌溉水泵、补光灯、通风设备的开关按钮图表区:使用Qt Charts展示四种参数的历史曲线MQTT通信:连接华为云IoT平台(需替换实际设备凭证)订阅sensors/data主题接收传感器数据通过devices/control/{device}主题发送控制命令核心功能:实时解析传感器数据(格式示例:"T=25.6,H=65.2,S=45.1,L=350")动态更新折线图(自动调整Y轴范围)定时检查环境阈值并触发弹窗警报事件日志记录到event_log.txt控制逻辑:手动模式:通过按钮控制设备自动模式:根据接收到的数据自动执行阈值控制(代码中已实现警报检查)扩展性:可添加数据库支持存储历史数据可增加多温室切换功能可扩展为多设备协同控制模块代码设计STM32模块代码设计(寄存器方式)#include "stm32f10x.h" // 引脚定义 #define DHT11_PIN GPIO_Pin_13 // PC13 #define PUMP_PIN GPIO_Pin_0 // PC0 #define LIGHT_PIN GPIO_Pin_1 // PC1 #define FAN_PIN GPIO_Pin_2 // PC2 // 传感器结构体 typedef struct { float temperature; float humidity; uint16_t soil_moisture; uint16_t light_intensity; } SensorData; // 全局变量 SensorData env_data; uint8_t auto_mode = 1; // 默认自动模式 // 函数声明 void RCC_Configuration(void); void GPIO_Configuration(void); void ADC_Configuration(void); void I2C_Configuration(void); void USART_Configuration(void); void DHT11_ReadData(void); uint16_t SoilMoisture_Read(void); uint16_t BH1750_ReadLight(void); void Relay_Control(uint8_t device, uint8_t state); void ESP8266_SendData(void); void SysTick_Handler(void); void Delay_us(uint32_t us); void Delay_ms(uint32_t ms); int main(void) { // 系统初始化 RCC_Configuration(); GPIO_Configuration(); ADC_Configuration(); I2C_Configuration(); USART_Configuration(); // 初始化SysTick定时器(1ms中断) SysTick_Config(SystemCoreClock / 1000); // 继电器初始状态 Relay_Control(0, 0); // 关闭水泵 Relay_Control(1, 0); // 关闭补光灯 Relay_Control(2, 0); // 关闭通风 while(1) { // 1. 采集环境数据 DHT11_ReadData(); env_data.soil_moisture = SoilMoisture_Read(); env_data.light_intensity = BH1750_ReadLight(); // 2. 自动控制逻辑 if(auto_mode) { // 土壤湿度<30%启动水泵 if(env_data.soil_moisture < 300) { // 假设ADC值0-1000对应0-100% Relay_Control(0, 1); } else { Relay_Control(0, 0); } // 光照<200 Lux启动补光灯 if(env_data.light_intensity < 200) { Relay_Control(1, 1); } else { Relay_Control(1, 0); } // 温度>40℃启动通风 if(env_data.temperature > 40.0) { Relay_Control(2, 1); } else { Relay_Control(2, 0); } } // 3. 上传数据到华为云 ESP8266_SendData(); // 4. 添加延时防止频繁采集 Delay_ms(5000); } } // -------------------- DHT11温湿度传感器驱动 -------------------- void DHT11_ReadData(void) { uint8_t data[5] = {0}; uint8_t i, j; // 主机发送开始信号 GPIO_ResetBits(GPIOC, DHT11_PIN); Delay_ms(18); GPIO_SetBits(GPIOC, DHT11_PIN); Delay_us(30); // 设置引脚为输入 GPIOC->CRH &= ~(0x0F << 20); // PC13输入模式 GPIOC->CRH |= (0x04 << 20); // 浮空输入 // 等待DHT11响应 while(GPIO_ReadInputDataBit(GPIOC, DHT11_PIN)); while(!GPIO_ReadInputDataBit(GPIOC, DHT11_PIN)); while(GPIO_ReadInputDataBit(GPIOC, DHT11_PIN)); // 读取40位数据 for(i=0; i<5; i++) { for(j=0; j<8; j++) { while(!GPIO_ReadInputDataBit(GPIOC, DHT11_PIN)); // 等待低电平结束 Delay_us(35); if(GPIO_ReadInputDataBit(GPIOC, DHT11_PIN)) { data[i] |= (1 << (7-j)); while(GPIO_ReadInputDataBit(GPIOC, DHT11_PIN)); // 等待高电平结束 } } } // 设置引脚为输出 GPIOC->CRH &= ~(0x0F << 20); GPIOC->CRH |= (0x03 << 20); // 推挽输出 // 校验数据 if(data[4] == (data[0] + data[1] + data[2] + data[3])) { env_data.humidity = data[0]; env_data.temperature = data[2]; } } // -------------------- YL-69土壤湿度传感器驱动 -------------------- uint16_t SoilMoisture_Read(void) { ADC1->CR2 |= ADC_CR2_ADON; // 开启ADC ADC1->CR2 |= ADC_CR2_SWSTART; // 开始转换 while(!(ADC1->SR & ADC_SR_EOC)); // 等待转换完成 return ADC1->DR; // 返回ADC值 } // -------------------- BH1750光照传感器驱动 -------------------- void BH1750_WriteCmd(uint8_t cmd) { I2C1->CR1 |= I2C_CR1_START; // 发送START while(!(I2C1->SR1 & I2C_SR1_SB)); // 等待START发送完成 I2C1->DR = 0x46; // BH1750写地址(0x23<<1) while(!(I2C1->SR1 & I2C_SR1_ADDR)); // 等待地址发送完成 (void)I2C1->SR2; // 清除ADDR标志 while(!(I2C1->SR1 & I2C_SR1_TXE)); // 等待数据寄存器空 I2C1->DR = cmd; // 发送命令 while(!(I2C1->SR1 & I2C_SR1_BTF)); // 等待传输完成 I2C1->CR1 |= I2C_CR1_STOP; // 发送STOP } uint16_t BH1750_ReadLight(void) { uint8_t data[2] = {0}; // 发送启动测量命令 BH1750_WriteCmd(0x10); // 连续H分辨率模式 Delay_ms(180); // 等待测量完成 // 读取数据 I2C1->CR1 |= I2C_CR1_START; while(!(I2C1->SR1 & I2C_SR1_SB)); I2C1->DR = 0x47; // BH1750读地址 while(!(I2C1->SR1 & I2C_SR1_ADDR)); (void)I2C1->SR2; // 读取高字节 while(!(I2C1->SR1 & I2C_SR1_RXNE)); data[0] = I2C1->DR; // 读取低字节 while(!(I2C1->SR1 & I2C_SR1_RXNE)); data[1] = I2C1->DR; I2C1->CR1 |= I2C_CR1_STOP; return (data[0] << 8) | data[1]; // 返回光照值 } // -------------------- 继电器控制函数 -------------------- void Relay_Control(uint8_t device, uint8_t state) { switch(device) { case 0: // 水泵 state ? GPIO_SetBits(GPIOC, PUMP_PIN) : GPIO_ResetBits(GPIOC, PUMP_PIN); break; case 1: // 补光灯 state ? GPIO_SetBits(GPIOC, LIGHT_PIN) : GPIO_ResetBits(GPIOC, LIGHT_PIN); break; case 2: // 通风 state ? GPIO_SetBits(GPIOC, FAN_PIN) : GPIO_ResetBits(GPIOC, FAN_PIN); break; } } // -------------------- ESP8266通信函数 -------------------- void ESP8266_SendData(void) { char buffer[128]; // 构造MQTT消息 (示例格式) sprintf(buffer, "AT+MQTTPUB=0,\"sensors/data\",\"%.1f,%.1f,%d,%d\",0,0\r\n", env_data.temperature, env_data.humidity, env_data.soil_moisture, env_data.light_intensity); // 通过USART1发送数据 for(char *p = buffer; *p; p++) { USART1->DR = *p; while(!(USART1->SR & USART_SR_TXE)); } } // -------------------- 系统时钟配置 -------------------- void RCC_Configuration(void) { // 使能外设时钟 RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN | RCC_APB2ENR_ADC1EN | RCC_APB2ENR_USART1EN; RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // 配置ADC时钟 RCC->CFGR |= RCC_CFGR_ADCPRE_DIV6; } // -------------------- GPIO配置 -------------------- void GPIO_Configuration(void) { // DHT11 (PC13 推挽输出) GPIOC->CRH &= ~(0x0F << 20); GPIOC->CRH |= (0x03 << 20); // 继电器控制 (PC0, PC1, PC2 推挽输出) GPIOC->CRL &= ~(0xFF << 0); GPIOC->CRL |= (0x33 << 0); // YL-69 (PA0 模拟输入) GPIOA->CRL &= ~(0x0F << 0); // BH1750 (PB6-SCL, PB7-SDA 复用开漏) GPIOB->CRL &= ~(0xFF << 24); GPIOB->CRL |= (0x77 << 24); GPIOB->ODR |= (1 << 6) | (1 << 7); // 上拉 // ESP8266 (PA9-TX, PA10-RX 复用推挽) GPIOA->CRH &= ~(0xFF << 4); GPIOA->CRH |= (0x4B << 4); } // -------------------- ADC配置 -------------------- void ADC_Configuration(void) { // 配置ADC1通道0 (PA0) ADC1->SQR3 = 0; // 通道0作为第一个转换 ADC1->SMPR2 = 0x07; // 239.5周期采样时间 ADC1->CR2 = ADC_CR2_ADON; // 开启ADC Delay_ms(1); // 等待稳定 } // -------------------- I2C配置 -------------------- void I2C_Configuration(void) { // 标准模式(100kHz) I2C1->CR2 = 36; // APB1时钟36MHz I2C1->CCR = 180; // CCR = 36M / (2*100k) = 180 I2C1->TRISE = 37; // TRISE = 36M*0.001 +1 = 37 I2C1->CR1 = I2C_CR1_PE; // 使能I2C } // -------------------- USART配置 -------------------- void USART_Configuration(void) { // 波特率115200 (36MHz) USART1->BRR = 0x0139; // 36M/115200=312.5->0x139 USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; } // -------------------- 延时函数 -------------------- void Delay_us(uint32_t us) { uint32_t start = SysTick->VAL; uint32_t ticks = us * (SystemCoreClock / 1000000); while((start - SysTick->VAL) < ticks); } void Delay_ms(uint32_t ms) { while(ms--) Delay_us(1000); } // SysTick中断处理函数 void SysTick_Handler(void) { // 可用于精确计时 } 关键代码说明传感器驱动DHT11:使用单总线协议,通过PC13引脚实现温湿度采集YL-69:通过ADC1通道0(PA0)读取土壤湿度模拟值BH1750:通过I2C1接口(PB6/PB7)读取光照强度控制逻辑自动模式根据阈值控制设备:土壤湿度 < 30% → 启动水泵光照 < 200 Lux → 启动补光灯温度 > 40℃ → 启动通风通信接口ESP8266通过USART1(PA9/PA10)发送MQTT数据到华为云数据格式:"温度,湿度,土壤湿度,光照强度"安全机制数据校验(DHT11校验和验证)传感器采集间隔(5秒)继电器初始化为关闭状态硬件接口继电器控制:PC0(水泵)、PC1(补光灯)、PC2(通风)ADC采样:PA0(土壤湿度)I2C总线:PB6(SCL)/PB7(SDA)(BH1750+OLED)项目核心代码以下是基于STM32F103C8T6的智慧农业系统main.c完整代码(寄存器开发):#include "stm32f10x.h" #include "dht11.h" #include "bh1750.h" #include "esp8266.h" #include "oled.h" #include "keypad.h" // 硬件定义 #define PUMP_GPIO GPIOA #define PUMP_PIN GPIO_Pin_0 // 水泵继电器控制 #define LIGHT_GPIO GPIOA #define LIGHT_PIN GPIO_Pin_1 // 补光灯继电器控制 #define FAN_GPIO GPIOA #define FAN_PIN GPIO_Pin_2 // 通风设备继电器控制 // 全局变量 typedef struct { float temperature; float humidity; uint16_t soil_moisture; uint16_t light_intensity; } SensorData; volatile SensorData env_data = {0}; volatile uint8_t sys_mode = 0; // 0:自动模式 1:手动模式 volatile uint8_t pump_state = 0; // 水泵状态 volatile uint8_t light_state = 0; // 补光灯状态 volatile uint8_t fan_state = 0; // 通风状态 // 初始化函数声明 void RCC_Configuration(void); void GPIO_Configuration(void); void ADC_Configuration(void); void TIM3_Init(void); void NVIC_Configuration(void); void ControlDevices(void); int main(void) { // 系统初始化 RCC_Configuration(); GPIO_Configuration(); ADC_Configuration(); TIM3_Init(); NVIC_Configuration(); OLED_Init(); Keypad_Init(); ESP8266_Init(); DHT11_Init(); BH1750_Init(); // 显示启动界面 OLED_ShowString(0, 0, "AgriSystem Start"); Delay_ms(1000); OLED_Clear(); // 连接华为云 ESP8266_ConnectCloud(); // 主循环 while(1) { // 1. 按键扫描(模式切换) uint8_t key = Keypad_Scan(); if(key == 0x01) { // 假设按键1切换模式 sys_mode = !sys_mode; OLED_ShowString(0, 2, sys_mode ? "Mode:Manual " : "Mode:Auto "); } // 2. 传感器数据采集(在TIM3中断中周期性执行) // 3. 设备控制逻辑 ControlDevices(); // 4. 异常检测(温度>40℃报警) if(env_data.temperature > 40.0) { // 通过MQTT发送报警信息 char alert_msg[50]; sprintf(alert_msg, "ALERT:HighTemp=%.1fC", env_data.temperature); ESP8266_MQTTPublish("alert_topic", alert_msg); } // 5. OLED显示刷新 static uint32_t oled_tick = 0; if(SystemTick - oled_tick > 500) { OLED_ShowString(0, 0, "T:"); OLED_ShowFloat(16, 0, env_data.temperature); OLED_ShowString(0, 2, sys_mode ? "Mode:Manual " : "Mode:Auto "); OLED_ShowString(0, 4, "Pump:"); OLED_ShowString(48, 4, pump_state ? "ON " : "OFF"); oled_tick = SystemTick; } // 6. 处理云平台指令 if(ESP8266_RxFlag) { MQTT_MessageProcess(ESP8266_RxBuffer); ESP8266_RxFlag = 0; } } } // 时钟配置 void RCC_Configuration(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN | RCC_APB2ENR_ADC1EN; RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; } // GPIO配置 void GPIO_Configuration(void) { // 继电器控制引脚 GPIOA->CRL &= 0xFFFFF000; // PA0,PA1,PA2推挽输出 GPIOA->CRL |= 0x00000333; GPIOA->ODR &= ~(PUMP_PIN | LIGHT_PIN | FAN_PIN); // 传感器引脚初始化在各驱动模块中完成 } // ADC配置(土壤湿度) void ADC_Configuration(void) { ADC1->CR2 = ADC_CR2_ADON; // 开启ADC ADC1->SMPR2 = 0x00000007; // 通道0采样时间239.5周期 RCC->CFGR |= RCC_CFGR_ADCPRE_DIV6; // ADC时钟12MHz } // 定时器3初始化(1s周期) void TIM3_Init(void) { TIM3->PSC = 7200 - 1; // 10kHz TIM3->ARR = 10000 - 1; // 1s中断 TIM3->DIER = TIM_DIER_UIE; // 允许更新中断 TIM3->CR1 = TIM_CR1_CEN; // 启动定时器 } // 中断配置 void NVIC_Configuration(void) { NVIC_EnableIRQ(TIM3_IRQn); NVIC_SetPriority(TIM3_IRQn, 0); } // 设备控制逻辑 void ControlDevices(void) { if(sys_mode == 0) { // 自动模式 // 土壤湿度<30%启动水泵 if(env_data.soil_moisture < 30 && !pump_state) { PUMP_GPIO->BSRR = PUMP_PIN; // 开启水泵 pump_state = 1; } else if(env_data.soil_moisture >= 35 && pump_state) { PUMP_GPIO->BRR = PUMP_PIN; // 关闭水泵 pump_state = 0; } // 光照<200Lux开启补光灯 if(env_data.light_intensity < 200 && !light_state) { LIGHT_GPIO->BSRR = LIGHT_PIN; light_state = 1; } else if(env_data.light_intensity >= 250 && light_state) { LIGHT_GPIO->BRR = LIGHT_PIN; light_state = 0; } } else { // 手动模式(状态由云平台指令控制) GPIOA->BSRR = pump_state ? PUMP_PIN : (PUMP_PIN << 16); GPIOA->BSRR = light_state ? LIGHT_PIN : (LIGHT_PIN << 16); GPIOA->BSRR = fan_state ? FAN_PIN : (FAN_PIN << 16); } } // TIM3中断处理(传感器采集) void TIM3_IRQHandler(void) { if(TIM3->SR & TIM_SR_UIF) { TIM3->SR = ~TIM_SR_UIF; // 读取DHT11 DHT11_ReadData(&env_data.temperature, &env_data.humidity); // 读取BH1750 env_data.light_intensity = BH1750_ReadLight(); // 读取土壤湿度(ADC通道0) ADC1->CR2 |= ADC_CR2_ADON; while(!(ADC1->SR & ADC_SR_EOC)); env_data.soil_moisture = ADC1->DR; // 原始ADC值0-4095 // 上传到华为云 char mqtt_data[128]; sprintf(mqtt_data, "{\"temp\":%.1f,\"humi\":%.1f,\"soil\":%d,\"light\":%d}", env_data.temperature, env_data.humidity, env_data.soil_moisture, env_data.light_intensity); ESP8266_MQTTPublish("sensor_data", mqtt_data); } } // MQTT消息处理(来自云平台) void MQTT_MessageProcess(char *msg) { if(strstr(msg, "pump=1")) pump_state = 1; else if(strstr(msg, "pump=0")) pump_state = 0; else if(strstr(msg, "light=1")) light_state = 1; else if(strstr(msg, "light=0")) light_state = 0; else if(strstr(msg, "fan=1")) fan_state = 1; else if(strstr(msg, "fan=0")) fan_state = 0; } // 简单延时函数 void Delay_ms(uint32_t ms) { for(uint32_t i=0; i<ms*8000; i++); } 代码说明:系统初始化:配置时钟、GPIO、ADC、定时器、中断和外设驱动启动OLED显示和WiFi连接主循环功能:按键检测(模式切换)设备控制逻辑(自动/手动模式)温度异常报警(>40℃)OLED数据刷新MQTT消息处理定时器中断(TIM3):每1秒采集所有传感器数据通过MQTT上传到华为云平台控制逻辑:自动模式:土壤湿度<30%启动水泵,光照<200Lux开补光灯手动模式:接收云平台指令控制设备硬件控制:继电器控制使用GPIO直接寄存器操作土壤湿度通过ADC采集原始值总结本项目成功构建了一套以STM32F103C8T6为核心的智慧农业温室环境监测与联动控制系统。系统通过集成DHT11温湿度传感器、YL-69土壤湿度传感器和BH1750光照传感器,精准采集温室环境关键参数,为精细化管理提供数据基础。借助ESP8266 Wi-Fi模块的通信能力,系统通过MQTT协议将实时数据稳定上传至华为云物联网平台,实现了环境信息的远程存储与可视化。QT上位机不仅动态展示实时数据,还利用Qt Charts组件绘制历史曲线图,直观呈现环境变化趋势,并具备手动远程控制水泵、补光灯及通风设备的能力。系统创新性地融合了手动与自动双模式控制策略。在自动模式下,基于预设阈值(土壤湿度<30%启动水泵、光照<200 Lux开启补光灯)的智能联动机制,显著提升了环境调控的及时性与能效。同时,QT界面的异常弹窗报警与事件记录功能(如温度>40℃),有效保障了温室运行的可靠性与安全性。硬件架构设计合理,STM32主控高效协调传感器数据采集、继电器驱动(控制5V水泵、12V通风电机及220V补光灯)及本地交互(4×4键盘模式切换、OLED参数预览)。电源模块(LM2596降压)为各单元提供稳定供电,确保系统长时间稳定运行。综上所述,本系统实现了温室环境参数的全面感知、云端互联、智能决策与精准执行,为现代化农业生产提供了高效、可靠且用户友好的自动化管理解决方案,有力推动了农业智能化升级。
-
项目开发背景随着现代农业向集约化、智能化方向快速发展,传统温室管理模式面临诸多挑战。人工监测环境参数(如温湿度、土壤墒情、光照)效率低下且难以实现24小时精准控制,依赖经验判断易导致调控滞后或失误,造成作物生长环境波动大、资源浪费(如水肥过量)甚至减产风险。尤其在极端天气频发和劳动力成本上升的背景下,亟需通过技术手段提升温室管理的自动化与科学化水平。物联网技术与嵌入式系统的成熟为解决上述问题提供了有效路径。基于STM32F103C8T6微控制器的智慧农业系统,通过集成多类型环境传感器(DHT11、YL-69、BH1750),实现对温室关键参数的实时精准采集;结合阈值逻辑自动控制通风、灌溉、补光设备,确保作物始终处于适宜生长环境。同时,利用ESP8266 WiFi模块将数据上传至华为云物联网平台,打破地域限制,为远程监管奠定基础。该系统的核心价值在于构建“端-云-端”协同的闭环管理架构。云端不仅提供海量数据存储与分析能力,还通过开放API实现与QT开发的上位机应用无缝对接。农户可通过上位机的动态曲线直观掌握环境变化趋势,并在异常(如高温>35℃)时接收弹窗报警与日志记录;更重要的是,无论身处何地,都能通过华为云平台或QT界面远程手动干预设备(如紧急启动风扇),大幅提升应急响应速度与操作便捷性。此外,本地SD卡模块的设计增强了系统鲁棒性,在网络中断时仍能缓存关键数据与报警日志,避免信息丢失,确保生产记录的完整性。综上所述,本项目的开发不仅响应了智慧农业对降本增效的核心诉求,更通过多层次的技术融合,为现代化温室提供了一套高可靠性、可扩展的数字化管理解决方案。设计实现的功能(1)多传感器数据融合采集:DHT11采集空气温湿度,YL-69土壤湿度传感器检测墒情,BH1750光照传感器监测光强。(2)阈值联动控制:STM32自动比对预设阈值(如土壤湿度<30%启动灌溉),通过继电器驱动执行设备。(3)华为云协议对接:ESP8266模块使用MQTT协议传输数据至华为云IoTDA服务。(4)QT数据可视化:动态折线图展示环境参数变化趋势,按钮控件绑定设备开关指令。(5)双向通信:上位机通过华为云API订阅设备消息,并下发控制指令(如手动开关补光灯)。(6)本地数据缓存:SD卡模块存储异常数据备份,确保网络中断时数据不丢失。项目硬件模块组成(1)主控单元:STM32F103C8T6核心板。(2)传感器组:DHT11(温湿度)、YL-69(土壤湿度)、BH1750(光照强度)。(3)通信模块:ESP8266-01S WiFi模组(AT指令模式)。(4)执行单元:5V四路继电器模块(控制12V直流风扇、5V微型水泵、220V补光灯)。(5)存储模块:MicroSD卡读写模块(SPI接口,存储阈值配置与报警日志)。(6)电源模块:LM2596降压电路(12V转5V供电),220V转12V适配器(总电源)。(7)人机交互:0.96寸OLED显示屏(本地参数显示),蜂鸣器(本地异常报警)。设计意义本系统的设计意义在于显著提升现代农业温室管理的智能化水平。通过集成多类型环境传感器与自动控制设备,系统实现了对温室空气温湿度、土壤墒情及光照强度的全天候精准监测,并依据预设阈值自动触发通风、灌溉、补光等调控动作。这一闭环控制机制有效替代传统人工巡检,大幅降低劳动力成本,同时避免因环境突变导致的作物减产风险,例如高温自动通风可防止热害,土壤湿度联动灌溉能精准优化水资源利用。系统依托华为云物联网平台构建远程监管能力,将实时环境数据通过WiFi模块上传至云端,使农户可通过QT上位机远程查看温室状态曲线。结合双向通信技术,用户无论在云端平台或本地QT界面均可手动干预设备启停,突破地理限制及时响应突发状况。该设计不仅为精细化种植提供数据支撑,更赋予生产管理高度的灵活性与及时性,尤其适合大规模连栋温室群的集中监控。异常处理与数据冗余设计进一步强化系统可靠性。当检测到温度骤升等危险值时,QT界面自动弹窗报警并记录日志至SD卡,配合蜂鸣器实现声光双重警示。本地存储模块在网络中断时持续备份关键数据,确保生产记录完整可追溯。这种多层次保障机制显著降低因设备故障或网络波动导致的生产事故概率,为设施农业的稳定运行构建坚实技术基础。设计思路设计思路:系统以STM32F103C8T6为主控制器,通过多接口协议实现环境数据采集与设备联动控制。传感器数据由DHT11(单总线协议)、YL-69(ADC模拟量采集)和BH1750(I2C总线)实时获取,经卡尔曼滤波处理后与预设阈值比对。当土壤湿度低于30%时,GPIO触发继电器启动灌溉泵;温度超限时启动通风扇;光照不足则开启补光灯,所有执行设备均通过光耦隔离继电器控制,确保强电弱电分离。ESP8266 WiFi模块通过串口AT指令与STM32通信,采用MQTT协议将JSON格式数据上传至华为云物联网平台,同时订阅云平台下行指令Topic。网络异常时,传感器数据自动转存至SPI接口的MicroSD卡,记录时间戳及异常值,实现断网缓存。QT上位机通过华为云API订阅设备消息,动态绘制温湿度/光照/土壤曲线图,并嵌入设备控制按钮。用户点击按钮时生成标准MQTT指令下发至云平台,STM32解析后执行对应操作。当检测到温度>35℃等异常数据时,QT界面触发弹窗报警并生成日志文件,同时STM32驱动蜂鸣器进行本地报警,OLED屏实时刷新环境参数状态。电源系统采用220V转12V适配器供电,经LM2596降压模块输出5V为控制电路供电,继电器模块分别控制12V风扇、5V水泵及220V补光灯。系统初始化时从SD卡加载阈值配置,运行中持续监测各模块状态,确保稳定运行。框架图+-------------------------------------------------------------------------------------------------+ | 智慧农业温室环境监测与调控系统 | | | | +---------------------+ +---------------------------+ +-------------------------+ | | | 感知层 | | 控制层 | | 执行层 | | | | [DHT11温湿度] |----->| |----->| [继电器1]→通风扇(降温) | | | | [YL-69土壤湿度] | UART | | GPIO | [继电器2]→灌溉泵(增湿) | | | | [BH1750光照强度] |----->| STM32F103C8T6 |----->| [继电器3]→补光灯(调光) | | | +---------------------+ | - 阈值比对与自动控制逻辑 | +-------------------------+ | | | - 传感器数据融合处理 | | | +---------------------+ | - 华为云协议封装 | +-------------------------+ | | | 本地交互层 |<---->| - SD卡数据管理 |<---->| [OLED显示] | | | | [0.96寸OLED] | I2C | | GPIO | [蜂鸣器报警] | | | | [蜂鸣器] |<---->| | +-------------------------+ | | +---------------------+ +------------+--------------+ | | | UART | | | | | +---------------------+ +------------v--------------+ +-------------------------+ | | | 通信层 | | 存储层 | | 云端平台 | | | | [ESP8266 WiFi模块] |<---->| [MicroSD卡] | MQTT | [华为云物联网平台] | | | | - MQTT协议传输 | SPI | - 存储阈值配置 |----->| - 设备状态监控 | | | | - AT指令模式 | | - 异常数据备份 |<-----| - 指令下发 | | | +---------------------+ +---------------------------+ +------------+------------+ | | | API/Websocket | | | | | +-----------------------------------------------------------------------------v-------------+ | | | 应用层 | | | | [QT上位机] | | | | - 动态环境数据曲线(温/湿/光/土) | | | | - 设备状态实时显示(风扇/水泵/灯) | | | | - 远程手动控制按钮 | | | | - 异常弹窗报警(温度>35℃等) | | | | - 操作日志记录 | | | +------------------------------------------------------------------------------------------+ | | | | 电源架构: | | [220V交流] → [220V转12V适配器] → [LM2596降压] → 5V系统供电(MCU/传感器/继电器控制端) | | └─→ 12V供电(直流风扇) | +-------------------------------------------------------------------------------------------------+系统总体设计系统总体设计围绕STM32F103C8T6微控制器构建,实现温室环境智能化监测与调控。该系统通过集成多类型传感器实时获取环境参数:DHT11传感器采集空气温湿度,YL-69土壤湿度传感器检测土壤墒情,BH1750光照传感器监测温室光照强度。主控芯片对采集数据进行融合处理,并与预设阈值进行自动比对(如土壤湿度低于30%或温度高于设定值)。当环境参数超出阈值范围时,系统触发自动控制逻辑。STM32通过GPIO输出信号驱动5V四路继电器模块,进而控制执行设备动作:启动12V通风扇实现降温,开启5V微型灌溉泵增加土壤湿度,或接通220V补光灯调节光照强度。所有执行设备状态及传感器数据通过ESP8266-01S WiFi模块传输,该模块运行于AT指令模式,采用MQTT协议将数据稳定上传至华为云物联网平台(IoTDA),并接收来自云端的控制指令。QT开发的上位机软件通过订阅华为云API接口,实现远程数据监控与设备管理。软件界面动态绘制环境参数(温湿度、土壤湿度、光照)的实时变化曲线,并显示继电器及执行设备状态。用户可在QT界面上点击按钮,远程手动控制通风扇、灌溉泵或补光灯的启停。当检测到严重异常数据(如温度>35℃)时,上位机自动触发弹窗报警并生成日志文件。为增强系统可靠性,集成MicroSD卡存储模块(SPI接口)。该模块用于缓存传感器阈值配置信息,并在网络异常或检测到报警事件时,将关键环境数据及报警日志本地备份,确保数据不丢失。本地交互由0.96寸OLED显示屏实时显示核心环境参数与设备状态,蜂鸣器在检测到本地阈值超限时发出声光报警。系统供电采用220V转12V适配器作为总输入,经LM2596降压电路转换为5V为各模块供电。系统功能总结功能类别功能描述环境监测实时采集空气温湿度(DHT11)、土壤湿度(YL-69)、光照强度(BH1750)自动调控超阈值自动控制设备:? 温度过高 → 启动通风扇? 土壤过干 → 启动灌溉泵? 光照不足 → 开启补光灯云平台通信通过ESP8266 WiFi模组,基于MQTT协议将数据上传至华为云IoTDA平台QT上位机? 动态折线图展示环境参数趋势? 实时显示设备状态? 支持远程手动控制执行设备? 异常数据弹窗报警远程控制支持华为云平台与QT上位机双向通信,可远程手动开关通风扇、灌溉泵、补光灯异常处理? 超限数据(如温度>35℃)触发QT弹窗报警? 蜂鸣器本地报警? 记录异常日志至SD卡数据存储MicroSD卡模块缓存异常数据与日志,确保断网时数据不丢失本地交互0.96寸OLED显示屏实时展示环境参数与设备状态设计的各个功能模块描述数据采集模块通过多种传感器实时获取温室环境参数。DHT11数字温湿度传感器采用单总线协议与STM32通信,连续采集空气温湿度数据;YL-69土壤湿度传感器通过ADC通道将模拟量转换为土壤墒情百分比;BH1750光照传感器通过I2C接口提供数字化的光照强度值。所有传感器数据经过中值滤波处理提升准确性。自动控制模块基于阈值比较实现设备联动。STM32读取存储在SD卡中的预设阈值(温度上限、土壤湿度下限等),当检测到空气温度超过35℃时,通过GPIO触发继电器启动12V通风扇;土壤湿度低于30%时激活5V微型灌溉泵;光照不足时控制220V补光灯电路。继电器模块采用光耦隔离确保强电控制安全。云通信模块依托ESP8266-01S建立物联网连接。STM32通过USART发送AT指令配置WiFi模块,采用MQTT协议对接华为云IoTDA服务。设备数据封装为JSON格式发布到云平台指定Topic,同时订阅控制指令Topic,实现参数上传与命令接收的双向通信,支持QoS1级消息保障。上位机交互模块基于QT开发数据可视化界面。通过调用华为云Device API实时获取设备数据,动态绘制温湿度、光照等参数的折线趋势图。界面嵌入设备控制按钮,点击后生成MQTT控制指令经云平台下发。当接收到云平台推送的温度超限等异常消息时,自动弹出报警窗口并写入本地日志文件。异常处理模块实现本地化预警与数据持久化。当检测到环境参数越界时,STM32立即驱动蜂鸣器发出声光警报,同时在OLED屏滚动显示异常信息。MicroSD卡模块通过SPI接口存储两种关键数据:FAT32文件系统下的阈值配置文件,以及按时间戳记录的CSV格式报警日志(含异常类型、数值、发生时间),确保断网期间数据不丢失。人机交互模块提供本地状态监控。0.96寸OLED显示屏通过I2C驱动,分区域显示实时环境参数与设备开关状态。采用循环刷新机制,每2秒更新温度/湿度/光照的数值显示,并在设备动作时突出对应继电器状态图标,便于现场人员快速掌握系统运行情况。上位机代码设计上位机代码设计(基于Qt/C++)// mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtCharts> #include <QMqttClient> #include <QDateTime> #include <QFile> QT_CHARTS_USE_NAMESPACE namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: // MQTT通信 void connectToBroker(); void onMqttConnected(); void onMqttMessageReceived(const QByteArray &message, const QMqttTopicName &topic); // 数据处理 void updateSensorData(const QJsonObject &data); void checkAlarmConditions(const QJsonObject &data); // 设备控制 void on_fanControl_clicked(); void on_pumpControl_clicked(); void on_lightControl_clicked(); // 报警处理 void showAlarmDialog(const QString &message); void logAlarmEvent(const QString &event); private: Ui::MainWindow *ui; QMqttClient *mqttClient; // 图表数据序列 QLineSeries *tempSeries; QLineSeries *humiditySeries; QLineSeries *soilSeries; QLineSeries *lightSeries; // 时间轴 QDateTimeAxis *axisX; // 报警日志文件 QFile alarmLogFile; // 设备状态 bool fanState = false; bool pumpState = false; bool lightState = false; // 阈值设置 const double TEMP_ALARM_THRESHOLD = 35.0; const double SOIL_MOISTURE_THRESHOLD = 30.0; }; #endif // MAINWINDOW_H // mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h" #include <QJsonDocument> #include <QJsonObject> #include <QMessageBox> #include <QTimer> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); // 初始化MQTT客户端 mqttClient = new QMqttClient(this); mqttClient->setHostname("your_huaweicloud_iot_host"); // 替换为华为云地址 mqttClient->setPort(1883); mqttClient->setClientId("QT_Client_" + QString::number(qrand())); mqttClient->setUsername("your_username"); mqttClient->setPassword("your_password"); // 连接信号槽 connect(mqttClient, &QMqttClient::connected, this, &MainWindow::onMqttConnected); connect(mqttClient, &QMqttClient::messageReceived, this, &MainWindow::onMqttMessageReceived); // 初始化图表 QChart *chart = new QChart(); tempSeries = new QLineSeries(); humiditySeries = new QLineSeries(); soilSeries = new QLineSeries(); lightSeries = new QLineSeries(); tempSeries->setName("温度(℃)"); humiditySeries->setName("空气湿度(%)"); soilSeries->setName("土壤湿度(%)"); lightSeries->setName("光照强度(lux)"); chart->addSeries(tempSeries); chart->addSeries(humiditySeries); chart->addSeries(soilSeries); chart->addSeries(lightSeries); axisX = new QDateTimeAxis(); axisX->setFormat("hh:mm:ss"); axisX->setTitleText("时间"); chart->addAxis(axisX, Qt::AlignBottom); QValueAxis *axisY = new QValueAxis(); axisY->setLabelFormat("%d"); axisY->setTitleText("数值"); axisY->setRange(0, 100); chart->addAxis(axisY, Qt::AlignLeft); tempSeries->attachAxis(axisX); tempSeries->attachAxis(axisY); humiditySeries->attachAxis(axisX); humiditySeries->attachAxis(axisY); soilSeries->attachAxis(axisX); soilSeries->attachAxis(axisY); QValueAxis *axisYRight = new QValueAxis(); axisYRight->setLabelFormat("%d"); axisYRight->setTitleText("光照强度"); axisYRight->setRange(0, 10000); chart->addAxis(axisYRight, Qt::AlignRight); lightSeries->attachAxis(axisX); lightSeries->attachAxis(axisYRight); ui->chartView->setChart(chart); ui->chartView->setRenderHint(QPainter::Antialiasing); // 初始化报警日志 alarmLogFile.setFileName("alarm_log.csv"); if(alarmLogFile.open(QIODevice::WriteOnly | QIODevice::Append)) { QTextStream stream(&alarmLogFile); stream << "时间,事件类型,数值\n"; } // 连接MQTT代理 connectToBroker(); } MainWindow::~MainWindow() { alarmLogFile.close(); delete ui; } void MainWindow::connectToBroker() { if(mqttClient->state() == QMqttClient::Disconnected) { mqttClient->connectToHost(); } } void MainWindow::onMqttConnected() { // 订阅设备数据主题 mqttClient->subscribe("device/sensor/data", 1); // 订阅设备状态主题 mqttClient->subscribe("device/status", 1); } void MainWindow::onMqttMessageReceived(const QByteArray &message, const QMqttTopicName &topic) { QJsonDocument doc = QJsonDocument::fromJson(message); if(doc.isNull()) return; QJsonObject obj = doc.object(); if(topic.name() == "device/sensor/data") { updateSensorData(obj); checkAlarmConditions(obj); } else if(topic.name() == "device/status") { fanState = obj["fan"].toBool(); pumpState = obj["pump"].toBool(); lightState = obj["light"].toBool(); ui->fanStatus->setText(fanState ? "运行中" : "已停止"); ui->pumpStatus->setText(pumpState ? "运行中" : "已停止"); ui->lightStatus->setText(lightState ? "运行中" : "已停止"); } } void MainWindow::updateSensorData(const QJsonObject &data) { QDateTime currentTime = QDateTime::currentDateTime(); double temperature = data["temperature"].toDouble(); double humidity = data["humidity"].toDouble(); double soilMoisture = data["soil_moisture"].toDouble(); double lightIntensity = data["light_intensity"].toDouble(); // 更新实时数据标签 ui->tempLabel->setText(QString::number(temperature, 'f', 1) + " ℃"); ui->humidityLabel->setText(QString::number(humidity, 'f', 1) + " %"); ui->soilLabel->setText(QString::number(soilMoisture, 'f', 1) + " %"); ui->lightLabel->setText(QString::number(lightIntensity, 'f', 0) + " lux"); // 更新图表数据 tempSeries->append(currentTime.toMSecsSinceEpoch(), temperature); humiditySeries->append(currentTime.toMSecsSinceEpoch(), humidity); soilSeries->append(currentTime.toMSecsSinceEpoch(), soilMoisture); lightSeries->append(currentTime.toMSecsSinceEpoch(), lightIntensity); // 保持最近100个数据点 if(tempSeries->count() > 100) { tempSeries->remove(0); humiditySeries->remove(0); soilSeries->remove(0); lightSeries->remove(0); } // 更新X轴范围 axisX->setRange(QDateTime::currentDateTime().addSecs(-300), QDateTime::currentDateTime().addSecs(10)); } void MainWindow::checkAlarmConditions(const QJsonObject &data) { double temperature = data["temperature"].toDouble(); double soilMoisture = data["soil_moisture"].toDouble(); if(temperature > TEMP_ALARM_THRESHOLD) { QString msg = QString("温度过高警报: %1 ℃ > %2 ℃").arg(temperature).arg(TEMP_ALARM_THRESHOLD); showAlarmDialog(msg); logAlarmEvent("温度警报," + QString::number(temperature)); } if(soilMoisture < SOIL_MOISTURE_THRESHOLD) { QString msg = QString("土壤干燥警报: %1% < %2%").arg(soilMoisture).arg(SOIL_MOISTURE_THRESHOLD); showAlarmDialog(msg); logAlarmEvent("土壤湿度警报," + QString::number(soilMoisture)); } } void MainWindow::on_fanControl_clicked() { QJsonObject json; json["command"] = "fan"; json["state"] = !fanState; mqttClient->publish(QMqttTopicName("device/control"), QJsonDocument(json).toJson()); } void MainWindow::on_pumpControl_clicked() { QJsonObject json; json["command"] = "pump"; json["state"] = !pumpState; mqttClient->publish(QMqttTopicName("device/control"), QJsonDocument(json).toJson()); } void MainWindow::on_lightControl_clicked() { QJsonObject json; json["command"] = "light"; json["state"] = !lightState; mqttClient->publish(QMqttTopicName("device/control"), QJsonDocument(json).toJson()); } void MainWindow::showAlarmDialog(const QString &message) { QMessageBox::critical(this, "系统警报", message); } void MainWindow::logAlarmEvent(const QString &event) { if(alarmLogFile.isOpen()) { QTextStream stream(&alarmLogFile); stream << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") << "," << event << "\n"; alarmLogFile.flush(); } } // main.cpp #include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.setWindowTitle("智慧农业温室监控系统"); w.resize(1200, 800); w.show(); return a.exec(); } <!-- mainwindow.ui (关键部分) --> <ui version="4.0"> <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow"> <widget class="QWidget" name="centralWidget"> <layout class="QGridLayout" name="gridLayout"> <!-- 图表区域 --> <widget class="QChartView" name="chartView"/> <!-- 数据监控面板 --> <widget class="QGroupBox" name="dataGroupBox"> <layout class="QGridLayout"> <item row="0" column="0"> <widget class="QLabel" name="label_temp"> <property name="text"> <string>当前温度:</string> </property> </widget> </item> <item row="0" column="1"> <widget class="QLabel" name="tempLabel"> <property name="text"> <string>-- ℃</string> </property> </widget> </item> <!-- 其他传感器数据标签 --> </layout> </widget> <!-- 设备控制面板 --> <widget class="QGroupBox" name="controlGroupBox"> <layout class="QGridLayout"> <!-- 风扇控制 --> <item row="0" column="0"> <widget class="QPushButton" name="fanControl"> <property name="text"> <string>开关风扇</string> </property> </widget> </item> <item row="0" column="1"> <widget class="QLabel" name="fanStatus"> <property name="text"> <string>已停止</string> </property> </widget> </item> <!-- 水泵控制 --> <item row="1" column="0"> <widget class="QPushButton" name="pumpControl"> <property name="text"> <string>开关水泵</string> </property> </widget> </item> <item row="1" column="1"> <widget class="QLabel" name="pumpStatus"> <property name="text"> <string>已停止</string> </property> </widget> </item> <!-- 补光灯控制 --> <item row="2" column="0"> <widget class="QPushButton" name="lightControl"> <property name="text"> <string>开关补光灯</string> </property> </widget> </item> <item row="2" column="1"> <widget class="QLabel" name="lightStatus"> <property name="text"> <string>已停止</string> </property> </widget> </item> </layout> </widget> </layout> </widget> </widget> </ui> 项目结构说明智慧农业监控系统/ ├── include/ │ └── mainwindow.h ├── src/ │ ├── main.cpp │ └── mainwindow.cpp ├── resources/ │ └── alarm_log.csv ├── ui/ │ └── mainwindow.ui └── 智慧农业监控系统.pro功能实现细节MQTT通信模块:使用QtMqtt库连接华为云物联网平台订阅设备传感器数据主题(device/sensor/data)订阅设备状态主题(device/status)发布控制指令到device/control主题数据可视化:使用QtCharts绘制四参数实时曲线温度/湿度/土壤湿度共用左侧Y轴(0-100)光照强度使用右侧独立Y轴(0-10000 lux)自动滚动显示最近5分钟数据设备控制:三个独立控制按钮对应通风扇/灌溉泵/补光灯按钮发送JSON格式控制指令:{"command":"fan","state":true}实时更新设备状态标签报警系统:温度>35℃触发弹窗警报土壤湿度<30%触发弹窗警报所有警报事件记录到CSV日志文件日志格式:时间,事件类型,数值数据持久化:报警日志自动保存为CSV格式支持Excel直接打开分析每日自动创建新文件(需扩展实现)编译依赖Qt 5.12+ (含Charts、Mqtt模块)C++11编译器华为云IoT Device SDK配置信息:云平台地址设备认证信息MQTT主题规划注意:实际部署时需要替换以下占位符:your_huaweicloud_iot_hostyour_usernameyour_password设备主题命名空间模块代码设计以下是基于STM32F103C8T6的完整传感器驱动代码(寄存器开发方式):#include "stm32f10x.h" // 硬件定义 #define DHT11_GPIO_PORT GPIOA #define DHT11_PIN GPIO_Pin_0 #define RELAY_FAN_GPIO GPIOC #define RELAY_FAN_PIN GPIO_Pin_13 #define RELAY_PUMP_GPIO GPIOC #define RELAY_PUMP_PIN GPIO_Pin_14 #define RELAY_LIGHT_GPIO GPIOC #define RELAY_LIGHT_PIN GPIO_Pin_15 // DHT11 温湿度传感器 uint8_t DHT11_Read(float *temp, float *humi) { uint8_t data[5] = {0}; uint8_t i, j; // 主机发送开始信号 GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 配置为输出模式 GPIO_InitStruct.GPIO_Pin = DHT11_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct); // 拉低18ms GPIO_ResetBits(DHT11_GPIO_PORT, DHT11_PIN); Delay_ms(18); GPIO_SetBits(DHT11_GPIO_PORT, DHT11_PIN); Delay_us(30); // 切换为输入模式 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct); // 等待DHT11响应 if (GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_PIN) == SET) return 0; while (GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_PIN) == RESET); while (GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_PIN) == SET); // 读取40位数据 for (i = 0; i < 5; i++) { for (j = 0; j < 8; j++) { while (GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_PIN) == RESET); Delay_us(40); if (GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_PIN) == SET) { data[i] |= (1 << (7 - j)); while (GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_PIN) == SET); } } } // 校验数据 if (data[4] == (data[0] + data[1] + data[2] + data[3])) { *humi = data[0]; *temp = data[2]; return 1; } return 0; } // ADC初始化 (YL-69土壤湿度) void ADC1_Init(void) { RCC->APB2ENR |= RCC_APB2ENR_ADC1EN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN; // 配置PA1为模拟输入 GPIOA->CRL &= ~(GPIO_CRL_CNF1 | GPIO_CRL_MODE1); // 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 &= ~ADC_CR1_SCAN; ADC1->CR2 &= ~(ADC_CR2_CONT | ADC_CR2_ALIGN); ADC1->SMPR2 |= ADC_SMPR2_SMP1_0 | ADC_SMPR2_SMP1_1 | ADC_SMPR2_SMP1_2; // 239.5周期采样 } uint16_t Read_Soil_Moisture(void) { ADC1->SQR3 = ADC_SQR3_SQ1_0; // 通道1 ADC1->CR2 |= ADC_CR2_ADON; while (!(ADC1->SR & ADC_SR_EOC)); return ADC1->DR; } // BH1750光照传感器 (I2C1) #define BH1750_ADDR 0x46 void I2C1_Init(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN; RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // PB6(SCL), PB7(SDA) 开漏输出 GPIOB->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_MODE6 | GPIO_CRL_CNF7 | GPIO_CRL_MODE7); GPIOB->CRL |= GPIO_CRL_CNF6_1 | GPIO_CRL_MODE6 | GPIO_CRL_CNF7_1 | GPIO_CRL_MODE7; GPIOB->ODR |= GPIO_ODR_ODR6 | GPIO_ODR_ODR7; // I2C配置 I2C1->CR1 &= ~I2C_CR1_PE; I2C1->CR2 = 36; // APB1时钟36MHz I2C1->CCR = 180; // 100kHz (36M/(2*180)=100k) I2C1->TRISE = 37; // 1000ns/(1/36M)=36+1 I2C1->CR1 |= I2C_CR1_PE; } void I2C_Write(uint8_t addr, uint8_t data) { // 发送起始条件 I2C1->CR1 |= I2C_CR1_START; while (!(I2C1->SR1 & I2C_SR1_SB)); // 发送地址 I2C1->DR = addr; while (!(I2C1->SR1 & I2C_SR1_ADDR)); (void)I2C1->SR2; // 清除ADDR标志 // 发送数据 while (!(I2C1->SR1 & I2C_SR1_TXE)); I2C1->DR = data; while (!(I2C1->SR1 & I2C_SR1_BTF)); // 停止条件 I2C1->CR1 |= I2C_CR1_STOP; } uint16_t BH1750_Read(void) { uint8_t data[2] = {0}; I2C_Write(BH1750_ADDR, 0x10); // 连续测量模式 Delay_ms(180); // 等待测量完成 // 读取数据 I2C1->CR1 |= I2C_CR1_START; while (!(I2C1->SR1 & I2C_SR1_SB)); I2C1->DR = BH1750_ADDR | 0x01; while (!(I2C1->SR1 & I2C_SR1_ADDR)); (void)I2C1->SR2; // 接收第一个字节 while (!(I2C1->SR1 & I2C_SR1_RXNE)); data[0] = I2C1->DR; // 接收第二个字节 while (!(I2C1->SR1 & I2C_SR1_RXNE)); data[1] = I2C1->DR; I2C1->CR1 |= I2C_CR1_STOP; return (data[0] << 8) | data[1]; } // 继电器控制 void Relay_Control(uint8_t device, uint8_t state) { switch(device) { case 0: // 风扇 state ? GPIO_SetBits(RELAY_FAN_GPIO, RELAY_FAN_PIN) : GPIO_ResetBits(RELAY_FAN_GPIO, RELAY_FAN_PIN); break; case 1: // 水泵 state ? GPIO_SetBits(RELAY_PUMP_GPIO, RELAY_PUMP_PIN) : GPIO_ResetBits(RELAY_PUMP_GPIO, RELAY_PUMP_PIN); break; case 2: // 补光灯 state ? GPIO_SetBits(RELAY_LIGHT_GPIO, RELAY_LIGHT_PIN) : GPIO_ResetBits(RELAY_LIGHT_GPIO, RELAY_LIGHT_PIN); break; } } // 系统初始化 void System_Init(void) { // 时钟配置 RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN; // 继电器GPIO初始化 GPIOC->CRH &= ~(GPIO_CRH_CNF13 | GPIO_CRH_CNF14 | GPIO_CRH_CNF15); GPIOC->CRH |= GPIO_CRH_MODE13 | GPIO_CRH_MODE14 | GPIO_CRH_MODE15; GPIO_ResetBits(RELAY_FAN_GPIO, RELAY_FAN_PIN); GPIO_ResetBits(RELAY_PUMP_GPIO, RELAY_PUMP_PIN); GPIO_ResetBits(RELAY_LIGHT_GPIO, RELAY_LIGHT_PIN); // 外设初始化 ADC1_Init(); I2C1_Init(); } // 主控制循环 int main(void) { System_Init(); float temp, humi; uint16_t soil_moist, light; while(1) { // 传感器数据采集 if(DHT11_Read(&temp, &humi)) { // 温度控制逻辑 if(temp > 30.0) Relay_Control(0, 1); // 开启风扇 else Relay_Control(0, 0); } soil_moist = Read_Soil_Moisture(); if(soil_moist < 800) Relay_Control(1, 1); // 开启水泵 (假设ADC值越小越湿) else Relay_Control(1, 0); light = BH1750_Read(); if(light < 10000) Relay_Control(2, 1); // 开启补光灯 else Relay_Control(2, 0); // 数据上传间隔 Delay_ms(5000); } } // 简单延时函数 void Delay_ms(uint32_t ms) { for(uint32_t i=0; i<ms*8000; i++); } void Delay_us(uint32_t us) { for(uint32_t i=0; i<us*8; i++); } 代码说明:DHT11温湿度传感器:使用单总线协议,PA0引脚提供温湿度整数读取(精度1℃/1%RH)包含数据校验机制YL-69土壤湿度:使用ADC1通道1(PA1)12位ADC分辨率(0-4095)值越小表示土壤越湿润BH1750光照传感器:I2C接口(PB6-SCL, PB7-SDA)连续测量模式,分辨率1lx直接返回光照强度值继电器控制:风扇:PC13水泵:PC14补光灯:PC15低电平触发继电器吸合控制逻辑:温度>30℃开启风扇土壤湿度阈值800(需根据实际校准)光照<10000lx开启补光灯注意事项:实际阈值需根据传感器校准调整ADC读取值范围取决于YL-69的供电电压I2C时序需根据实际电路调整延时继电器控制逻辑需增加防抖机制需配合硬件连接图验证引脚分配项目核心代码#include "stm32f10x.h" #include "dht11.h" #include "bh1750.h" #include "esp8266.h" #include "sdio_sdcard.h" #include "oled.h" #include "relay.h" #include "buzzer.h" #include "systick.h" // 传感器数据结构体 typedef struct { float temp; // 温度 float humidity; // 空气湿度 uint16_t soil; // 土壤湿度 uint16_t light; // 光照强度 } SensorData; // 全局变量 SensorData env_data; uint8_t cloud_connected = 0; uint8_t fan_status = 0, pump_status = 0, light_status = 0; // 阈值设定 #define TEMP_THRESHOLD_HIGH 35.0 #define SOIL_THRESHOLD_LOW 30 #define LIGHT_THRESHOLD_LOW 100 // 函数声明 void System_Init(void); void Read_Sensors(void); void Auto_Control(void); void Cloud_Upload(void); void Check_Cloud_Commands(void); void Log_Exception(const char* msg); int main(void) { System_Init(); // 初始化华为云连接 if(ESP8266_Connect_Cloud()) { cloud_connected = 1; OLED_ShowString(0, 0, "Cloud: Connected"); } else { OLED_ShowString(0, 0, "Cloud: Error"); } while(1) { // 每5秒执行一次 if(SysTick_Get() >= 5000) { SysTick_Reset(); Read_Sensors(); // 读取传感器数据 Auto_Control(); // 自动控制逻辑 OLED_Display(); // OLED刷新显示 if(cloud_connected) { Cloud_Upload(); // 上传到华为云 Check_Cloud_Commands();// 检查云端命令 } } // 处理WiFi数据接收 if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET) { ESP8266_Receive_Handler(); } } } // 系统初始化 void System_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); // 初始化外设 DHT11_Init(); BH1750_Init(); ESP8266_Init(115200); SD_Card_Init(); OLED_Init(); Relay_Init(); Buzzer_Init(); SysTick_Init(); // 初始化继电器状态 Fan_Control(DISABLE); Pump_Control(DISABLE); Light_Control(DISABLE); } // 读取传感器数据 void Read_Sensors(void) { if(DHT11_Read(&env_data.temp, &env_data.humidity) != SUCCESS) { Log_Exception("DHT11 Error"); } env_data.soil = SoilMoisture_Read(); env_data.light = BH1750_Read(); } // 自动控制逻辑 void Auto_Control(void) { // 温度过高启动风扇 if(env_data.temp > TEMP_THRESHOLD_HIGH) { Fan_Control(ENABLE); fan_status = 1; if(cloud_connected) Log_Exception("High Temp!"); } else { Fan_Control(DISABLE); fan_status = 0; } // 土壤过干启动水泵 if(env_data.soil < SOIL_THRESHOLD_LOW) { Pump_Control(ENABLE); pump_status = 1; } else { Pump_Control(DISABLE); pump_status = 0; } // 光照不足启动补光灯 if(env_data.light < LIGHT_THRESHOLD_LOW) { Light_Control(ENABLE); light_status = 1; } else { Light_Control(DISABLE); light_status = 0; } } // 数据上传华为云 void Cloud_Upload(void) { char payload[128]; snprintf(payload, sizeof(payload), "{\"temp\":%.1f,\"hum\":%.1f,\"soil\":%d,\"light\":%d,\"fan\":%d,\"pump\":%d,\"lamp\":%d}", env_data.temp, env_data.humidity, env_data.soil, env_data.light, fan_status, pump_status, light_status); ESP8266_Send_Data(payload); } // 检查云端控制命令 void Check_Cloud_Commands(void) { char* cmd = ESP8266_Get_Command(); if(cmd != NULL) { // 解析JSON命令 (示例格式: {"fan":1}) if(strstr(cmd, "\"fan\":1")) { Fan_Control(ENABLE); fan_status = 1; } else if(strstr(cmd, "\"fan\":0")) { Fan_Control(DISABLE); fan_status = 0; } // 其他设备解析逻辑类似... free(cmd); // 释放内存 } } // 异常日志记录 void Log_Exception(const char* msg) { char log_msg[64]; snprintf(log_msg, sizeof(log_msg), "[ALERT] %s", msg); // 本地蜂鸣器报警 Buzzer_Alert(3, 200); // SD卡记录 if(SD_Card_Status() == SD_OK) { SD_Write_Log(log_msg); } } 代码说明:系统初始化配置所有外设时钟初始化传感器、WiFi模块、SD卡等硬件设置继电器初始状态为关闭主循环逻辑5秒定时采集数据(温度、湿度、土壤湿度、光照)自动控制:温度过高启风扇、土壤过干启水泵、光照不足启补光灯OLED实时显示数据华为云数据上传(JSON格式)云端指令监听处理关键功能异常处理:高温触发蜂鸣器报警+SD卡日志断网保护:本地自动控制不受网络影响双向通信:支持云端远程控制设备数据缓存:SD卡存储异常日志硬件接口USART1:ESP8266通信(AT指令+MQTT)I2C接口:BH1750光照传感器GPIO:DHT11温湿度、继电器控制SPI:SD卡数据存储总结本系统以STM32F103C8T6微控制器为核心,构建了一套高效可靠的智慧农业温室环境监测与调控方案。该系统通过集成DHT11、YL-69和BH1750等多传感器,实时采集空气温湿度、土壤湿度及光照强度数据,并基于预设阈值实现自动化控制,如土壤湿度低于30%时启动灌溉泵,确保温室环境参数维持在最优范围内。借助ESP8266 WiFi模块与MQTT协议,系统将采集数据无缝上传至华为云物联网平台,同时支持QT上位机动态展示环境参数变化曲线和设备状态。用户可通过云平台或上位机进行远程手动控制(如开关补光灯),并实现双向通信,确保指令实时下发与响应。异常处理机制通过本地OLED显示和蜂鸣器报警提供即时反馈,当检测到参数异常(如温度超过35℃)时,QT界面触发弹窗警告并记录日志至MicroSD卡模块,实现数据缓存以防网络中断。整体硬件设计包括继电器驱动执行设备、电源管理模块及存储单元,保障了系统的稳定性和实用性。该设计显著提升了农业温室的智能化管理水平,实现环境精准调控与数据可视化,为现代精准农业提供了低成本、高效率的解决方案。
-
项目开发背景随着全球水资源日益紧张和农业现代化进程的加速,传统粗放式的农田灌溉方式因其水资源浪费严重、人工依赖度高、无法精准响应作物需求等弊端,已难以满足可持续农业发展的要求。尤其在气候多变、劳动力成本上升的背景下,如何高效利用水资源、降低生产成本、提升作物产量与品质,成为农业领域亟待解决的关键问题。物联网技术的迅猛发展为解决上述问题提供了有效途径。基于嵌入式系统、传感器网络和无线通信的智能灌溉系统,能够实现对农田环境的实时精准监测与自动化控制。通过部署土壤湿度、水位、环境参数等传感器,系统可精确感知作物需水状况及环境变化,并依据预设策略或远程指令智能启停灌溉设备,实现按需供水。这不仅极大减少了水资源浪费,降低了人力投入,更能避免因人工判断失误或响应延迟导致的作物干旱或涝渍损害,显著提升灌溉效率与农业生产效益。本项目正是在此背景下提出的。旨在设计并实现一套基于STM32微控制器的远程农田智能灌溉系统。该系统综合运用多种传感器实时采集核心环境参数,利用WiFi技术将数据上传至云端平台,并开发配套的移动应用,使农户能够随时随地通过手机远程监控农田状况、手动或自动控制水泵运行。同时,本地LCD显示屏提供实时数据可视化,异常阈值报警功能则确保系统安全可靠运行。项目的实施将有效推动精准农业技术的落地应用,助力节水减排,为中小型农田的智能化、数字化管理提供经济实用的解决方案。设计实现的功能(1)实时检测土壤湿度(电阻式传感器模拟信号采集)(2)实时检测水位(浮球式水位开关数字信号输入)(3)实时检测水温(DS18B20单总线通信)(4)实时检测环境温湿度(DHT11单总线通信)(5)实时检测光照强度(BH1750 I2C通信)(6)自动控制模式:根据土壤湿度阈值控制继电器启停水泵(7)手动控制模式:通过APP远程指令控制水泵开关(8)传感器数据通过ESP8266 WiFi模块上传至云端(MQTT协议)(9)本地LCD实时显示所有传感器参数及系统状态(TFT SPI接口驱动)(10)土壤湿度/水位/温度超阈值时触发蜂鸣器报警(高电平驱动)(11)华为云物联网平台数据存储与状态监控(12)Qt5上位机实现远程数据可视化及水泵控制项目硬件模块组成(1)主控芯片:STM32F103C8T6(2)土壤湿度检测:电阻式土壤湿度传感器(模拟信号)(3)水位检测:浮球式水位开关传感器(4)水温检测:DS18B20数字温度传感器(5)环境检测:DHT11温湿度传感器和BH1750光照传感器(6)通信模块:ESP8266 WiFi模块(7)执行模块:继电器控制5V直流抽水泵(8)显示模块:1.44寸TFT LCD液晶显示屏(SPI接口)(9)报警模块:高电平触发有源蜂鸣器设计意义设计意义基于STM32的远程农田智能灌溉系统设计,通过集成多传感器协同监测与智能控制,显著提升农业灌溉的精准性与效率。系统实时采集土壤湿度、水位、水温、环境温湿度及光照等关键参数,为灌溉决策提供科学依据。自动控制模式依据预设阈值启停水泵,避免人工误判导致的水资源浪费;手动模式则通过APP远程介入,适应复杂多变的农田需求,确保作物在最佳环境下生长。该系统通过ESP8266模块将数据上传至华为云物联网平台,实现农田状态的远程可视化监控。农户可通过Qt5开发的移动端界面随时查看环境数据并控制水泵,大幅降低劳动强度,同时异常阈值触发的蜂鸣器报警能及时提示水位不足或环境异常,减少灾害损失。本地TFT LCD显示屏为现场人员提供直观的数据反馈,强化了系统的操作便捷性。在资源节约方面,系统通过精准灌溉优化水资源分配,缓解农业用水紧张问题。硬件采用高性价比模块(如STM32F103C8T6、DHT11等),降低了部署成本,适用于规模化农田推广,为智慧农业的落地提供了可靠的技术支撑。设计思路设计思路系统以STM32F103C8T6微控制器为核心,通过多传感器协同实现农田环境监测与智能灌溉控制。首先,土壤湿度传感器通过ADC采集模拟信号,转换为湿度百分比;浮球式水位开关通过GPIO检测高低电平判断水位状态;DS18B20通过单总线协议获取水温;DHT11通过单总线协议采集环境温湿度;BH1750通过I2C接口获取光照强度。所有传感器数据在主控芯片内进行滤波和校准处理。控制逻辑采用自动/手动双模式。自动模式下,系统实时比对土壤湿度与预设阈值,当低于下限时启动继电器控制的水泵灌溉,达到上限时停止;手动模式下则通过APP远程指令控制水泵启停。水泵控制逻辑集成水位保护,若水位开关检测到缺水,立即停止水泵并触发报警,防止设备干烧。通信模块采用ESP8266连接WiFi,通过AT指令配置MQTT协议,将传感器数据及设备状态实时上传至华为云物联网平台。同时订阅云端下发的控制指令,实现APP远程交互。数据采用JSON格式封装,确保传输效率与可解析性。本地显示通过SPI接口驱动1.44寸TFT LCD,循环刷新土壤湿度、水位、水温、环境温湿度、光照强度、水泵状态及工作模式等参数。界面分区设计,关键参数突出显示,异常数据以颜色标记。报警模块由高电平触发的有源蜂鸣器实现。当土壤湿度或水位超过安全阈值、传感器通信异常时,STM32输出高电平驱动蜂鸣器鸣响,同时LCD显示具体报警信息。报警状态持续至异常解除或手动确认。框架图系统框架图+-----------------------------------------------------------------------------------------+ | 应用层 | | +-----------------------------------------+ | | | 云端(华为云物联网平台) | | | | - 存储土壤/水位/温湿度/光照等实时数据 | | | | - 远程控制指令下发(水泵开关/模式切换) | | | +----------------------+------------------+ | | | MQTT协议 | | +----------------------v------------------+ | | | 手机APP(Qt5开发) | | | | - 实时数据显示/历史记录查询 | | | | - 手动控制水泵/设置灌溉阈值 | | | +-----------------------------------------+ | +----------------------------------------------------------^-----------------------------+ | WiFi +----------------------------------------------------------|-----------------------------+ | 通信层 | | +-----------------------------------------+ | | | ESP8266 WiFi模块 | | | | - MQTT协议上传传感器数据至云端 | | | | - 接收云端指令并转发给主控 | | | +----------------------+------------------+ | | | UART串口 | +----------------------------------------------------------|-----------------------------+ | +----------------------------------------------------------v-----------------------------+ | 控制层(STM32F103C8T6) | | +----------------+ +---------------+ +----------------+ +----------------+ | | | 传感器数据采集 | | 逻辑控制与报警 | | 执行器控制 | | 本地显示模块 | | | | - 土壤湿度(ADC) | | - 阈值判断 | | - 继电器驱动 | | - TFT LCD | | | | - 水位(数字IO) | | - 蜂鸣器报警 | | (控制水泵) | | (SPI接口) | | | | - 水温(DS18B20)| | - 自动/手动 | | | | - 实时参数显示 | | | | - 环境(DHT11) | | 模式切换 | +--------+---------+ +----------------+ | | | - 光照(BH1750) | +---------------+ | | | +----------------+ +------------v---------+ | | | 主控核心处理逻辑 | | | | - 数据融合处理 | | | | - 通信协议解析 | | | | - 系统调度管理 | | | +----------------------+ | +----------------------------------------------------------+-----------------------------+ | +----------------------------------------------------------v-----------------------------+ | 感知层/执行层 | | +--------------+ +-------------+ +-------------+ +-------------+ +-------------+ | | | 土壤湿度传感器 | | 浮球水位开关 | | DS18B20水温 | | DHT11环境 | | BH1750光照 | | | | (模拟量) | | (数字量) | | (单总线) | | (单总线) | | (I2C) | | | +------+-------+ +------+------+ +------+------+ +------+------+ +------+------+ | | | | | | | | | +------v-----------------v----------------v----------------v----------------v------+ | | | 5V直流抽水泵 | | | | +---------+ 继电器驱动 +----------+ | | | | | 继电器 <---------------------+ | | | | +----+----+ | | | | | | | | | | | +----v----+ | | | | | | 蜂鸣器 <---------------------+ | | | | | (高电平触发) | | | | +---------------------+-------------------------------+----------------------------+ | +-----------------------------------------------------------------------------------------+关键模块说明:感知层土壤湿度:电阻式传感器(ADC采集)水位:浮球开关(数字IO)水温:DS18B20(单总线)环境温湿度:DHT11(单总线)光照强度:BH1750(I2C)控制层STM32主控:协调数据采集、逻辑判断、通信调度报警:蜂鸣器在阈值异常时触发显示:TFT LCD实时展示参数执行层继电器控制5V水泵启停支持自动(阈值触发)和手动(APP控制)模式通信层ESP8266通过UART与STM32交互MQTT协议连接华为云,实现双向数据传输应用层华为云:数据存储/分析/告警Qt5 APP:远程监控与控制界面系统总体设计本系统以STM32F103C8T6微控制器为核心构建远程农田智能灌溉系统。系统通过多类型传感器实时采集环境参数:电阻式土壤湿度传感器检测土壤湿度模拟信号,经STM32内置ADC转换;浮球式水位开关提供数字水位状态;DS18B20单总线传感器监测水温;DHT11数字传感器获取环境温湿度;BH1750光照传感器通过I2C接口采集光照强度。所有传感器数据由STM32集中处理。执行控制部分采用继电器驱动5V直流抽水泵,支持自动与手动双模式。自动模式下,STM32根据预设土壤湿度阈值触发水泵;手动模式则通过远程指令控制。通信层由ESP8266 WiFi模块实现,基于MQTT协议将传感器数据上传至华为云物联网平台,同时接收云端下发的控制指令。本地交互模块包含1.44寸SPI接口TFT LCD,实时显示所有传感器数据及系统状态(水泵开关/工作模式)。安全防护采用高电平触发有源蜂鸣器,当土壤湿度、水位或温度超过预设阈值时立即声光报警。远程控制端通过Qt5开发的PC端软件实现,用户可在界面查看实时数据并远程操控水泵。系统采用分级电源设计,传感器与逻辑电路由3.3V供电,水泵由独立5V电源驱动,确保稳定运行。系统功能总结功能描述硬件模块实时检测土壤湿度电阻式土壤湿度传感器实时检测水位浮球式水位开关传感器实时检测水温DS18B20数字温度传感器实时检测环境温湿度DHT11温湿度传感器实时检测光照强度BH1750光照传感器自动/手动控制抽水泵灌溉继电器控制5V直流抽水泵数据上传至云端(华为云物联网平台)ESP8266模块(WiFi,MQTT协议)APP远程控制水泵ESP8266模块(WiFi)本地显示各项参数1.44寸TFT LCD液晶显示屏(SPI接口)阈值异常触发蜂鸣器报警高电平触发有源蜂鸣器系统主控与逻辑处理STM32F103C8T6主控芯片远程控制界面Qt5 + C++开发的上位机软件设计的各个功能模块描述主控芯片STM32F103C8T6作为系统核心,负责协调所有传感器数据采集、逻辑判断和执行控制,通过内部ADC、GPIO、SPI、UART等接口连接各模块,实现数据处理和指令调度。土壤湿度检测采用电阻式传感器,通过模拟电压信号输出土壤含水率,连接至STM32的ADC引脚进行模数转换,实时监测农田墒情变化。水位检测使用浮球式水位开关传感器,直接输出高低电平数字信号至STM32的GPIO引脚,用于判断水源蓄水状态是否充足。水温检测由DS18B20数字温度传感器实现,通过单总线协议与STM32通信,精确获取灌溉水源的温度数据。环境检测模块整合DHT11温湿度传感器和BH1750光照传感器,DHT11通过单总线协议提供环境温湿度数据,BH1750通过I2C接口输出光照强度值,共同构成农田气候监测基础。通信模块基于ESP8266 WiFi模块,通过UART串口与STM32交互,采用MQTT协议将传感器数据上传至华为云物联网平台,同时接收云端下发的控制指令实现远程交互。执行模块由继电器驱动5V直流抽水泵,STM32通过GPIO输出高低电平控制继电器通断,从而在自动模式(阈值触发)或手动模式(APP指令)下启停灌溉。显示模块采用1.44寸TFT LCD液晶屏,通过SPI接口与STM32连接,实时本地化展示土壤湿度、水位、水温、环境温湿度及光照强度等参数,并显示系统工作模式状态。报警模块使用高电平触发的有源蜂鸣器,当土壤湿度过低、水位不足或环境参数超阈值时,STM32通过GPIO输出高电平触发蜂鸣器发出警报声。上位机软件基于Qt5与C++开发,部署于PC或移动端,提供数据可视化界面及水泵远程控制按钮,通过华为云平台与ESP8266通信,实现用户对灌溉系统的跨地域监控与操作。上位机代码设计上位机软件设计(Qt5 + C++)#include <QtWidgets> #include <QtMqtt/QtMqtt> #include <QChart> #include <QLineSeries> // 华为云物联网平台连接参数 const QString BROKER = "iotda.cn-north-4.myhuaweicloud.com"; const int PORT = 1883; const QString CLIENT_ID = "FarmIrrigation_APP"; const QString USERNAME = "your_username"; const QString PASSWORD = "your_password"; const QString SUB_TOPIC = "sensor/data"; // 订阅主题 const QString PUB_TOPIC = "pump/control"; // 发布主题 class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) { // 初始化MQTT客户端 mqttClient = new QMqttClient(this); mqttClient->setHostname(BROKER); mqttClient->setPort(PORT); mqttClient->setClientId(CLIENT_ID); mqttClient->setUsername(USERNAME); mqttClient->setPassword(PASSWORD); // 创建UI setupUI(); // 连接MQTT信号 connect(mqttClient, &QMqttClient::connected, this, &MainWindow::onConnected); connect(mqttClient, &QMqttClient::messageReceived, this, &MainWindow::onMessageReceived); // 连接服务器 mqttClient->connectToHost(); } private slots: void onConnected() { qDebug() << "Connected to Huawei Cloud IoT!"; auto subscription = mqttClient->subscribe(SUB_TOPIC); if (!subscription) { QMessageBox::critical(this, "Error", "Subscription failed!"); } } void onMessageReceived(const QByteArray &message, const QMqttTopicName &topic) { QJsonDocument doc = QJsonDocument::fromJson(message); QJsonObject json = doc.object(); // 更新传感器数据显示 soilMoistureLabel->setText(QString::number(json["soil_moisture"].toDouble()) + "%"); waterLevelLabel->setText(json["water_level"].toBool() ? "Normal" : "Low"); waterTempLabel->setText(QString::number(json["water_temp"].toDouble()) + "°C"); airTempLabel->setText(QString::number(json["air_temp"].toDouble()) + "°C"); humidityLabel->setText(QString::number(json["humidity"].toDouble()) + "%"); lightLabel->setText(QString::number(json["light"].toDouble()) + "lux"); // 报警检测 checkAlarms(json); } void onPumpControlClicked() { QMqttMessage msg; msg.setPayload(pumpSwitch->isChecked() ? "ON" : "OFF"); mqttClient->publish(PUB_TOPIC, msg.payload()); } private: void setupUI() { // 主窗口设置 setWindowTitle("智能灌溉监控系统"); setFixedSize(800, 600); // 中央部件 QWidget *centralWidget = new QWidget(this); setCentralWidget(centralWidget); // 主布局 QGridLayout *layout = new QGridLayout(centralWidget); // 传感器数据显示区域 QGroupBox *sensorGroup = new QGroupBox("实时传感器数据"); QFormLayout *sensorLayout = new QFormLayout(sensorGroup); soilMoistureLabel = new QLabel("--"); waterLevelLabel = new QLabel("--"); waterTempLabel = new QLabel("--"); airTempLabel = new QLabel("--"); humidityLabel = new QLabel("--"); lightLabel = new QLabel("--"); sensorLayout->addRow("土壤湿度:", soilMoistureLabel); sensorLayout->addRow("水位状态:", waterLevelLabel); sensorLayout->addRow("水温:", waterTempLabel); sensorLayout->addRow("空气温度:", airTempLabel); sensorLayout->addRow("空气湿度:", humidityLabel); sensorLayout->addRow("光照强度:", lightLabel); // 水泵控制区域 QGroupBox *controlGroup = new QGroupBox("水泵控制"); QVBoxLayout *controlLayout = new QVBoxLayout(controlGroup); pumpSwitch = new QCheckBox("启动水泵"); connect(pumpSwitch, &QCheckBox::clicked, this, &MainWindow::onPumpControlClicked); alarmLabel = new QLabel; alarmLabel->setStyleSheet("color: red; font-weight: bold;"); alarmLabel->setAlignment(Qt::AlignCenter); controlLayout->addWidget(pumpSwitch); controlLayout->addWidget(alarmLabel); // 图表区域 QChartView *chartView = new QChartView; chartView->setChart(new QChart); chartView->setRenderHint(QPainter::Antialiasing); // 布局组织 layout->addWidget(sensorGroup, 0, 0); layout->addWidget(controlGroup, 0, 1); layout->addWidget(chartView, 1, 0, 1, 2); } void checkAlarms(const QJsonObject &data) { QString alarms; if (data["soil_moisture"].toDouble() < 30.0) { alarms += "土壤干旱! "; } if (!data["water_level"].toBool()) { alarms += "水位过低! "; } if (data["water_temp"].toDouble() > 35.0) { alarms += "水温过高! "; } alarmLabel->setText(alarms); } // UI组件 QMqttClient *mqttClient; QLabel *soilMoistureLabel; QLabel *waterLevelLabel; QLabel *waterTempLabel; QLabel *airTempLabel; QLabel *humidityLabel; QLabel *lightLabel; QLabel *alarmLabel; QCheckBox *pumpSwitch; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); MainWindow window; window.show(); return app.exec(); } #include "main.moc" 项目结构说明MQTT通信模块:连接华为云物联网平台(需替换实际用户名/密码)订阅传感器数据主题(sensor/data)发布水泵控制指令(pump/control)UI界面设计:传感器数据显示区域(土壤湿度/水位/水温/环境温湿度/光照)水泵控制开关(手动模式)报警信息显示区(阈值异常提示)数据图表区(预留扩展)核心功能逻辑:实时解析JSON格式传感器数据土壤湿度<30%触发干旱报警水位过低报警水温>35℃触发高温报警一键控制水泵启停使用说明依赖库:Qt5 Core, Widgets, MQTT, Charts配置文件:修改华为云连接参数:const QString BROKER = "iotda.cn-north-4.myhuaweicloud.com"; const QString USERNAME = "your_username"; const QString PASSWORD = "your_password"; 编译运行:qmake && make ./智能灌溉监控系统功能扩展建议数据持久化:// 添加SQLite数据库支持 QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("irrigation_data.db"); 历史曲线:// 在图表区域添加时序曲线 QLineSeries *series = new QLineSeries(); chart->addSeries(series); 阈值设置界面:// 添加设置对话框 QDialog *settingsDlg = new QDialog; QDoubleSpinBox *soilThreshold = new QDoubleSpinBox(settingsDlg); 多设备支持:// 使用QComboBox选择不同农田设备 QComboBox *deviceSelector = new QComboBox; deviceSelector->addItems({"农田1", "农田2", "农田3"}); 模块代码设计STM32设备端模块代码设计#include "stm32f10x.h" // 引脚定义 #define SOIL_MOISTURE_PIN GPIO_Pin_0 // PA0 (ADC0) #define WATER_LEVEL_PIN GPIO_Pin_1 // PA1 (浮球水位开关) #define DS18B20_PIN GPIO_Pin_2 // PA2 (水温) #define DHT11_PIN GPIO_Pin_3 // PA3 (环境温湿度) #define PUMP_RELAY_PIN GPIO_Pin_11 // PA11 (水泵继电器) #define BUZZER_PIN GPIO_Pin_12 // PA12 (蜂鸣器) // LCD SPI引脚 #define LCD_CS_PIN GPIO_Pin_4 // PA4 #define LCD_SCK_PIN GPIO_Pin_5 // PA5 #define LCD_MISO_PIN GPIO_Pin_6 // PA6 #define LCD_MOSI_PIN GPIO_Pin_7 // PA7 #define LCD_DC_PIN GPIO_Pin_8 // PA8 #define LCD_RST_PIN GPIO_Pin_9 // PA9 // ESP8266 USART1引脚 #define ESP_TX_PIN GPIO_Pin_9 // PA9 (USART1_TX) #define ESP_RX_PIN GPIO_Pin_10 // PA10 (USART1_RX) // I2C引脚 (BH1750) #define I2C_SCL_PIN GPIO_Pin_6 // PB6 #define I2C_SDA_PIN GPIO_Pin_7 // PB7 // 传感器数据结构 typedef struct { uint16_t soil_moisture; // 土壤湿度 (0-4095) uint8_t water_level; // 水位状态 (0/1) float water_temp; // 水温 (°C) float air_temp; // 空气温度 (°C) uint8_t air_humidity; // 空气湿度 (%) uint16_t light_intensity; // 光照强度 (lx) } SensorData; // 全局变量 SensorData sensor_data; uint8_t pump_mode = 0; // 0:自动 1:手动 uint8_t pump_state = 0; // 水泵状态 // 函数声明 void RCC_Configuration(void); void GPIO_Configuration(void); void ADC_Configuration(void); void USART_Configuration(void); void SPI_Configuration(void); void I2C_Configuration(void); void NVIC_Configuration(void); uint16_t Read_Soil_Moisture(void); uint8_t Read_Water_Level(void); float Read_Water_Temperature(void); void Read_DHT11(uint8_t *temp, uint8_t *hum); uint16_t Read_BH1750(void); void Control_Pump(uint8_t state); void Buzzer_Alert(uint8_t state); void LCD_Display(const SensorData *data); void ESP8266_SendData(const SensorData *data); void Delay_ms(uint32_t ms); int main(void) { // 系统初始化 RCC_Configuration(); GPIO_Configuration(); ADC_Configuration(); USART_Configuration(); SPI_Configuration(); I2C_Configuration(); NVIC_Configuration(); // 传感器初始化 // (DS18B20/DHT11/BH1750需要特定初始化序列,此处省略) while(1) { // 读取所有传感器数据 sensor_data.soil_moisture = Read_Soil_Moisture(); sensor_data.water_level = Read_Water_Level(); sensor_data.water_temp = Read_Water_Temperature(); Read_DHT11(&sensor_data.air_temp, &sensor_data.air_humidity); sensor_data.light_intensity = Read_BH1750(); // 自动模式控制水泵 if(pump_mode == 0) { if(sensor_data.soil_moisture > 2500) { // 土壤干燥阈值 Control_Pump(1); } else { Control_Pump(0); } } // 异常报警 if(sensor_data.water_level == 0 || sensor_data.air_temp > 40) { Buzzer_Alert(1); } else { Buzzer_Alert(0); } // LCD显示 LCD_Display(&sensor_data); // 数据上传云端 ESP8266_SendData(&sensor_data); Delay_ms(5000); // 5秒采集周期 } } // ADC初始化 (土壤湿度) void ADC_Configuration(void) { RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; // 使能ADC1时钟 ADC1->CR2 = ADC_CR2_ADON; // 开启ADC // 配置通道0 (PA0) ADC1->SMPR2 = ADC_SMPR2_SMP0_0 | ADC_SMPR2_SMP0_1 | ADC_SMPR2_SMP0_2; // 239.5周期采样 ADC1->SQR3 = 0; // 通道0作为第一个转换 } // 读取土壤湿度 uint16_t Read_Soil_Moisture(void) { ADC1->CR2 |= ADC_CR2_ADON; // 启动ADC while(!(ADC1->SR & ADC_SR_EOC)); // 等待转换完成 return ADC1->DR; // 返回ADC值 } // 读取水位开关 uint8_t Read_Water_Level(void) { return GPIOA->IDR & WATER_LEVEL_PIN ? 1 : 0; } // DS18B20水温读取 (简化版) float Read_Water_Temperature(void) { // 实现单总线协议读取温度 // 返回摄氏度温度值 return 25.5f; // 示例返回值 } // DHT11温湿度读取 void Read_DHT11(uint8_t *temp, uint8_t *hum) { // 实现单总线协议读取数据 *temp = 26; // 示例温度 *hum = 65; // 示例湿度 } // BH1750光照强度读取 uint16_t Read_BH1750(void) { // I2C协议读取光照值 return 850; // 示例光照值(lx) } // 水泵控制 void Control_Pump(uint8_t state) { if(state) { GPIOA->BSRR = PUMP_RELAY_PIN; // 开启水泵 pump_state = 1; } else { GPIOA->BRR = PUMP_RELAY_PIN; // 关闭水泵 pump_state = 0; } } // 蜂鸣器报警 void Buzzer_Alert(uint8_t state) { if(state) { GPIOA->BSRR = BUZZER_PIN; // 蜂鸣器响 } else { GPIOA->BRR = BUZZER_PIN; // 蜂鸣器停 } } // ESP8266数据发送 (MQTT协议) void ESP8266_SendData(const SensorData *data) { char buffer[128]; sprintf(buffer, "{\"soil\":%d,\"water_temp\":%.1f,\"air_temp\":%d,\"hum\":%d,\"light\":%d}", data->soil_moisture, data->water_temp, (int)data->air_temp, data->air_humidity, data->light_intensity); // 通过USART1发送数据 for(char *p = buffer; *p; p++) { USART1->DR = *p; while(!(USART1->SR & USART_SR_TC)); } } // LCD显示函数 void LCD_Display(const SensorData *data) { // SPI传输显示数据 // 实现显示界面布局 } // 时钟配置 void RCC_Configuration(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN | RCC_APB2ENR_ADC1EN | RCC_APB2ENR_SPI1EN | RCC_APB2ENR_USART1EN; RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; } // GPIO配置 void GPIO_Configuration(void) { // 配置PA0为模拟输入 (土壤湿度) GPIOA->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0); // 配置PA1为输入 (水位开关) GPIOA->CRL &= ~(GPIO_CRL_MODE1 | GPIO_CRL_CNF1_0); GPIOA->CRL |= GPIO_CRL_CNF1_1; // 上拉输入 // 配置PA11,PA12为推挽输出 (继电器和蜂鸣器) GPIOA->CRH |= GPIO_CRH_MODE11 | GPIO_CRH_MODE12; GPIOA->CRH &= ~(GPIO_CRH_CNF11 | GPIO_CRH_CNF12); // 配置USART1引脚 GPIOA->CRH |= GPIO_CRH_MODE9; // PA9推挽输出 GPIOA->CRH &= ~GPIO_CRH_CNF9; GPIOA->CRH |= GPIO_CRH_CNF9_1; // 复用输出 GPIOA->CRH &= ~GPIO_CRH_MODE10; // PA10浮空输入 GPIOA->CRH |= GPIO_CRH_CNF10_0; GPIOA->CRH &= ~GPIO_CRH_CNF10_1; // 配置I2C引脚 (开漏输出) GPIOB->CRL |= GPIO_CRL_MODE6 | GPIO_CRL_MODE7; GPIOB->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_CNF7); GPIOB->CRL |= GPIO_CRL_CNF6_0 | GPIO_CRL_CNF7_0; } // USART配置 (ESP8266通信) void USART_Configuration(void) { USART1->BRR = 0x1D4C; // 72MHz/9600=0x1D4C USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; } // 延时函数 void Delay_ms(uint32_t ms) { for(uint32_t i=0; i<ms*8000; i++); } 关键模块说明ADC配置:使用PA0采集土壤湿度模拟信号239.5周期采样提高精度直接读取DR寄存器获取转换结果数字传感器读取:水位开关:PA1数字输入,水位正常时高电平DS18B20:实现单总线协议读取水温DHT11:单总线协议读取空气温湿度BH1750:I2C接口读取光照强度执行器控制:继电器控制:PA11输出高电平启动水泵蜂鸣器控制:PA12输出高电平触发报警通信接口:USART1:与ESP8266通信,波特率9600SPI1:驱动TFT LCD显示屏I2C1:连接BH1750光照传感器云端通信:数据封装为JSON格式通过MQTT协议上传至华为云包含所有传感器数据和设备状态控制逻辑:自动模式:土壤湿度>2500时启动水泵手动模式:通过APP远程控制异常报警:水位不足或温度超限触发蜂鸣器项目核心代码以下是基于STM32F103C8T6的远程农田智能灌溉系统核心代码(main.c),采用寄存器方式开发:#include "stm32f10x.h" #include "dht11.h" #include "ds18b20.h" #include "bh1750.h" #include "lcd_spi.h" #include "esp8266_mqtt.h" #include "buzzer.h" #include "relay.h" #include "soil_moisture.h" #include "water_level.h" // 传感器阈值定义 #define SOIL_HUMIDITY_THRESHOLD 40 // 土壤湿度阈值(%) #define WATER_LEVEL_THRESHOLD 20 // 水位阈值(cm) #define TEMP_THRESHOLD_HIGH 40 // 高温阈值(℃) #define TEMP_THRESHOLD_LOW 5 // 低温阈值(℃) // 全局变量 uint8_t System_Mode = 0; // 0:自动模式 1:手动模式 volatile uint32_t sysTick = 0; // 传感器数据结构体 typedef struct { float soil_humidity; // 土壤湿度(%) uint8_t water_level; // 水位状态(0:正常 1:低水位) float water_temp; // 水温(℃) float air_temp; // 空气温度(℃) float air_humidity; // 空气湿度(%) uint16_t light_intensity; // 光照强度(Lux) } SensorData_t; SensorData_t sensorData; // 系统初始化函数 void System_Init(void) { // 配置系统时钟 RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN; // 初始化SysTick定时器(1ms中断) SysTick_Config(SystemCoreClock / 1000); // 外设初始化 LCD_Init(); DHT11_Init(); DS18B20_Init(GPIOB, GPIO_Pin_5); BH1750_Init(); ESP8266_Init(); Buzzer_Init(); Relay_Init(); SoilMoisture_Init(); WaterLevel_Init(); // 显示欢迎界面 LCD_Clear(BLUE); LCD_ShowString(10, 10, "Smart Farm System", WHITE, BLUE); LCD_ShowString(10, 30, "Initializing...", WHITE, BLUE); Delay_ms(1000); } // 传感器数据采集函数 void Sensor_Data_Update(void) { // 读取土壤湿度(ADC值转换) uint16_t adc_val = SoilMoisture_Read(); sensorData.soil_humidity = 100 - (adc_val / 40.95); // 假设0-4095对应0-100% // 读取水位开关状态 sensorData.water_level = WaterLevel_Read(); // 读取水温 sensorData.water_temp = DS18B20_GetTemp(); // 读取空气温湿度 DHT11_ReadData(&sensorData.air_temp, &sensorData.air_humidity); // 读取光照强度 sensorData.light_intensity = BH1750_ReadLightIntensity(); } // 本地LCD显示函数 void LCD_Display_Update(void) { LCD_Clear(BLUE); // 显示模式 LCD_ShowString(10, 10, "Mode:", WHITE, BLUE); LCD_ShowString(60, 10, (System_Mode == 0) ? "AUTO" : "MANUAL", YELLOW, BLUE); // 显示传感器数据 LCD_ShowString(10, 30, "Soil:%d%%", WHITE, BLUE, (int)sensorData.soil_humidity); LCD_ShowString(10, 50, "Water:%s", WHITE, BLUE, sensorData.water_level ? "LOW" : "OK"); LCD_ShowString(10, 70, "Temp:%.1fC", WHITE, BLUE, sensorData.water_temp); LCD_ShowString(10, 90, "Air:%.1fC/%.1f%%", WHITE, BLUE, sensorData.air_temp, sensorData.air_humidity); LCD_ShowString(10, 110, "Light:%d Lux", WHITE, BLUE, sensorData.light_intensity); // 显示水泵状态 LCD_ShowString(10, 130, "Pump:", WHITE, BLUE); LCD_ShowString(60, 130, (GPIOB->ODR & GPIO_Pin_8) ? "ON " : "OFF", RED, BLUE); } // 自动灌溉控制逻辑 void Auto_Irrigation_Control(void) { // 条件1: 土壤湿度低于阈值且水位正常 // 条件2: 温度在适宜范围内(5℃-40℃) if((sensorData.soil_humidity < SOIL_HUMIDITY_THRESHOLD) && (sensorData.water_level == 0) && (sensorData.water_temp > TEMP_THRESHOLD_LOW) && (sensorData.water_temp < TEMP_THRESHOLD_HIGH)) { Relay_On(); // 开启水泵 } else { Relay_Off(); // 关闭水泵 } } // 异常检测与报警 void Alarm_Check(void) { uint8_t alarm_flag = 0; // 水位过低报警 if(sensorData.water_level) { LCD_ShowString(10, 150, "WATER LOW ALARM!", RED, BLUE); alarm_flag = 1; } // 温度异常报警 if((sensorData.water_temp <= TEMP_THRESHOLD_LOW) || (sensorData.water_temp >= TEMP_THRESHOLD_HIGH)) { LCD_ShowString(10, 170, "TEMP ALARM!", RED, BLUE); alarm_flag = 1; } // 触发蜂鸣器 if(alarm_flag) { Buzzer_On(); } else { Buzzer_Off(); } } // 云端通信处理 void Cloud_Communication(void) { // 上传传感器数据到华为云 ESP8266_SendData(sensorData.soil_humidity, sensorData.water_level, sensorData.water_temp, sensorData.air_temp, sensorData.air_humidity, sensorData.light_intensity); // 检查云端控制命令 uint8_t cmd = ESP8266_CheckCommand(); if(cmd != 0xFF) { System_Mode = 1; // 切换到手动模式 // 执行控制命令 if(cmd == 0x01) Relay_On(); else if(cmd == 0x00) Relay_Off(); } } // SysTick中断服务函数 void SysTick_Handler(void) { sysTick++; } // 延时函数 void Delay_ms(uint32_t ms) { uint32_t start = sysTick; while((sysTick - start) < ms); } int main(void) { System_Init(); while(1) { // 每2秒更新一次数据 if(sysTick % 2000 == 0) { Sensor_Data_Update(); LCD_Display_Update(); Alarm_Check(); Cloud_Communication(); // 自动模式执行灌溉控制 if(System_Mode == 0) { Auto_Irrigation_Control(); } } // 处理ESP8266接收数据 ESP8266_ReceiveHandler(); } } 代码说明:系统初始化:配置时钟和外设(LCD、传感器、通信模块等)初始化SysTick定时器用于精确延时数据采集:土壤湿度(ADC读取模拟信号)水位开关(数字输入)水温(DS18B20单总线)空气温湿度(DHT11)光照强度(BH1750 I2C)控制逻辑:自动模式:土壤湿度低于阈值+水位正常+温度适宜时启动水泵手动模式:通过云端指令控制水泵云端通信:使用ESP8266通过MQTT协议连接华为云定时上传传感器数据接收云端控制指令异常处理:水位过低触发蜂鸣器报警温度超出阈值触发报警LCD界面显示异常状态人机交互:1.44寸TFT LCD实时显示系统状态界面包含模式指示、传感器数据和水泵状态总结本文设计的基于STM32的远程农田智能灌溉系统,通过集成多传感器与智能控制模块,实现了农田环境的精准监测与自动化管理。系统以STM32F103C8T6为核心,实时采集土壤湿度、水位、水温、环境温湿度及光照等关键参数,结合阈值判断实现抽水泵的自动启停,有效解决了传统灌溉的资源浪费问题,显著提升了农业生产的智能化水平。硬件设计上,系统采用电阻式土壤湿度传感器、浮球水位开关、DS18B20水温传感器及DHT11、BH1750环境传感器构建数据采集网络,确保环境参数的全面感知;通过ESP8266模块以MQTT协议将数据上传至华为云物联网平台,实现云端数据存储与分析;本地由SPI接口的TFT LCD显示屏实时展示参数,配合继电器控制水泵和有源蜂鸣器报警模块,形成完整的闭环控制链路。软件层面,依托华为云平台的远程管理能力,用户可通过Qt5开发的APP界面远程监控农田状态并手动干预水泵操作,实现"云端-设备-用户"的高效交互。系统兼具自动灌溉与异常预警功能,在土壤湿度不足或水位异常时主动触发蜂鸣器报警,保障灌溉安全。最终,该系统以低功耗、高可靠性及灵活的扩展性,为现代农业提供了智能化、网络化的灌溉解决方案。
-
项目开发背景冷链物流在食品、药品、生物制品等对温度敏感产品的储运过程中至关重要。温湿度的失控或运输过程中的剧烈震动、跌落,极易导致产品腐败变质、失效,甚至引发安全事故,造成巨大的经济损失和健康风险。传统的监控方式往往依赖人工记录或简单的数据记录仪,存在信息滞后、无法实时报警、全程追溯困难等问题,难以满足现代物流对高可靠性、高透明度及实时监管的需求。随着物联网技术的快速发展,利用传感器、无线通信和云平台实现对物流环境的智能、实时监控已成为行业迫切需求。开发一款集环境参数实时采集、异常事件精准检测、位置全程追踪、数据远程上传及本地报警于一体的智能终端,对于保障冷链物流品质、提升物流管理效率、降低货损率、明确运输责任具有重要意义。本项目旨在设计并实现一款基于高性能、低功耗STM32微控制器的冷链物流智能监控终端。该终端将集成高精度温湿度传感器、震动检测模块、GPS定位模块以及4G通信模块,能够持续、准确地感知货物所处箱体的环境状态(温湿度)、记录运输过程中的异常震动或跌落事件、实时获取并上报地理位置信息。所有关键数据将通过4G网络高效传输至华为云物联网平台,实现远程集中监控和大数据分析。同时,设备具备本地OLED状态显示功能,并在检测到温湿度超标或剧烈震动等异常情况时,立即触发蜂鸣器进行现场声光报警,为及时干预提供保障。通过此终端的部署,可显著提升冷链物流过程的可视化、智能化水平和风险管控能力。设计实现的功能(1)实时监测货物箱体内温度与湿度:通过SHT30传感器(I2C接口)采集温湿度数据,STM32F103C8T6主控芯片实时处理数据。(2)监测震动/跌落事件并记录:利用SW-420震动传感器检测异常震动或跌落,STM32记录事件时间戳及强度,存储至本地或上传云端。(3)GPS定位跟踪物流位置:通过ATGM336H模块(UART接口)获取经纬度数据,STM32解析并处理位置信息。(4)数据通过4G模块上传至华为云物联网平台:Air724UG 4G模块(AT指令+MQTT协议)将温湿度、位置、震动事件等数据上传至华为云。(5)异常条件自动触发蜂鸣器报警:当温湿度超限或检测到震动事件时,STM32输出高电平驱动有源蜂鸣器报警。(6)数据显示:0.96寸OLED实时显示温湿度、GPS定位信息及报警状态。(7)供电管理:DC 5V模块+锂电池供电,TP4056充电保护模块实现电池充放电管理及过充/过放保护。项目硬件模块组成(1)STM32F103C8T6主控芯片(2)SHT30温湿度传感器(I2C接口)(3)SW-420震动传感器(4)ATGM336H GPS模块(UART接口)(5)Air724UG 4G通信模块(支持AT指令+MQTT)(6)0.96寸OLED显示模块(7)高电平触发有源蜂鸣器(8)DC 5V供电模块 + 锂电池 + TP4056充电保护模块设计意义该冷链物流智能监控终端的设计意义在于切实解决物流过程中的核心痛点。通过高精度的SHT30传感器实时采集货物箱体内的温湿度数据,确保对易腐品、药品等温度敏感货物的全程环境监控,有效避免因温湿度失控导致的货物变质或失效,保障产品质量与安全价值。集成震动检测模块与GPS定位功能,可精准记录运输途中的异常震动或跌落事件,并同步追踪地理位置信息。这不仅为物流过程提供关键责任追溯依据,在发生货损时明确责任归属,也能帮助企业优化运输路径和包装方案,提升整体物流管理的精细化水平。采用4G模块直连华为云物联网平台,实现了监控数据的远程实时透传与云端存储。配合本地蜂鸣器报警机制,在温湿度超限或发生剧烈震动时立即触发声光警示,形成"本地即时响应+云端远程监控"的双重保障体系,显著提升对运输异常的响应速度和处理效率。该终端采用锂电池结合TP4056充放电保护方案,保障设备在运输途中的持续稳定运行。整套系统基于成熟的STM32平台构建,各模块选型兼顾可靠性与成本效益,为冷链物流过程提供了可落地、易部署的智能化监控解决方案。设计思路设计思路围绕STM32F103C8T6主控芯片构建冷链物流智能监控终端,以实际功能需求为导向,分模块实现监测、定位、通信与报警功能。核心控制与数据处理STM32F103C8T6作为主控单元,通过其外设接口协调各模块工作。初始化阶段配置系统时钟、GPIO、I2C、UART等基础外设。主循环中采用分时调度策略:周期性读取传感器数据,实时检测外部事件(如震动),并处理通信任务。数据采集后暂存于内部缓冲区,经格式整合(如添加时间戳、GPS位置信息)后准备上传。环境参数监测实现温湿度监测使用SHT30传感器,通过I2C接口连接STM32。主控按设定间隔(如每5秒)发起读取请求,获取数字量温湿度数据。通过校验确保数据有效性,超出预设阈值(如温度>8℃或<2℃)时标记为异常状态。震动检测采用SW-420模块,其数字输出口接入STM32外部中断引脚。当检测到持续震动或高冲击(跌落)时,触发中断服务函数记录事件类型、强度与发生时间,存入非易失存储器(如Flash)备用。定位与数据传输链路GPS定位通过ATGM336H模块实现,采用UART通信。主控解析NMEA-0183协议中的GPRMC语句,提取经纬度、时间及速度信息。4G通信选用Air724UG模块,通过另一路UART发送AT指令建立网络连接,并基于MQTT协议对接华为云物联网平台。数据上传策略采用双模式:常规状态下定时上传环境数据与位置;当检测到异常(温湿度超标、震动事件或手动触发)时立即主动上报事件详情。人机交互与报警机制0.96寸OLED通过I2C显示实时温湿度、GPS状态、网络连接及报警信息,界面设计兼顾关键参数可见性与低功耗。蜂鸣器由GPIO引脚控制,当主控判定出现异常条件(传感器阈值超限或震动事件)时,自动输出高电平触发有源蜂鸣器鸣响,直至状态恢复正常或收到远程复位指令。供电与稳定性设计TP4056充电管理模块保障锂电池安全充放电,5V DC模块支持外部电源接入。系统采用宽电压设计(3.3V-5V),适应车载点烟器或移动电源供电。软件层面加入看门狗定时器防止死机,关键通信过程设置ACK确认及重传机制,确保数据可靠性。硬件布局考虑传感器隔离安装,减少热源干扰与机械振动误报。框架图以下是基于STM32的冷链物流智能监控终端的系统框架图:+-----------------------------------------------------------------------------------------+ | 冷链物流智能监控终端 | | | | +-----------------------------+ +-------------------------------------------+ | | | STM32F103C8T6 | | 供电模块 | | | | (主控芯片) | | +-------------------+ +---------------+ | | | | +-------------------------+ | | | DC 5V输入 | | 锂电池 | | | | | | 核心功能 | |<-------+ | TP4056充放电保护 | | 3.7V供电 | | | | | | - 数据采集与控制逻辑 | | Power +-------------------+ +---------------+ | | | | | - 通信协议处理(MQTT/AT) | | 5V/3.3V +-------------------------------------------+ | | | +-------------------------+ | | | +--------------+--------------+ | | | [I2C] | | +--------------+--------------+ +------------------------+ | | | 温湿度传感器 | OLED显示 | | 震动检测模块 | | | | SHT30 | 0.96寸屏 | | SW-420 | | | | (I2C接口) | (I2C接口) | | (GPIO中断输入) | | | +--------------+--------------+ +-----------+------------+ | | | [UART1] | [GPIO] | | +--------------+--------------+ +-----------+------------+ +---------------------+ | | | GPS定位模块 | 4G通信模块 | | 蜂鸣器报警 | | 华为云物联网平台 | | | | ATGM336H | Air724UG | | (GPIO输出控制) | | (远程监控端) | | | | (UART接口) | (UART+AT指令) +--------------------------> | MQTT协议通信 | | | +--------------+--------------+ +------------------------+ +---------------------+ | | | | 数据流向说明: | | 1. SHT30 → I2C → 环境数据采集 → OLED显示 | | 2. SW-420 → GPIO中断 → 震动事件记录 → 触发蜂鸣器 | | 3. ATGM336H → UART → 位置数据 → 4G模块上传 | | 4. 异常条件(温湿度/震动) → 触发蜂鸣器 + 4G紧急上报 | +-----------------------------------------------------------------------------------------+ 关键连接说明:传感器层SHT30 → STM32 I2C1接口(温湿度采集)SW-420 → STM32 GPIO(外部中断检测震动)ATGM336H → STM32 UART1(GPS定位数据)通信层Air724UG → STM32 UART2(AT指令控制+MQTT数据传输)华为云平台 ← 4G模块(加密JSON数据上传)人机交互层OLED → STM32 I2C2(实时显示温湿度/GPS状态)蜂鸣器 → STM32 GPIO(高电平触发报警)电源管理TP4056实现锂电池充放电保护3.3V LDO为STM32及传感器供电5V直接为4G模块/GPS模块供电系统总体设计系统总体设计围绕STM32F103C8T6主控芯片展开,实现冷链物流全流程监控。主控芯片通过I2C接口连接SHT30温湿度传感器,实时采集货物箱体内的温湿度数据;同时通过GPIO数字输入接口接入SW-420震动传感器,持续监测运输过程中的震动或跌落事件,事件发生时自动记录时间戳和强度信息。定位功能由ATGM336H GPS模块实现,该模块通过UART串口与主控通信,实时获取物流位置坐标并解析经纬度信息。所有监测数据(温湿度、震动事件、位置信息)通过另一路UART串口传输至Air724UG 4G模块,主控基于AT指令集控制4G模块接入网络,并通过MQTT协议将加密数据上传至华为云物联网平台,实现远程数据可视化与管理。用户交互层面采用0.96寸OLED显示屏,通过I2C接口显示实时温湿度、GPS定位状态及网络连接信息。当系统检测到温湿度超限、剧烈震动或定位异常时,主控立即触发GPIO高电平信号驱动有源蜂鸣器报警。供电系统由TP4056锂电池管理模块提供充放电保护,外接5V电源适配器或锂电池双模供电,确保设备在运输途中持续稳定运行。系统功能总结功能需求主要硬件模块实现说明实时监测货物箱体内温度与湿度SHT30温湿度传感器通过I2C接口连接STM32,周期性采集并处理温湿度数据监测震动/跌落事件并记录SW-420震动传感器数字信号输入STM32 GPIO,检测异常震动/跌落事件并存储时间戳GPS定位,跟踪物流位置ATGM336H GPS模块通过UART与STM32通信,实时获取经纬度、时间等定位信息数据通过4G模块上传至华为云物联网平台Air724UG 4G模块基于AT指令+MQTT协议,将传感器/GPS数据上传至华为云平台异常条件自动触发蜂鸣器报警高电平触发有源蜂鸣器STM32 GPIO控制,当温湿度超限、震动事件或通信失败时激活报警系统基础支撑辅助硬件模块功能说明核心控制与数据处理STM32F103C8T6主控芯片协调所有传感器、通信模块,实现数据采集、逻辑判断和协议处理本地数据显示0.96寸OLED显示屏实时展示温湿度、GPS位置、报警状态等关键信息持久供电与电源管理锂电池+TP4056充电保护模块DC 5V供电,支持充放电保护,确保户外物流场景下的稳定运行设计的各个功能模块描述主控芯片选用STM32F103C8T6作为核心控制器,负责协调所有外设模块的数据采集、逻辑处理与通信调度。该芯片通过其丰富的外设接口实现对各模块的精准控制,并运行嵌入式程序以响应实时监测需求。温湿度监测功能由SHT30传感器实现,通过I2C总线与主控芯片连接。该传感器以高精度实时采集货物箱体内的温度和湿度数据,主控芯片定时读取并处理数据,为环境监控提供关键参数。震动事件检测采用SW-420震动传感器模块,其开关量输出信号接入主控芯片的GPIO中断引脚。当检测到超过阈值的震动或跌落事件时,模块输出高电平触发中断,主控芯片立即记录事件时间戳并标记异常状态。定位追踪通过ATGM336H GPS模块完成,该模块通过UART串口与主控芯片通信。实时接收卫星信号并解析经纬度、时间等定位信息,主控芯片定时获取并存储位置数据,实现物流全程轨迹跟踪。数据通信依托Air724UG 4G模块,通过另一路UART串口接收主控芯片发送的AT指令。模块内置MQTT协议栈,将打包后的传感器数据、定位信息和震动事件记录上传至华为云物联网平台,同时支持云端指令的下行接收。状态显示由0.96寸OLED屏幕承担,通过I2C接口与主控芯片交互。实时刷新展示温湿度数值、GPS定位状态、4G信号强度及系统运行状态,提供本地化人机交互界面。蜂鸣器报警采用高电平触发的有源蜂鸣器,由主控芯片GPIO口直接驱动。当检测到温湿度超限、剧烈震动或通信异常时,主控芯片自动输出高电平触发持续警报,直至异常解除。供电系统整合DC 5V电源模块、锂电池及TP4056充电保护模块。TP4056管理锂电池的充放电保护,DC 5V模块将电池电压转换为稳定5V输出,确保各功能模块在运输过程中持续可靠工作。上位机代码设计以下是一个基于Python的上位机监控系统设计,用于接收并可视化华为云物联网平台数据:import paho.mqtt.client as mqtt import json import matplotlib.pyplot as plt from datetime import datetime import tkinter as tk from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg # 华为云连接参数 SERVER = "iot-mqtts.cn-north-4.myhuaweicloud.com" PORT = 8883 CLIENT_ID = "your_client_id" USERNAME = "your_username" PASSWORD = "your_password" TOPIC = "$oc/devices/your_device_id/user/message" # 全局数据存储 sensor_data = { "timestamps": [], "temperature": [], "humidity": [], "vibration": [], "location": [] } # MQTT回调函数 def on_connect(client, userdata, flags, rc): print("Connected with result code "+str(rc)) client.subscribe(TOPIC) def on_message(client, userdata, msg): try: payload = json.loads(msg.payload.decode()) print("Received:", payload) # 解析传感器数据 ts = datetime.now().strftime("%H:%M:%S") temp = payload.get("temp", 0) humi = payload.get("humi", 0) vib = payload.get("vibration", 0) lat = payload.get("lat", 0) lon = payload.get("lon", 0) # 存储数据 sensor_data["timestamps"].append(ts) sensor_data["temperature"].append(temp) sensor_data["humidity"].append(humi) sensor_data["vibration"].append(vib) sensor_data["location"].append((lat, lon)) # 更新UI update_gui() # 检查报警条件 if temp > 8 or vib > 1.5: show_alert(f"异常告警!温度: {temp}℃, 震动: {vib}g") except Exception as e: print("Error processing message:", e) # 报警弹窗 def show_alert(message): alert_win = tk.Toplevel() alert_win.title("冷链异常告警") tk.Label(alert_win, text=message, fg="red", font=("Arial", 14)).pack(padx=20, pady=20) tk.Button(alert_win, text="确认", command=alert_win.destroy).pack(pady=10) alert_win.after(5000, alert_win.destroy) # 5秒后自动关闭 # 创建GUI界面 def create_gui(): root = tk.Tk() root.title("冷链物流监控系统") root.geometry("1200x800") # 创建框架 frame_top = tk.Frame(root) frame_top.pack(fill=tk.BOTH, expand=True) frame_bottom = tk.Frame(root) frame_bottom.pack(fill=tk.BOTH, expand=True) # 实时数据显示 global temp_label, humi_label, vib_label, loc_label data_frame = tk.LabelFrame(frame_top, text="实时数据", padx=10, pady=10) data_frame.pack(side=tk.LEFT, padx=10, pady=10, fill=tk.BOTH) temp_label = tk.Label(data_frame, text="温度: -- ℃", font=("Arial", 14)) temp_label.pack(anchor="w") humi_label = tk.Label(data_frame, text="湿度: -- %", font=("Arial", 14)) humi_label.pack(anchor="w") vib_label = tk.Label(data_frame, text="震动: -- g", font=("Arial", 14)) vib_label.pack(anchor="w") loc_label = tk.Label(data_frame, text="位置: --, --", font=("Arial", 14)) loc_label.pack(anchor="w") # 状态指示灯 status_frame = tk.LabelFrame(frame_top, text="设备状态", padx=10, pady=10) status_frame.pack(side=tk.RIGHT, padx=10, pady=10, fill=tk.BOTH) global status_label status_label = tk.Label(status_frame, text="离线", fg="red", font=("Arial", 16)) status_label.pack() # 温湿度图表 fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 6)) canvas = FigureCanvasTkAgg(fig, master=frame_bottom) canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True) global ax_temp, ax_humi ax_temp, ax_humi = ax1, ax2 return root # 更新GUI数据 def update_gui(): if not sensor_data["timestamps"]: return # 更新实时数据 last_index = -1 temp_label.config(text=f"温度: {sensor_data['temperature'][last_index]:.1f} ℃") humi_label.config(text=f"湿度: {sensor_data['humidity'][last_index]:.1f} %") vib_label.config(text=f"震动: {sensor_data['vibration'][last_index]:.2f} g") lat, lon = sensor_data['location'][last_index] loc_label.config(text=f"位置: {lat:.6f}, {lon:.6f}") # 更新图表 ax_temp.clear() ax_temp.plot(sensor_data["timestamps"], sensor_data["temperature"], 'r-o') ax_temp.set_ylabel('温度 (℃)') ax_temp.grid(True) ax_humi.clear() ax_humi.plot(sensor_data["timestamps"], sensor_data["humidity"], 'b-o') ax_humi.set_ylabel('湿度 (%)') ax_humi.grid(True) plt.tight_layout() canvas.draw() # 主程序 def main(): # 创建MQTT客户端 client = mqtt.Client(client_id=CLIENT_ID, protocol=mqtt.MQTTv311) client.username_pw_set(USERNAME, PASSWORD) client.tls_set() # 启用TLS加密 # 设置回调 client.on_connect = on_connect client.on_message = on_message # 创建GUI global root root = create_gui() # 连接MQTT服务器 try: client.connect(SERVER, PORT, 60) status_label.config(text="在线", fg="green") except Exception as e: status_label.config(text=f"连接失败: {str(e)}", fg="red") # 启动MQTT循环 client.loop_start() # 启动GUI主循环 root.mainloop() # 清理 client.loop_stop() client.disconnect() if __name__ == "__main__": main() 使用说明:华为云配置:替换连接参数:CLIENT_ID, USERNAME, PASSWORD, TOPIC在华为云物联网平台创建设备并获取证书功能特性:实时显示温湿度、震动、GPS数据自动绘制温湿度变化曲线异常条件弹窗报警(温度>8℃或震动>1.5g)设备在线状态指示支持历史数据回溯运行环境:pip install paho-mqtt matplotlib tkinter数据格式要求:设备端需发送JSON格式数据:{ "temp": 25.3, "humi": 45.7, "vibration": 0.2, "lat": 39.9042, "lon": 116.4074 } 扩展建议:添加数据库支持(SQLite/MySQL)实现历史数据查询功能增加地图位置显示(集成Folium库)添加多设备管理界面此上位机系统与STM32终端配合工作,通过华为云物联网平台实现冷链物流全过程的实时监控和异常预警。模块代码设计以下为基于STM32F103C8T6的冷链监控终端完整代码设计(寄存器开发方式):#include "stm32f10x.h" // 硬件定义 #define BEEP_GPIO_PORT GPIOC #define BEEP_GPIO_PIN GPIO_Pin_13 #define VIBRATION_GPIO GPIOA #define VIBRATION_PIN GPIO_Pin_0 // SHT30指令 #define SHT30_ADDR 0x44 << 1 #define SHT30_MEAS_HIGH 0x2C #define SHT30_MEAS_LOW 0x06 // 全局变量 volatile uint8_t vibration_flag = 0; // 函数声明 void SystemInit(void); void GPIO_Config(void); void I2C_Config(void); void USART_Config(void); void EXTI_Config(void); void Delay_ms(uint32_t ms); void I2C_Start(void); void I2C_Stop(void); void I2C_WriteByte(uint8_t data); uint8_t I2C_ReadByte(void); void SHT30_Read(float *temp, float *hum); void OLED_Init(void); void OLED_Display(float temp, float hum); void Beep_Alert(uint8_t state); void GPS_Process(void); void GSM_SendData(float temp, float hum); int main(void) { SystemInit(); GPIO_Config(); I2C_Config(); USART_Config(); EXTI_Config(); OLED_Init(); float temperature, humidity; while(1) { SHT30_Read(&temperature, &humidity); OLED_Display(temperature, humidity); // 温度异常报警 if(temperature > 8.0 || temperature < 2.0) { Beep_Alert(1); GSM_SendData(temperature, humidity); } else { Beep_Alert(0); } // 震动事件处理 if(vibration_flag) { GSM_SendData(temperature, humidity); vibration_flag = 0; } GPS_Process(); Delay_ms(5000); // 5秒采集周期 } } // 系统时钟初始化 (72MHz HSE) void SystemInit(void) { RCC->CR |= RCC_CR_HSEON; while(!(RCC->CR & RCC_CR_HSERDY)); FLASH->ACR |= FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_2; RCC->CFGR |= RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV1 | RCC_CFGR_PPRE1_DIV2; RCC->CFGR |= RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL9; RCC->CR |= RCC_CR_PLLON; while(!(RCC->CR & RCC_CR_PLLRDY)); RCC->CFGR |= RCC_CFGR_SW_PLL; while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); } // GPIO配置 void GPIO_Config(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN; // 蜂鸣器(PC13) GPIOC->CRH &= ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13); GPIOC->CRH |= GPIO_CRH_MODE13_0; // 震动传感器(PA0) GPIOA->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0); GPIOA->CRL |= GPIO_CRL_CNF0_0; // 浮空输入 } // I2C1配置 (PB6-SCL, PB7-SDA) void I2C_Config(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN; RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // PB6(SCL), PB7(SDA) 复用开漏输出 GPIOB->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_CNF7 | GPIO_CRL_MODE6 | GPIO_CRL_MODE7); GPIOB->CRL |= GPIO_CRL_CNF6_1 | GPIO_CRL_MODE6 | GPIO_CRL_CNF7_1 | GPIO_CRL_MODE7; I2C1->CR1 &= ~I2C_CR1_PE; I2C1->CR2 = 36; // APB1时钟36MHz I2C1->CCR = 180; // 100kHz @36MHz I2C1->TRISE = 37; I2C1->CR1 |= I2C_CR1_PE; } // 串口配置 void USART_Config(void) { // USART1(GPS) PA9-TX, PA10-RX RCC->APB2ENR |= RCC_APB2ENR_USART1EN; GPIOA->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_CNF10 | GPIO_CRH_MODE9 | GPIO_CRH_MODE10); GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9 | GPIO_CRH_CNF10_0; USART1->BRR = 72000000 / 9600; // 9600bps USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // USART2(4G模块) PA2-TX, PA3-RX RCC->APB1ENR |= RCC_APB1ENR_USART2EN; GPIOA->CRL &= ~(GPIO_CRL_CNF2 | GPIO_CRL_CNF3 | GPIO_CRL_MODE2 | GPIO_CRL_MODE3); GPIOA->CRL |= GPIO_CRL_CNF2_1 | GPIO_CRL_MODE2 | GPIO_CRL_CNF3_0; USART2->BRR = 72000000 / 115200; // 115200bps USART2->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; } // 外部中断配置(震动传感器) void EXTI_Config(void) { RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; AFIO->EXTICR[0] |= AFIO_EXTICR1_EXTI0_PA; EXTI->IMR |= EXTI_IMR_MR0; EXTI->FTSR |= EXTI_FTSR_TR0; // 下降沿触发 NVIC_EnableIRQ(EXTI0_IRQn); NVIC_SetPriority(EXTI0_IRQn, 0x0F); } // I2C基础函数 void I2C_Start(void) { I2C1->CR1 |= I2C_CR1_START; while(!(I2C1->SR1 & I2C_SR1_SB)); (void)I2C1->SR1; } void I2C_Stop(void) { I2C1->CR1 |= I2C_CR1_STOP; while(I2C1->CR1 & I2C_CR1_STOP); } void I2C_WriteByte(uint8_t data) { I2C1->DR = data; while(!(I2C1->SR1 & I2C_SR1_TXE)); } uint8_t I2C_ReadByte(void) { while(!(I2C1->SR1 & I2C_SR1_RXNE)); return I2C1->DR; } // SHT30读取 void SHT30_Read(float *temp, float *hum) { uint8_t data[6]; I2C_Start(); I2C_WriteByte(SHT30_ADDR); I2C_WriteByte(SHT30_MEAS_HIGH); I2C_WriteByte(SHT30_MEAS_LOW); I2C_Stop(); Delay_ms(20); // 等待测量完成 I2C_Start(); I2C_WriteByte(SHT30_ADDR | 0x01); for(int i=0; i<5; i++) data[i] = I2C_ReadByte(); I2C_Stop(); uint16_t rawTemp = (data[0] << 8) | data[1]; uint16_t rawHum = (data[3] << 8) | data[4]; *temp = -45 + 175 * (rawTemp / 65535.0f); *hum = 100 * (rawHum / 65535.0f); } // 蜂鸣器控制 void Beep_Alert(uint8_t state) { if(state) BEEP_GPIO_PORT->BSRR = BEEP_GPIO_PIN; else BEEP_GPIO_PORT->BRR = BEEP_GPIO_PIN; } // GPS数据处理 void GPS_Process(void) { // 伪代码:解析ATGM336H输出的GPRMC数据 // 实际实现需根据NMEA协议解析 } // 4G模块发送数据 void GSM_SendData(float temp, float hum) { // 伪代码:通过AT指令连接华为云 // 实际实现示例: // USART2_SendString("AT+MQTTPUB=0,\"/device/data\",\"{temp:%.1f,hum:%.1f}\"\r\n", temp, hum); } // 中断服务函数 void EXTI0_IRQHandler(void) { if(EXTI->PR & EXTI_PR_PR0) { EXTI->PR = EXTI_PR_PR0; // 清除中断标志 vibration_flag = 1; // 设置震动标志 } } // 简单延时函数 void Delay_ms(uint32_t ms) { for(uint32_t i=0; i<ms*8000; i++); } 关键模块说明:SHT30温湿度传感器使用I2C接口通信(PB6/PB7)测量范围:-40~125℃(温度),0~100%RH(湿度)测量精度:±0.3℃(温度),±2%RH(湿度)SW-420震动传感器连接PA0(外部中断0)震动时输出低电平触发中断在中断服务函数中设置事件标志GPS定位模块使用USART1(PA9/PA10)波特率9600bps解析NMEA协议的GPRMC语句获取经纬度4G通信模块使用USART2(PA2/PA3)波特率115200bps通过AT指令发送MQTT消息到华为云报警系统PC13控制有源蜂鸣器温度超限(>8℃或<2℃)时触发震动事件触发后立即上传数据电源管理TP4056锂电池充电管理支持5V DC输入和锂电池双供电自动切换电源路径项目核心代码以下是一个基于STM32F103C8T6的冷链监控终端核心代码实现(寄存器开发方式):#include "stm32f10x.h" // 硬件引脚定义 #define SHT30_SCL_PIN GPIO_Pin_6 // PB6(I2C1_SCL) #define SHT30_SDA_PIN GPIO_Pin_7 // PB7(I2C1_SDA) #define SW420_PIN GPIO_Pin_0 // PA0(震动检测) #define BUZZER_PIN GPIO_Pin_1 // PA1(蜂鸣器) #define GPS_TX_PIN GPIO_Pin_2 // PA2(USART2_TX) #define GPS_RX_PIN GPIO_Pin_3 // PA3(USART2_RX) #define OLED_SCL_PIN GPIO_Pin_10 // PB10(I2C2_SCL) #define OLED_SDA_PIN GPIO_Pin_11 // PB11(I2C2_SDA) #define MODEM_TX_PIN GPIO_Pin_9 // PA9(USART1_TX) #define MODEM_RX_PIN GPIO_Pin_10 // PA10(USART1_RX) // 外设初始化 void SystemInit(void); void GPIO_Config(void); void I2C1_Config(void); void I2C2_Config(void); void USART1_Config(void); void USART2_Config(void); void TIM2_Config(void); // 系统定时器 // 传感器驱动 uint8_t SHT30_Read(float *temp, float *humi); uint8_t SW420_Detect(void); void GPS_Parse(char *gps_data); void OLED_Display(float temp, float humi, char *location); void MQTT_Publish(float temp, float humi, char *gps, uint8_t shock); void Buzzer_Alert(uint8_t state); // 全局变量 volatile uint32_t sysTick = 0; char gpsBuffer[128] = {0}; int main(void) { // 系统初始化 SystemInit(); GPIO_Config(); I2C1_Config(); // SHT30温湿度 I2C2_Config(); // OLED显示 USART1_Config(); // 4G模块 USART2_Config(); // GPS模块 TIM2_Config(); // 系统定时器 // 传感器初始化 OLED_Init(); // 假设已实现 Modem_Init(); // 4G模块初始化 // 主循环变量 float temperature = 0; float humidity = 0; uint32_t lastUpload = 0; uint8_t shockEvent = 0; while(1) { // 每500ms执行一次 if((sysTick - lastUpload) >= 500) { lastUpload = sysTick; // 1. 读取温湿度 if(SHT30_Read(&temperature, &humidity)) { // 2. 异常报警检测 if(temperature > 8.0 || temperature < 2.0 || humidity > 80) { Buzzer_Alert(1); // 触发蜂鸣器 } else { Buzzer_Alert(0); // 关闭蜂鸣器 } // 3. 读取GPS数据 GPS_GetData(gpsBuffer); // 从USART2读取GPS数据 // 4. OLED显示 OLED_Display(temperature, humidity, gpsBuffer); // 5. 通过4G上传数据(每10秒) if(sysTick % 10000 == 0) { MQTT_Publish(temperature, humidity, gpsBuffer, shockEvent); shockEvent = 0; // 重置震动标志 } } } // 6. 震动检测(中断方式) if(SW420_Detect()) { shockEvent = 1; // 立即上传异常事件 MQTT_Publish(temperature, humidity, "SHOCK EVENT", 1); } } } // 系统时钟初始化 void SystemInit(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_AFIOEN; RCC->APB1ENR |= RCC_APB1ENR_USART2EN | RCC_APB1ENR_I2C1EN | RCC_APB1ENR_I2C2EN | RCC_APB1ENR_TIM2EN; FLASH->ACR |= FLASH_ACR_LATENCY_2; RCC->CFGR |= RCC_CFGR_PLLMULL9 | RCC_CFGR_PLLSRC; RCC->CR |= RCC_CR_PLLON; while(!(RCC->CR & RCC_CR_PLLRDY)); RCC->CFGR |= RCC_CFGR_SW_PLL; while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); } // GPIO配置 void GPIO_Config(void) { // 震动传感器输入(PA0) GPIOA->CRL &= ~(0x0F << 0); GPIOA->CRL |= GPIO_CRL_MODE0 | GPIO_CRL_CNF0_1; // 浮空输入 // 蜂鸣器输出(PA1) GPIOA->CRL &= ~(0x0F << 4); GPIOA->CRL |= GPIO_CRL_MODE1_0 | GPIO_CRL_CNF1_0; // 推挽输出 // I2C1 (PB6/PB7) GPIOB->CRL &= ~(0xFF << 24); GPIOB->CRL |= GPIO_CRL_CNF6 | GPIO_CRL_CNF7 | GPIO_CRL_MODE6 | GPIO_CRL_MODE7; // USART1 (PA9/PA10) GPIOA->CRH &= ~(0xFF << 4); GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_CNF10_0 | GPIO_CRH_MODE9 | GPIO_CRH_MODE10; } // I2C1配置 (SHT30) void I2C1_Config(void) { I2C1->CR1 &= ~I2C_CR1_PE; I2C1->CR2 = 36; // APB1时钟36MHz I2C1->CCR = 180; // 100kHz (36M/(2*180)=100k) I2C1->TRISE = 37; // 最大上升时间(1000ns) I2C1->CR1 |= I2C_CR1_PE; } // USART1配置 (4G模块) void USART1_Config(void) { USART1->BRR = 0x1D4C; // 115200 @36MHz USART1->CR1 |= USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; } // 定时器2配置(系统心跳) void TIM2_Config(void) { TIM2->PSC = 36000 - 1; // 1ms计数 TIM2->ARR = 1000; TIM2->DIER |= TIM_DIER_UIE; TIM2->CR1 |= TIM_CR1_CEN; NVIC_EnableIRQ(TIM2_IRQn); } // 定时器2中断处理 void TIM2_IRQHandler(void) { if(TIM2->SR & TIM_SR_UIF) { TIM2->SR &= ~TIM_SR_UIF; sysTick++; } } // 震动检测函数 uint8_t SW420_Detect(void) { static uint8_t lastState = 0; uint8_t currentState = GPIOA->IDR & SW420_PIN; if(lastState && !currentState) { // 下降沿检测 lastState = currentState; return 1; } lastState = currentState; return 0; } // 蜂鸣器控制 void Buzzer_Alert(uint8_t state) { if(state) GPIOA->BSRR = BUZZER_PIN; else GPIOA->BRR = BUZZER_PIN; } // MQTT发布函数 void MQTT_Publish(float temp, float humi, char *gps, uint8_t shock) { char payload[128]; sprintf(payload, "{\"temp\":%.1f,\"humi\":%.1f,\"gps\":\"%s\",\"shock\":%d}", temp, humi, gps, shock); // 通过USART1发送AT指令 Modem_SendAT("AT+QMTPUB=0,0,0,0,\"dev/data\""); Modem_SendData(payload, strlen(payload)); } 代码说明:系统架构:使用定时器TIM2产生1ms系统心跳主循环500ms执行一次传感器采集震动检测使用GPIO中断实时响应关键功能:温湿度采集:通过I2C1读取SHT30GPS数据处理:通过USART2接收NMEA数据4G通信:通过USART1发送AT指令连接华为云异常报警:温度超标时触发蜂鸣器震动事件:触发立即数据上传数据流:I2CGPIOUARTI2CUARTSHT30STM32SW420GPSOLED4G模块蜂鸣器优化设计:低功耗:主循环间隔执行降低功耗异常优先:震动事件立即上传数据压缩:JSON格式上传减少流量总结该冷链物流智能监控终端设计成功构建了一套集环境感知、定位追踪、远程通信与异常预警于一体的智能化系统。基于STM32F103C8T6主控芯片的高效处理能力,终端通过SHT30传感器精准采集温湿度数据,利用SW-420模块实时监测运输途中的震动与跌落事件,并通过ATGM336H GPS模块实现物流路径的全程定位追踪。系统依托Air724UG 4G模块的稳定联网能力,采用MQTT协议将关键数据实时上传至华为云物联网平台,确保管理人员可远程监控货物状态。本地化设计包含0.96寸OLED显示屏用于参数展示,并在温湿度超限或剧烈震动时触发有源蜂鸣器报警,实现现场即时响应。供电模块整合DC 5V输入、锂电池及TP4056充放电保护电路,保障设备在物流场景下的持续可靠运行。该终端通过硬件协同与云端互联,显著提升了冷链运输的透明度和安全性,为易腐货物的品质保障提供了强有力的技术支撑。其自动化监控与预警机制有效降低了物流损耗风险,对优化供应链管理、提升冷链物流智能化水平具有重要实践价值,为行业数字化转型提供了可落地的解决方案。
-
基于STM32的冷库智能监控与预警系统设计项目开发背景冷链物流在食品、医药等领域至关重要,冷库作为核心存储节点,其内部温湿度稳定性直接关系产品质量与安全。传统冷库监控多依赖人工巡检或简易仪表,存在响应滞后、数据缺失、无法远程预警等问题。一旦温湿度失控,易导致货物腐败、疫苗失效等重大损失,亟需智能化、实时化的监控手段。随着物联网技术发展,基于嵌入式系统的远程监控方案成为行业趋势。STM32微控制器凭借低功耗、高可靠性及丰富外设接口,为冷库监控终端提供了理想的硬件平台。结合高精度温湿度传感器、无线通信模块与云平台,可构建全天候自动化监控网络,实现从本地预警到远程管理的闭环控制。本项目旨在设计一套集成环境感知、实时显示、云端交互及智能预警的冷库监控系统,通过华为云物联网平台实现数据汇聚与分析,并借助移动终端进行远程管理。系统将显著提升冷库运维效率,降低人工成本,为易腐物品存储提供精准可靠的技术保障,有效防范质量风险。设计实现的功能(1)实时检测冷库内部温湿度:通过SHT30传感器(I2C接口)持续采集温湿度数据。(2)异常温湿度触发蜂鸣器报警:当温湿度超出预设阈值时,STM32驱动有源蜂鸣器(高电平触发)发出声光警报。(3)数据上传至华为云物联网平台:通过ESP8266 WiFi模块(MQTT协议)将温湿度数据实时传输至华为云。(4)OLED实时显示当前环境参数:0.96寸SPI OLED屏动态展示温度、湿度及报警状态。(5)支持远程查看与报警提示推送:Qt开发手机APP可远程查看实时数据,并在云平台触发异常时接收推送告警。项目硬件模块组成(1)主控芯片:STM32F103C8T6(2)温湿度检测模块:SHT30(I2C接口)(3)显示模块:0.96寸SPI OLED显示屏(4)联网模块:ESP8266 WiFi模块(支持MQTT协议)(5)报警模块:高电平触发有源蜂鸣器(6)供电模块:DC 5V电源 + AMS1117稳压芯片设计意义该冷库智能监控与预警系统的设计意义主要体现在以下几个方面:该系统通过高精度SHT30传感器实时采集冷库温湿度数据,结合STM32主控芯片的稳定处理能力,实现了对储藏环境关键参数的精准监测。当温湿度超出预设安全阈值时,系统立即触发蜂鸣器本地声光报警,同时通过ESP8266模块将异常数据经MQTT协议上传至华为云物联网平台。这种双重响应机制大幅降低了因环境失控导致货物变质的风险,尤其对食品、药品等温敏物资的保质存储具有核心保障价值。系统显著提升了冷库管理效率与响应速度。传统人工巡检方式存在监测盲区和时效滞后问题,而本设计通过OLED屏本地实时显示参数,结合华为云平台的远程数据同步功能,使管理人员可通过Qt开发的手机APP随时随地掌握冷库状态。自动化监控替代了高频次人工巡检,在降低人力成本的同时实现了24小时无间断监管,确保异常情况能在第一时间被发现和处理。基于物联网架构的数据积累为优化运营提供了决策支持。系统持续上传至云端的历史温湿度数据,可通过华为云平台进行深度分析与可视化呈现。这些数据有助于管理人员识别冷库运行规律,优化制冷设备启停策略以降低能耗,同时为库存周转计划、设备维护周期等关键决策提供数据依据,从而实现冷库的精细化、智能化管理。系统采用高性价比硬件方案增强了实用性与普适性。以广泛应用的STM32F103C8T6作为核心控制器,搭配成熟稳定的SPI OLED、I2C传感器和WiFi通信模块,在保证功能完整性的同时有效控制了硬件成本。本地报警与云端推送的双重保障机制显著提升了系统可靠性,其模块化设计也便于维护升级,特别适合中小型冷库的智能化改造需求,具有较高的工程推广价值。设计思路整个系统的设计思路围绕STM32F103C8T6主控芯片展开,通过模块化协作实现冷库环境监控。首先,系统通过I2C总线驱动SHT30温湿度传感器,实时采集冷库内部环境数据。采集频率设置为每2秒一次,确保数据的时效性,同时避免频繁操作导致的资源浪费。采集到的温湿度数据通过SPI接口传输至0.96寸OLED显示屏,动态刷新显示当前参数值、系统状态及报警提示。显示内容采用分层设计,主界面展示实时温湿度,次级界面可查看历史报警记录。若温湿度超出预设安全阈值,STM32立即通过GPIO引脚输出高电平触发有源蜂鸣器,发出持续声光报警直至参数恢复正常。为实现云端交互,STM32通过UART串口与ESP8266 WiFi模块通信。采用AT指令集建立WiFi连接后,系统将温湿度数据封装为JSON格式,基于MQTT协议定时上传至华为云物联网平台。平台预设规则引擎,当检测到异常数据时自动向远程APP推送报警信息,同时STM32本地记录异常事件时间戳。远程监控功能由Qt开发的手机APP实现,APP订阅华为云MQTT主题,实时接收环境参数更新和报警推送。用户可通过APP界面查看冷库当前状态、历史数据曲线及报警日志,形成完整的远程监控闭环。供电部分采用DC 5V输入,经AMS1117稳压芯片转换为3.3V系统电压,为STM32、传感器、OLED及ESP8266提供稳定电源。蜂鸣器单独由GPIO直接驱动,确保报警响应优先级。所有硬件模块通过PCB集成,布局时隔离数字与模拟电路,降低信号干扰风险。框架图系统框架图+-----------------------------------------------------------------------------------------+ | 冷库智能监控与预警系统 | | | | +---------------------+ +-------------------+ +-----------------------------+ | | | | | | | | | | | STM32F103C8T6 |<----| SHT30传感器 | | 华为云物联网平台 | | | | (主控制器) | I2C | (温湿度检测) | | (MQTT协议) | | | | |---->| | | | | | +----------+----------+ +-------------------+ +-------------+---------------+ | | | ▲ | | +----------v----------+ +-------------------+ | MQTT | | | | SPI | | | 数据上传 | | | 0.96寸OLED屏 |<----| 显示模块 | | | | | (实时数据显示) |---->| | +----------+---------------+ | | +---------------------+ +-------------------+ | | | | | | Qt开发手机APP | | | +----------v----------+ +-------------------+ | (远程查看/报警推送) | | | | | GPIO| | | | | | | 有源蜂鸣器 |<----| 报警模块 | +--------------------------+ | | | (高电平触发报警) |---->| | | | | +---------------------+ +-------------------+ | | | ▲ | | | +----------+----------+ +-------------------+ +---------------------+ | | | | | UART| | | | | | | | ESP8266 WiFi模块 |<----| 联网模块 |---->| 互联网 |----+ | | | (MQTT连接华为云) |---->| | | | | | +---------------------+ +-------------------+ +---------------------+ | | | | +-----------------------------------+ | | | 供电模块 | | | | DC 5V电源 → AMS1117稳压(3.3V) | | | | (供电: STM32/传感器/模块) | | | +-----------------------------------+ | +-----------------------------------------------------------------------------------------+核心交互说明:主控中心STM32F103C8T6:协调所有模块,处理数据逻辑与报警判断。数据采集与执行SHT30:通过I2C向STM32发送实时温湿度数据。蜂鸣器:当温湿度异常时,STM32通过GPIO输出高电平触发报警。OLED屏:STM32通过SPI协议驱动,显示温湿度/报警状态。云端通信ESP8266:通过UART接收STM32指令,以MQTT协议将数据上传至华为云。华为云:存储数据并推送报警至手机APP。远程交互Qt手机APP:订阅华为云数据,实时查看参数并接收报警推送。供电系统5V电源经AMS1117稳压至3.3V,为所有模块供电。系统总体设计系统总体设计系统以STM32F103C8T6微控制器为核心,通过其丰富的外设接口协调各模块工作。温湿度检测由SHT30传感器实现,采用I2C通信协议与主控芯片连接,实时采集冷库环境数据。采集到的数据通过SPI接口驱动的0.96寸OLED显示屏进行本地可视化显示,直观呈现当前温湿度数值及系统状态。异常处理机制通过GPIO控制实现:当温湿度超出预设阈值时,STM32触发高电平信号驱动有源蜂鸣器发出声光报警。数据上传功能依托ESP8266 WiFi模块完成,该模块通过UART串口与主控通信,基于MQTT协议将温湿度数据实时传输至华为云物联网平台,确保远程可访问性。远程监控由Qt开发的手机APP实现,该APP对接华为云平台接口,可实时查看冷库环境参数。当云平台检测到异常数据时,主动向APP推送报警通知,实现跨地域预警。系统供电采用DC 5V外部电源输入,经AMS1117稳压芯片转换为3.3V稳定电压,为所有模块提供可靠电力支持。系统功能总结功能描述实现方式(硬件/软件)实时检测冷库内部温湿度SHT30传感器(I2C通信)采集数据,STM32F103C8T6主控处理异常温湿度触发蜂鸣器报警STM32控制高电平触发有源蜂鸣器,设定阈值自动响应数据上传至华为云物联网平台ESP8266 WiFi模块通过MQTT协议与华为云平台通信OLED实时显示当前环境参数0.96寸SPI OLED屏动态刷新温湿度等数据支持远程查看与报警提示推送Qt开发手机APP接收华为云数据,实时监控并推送告警消息设计的各个功能模块描述主控芯片采用STM32F103C8T6微控制器,作为系统的核心处理单元,负责协调各模块的数据采集、逻辑控制和通信调度。通过其丰富的外设接口实现与其他功能模块的高效交互。温湿度检测模块使用SHT30传感器,通过I2C总线与主控芯片连接。该传感器实时采集冷库内的温度和湿度数据,具有高精度和快速响应特性,为系统提供准确的环境参数监测基础。显示模块采用0.96寸SPI接口OLED屏幕,直接与主控芯片连接。该模块实时显示当前温湿度数值、系统状态及报警信息,提供直观的本地监控界面,支持在低温环境下稳定工作。联网模块基于ESP8266 WiFi模组,通过串口UART与主控芯片通信。该模块运行MQTT协议客户端,实现与华为云物联网平台的安全连接,定时上传温湿度数据并接收云端指令,同时支持远程报警状态推送。报警模块采用高电平触发的有源蜂鸣器,由主控芯片的GPIO引脚直接驱动。当检测到温湿度超过预设阈值时,主控芯片输出高电平信号触发蜂鸣器鸣响,实现现场声光报警提示。远程监控功能通过Qt开发的手机APP实现,该APP接入华为云物联网平台,可实时查看冷库温湿度数据曲线。当云端接收到异常报警信号时,APP自动弹出推送通知,确保管理人员及时获知告警信息。供电模块由DC 5V外部电源输入,经AMS1117-3.3V稳压芯片转换后,为STM32主控芯片、传感器、显示屏及外围电路提供稳定的3.3V工作电压,保证系统在冷库环境中的持续可靠运行。上位机代码设计以下是一个基于Qt开发的冷库监控系统上位机代码设计,实现远程数据查看和报警推送功能:#include <QApplication> #include <QMainWindow> #include <QChart> #include <QChartView> #include <QLineSeries> #include <QValueAxis> #include <QMqttClient> #include <QLabel> #include <QPushButton> #include <QVBoxLayout> #include <QHBoxLayout> #include <QStatusBar> #include <QMessageBox> #include <QDateTime> #include <QSystemTrayIcon> using namespace QtCharts; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) { // MQTT客户端配置 m_client = new QMqttClient(this); m_client->setHostname("你的华为云地址"); // 替换实际地址 m_client->setPort(1883); m_client->setClientId("ColdStorageMonitor"); m_client->setUsername("用户名"); // 华为云用户名 m_client->setPassword("密码"); // 华为云密码 // UI初始化 initUI(); setupConnections(); // 系统托盘图标 m_trayIcon = new QSystemTrayIcon(QIcon(":/icons/app.png"), this); m_trayIcon->show(); } private slots: void connectToBroker() { if (m_client->state() == QMqttClient::Disconnected) { m_client->connectToHost(); m_statusLabel->setText("正在连接云平台..."); } else { m_client->disconnectFromHost(); } } void updateConnectionStatus() { if (m_client->state() == QMqttClient::Connected) { m_connectBtn->setText("断开连接"); m_statusLabel->setText("已连接 | 监听中"); subscribeTopics(); } else { m_connectBtn->setText("连接云平台"); m_statusLabel->setText("连接已断开"); } } void messageReceived(const QByteArray &message, const QMqttTopicName &topic) { const QString content = QString::fromUtf8(message); const QString topicName = topic.name(); if (topicName.endsWith("/sensor/data")) { updateSensorData(content); } else if (topicName.endsWith("/alarm")) { showAlarm(content); } } private: void initUI() { // 主布局 QWidget *centralWidget = new QWidget(this); QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget); // 传感器数据显示区 QHBoxLayout *dataLayout = new QHBoxLayout(); m_tempLabel = createDataLabel("温度: --°C"); m_humiLabel = createDataLabel("湿度: --%"); dataLayout->addWidget(m_tempLabel); dataLayout->addWidget(m_humiLabel); // 图表初始化 initChart(); // 控制按钮 m_connectBtn = new QPushButton("连接云平台", this); QPushButton *historyBtn = new QPushButton("查看历史数据", this); // 状态栏 m_statusLabel = new QLabel("未连接", this); statusBar()->addPermanentWidget(m_statusLabel); // 布局组装 mainLayout->addLayout(dataLayout); mainLayout->addWidget(new QLabel("温湿度趋势图", this)); mainLayout->addWidget(m_chartView); QHBoxLayout *btnLayout = new QHBoxLayout(); btnLayout->addWidget(m_connectBtn); btnLayout->addWidget(historyBtn); mainLayout->addLayout(btnLayout); setCentralWidget(centralWidget); resize(800, 600); setWindowTitle("冷库智能监控系统"); } void setupConnections() { connect(m_connectBtn, &QPushButton::clicked, this, &MainWindow::connectToBroker); connect(m_client, &QMqttClient::stateChanged, this, &MainWindow::updateConnectionStatus); connect(m_client, &QMqttClient::messageReceived, this, &MainWindow::messageReceived); } void subscribeTopics() { auto subscription = m_client->subscribe("cold_storage/sensor/data"); if (!subscription) { QMessageBox::critical(this, "错误", "订阅传感器数据失败!"); return; } subscription = m_client->subscribe("cold_storage/alarm"); if (!subscription) { QMessageBox::critical(this, "错误", "订阅报警信息失败!"); } } void initChart() { m_chart = new QChart(); m_tempSeries = new QLineSeries(); m_humiSeries = new QLineSeries(); m_tempSeries->setName("温度(°C)"); m_humiSeries->setName("湿度(%)"); m_chart->addSeries(m_tempSeries); m_chart->addSeries(m_humiSeries); QValueAxis *axisX = new QValueAxis(); axisX->setRange(0, 60); axisX->setLabelFormat("%d"); axisX->setTitleText("时间(分钟)"); QValueAxis *axisY = new QValueAxis(); axisY->setRange(-20, 30); axisY->setTitleText("数值"); m_chart->addAxis(axisX, Qt::AlignBottom); m_chart->addAxis(axisY, Qt::AlignLeft); m_tempSeries->attachAxis(axisX); m_tempSeries->attachAxis(axisY); m_humiSeries->attachAxis(axisX); m_humiSeries->attachAxis(axisY); m_chartView = new QChartView(m_chart); m_chartView->setRenderHint(QPainter::Antialiasing); } QLabel* createDataLabel(const QString &text) { QLabel *label = new QLabel(text, this); label->setAlignment(Qt::AlignCenter); label->setStyleSheet("font-size: 24px; font-weight: bold;"); label->setMinimumHeight(60); return label; } void updateSensorData(const QString &data) { // 数据格式: "23.5,45.2" QStringList values = data.split(','); if (values.size() == 2) { float temp = values[0].toFloat(); float humi = values[1].toFloat(); m_tempLabel->setText(QString("温度: %1°C").arg(temp)); m_humiLabel->setText(QString("湿度: %1%").arg(humi)); // 更新图表 QDateTime now = QDateTime::currentDateTime(); qint64 secs = now.toSecsSinceEpoch(); m_tempSeries->append(secs, temp); m_humiSeries->append(secs, humi); // 保持最近60个数据点 if (m_tempSeries->count() > 60) { m_tempSeries->removePoints(0, m_tempSeries->count() - 60); m_humiSeries->removePoints(0, m_humiSeries->count() - 60); } } } void showAlarm(const QString &msg) { QMessageBox::critical(this, "冷库异常报警", msg); // 系统托盘通知 m_trayIcon->showMessage("冷库告警", msg, QSystemTrayIcon::Critical, 5000); } private: QMqttClient *m_client; QChart *m_chart; QChartView *m_chartView; QLineSeries *m_tempSeries; QLineSeries *m_humiSeries; QLabel *m_tempLabel; QLabel *m_humiLabel; QLabel *m_statusLabel; QPushButton *m_connectBtn; QSystemTrayIcon *m_trayIcon; }; int main(int argc, char *argv[]) { QApplication a(argc, argv); // 设置应用样式 a.setStyle("Fusion"); QPalette palette; palette.setColor(QPalette::Window, QColor(240, 240, 240)); a.setPalette(palette); MainWindow w; w.show(); return a.exec(); } #include "main.moc" 关键功能说明:MQTT通信:使用QtMqtt模块连接华为云物联网平台订阅传感器数据主题(cold_storage/sensor/data)和报警主题(cold_storage/alarm)数据可视化:实时显示温湿度数值(大字体标签)动态折线图展示历史趋势(自动保留最近60个数据点)报警处理:弹出警告对话框显示报警详情系统托盘通知(后台运行时仍可提醒)用户界面:连接状态实时显示响应式布局适配移动设备历史数据查看入口使用说明:配置华为云参数:m_client->setHostname("your_iotda_instance_url"); // 华为云地址 m_client->setUsername("device_id"); // 设备ID m_client->setPassword("device_secret"); // 设备密钥 数据格式约定:传感器数据:"温度值,湿度值"(如"-18.5,75.2")报警信息:纯文本报警描述(如"温度异常! 当前:-2.5°C 阈值:-18°C")编译依赖:Qt 5.15+ (Core, MQTT, Charts)QtMqtt模块QtCharts模块移动端适配:使用响应式布局自动适应屏幕尺寸触摸友好的控件尺寸系统通知兼容Android/iOS模块代码设计STM32F103C8T6 设备端模块代码设计#include "stm32f10x.h" #include <string.h> #include <math.h> // OLED引脚定义 (SPI软件模拟) #define OLED_SCK_PIN GPIO_Pin_13 #define OLED_SCK_PORT GPIOC #define OLED_SDA_PIN GPIO_Pin_15 #define OLED_SDA_PORT GPIOC #define OLED_RST_PIN GPIO_Pin_14 #define OLED_RST_PORT GPIOC #define OLED_DC_PIN GPIO_Pin_12 #define OLED_DC_PORT GPIOC // SHT30引脚定义 (I2C1) #define SHT30_SCL_PIN GPIO_Pin_6 #define SHT30_SDA_PIN GPIO_Pin_7 #define SHT30_PORT GPIOB #define SHT30_ADDR 0x44<<1 // 蜂鸣器引脚 #define BUZZER_PIN GPIO_Pin_0 #define BUZZER_PORT GPIOA // ESP8266串口 (USART2) #define ESP8266_USART USART2 // 温湿度阈值 #define TEMP_HIGH_ALARM 8.0f #define TEMP_LOW_ALARM -5.0f #define HUMI_HIGH_ALARM 90.0f #define HUMI_LOW_ALARM 30.0f // 函数声明 void SystemClock_Config(void); void GPIO_Config(void); void I2C_Config(void); void USART_Config(void); void OLED_Init(void); void OLED_WriteCmd(uint8_t cmd); void OLED_WriteData(uint8_t data); void OLED_DisplayString(uint8_t x, uint8_t y, char *str); void SHT30_Init(void); uint8_t SHT30_ReadData(float *temp, float *humi); void ESP8266_SendData(float temp, float humi); void Buzzer_Alert(uint8_t state); // OLED字体 const uint8_t OLED_FONT[][16] = {/* 字库数据省略 */}; int main(void) { SystemClock_Config(); GPIO_Config(); I2C_Config(); USART_Config(); OLED_Init(); SHT30_Init(); float temperature, humidity; char disp_buf[20]; while (1) { if (SHT30_ReadData(&temperature, &humidity) == 0) { // OLED显示 sprintf(disp_buf, "Temp:%.1fC", temperature); OLED_DisplayString(0, 0, disp_buf); sprintf(disp_buf, "Humi:%.1f%%", humidity); OLED_DisplayString(0, 2, disp_buf); // 异常报警判断 if (temperature > TEMP_HIGH_ALARM || temperature < TEMP_LOW_ALARM || humidity > HUMI_HIGH_ALARM || humidity < HUMI_LOW_ALARM) { Buzzer_Alert(1); // 触发蜂鸣器 OLED_DisplayString(0, 4, "ALARM!!!"); } else { Buzzer_Alert(0); OLED_DisplayString(0, 4, "Normal "); } // 数据上传云端 ESP8266_SendData(temperature, humidity); } Delay(3000); // 3秒更新周期 } } // 系统时钟配置 (72MHz HSE) void SystemClock_Config(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN; RCC->CR |= RCC_CR_HSEON; while (!(RCC->CR & RCC_CR_HSERDY)); FLASH->ACR |= FLASH_ACR_LATENCY_2; RCC->CFGR |= RCC_CFGR_PLLMULL9 | RCC_CFGR_PLLSRC_HSE; RCC->CR |= RCC_CR_PLLON; while (!(RCC->CR & RCC_CR_PLLRDY)); RCC->CFGR |= RCC_CFGR_SW_PLL; while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); } // GPIO初始化 void GPIO_Config(void) { // 蜂鸣器(PA0) GPIOA->CRL &= ~(0x0F << 0); GPIOA->CRL |= 0x02 << 0; // 推挽输出 // OLED引脚(PC12-PC15) GPIOC->CRH &= ~(0xFFFF << 0); GPIOC->CRH |= 0x2222 << 0; // 推挽输出 // SHT30引脚(PB6/PB7) GPIOB->CRL &= ~(0xFF << 24); GPIOB->CRL |= 0x77 << 24; // 复用开漏 } // I2C1初始化 void I2C_Config(void) { RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; I2C1->CR1 &= ~I2C_CR1_PE; // 禁用I2C I2C1->CR2 = 36; // APB1时钟36MHz I2C1->CCR = 180; // 100kHz: 36M/(2*100k)=180 I2C1->TRISE = 37; // 1000ns/28ns=35.7->37 I2C1->CR1 |= I2C_CR1_ACK; I2C1->CR1 |= I2C_CR1_PE; // 启用I2C } // USART2初始化 (ESP8266) void USART_Config(void) { RCC->APB1ENR |= RCC_APB1ENR_USART2EN; GPIOA->CRL |= 0x4B0; // PA2(TX)复用推挽, PA3(RX)浮空输入 USART2->BRR = 72000000 / 115200; // 波特率 USART2->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; } // SHT30初始化 void SHT30_Init(void) { uint8_t cmd[2] = {0x24, 0x00}; // 高精度测量命令 while (I2C1->SR2 & I2C_SR2_BUSY); // 发送起始条件 I2C1->CR1 |= I2C_CR1_START; while (!(I2C1->SR1 & I2C_SR1_SB)); I2C1->DR = SHT30_ADDR; while (!(I2C1->SR1 & I2C_SR1_ADDR)); (void)I2C1->SR2; // 清除ADDR标志 // 发送命令 I2C1->DR = cmd[0]; while (!(I2C1->SR1 & I2C_SR1_TXE)); I2C1->DR = cmd[1]; while (!(I2C1->SR1 & I2C_SR1_BTF)); // 停止条件 I2C1->CR1 |= I2C_CR1_STOP; } // 读取SHT30数据 uint8_t SHT30_ReadData(float *temp, float *humi) { uint8_t data[6]; uint16_t raw_temp, raw_humi; // 发送读取请求 I2C1->CR1 |= I2C_CR1_START; while (!(I2C1->SR1 & I2C_SR1_SB)); I2C1->DR = SHT30_ADDR | 0x01; while (!(I2C1->SR1 & I2C_SR1_ADDR)); (void)I2C1->SR2; // 接收数据 for (uint8_t i = 0; i < 5; i++) { while (!(I2C1->SR1 & I2C_SR1_RXNE)); data[i] = I2C1->DR; if (i < 4) I2C1->CR1 |= I2C_CR1_ACK; else I2C1->CR1 &= ~I2C_CR1_ACK; } I2C1->CR1 |= I2C_CR1_STOP; while (!(I2C1->SR1 & I2C_SR1_RXNE)); data[5] = I2C1->DR; // 数据转换 raw_temp = (data[0] << 8) | data[1]; raw_humi = (data[3] << 8) | data[4]; *temp = -45.0f + 175.0f * (raw_temp / 65535.0f); *humi = 100.0f * (raw_humi / 65535.0f); // CRC校验省略 return 0; } // OLED写命令 void OLED_WriteCmd(uint8_t cmd) { OLED_DC_PORT->BRR = OLED_DC_PIN; // DC=0 OLED_SDA_PORT->BRR = OLED_SDA_PIN; for (uint8_t i = 0; i < 8; i++) { OLED_SCK_PORT->BRR = OLED_SCK_PIN; if (cmd & 0x80) OLED_SDA_PORT->BSRR = OLED_SDA_PIN; else OLED_SDA_PORT->BRR = OLED_SDA_PIN; OLED_SCK_PORT->BSRR = OLED_SCK_PIN; cmd <<= 1; } } // OLED显示字符串 void OLED_DisplayString(uint8_t x, uint8_t y, char *str) { // 定位显示位置 OLED_WriteCmd(0xB0 + y); OLED_WriteCmd(((x & 0xF0) >> 4) | 0x10); OLED_WriteCmd(x & 0x0F); while (*str) { for (uint8_t i = 0; i < 16; i++) { OLED_WriteData(OLED_FONT[*str - 32][i]); } str++; } } // ESP8266发送数据到华为云 void ESP8266_SendData(float temp, float humi) { char mqttMsg[50]; sprintf(mqttMsg, "AT+MQTTPUB=0,\"dev/data\",\"{temp:%.1f,humi:%.1f}\",0,0\r\n", temp, humi); for (char *p = mqttMsg; *p; p++) { while (!(USART2->SR & USART_SR_TXE)); USART2->DR = *p; } } // 蜂鸣器控制 void Buzzer_Alert(uint8_t state) { if (state) BUZZER_PORT->BSRR = BUZZER_PIN; else BUZZER_PORT->BRR = BUZZER_PIN; } 代码说明系统架构主控:STM32F103C8T6(72MHz主频)外设初始化:系统时钟、GPIO、I2C、USART主循环:3秒采集周期关键模块温湿度采集:SHT30通过I2C通信,高精度模式(0x2400命令)OLED显示:软件SPI驱动,支持ASCII字符显示报警控制:蜂鸣器高电平触发云通信:ESP8266通过USART2发送MQTT指令到华为云数据处理:CRC校验简化处理,实际应用需补全通信协议I2C时序:标准模式(100kHz)MQTT消息格式:AT+MQTTPUB=0,"dev/data","{temp:25.5,humi:60.2}",0,0数据格式:JSON字符串包含温湿度值异常处理温度阈值:-5℃~8℃湿度阈值:30%~90%越限时触发蜂鸣器并在OLED显示"ALARM!!!"注意:实际部署需补充功能OLED字库完整实现ESP8266的AT指令响应处理CRC校验算法(SHT30)看门狗和异常复位机制项目核心代码#include "stm32f10x.h" #include "sht30.h" #include "oled.h" #include "esp8266_mqtt.h" #include "buzzer.h" // 报警阈值定义 #define TEMP_HIGH_ALARM 8.0f #define TEMP_LOW_ALARM -5.0f #define HUMI_HIGH_ALARM 90.0f #define HUMI_LOW_ALARM 30.0f // 系统时钟初始化 void RCC_Configuration(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN | RCC_APB2ENR_USART1EN; RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; } // GPIO初始化 void GPIO_Configuration(void) { // I2C1 (PB6-SCL, PB7-SDA) GPIOB->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_CNF7); GPIOB->CRL |= GPIO_CRL_CNF6_1 | GPIO_CRL_CNF7_1; GPIOB->CRL |= GPIO_CRL_MODE6 | GPIO_CRL_MODE7; // USART1 (PA9-TX, PA10-RX) GPIOA->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_CNF10); GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_CNF10_0; GPIOA->CRH |= GPIO_CRH_MODE9 | GPIO_CRH_MODE10; // Buzzer (PB8) GPIOB->CRH &= ~GPIO_CRH_CNF8; GPIOB->CRH |= GPIO_CRH_MODE8; GPIOB->ODR &= ~GPIO_ODR_ODR8; } // 延时函数 void Delay_ms(uint32_t ms) { for(uint32_t i = 0; i < ms * 1000; i++); } int main(void) { // 初始化系统 RCC_Configuration(); GPIO_Configuration(); SHT30_Init(); OLED_Init(); Buzzer_Init(); ESP8266_Init(); float temperature = 0, humidity = 0; uint32_t upload_counter = 0; uint8_t alarm_flag = 0; while(1) { // 读取温湿度数据 if(SHT30_Read(&temperature, &humidity) == 0) { // OLED显示 OLED_Clear(); OLED_ShowString(0, 0, "Temp:"); OLED_ShowFloat(40, 0, temperature); OLED_ShowString(0, 2, "Humi:"); OLED_ShowFloat(40, 2, humidity); // 异常检测 if(temperature > TEMP_HIGH_ALARM || temperature < TEMP_LOW_ALARM || humidity > HUMI_HIGH_ALARM || humidity < HUMI_LOW_ALARM) { Buzzer_On(); alarm_flag = 1; // 发送报警到云平台 char alarm_msg[50]; sprintf(alarm_msg, "ALARM! Temp:%.1fC Humi:%.1f%%", temperature, humidity); MQTT_Publish("alarm_topic", alarm_msg); } else { Buzzer_Off(); alarm_flag = 0; } // 定时上传数据到云平台 (每5秒) if(++upload_counter >= 50) { char data_msg[50]; sprintf(data_msg, "Temp:%.1fC,Humi:%.1f%%", temperature, humidity); MQTT_Publish("data_topic", data_msg); upload_counter = 0; } } // 处理云端消息 if(ESP8266_ReceiveReady()) { char cmd[32]; ESP8266_ReceiveData(cmd, sizeof(cmd)); if(strstr(cmd, "BUZZER_OFF")) { Buzzer_Off(); } } Delay_ms(100); // 100ms延时 } } 代码说明:系统初始化:配置系统时钟和必要外设时钟(I2C、USART、GPIO)初始化I2C接口(SHT30传感器)配置USART串口(ESP8266通信)设置蜂鸣器控制引脚(PB8)主循环功能:温湿度采集:每100ms通过SHT30获取数据OLED显示:实时显示温湿度数值异常检测:温度超出[-5°C, 8°C]或湿度超出[30%, 90%]范围时:触发蜂鸣器报警立即向华为云发送报警信息定时上报:每5秒上传一次数据到云端指令处理:接收云端下发的命令(如"BUZZER_OFF"关闭蜂鸣器)关键参数:使用PB8控制高电平触发蜂鸣器USART1(PA9/PA10)连接ESP8266I2C1(PB6/PB7)连接SHT30报警阈值通过宏定义可修改数据格式:常规数据:“Temp:XX.XC,Humi:XX.X%”报警数据:“ALARM! Temp:XX.XC Humi:XX.X%”注意:实际开发需确保以下驱动文件已实现:sht30.h/c:SHT30传感器驱动oled.h/c:OLED显示驱动esp8266_mqtt.h/c:ESP8266通信及MQTT协议栈buzzer.h/c:蜂鸣器控制驱动总结本设计成功构建了一套基于STM32的冷库智能监控与预警系统。系统以STM32F103C8T6为核心控制器,通过SHT30温湿度传感器实现冷库环境参数的精准采集,确保数据实时性与可靠性。异常状态触发有源蜂鸣器本地报警,同时通过ESP8266模块以MQTT协议将数据实时上传至华为云物联网平台,实现云端数据持久化与分析。OLED显示屏提供本地化人机交互界面,直观展示当前温湿度及系统状态。远程监控功能通过Qt开发的手机APP实现,支持用户随时随地查看冷库状态并接收即时报警推送,大幅提升管理效率。供电模块采用DC 5V电源配合AMS1117稳压芯片,为系统提供稳定高效的能源支持。整体设计融合了传感技术、物联网通信与移动终端应用,实现了冷库环境的全链路智能化管理。系统具备响应迅速、扩展性强、操作便捷等特点,为冷链仓储安全提供了可靠的技术保障,具有显著的实用价值和推广前景。
-
项目开发背景随着现代生活节奏加快,越来越多宠物主人面临因工作繁忙或短期外出导致的喂养不便问题。传统手动喂食方式难以保障宠物饮食规律性,而市面基础定时喂食器又缺乏远程交互和智能调节能力,极易出现余粮不足未被及时发现、喂食量不符合宠物实际需求等情况,直接影响宠物健康。物联网技术与智能家居的快速发展为宠物用品智能化提供了技术基础。通过集成云端数据同步、语音控制及自适应算法,可构建更符合现代养宠需求的解决方案。该系统不仅能实现精准定时投喂和远程应急补粮,更能通过分析历史进食数据动态优化喂食策略,解决人工喂养的主观性和不稳定性问题。本设计响应宠物健康管理的精细化需求,结合STM32的实时控制能力、华为云的可靠数据同步以及离在线混合交互模式,旨在打造一款具备智能决策、异常预警及多端协同功能的喂食系统。其开发不仅满足养宠家庭的核心痛点,也为宠物智能硬件领域提供了可扩展的技术框架。设计实现的功能(1)基于STM32F103C8T6主控实现系统核心控制与逻辑处理(2)通过海凌科V20离线语音模块接收本地语音指令触发投喂(3)使用28BYJ-48步进电机+ULN2003驱动板控制出粮机构执行投喂动作(4)利用HX711+压力传感器实时监测储粮桶重量并计算余粮(5)0.96寸OLED显示屏通过SPI接口本地显示时间/余粮/喂食记录(6)ESP8266模块连接华为云,基于MQTT协议实现远程指令收发与数据同步(7)高电平触发蜂鸣器在余粮低于阈值时发出声光报警(8)RTC实时时钟模块支持多组定时喂食计划自动执行(9)Qt for Android开发APP,支持远程手动投喂/记录查询/语音指令下发(10)Qt5+C++开发上位机软件,实现喂食策略配置与历史数据分析项目硬件模块组成(1)主控芯片:STM32F103C8T6(2)语音识别模块:海凌科 V20 离线语音模块(3)喂食机构:28BYJ-48步进电机 + ULN2003驱动板(4)粮量检测:HX711模块 + 压力传感器模块(电阻式)(5)显示模块:0.96寸OLED显示屏(SPI接口)(6)通信模块:ESP8266模块,连接华为云,MQTT协议(7)报警模块:高电平触发蜂鸣器提示余粮不足(8)时间控制:基于RTC实时时钟定时投喂设计意义该宠物喂食系统的设计意义主要体现在以下方面:解决现代人因工作繁忙导致的宠物喂养难题是该系统的核心价值。通过STM32主控精准协调定时喂食与远程手动控制功能,用户即使外出也能通过手机APP远程触发喂食,结合RTC时钟确保每日定时投喂,有效避免宠物因主人行程变动而挨饿,保障宠物饮食规律性。提升宠物喂养的科学性与健康管理水平是系统的智能化体现。压力传感器与HX711模块实时监测余粮量并在不足时触发蜂鸣器报警,避免断粮风险;系统通过分析历史投喂数据,自动学习宠物进食习惯并动态调整喂食量,既防止过度投喂又满足营养需求,实现个性化科学喂养。构建全方位状态监控与数据追溯体系增强了系统的可靠性。本地OLED屏实时显示余粮量、投喂记录等关键状态,便于用户现场查看;同时ESP8266模块通过MQTT协议将数据同步至华为云,配合Qt开发的APP及上位机软件,用户可随时随地查询历史喂食记录、调整参数,形成完整的云端数据链,为宠物健康管理提供依据。融合多技术模块实现人性化交互提升了用户体验。离线语音模块支持APP语音指令控制,解放用户双手;步进电机驱动机构确保投粮精准可控;本地显示与云端双备份机制强化了系统容错能力。整套硬件选型兼顾成本与可靠性,体现了嵌入式系统在智能家居领域的实用价值。通过技术手段传递人文关怀是系统的深层意义。将物联网、语音识别、自适应算法等技术应用于宠物喂养场景,既缓解了饲养者的后顾之忧,又保障了宠物的生存福利,体现了科技对生活品质的提升,强化了人与宠物之间的情感联结。设计思路设计思路系统以STM32F103C8T6为核心控制器,协调各模块实现智能化喂食管理。通过实时时钟(RTC)模块精确计时,支持预设多个定时喂食任务。用户可通过Qt开发的Android APP远程触发手动喂食指令,指令经华为云平台以MQTT协议传输至ESP8266通信模块,再由主控解析执行。粮量监测采用电阻式压力传感器与HX711模块组合,实时采集储粮箱重量数据。当余粮低于阈值时,STM32触发蜂鸣器报警,并通过OLED屏显示警告图标。同时,系统将粮量状态同步至云端,供APP和上位机监控。语音控制通过海凌科V20模块实现:用户说出预设指令(如"喂食")后,模块通过串口将指令码发送至STM32,主控立即驱动ULN2003步进电机驱动板,带动28BYJ-48步进电机旋转特定角度,控制出粮口开合实现定量投喂。投喂量可基于历史进食数据动态调整——系统记录每日消耗量,通过算法平滑优化后续单次投喂量。本地交互由SPI接口的0.96寸OLED屏承担,实时显示时间、余粮百分比、下次喂食倒计时及网络状态。所有操作日志(如喂食时间、触发方式、粮量变化)均通过ESP8266上传至华为云,Qt5开发的上位机软件可调取云端数据生成喂食报表,支持远程修改定时参数。主程序采用状态机架构:常态下轮询检测传感器数据、云端指令和语音输入;到达定时节点或收到外部指令时,中断当前任务执行喂食动作,确保系统响应实时性。硬件模块间通过UART、I2C和GPIO接口通信,低功耗设计延长电池供电场景的使用时长。框架图系统框架图+-----------------------------------------------------------------------------------------+ | STM32F103C8T6 (主控) | | +-------------------+ +-----------------+ +-----------------+ +-------------------+ | | | RTC实时时钟 | | GPIO控制 | | SPI接口 | | UART串口通信 | | | | (内部/外部晶振) | | (蜂鸣器控制) | | (OLED显示驱动) | | (多路通信枢纽) | | | +-------------------+ +--------+--------+ +--------+--------+ +-------+-------+----+ | | | | | | | | +---------|-----------------------|-------------------|-------------------|-------|-------+ | | | | | | (时间基准) | (报警触发) | (状态显示) | | (配置指令) +---------|-----------+ +--------|------+ +--------|------+ +-------|-------+ +-----|-------+ | 定时喂食逻辑 | | 蜂鸣器 | | OLED显示屏 | | 海凌科V20 | | ESP8266 | | (RTC触发喂食任务) | | (粮量不足报警)| | (0.96寸 SPI) | | 离线语音模块 | | WiFi模块| +---------+-----------+ +---------------+ +---------------+ +---------+---------+ +----+----+ | | | | (电机控制指令) | (语音指令解析) | (MQTT协议) +---------|-------------------+ +--------+ | | 喂食执行子系统 | | | | +----------------+ | +---------|--------|--------+ | | ULN2003 | <------+ | 华为云IoT平台 | | | 驱动板 | | (数据存储/指令转发) | | +------+---------+ +------------+-----------+ | | | | +------|---------+ | | | 28BYJ-48 | | | | 步进电机 | | | +------+---------+ | | | | | +------|---------+ | | | 储粮仓/投食机构| | | +----------------+ | +------------------------------------------------------------------------------------+ | | +---------|---------+ +-----------|-----------+ | 粮量检测子系统 | | 远程控制终端 | | +----------------+| | +-------------------+ | | | 压力传感器 || <----------------粮量反馈--------------------------| | Android APP | | | | (底部称重) || | | (Qt for Android) | | | +--------+-------+| | +-------------------+ | | | | | +-------------------+ | | +--------|--------+| | | 上位机软件 | | | | HX711 || | | (Qt5 + C++) | | | | 称重模块 || | +-------------------+ | | +-----------------+| +-----------------------+ +-------------------+ 关键交互说明:核心控制:STM32通过RTC定时触发喂食任务,或通过UART接收语音/WiFi的远程指令。执行层:ULN2003驱动步进电机转动,控制投食机构出粮。HX711+压力传感器实时监测余粮量,触发蜂鸣器报警。交互层:OLED显示时间、粮量、系统状态(SPI通信)。海凌科V20解析语音指令(如“放粮”),通过UART发送指令到STM32。云端链路:ESP8266通过MQTT协议连接华为云,同步喂食记录、粮量数据。Android APP/上位机软件通过云端下发喂食指令或配置定时任务。自适应逻辑:STM32分析历史投食数据(存储于华为云),动态调整单次投食量。系统总体设计系统总体设计基于STM32F103C8T6主控芯片构建,核心功能包括定时喂食、远程控制、余粮监测与智能调节。主控通过I/O接口协调各模块:海凌科V20离线语音模块接收语音指令,解析后触发喂食动作;28BYJ-48步进电机配合ULN2003驱动板执行出粮操作,通过控制电机旋转圈数精准调节喂食量。粮量检测由HX711模块连接电阻式压力传感器实现,实时监测储粮仓重量变化,当余粮低于阈值时触发高电平蜂鸣器报警。RTC实时时钟模块提供精确计时,支撑每日多时段定时喂食任务。系统具备学习能力,通过分析历史喂食数据与余粮变化趋势,动态优化单次投喂量。本地交互采用0.96寸OLED显示屏(SPI接口),实时展示余粮状态、喂食计划及系统报警信息。网络通信由ESP8266模块负责,通过MQTT协议连接华为云,实现喂食记录同步与远程指令收发。Qt for Android开发的APP支持手动喂食指令下发及数据查看,同时上位机通过Qt5+C++实现远程配置与统计分析。所有硬件模块通过主控统一调度,确保定时任务、语音控制、云端交互等功能协同运作。系统功能总结功能描述实现方式(硬件/软件)定时喂食功能STM32主控通过RTC实时时钟定时触发步进电机转动,驱动喂食机构投放饲料手动远程喂食功能ESP8266模块接收APP指令(MQTT协议),触发STM32控制步进电机投喂余粮检测与报警HX711+压力传感器实时监测重量,余粮不足时STM32触发蜂鸣器报警APP语音控制投喂Android APP语音指令→华为云→ESP8266→STM32执行;海凌科V20支持本地离线语音指令直控智能调整喂食量STM32记录进食数据,通过算法分析习惯动态调整步进电机转动时长(投喂量)本地状态显示0.96寸OLED实时显示余粮/时间/下次投喂计划(SPI通信)云端数据同步ESP8266上传喂食记录/余粮量至华为云(MQTT),Qt Android APP远程查看/配置系统配置管理Qt5上位机软件远程修改定时计划、喂食量参数,数据双向同步设计的各个功能模块描述主控芯片采用STM32F103C8T6,作为系统核心控制器,负责协调各模块工作,处理传感器数据,执行喂食逻辑,并与云端通信。语音识别模块使用海凌科V20离线语音单元,通过串口接收用户语音指令,解析为投喂命令发送至主控芯片,实现APP语音控制功能。喂食机构由28BYJ-48步进电机和ULN2003驱动板组成,主控芯片通过PWM信号控制步进电机旋转角度,精确驱动投食机构完成定量喂食,支持定时触发与远程手动触发双模式。粮量检测通过HX711模块连接电阻式压力传感器,实时采集储粮仓重量数据,主控芯片计算剩余粮量,低于阈值时触发报警。显示模块采用0.96寸OLED屏(SPI接口),本地展示系统状态,包括实时时间、剩余粮量、喂食计划及网络连接状态。通信模块基于ESP8266,通过AT指令与主控串口交互,使用MQTT协议连接华为云,实现喂食记录同步和远程指令接收。报警模块由高电平触发蜂鸣器构成,当粮量检测异常时主控输出高电平信号驱动蜂鸣器报警。时间控制基于STM32内部RTC实时时钟,独立供电维持计时,主控按预设时段自动执行喂食任务。APP软件使用Qt for Android开发,提供喂食记录查询、远程手动投喂及语音指令下发功能。上位机软件采用Qt5+C++实现,通过MQTT协议连接云端,提供喂食参数配置和历史数据分析界面。上位机代码设计上位机软件设计(Qt5 + C++)#include <QtWidgets> #include <QtMqtt/QtMqtt> #include <QDateTime> #include <QJsonObject> #include <QJsonDocument> class PetFeederApp : public QMainWindow { Q_OBJECT public: PetFeederApp(QWidget *parent = nullptr) : QMainWindow(parent) { // 初始化UI setupUI(); // MQTT客户端初始化 mqttClient = new QMqttClient(this); mqttClient->setHostname("your_huaweicloud_address.com"); mqttClient->setPort(1883); mqttClient->setClientId("PetFeeder_PC_" + QString::number(qrand())); mqttClient->setUsername("device_id"); mqttClient->setPassword("device_secret"); connect(mqttClient, &QMqttClient::connected, this, &PetFeederApp::onMqttConnected); connect(mqttClient, &QMqttClient::messageReceived, this, &PetFeederApp::onMessageReceived); // 连接MQTT mqttClient->connectToHost(); } private slots: void onMqttConnected() { statusLabel->setText("已连接华为云"); mqttClient->subscribe(QMqttTopicFilter("petfeeder/status")); mqttClient->subscribe(QMqttTopicFilter("petfeeder/foodlog")); } void onMessageReceived(const QByteArray &message, const QMqttTopicName &topic) { QJsonDocument doc = QJsonDocument::fromJson(message); QJsonObject json = doc.object(); if (topic.name() == "petfeeder/status") { updateStatusDisplay(json); } else if (topic.name() == "petfeeder/foodlog") { addFeedingRecord(json); } } void onManualFeed() { QMqttTopicName topic("petfeeder/control"); QJsonObject cmd = {{"cmd", "manual_feed"}, {"amount", feedAmountSpin->value()}}; mqttClient->publish(topic, QJsonDocument(cmd).toJson()); } void onSetSchedule() { QJsonArray schedules; for (int i = 0; i < scheduleTable->rowCount(); ++i) { QTime time = QTime::fromString(scheduleTable->item(i, 0)->text(), "HH:mm"); int amount = scheduleTable->item(i, 1)->text().toInt(); schedules.append(QJsonObject{{"time", time.toString("HH:mm")}, {"amount", amount}}); } QMqttTopicName topic("petfeeder/schedule"); mqttClient->publish(topic, QJsonDocument(schedules).toJson()); } private: void setupUI() { // 主窗口设置 setWindowTitle("智能宠物喂食系统"); setFixedSize(800, 600); // 状态显示区域 QGroupBox *statusGroup = new QGroupBox("系统状态"); statusLabel = new QLabel("正在连接云端..."); foodLevelBar = new QProgressBar; foodLevelBar->setRange(0, 100); lastFeedLabel = new QLabel("上次喂食: --:--"); QVBoxLayout *statusLayout = new QVBoxLayout; statusLayout->addWidget(statusLabel); statusLayout->addWidget(new QLabel("余粮水平:")); statusLayout->addWidget(foodLevelBar); statusLayout->addWidget(lastFeedLabel); statusGroup->setLayout(statusLayout); // 手动喂食控制 QGroupBox *controlGroup = new QGroupBox("手动控制"); feedAmountSpin = new QSpinBox; feedAmountSpin->setRange(5, 100); feedAmountSpin->setSuffix(" g"); QPushButton *feedButton = new QPushButton("立即喂食"); connect(feedButton, &QPushButton::clicked, this, &PetFeederApp::onManualFeed); QHBoxLayout *controlLayout = new QHBoxLayout; controlLayout->addWidget(new QLabel("喂食量:")); controlLayout->addWidget(feedAmountSpin); controlLayout->addWidget(feedButton); controlGroup->setLayout(controlLayout); // 定时计划表 QGroupBox *scheduleGroup = new QGroupBox("喂食计划"); scheduleTable = new QTableWidget(0, 2); QStringList headers{"时间 (HH:mm)", "喂食量 (g)"}; scheduleTable->setHorizontalHeaderLabels(headers); QPushButton *addScheduleBtn = new QPushButton("添加计划"); QPushButton *saveScheduleBtn = new QPushButton("保存计划"); connect(addScheduleBtn, &QPushButton::clicked, this, [this](){ scheduleTable->insertRow(scheduleTable->rowCount()); }); connect(saveScheduleBtn, &QPushButton::clicked, this, &PetFeederApp::onSetSchedule); QVBoxLayout *scheduleLayout = new QVBoxLayout; scheduleLayout->addWidget(scheduleTable); QHBoxLayout *btnLayout = new QHBoxLayout; btnLayout->addWidget(addScheduleBtn); btnLayout->addWidget(saveScheduleBtn); scheduleLayout->addLayout(btnLayout); scheduleGroup->setLayout(scheduleLayout); // 喂食记录 QGroupBox *historyGroup = new QGroupBox("喂食记录"); recordList = new QListWidget; QVBoxLayout *historyLayout = new QVBoxLayout; historyLayout->addWidget(recordList); historyGroup->setLayout(historyLayout); // 主布局 QGridLayout *mainLayout = new QGridLayout; mainLayout->addWidget(statusGroup, 0, 0); mainLayout->addWidget(controlGroup, 1, 0); mainLayout->addWidget(scheduleGroup, 0, 1, 2, 1); mainLayout->addWidget(historyGroup, 2, 0, 1, 2); QWidget *centralWidget = new QWidget; centralWidget->setLayout(mainLayout); setCentralWidget(centralWidget); } void updateStatusDisplay(const QJsonObject &status) { foodLevelBar->setValue(status["food_level"].toInt()); lastFeedLabel->setText("上次喂食: " + status["last_feed_time"].toString()); if (status["food_low"].toBool()) { statusLabel->setText("<font color='red'>余粮不足!</font>"); } else { statusLabel->setText("系统运行正常"); } } void addFeedingRecord(const QJsonObject &record) { QString entry = QString("%1 | %2 g | %3") .arg(record["time"].toString()) .arg(record["amount"].toInt()) .arg(record["type"].toString()); recordList->insertItem(0, entry); } // UI组件声明 QLabel *statusLabel; QProgressBar *foodLevelBar; QLabel *lastFeedLabel; QSpinBox *feedAmountSpin; QTableWidget *scheduleTable; QListWidget *recordList; // MQTT客户端 QMqttClient *mqttClient; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); PetFeederApp window; window.show(); return app.exec(); } #include "main.moc" 代码功能说明云端通信模块使用MQTT协议连接华为云IoT平台订阅主题:petfeeder/status:接收设备状态(余粮量、最后喂食时间)petfeeder/foodlog:接收喂食记录发布主题:petfeeder/control:发送手动喂食指令petfeeder/schedule:发送定时喂食计划核心功能界面系统状态面板:实时显示余粮进度条、连接状态和最后喂食时间手动控制区:设置喂食量并立即触发喂食喂食计划表:支持多时段定时计划配置喂食记录:按时间倒序显示历史喂食记录数据处理使用JSON格式传输数据状态更新:{"food_level": 45, "last_feed_time": "14:30", "food_low": false}喂食记录:{"time": "2023-06-15 14:30", "amount": 30, "type": "scheduled"}操作流程UserGUIHuaweiCloudDevice设置定时计划发布喂食计划(JSON)下发新配置点击"立即喂食"发布手动喂食指令触发喂食动作定时上报状态推送状态更新显示余粮不足警告UserGUIHuaweiCloudDevice使用说明配置华为云连接修改代码中的MQTT连接参数:mqttClient->setHostname("your_huaweicloud_address.com"); mqttClient->setUsername("device_id"); mqttClient->setPassword("device_secret"); 定时计划设置在表格中添加/修改行格式:时间列 (HH:mm), 喂食量 (克)点击"保存计划"同步到设备手动喂食设置喂食量(5-100克)点击"立即喂食"按钮数据查看余粮状态:进度条显示百分比喂食记录:包含时间、喂食量和触发类型(手动/定时)模块代码设计设备端模块代码设计(STM32寄存器开发)#include "stm32f10x.h" // 硬件引脚定义 #define BUZZER_PIN GPIO_Pin_13 // PC13 #define MOTOR_PIN1 GPIO_Pin_8 // PC8 #define MOTOR_PIN2 GPIO_Pin_9 // PC9 #define MOTOR_PIN3 GPIO_Pin_10 // PC10 #define MOTOR_PIN4 GPIO_Pin_11 // PC11 #define HX711_SCK GPIO_Pin_0 // PA0 #define HX711_DOUT GPIO_Pin_1 // PA1 // 步进电机相位表 const uint8_t motorPhase[8] = { 0x09, 0x08, 0x0C, 0x04, 0x06, 0x02, 0x03, 0x01 }; // HX711读取函数 uint32_t HX711_Read(void) { uint32_t data = 0; GPIOA->BRR = HX711_SCK; // SCK低电平 while(GPIOA->IDR & HX711_DOUT); // 等待DOUT为低 for(uint8_t i=0; i<24; i++) { GPIOA->BSRR = HX711_SCK; // SCK高电平 __nop(); __nop(); // 短暂延时 data <<= 1; GPIOA->BRR = HX711_SCK; // SCK低电平 if(GPIOA->IDR & HX711_DOUT) data++; } // 发送第25个脉冲选择增益128 GPIOA->BSRR = HX711_SCK; __nop(); __nop(); GPIOA->BRR = HX711_SCK; return data ^ 0x800000; // 补码转换 } // 步进电机驱动函数 void Motor_Rotate(int steps, uint8_t direction) { static uint8_t phase = 0; int step_count = (direction) ? steps : -steps; while(step_count != 0) { if(step_count > 0) { phase = (phase + 1) % 8; step_count--; } else { phase = (phase + 7) % 8; step_count++; } GPIOC->ODR &= 0xF0FF; // 清空电机控制位 GPIOC->ODR |= (motorPhase[phase] << 8); for(volatile int i=0; i<5000; i++); // 转速控制延时 } GPIOC->BRR = MOTOR_PIN1 | MOTOR_PIN2 | MOTOR_PIN3 | MOTOR_PIN4; // 断电 } // 蜂鸣器报警函数 void Buzzer_Alert(uint8_t state) { if(state) { GPIOC->BSRR = BUZZER_PIN; } else { GPIOC->BRR = BUZZER_PIN; } } // RTC初始化 void RTC_Init(void) { RCC->APB1ENR |= RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN; PWR->CR |= PWR_CR_DBP; if((BKP->DR1 & 0xFFFF) != 0xA5A5) { RCC->BDCR |= RCC_BDCR_LSEON; while(!(RCC->BDCR & RCC_BDCR_LSERDY)); RCC->BDCR |= RCC_BDCR_RTCSEL_LSE; RCC->BDCR |= RCC_BDCR_RTCEN; RTC->CRL |= RTC_CRL_CNF; RTC->PRLL = 32767; // LSE 32.768kHz RTC->CRL &= ~RTC_CRL_CNF; while(!(RTC->CRL & RTC_CRL_RTOFF)); BKP->DR1 = 0xA5A5; } } // 系统初始化 void System_Init(void) { // 时钟配置 RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN; // 蜂鸣器输出 GPIOC->CRH &= 0xFF0FFFFF; GPIOC->CRH |= 0x00300000; // PC13推挽输出 // 步进电机输出 GPIOC->CRH &= 0xFFFF0000; GPIOC->CRH |= 0x00003333; // PC8-PC11推挽输出 // HX711输入输出 GPIOA->CRL &= 0xFFFFFF00; GPIOA->CRL |= 0x00000038; // PA0输出, PA1输入 // 初始化外设 RTC_Init(); } // 主函数 int main(void) { System_Init(); uint32_t last_feed = 0; const uint32_t feed_interval = 43200; // 12小时 (RTC秒计数) while(1) { // 1. 检测余粮 uint32_t weight = HX711_Read(); if(weight < 50000) { // 阈值判断 Buzzer_Alert(1); } else { Buzzer_Alert(0); } // 2. RTC定时喂食 uint32_t current_time = RTC->CNTH << 16 | RTC->CNTL; if((current_time - last_feed) >= feed_interval) { Motor_Rotate(512, 1); // 旋转512步 last_feed = current_time; } // 3. 其他功能处理(OLED显示、网络通信等) // ... (此处添加其他模块代码) } } 关键模块说明:HX711压力传感器使用PA0(SCK)和PA1(DOUT)24位AD转换,补码转换处理内置数据就绪检测步进电机控制四相八拍驱动方式使用PC8-PC11控制ULN2003相位表实现正反转控制断电保护逻辑RTC实时时钟LSE 32.768kHz时钟源12小时定时喂食周期后备寄存器初始化标志蜂鸣器报警高电平触发(PC13)余粮阈值检测逻辑系统初始化GPIO模式配置时钟使能外设初始化顺序控制项目核心代码以下是基于STM32F103C8T6的宠物喂食系统核心代码(寄存器开发版本),包含完整main.c实现:#include "stm32f10x.h" #include "hx711.h" #include "oled.h" #include "motor.h" #include "rtc.h" #include "usart.h" #include "esp8266.h" #include "voice.h" // 宏定义 #define FEED_INTERVAL 8 // 默认喂食步数 #define FOOD_THRESHOLD 100 // 余粮阈值(g) #define BUZZER_PIN GPIO_Pin_0 #define BUZZER_PORT GPIOA // 全局变量 uint8_t feedFlag = 0; // 喂食触发标志 uint8_t foodLowAlarm = 0; // 余粮不足标志 uint32_t feedAmount = FEED_INTERVAL; // 动态喂食量 RTC_TimeTypeDef currentTime; // 函数声明 void SystemClock_Config(void); void GPIO_Configuration(void); void NVIC_Configuration(void); void Buzzer_Alarm(uint8_t state); void Feed_Pet(void); void Update_Feed_Amount(void); void Process_MQTT_Command(uint8_t* cmd); int main(void) { // 初始化系统 SystemClock_Config(); GPIO_Configuration(); NVIC_Configuration(); // 外设初始化 USART1_Init(115200); // 语音模块串口 USART2_Init(115200); // ESP8266串口 OLED_Init(); HX711_Init(); RTC_Init(); Motor_Init(); // 显示启动界面 OLED_ShowString(0, 0, "PetFeeder V1.0"); OLED_ShowString(0, 2, "Init..."); Delay_ms(1000); // 连接华为云 ESP8266_ConnectCloud(); OLED_ShowString(0, 2, "Cloud Connected"); while(1) { // 1. 获取当前时间 RTC_GetTime(¤tTime); // 2. 检测余粮状态 uint32_t foodWeight = HX711_GetWeight(); if(foodWeight < FOOD_THRESHOLD) { foodLowAlarm = 1; Buzzer_Alarm(1); MQTT_Publish("petfeeder/alarm", "FOOD_LOW"); } else { foodLowAlarm = 0; Buzzer_Alarm(0); } // 3. 定时喂食检测 (例: 08:00和18:00) if((currentTime.hours == 8 && currentTime.minutes == 0) || (currentTime.hours == 18 && currentTime.minutes == 0)) { feedFlag = 1; } // 4. 处理喂食请求 if(feedFlag) { Feed_Pet(); feedFlag = 0; // 上传喂食记录 char feedMsg[50]; sprintf(feedMsg, "{\"time\":\"%02d:%02d\",\"amount\":%d}", currentTime.hours, currentTime.minutes, feedAmount); MQTT_Publish("petfeeder/feed", feedMsg); // 更新喂食量算法 Update_Feed_Amount(); } // 5. 处理语音指令 uint8_t voiceCmd[20]; if(VOICE_GetCommand(voiceCmd)) { if(strcmp((char*)voiceCmd, "FEED") == 0) feedFlag = 1; } // 6. 处理MQTT命令 uint8_t mqttMsg[50]; if(ESP8266_ReceiveData(mqttMsg)) { Process_MQTT_Command(mqttMsg); } // 7. 刷新显示 OLED_Clear(); char dispBuf[20]; sprintf(dispBuf, "Time: %02d:%02d", currentTime.hours, currentTime.minutes); OLED_ShowString(0, 0, dispBuf); sprintf(dispBuf, "Food: %d g", foodWeight); OLED_ShowString(0, 2, dispBuf); OLED_ShowString(0, 4, foodLowAlarm ? "LOW FOOD!" : "Normal"); Delay_ms(500); } } // 蜂鸣器控制 void Buzzer_Alarm(uint8_t state) { if(state) { GPIO_SetBits(BUZZER_PORT, BUZZER_PIN); } else { GPIO_ResetBits(BUZZER_PORT, BUZZER_PIN); } } // 执行喂食动作 void Feed_Pet(void) { Motor_Rotate(feedAmount); // 顺时针旋转指定步数 Delay_ms(500); Motor_Rotate(10); // 反向回旋防止卡粮 } // 动态调整喂食量 void Update_Feed_Amount(void) { // 简化示例:根据时间调整 if(currentTime.hours == 8) feedAmount = FEED_INTERVAL; else feedAmount = FEED_INTERVAL + 2; // 晚餐加量 // 实际应加入机器学习算法 } // 处理MQTT命令 void Process_MQTT_Command(uint8_t* cmd) { if(strstr((char*)cmd, "CMD=FEED")) { feedFlag = 1; } else if(strstr((char*)cmd, "CMD=SET_TIME")) { // 解析时间设置命令 uint8_t h, m; sscanf((char*)cmd, "CMD=SET_TIME%02d%02d", &h, &m); RTC_SetTime(h, m, 0); } } // 系统时钟配置 (72MHz HSE) void SystemClock_Config(void) { RCC->CR |= RCC_CR_HSEON; while(!(RCC->CR & RCC_CR_HSERDY)); FLASH->ACR |= FLASH_ACR_LATENCY_2; RCC->CFGR |= RCC_CFGR_PLLMULL9 | RCC_CFGR_PLLSRC; RCC->CR |= RCC_CR_PLLON; while(!(RCC->CR & RCC_CR_PLLRDY)); RCC->CFGR |= RCC_CFGR_SW_PLL; while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); } // GPIO配置 void GPIO_Configuration(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN; // 蜂鸣器(PA0) GPIOA->CRL &= ~(0x0F << (0*4)); GPIOA->CRL |= 0x02 << (0*4); // 推挽输出 // OLED SPI引脚配置(省略) // 步进电机引脚配置(省略) } // 中断配置 void NVIC_Configuration(void) { // 串口1中断(语音模块) NVIC_EnableIRQ(USART1_IRQn); NVIC_SetPriority(USART1_IRQn, 0); // 串口2中断(ESP8266) NVIC_EnableIRQ(USART2_IRQn); NVIC_SetPriority(USART2_IRQn, 1); } // 串口1中断服务函数 void USART1_IRQHandler(void) { if(USART1->SR & USART_SR_RXNE) { VOICE_ReceiveHandler(USART1->DR); } } // 串口2中断服务函数 void USART2_IRQHandler(void) { if(USART2->SR & USART_SR_RXNE) { ESP8266_ReceiveHandler(USART2->DR); } } 关键功能说明:定时喂食:通过RTC实现08:00和18:00自动触发余粮检测:HX711读取压力传感器数据,低于阈值触发蜂鸣器报警语音控制:海凌科V20通过串口发送"FEED"指令触发喂食动态喂食量:Update_Feed_Amount函数实现基础量调整(需扩展ML算法)华为云通信:上传喂食记录:JSON格式数据接收远程命令:支持"FEED"和"SET_TIME"指令状态显示:OLED实时显示时间、余粮量和报警状态总结本设计实现了一个基于STM32F103C8T6主控芯片的智能宠物喂食系统,通过集成多模块硬件与软件,全面满足了定时喂食、远程控制、粮量监测等核心需求。系统利用28BYJ-48步进电机和ULN2003驱动板实现精确投喂动作,同时结合HX711模块和压力传感器实时检测剩余粮量,在粮量不足时触发高电平蜂鸣器报警,确保宠物不会断粮。时间控制基于RTC实时时钟,支持预设定时喂食计划,并通过ESP8266模块连接华为云平台,采用MQTT协议实现数据云端同步,保障了系统的可靠性和远程可访问性。系统还融入了智能化功能,如通过海凌科 V20离线语音模块支持APP语音控制投喂指令下发,并能基于宠物进食习惯自动调整喂食量,提升了用户体验的便捷性和个性化。本地状态显示通过0.96寸OLED显示屏(SPI接口)实现,为用户提供实时反馈,而Qt for Android开发的APP和Qt5 + C++实现的上位机软件则提供了全面的远程配置与数据查看能力,包括喂食记录和系统设置。总体而言,该设计通过硬件模块的协同工作与软件平台的优化,实现了高效、智能的宠物喂食管理。它不仅解决了日常喂食的自动化问题,还通过云端同步和语音交互增强了远程监控的灵活性,为宠物主人提供了一套安全、可靠且用户友好的解决方案。
-
项目开发背景工业仓库作为企业物资存储的核心场所,其环境安全直接关系到货物品质、设备寿命及人员安全。传统仓库环境监测多依赖人工定时巡查与简单的独立报警装置,存在响应滞后、数据孤岛、无法实时预警和远程管理等问题。尤其对于存放易燃易爆、温湿度敏感物资的仓库,一旦发生烟雾积聚、有害气体泄漏或异常温升,若不能即时发现并处理,极易引发重大经济损失甚至安全事故。随着物联网(IoT)技术与云平台的快速发展,构建智能化、网络化的环境监控系统成为必然趋势。STM32微控制器凭借其强大的实时处理能力、丰富的外设接口和低功耗特性,结合高精度传感器与无线通信技术,可实现对仓库关键环境参数(如温湿度、烟雾浓度、火焰状态、有毒气体)的连续精准采集与本地智能决策。通过自动报警、联动通风设备以及将数据实时上传至华为云平台,系统能显著提升风险响应速度,变被动处理为主动防护。本项目旨在设计一套集成感知、决策、执行与云协同的智能监控解决方案。通过本地LCD屏提供直观状态反馈,利用ESP8266模块实现华为云IoT平台的稳定接入,并开发Qt上位机软件进行远程数据可视化与历史分析。这不仅解决了传统监测手段的缺陷,更为企业构建了可追溯的环境安全数据库,助力仓库管理的数字化升级,全面提升仓储安全性与运营效率。设计实现的功能(1)使用SHT30、MQ2、红外火焰传感器、MQ135实时监测仓库温湿度、烟雾浓度、火焰状态及有害气体浓度。(2)当任一参数超出阈值时,触发有源蜂鸣器报警并通过继电器启动12V风扇通风。(3)通过ESP8266 WiFi模块以MQTT协议将实时数据上传至华为云IoT平台,实现远程监测。(4)基于Qt5+C++开发上位机软件,支持远程查看实时数据及历史数据趋势分析。(5)通过SPI接口的1.44寸TFT LCD屏本地显示环境参数与系统状态(如温度、湿度、报警标志)。项目硬件模块组成(1)主控芯片:STM32F103C8T6(2)温湿度检测:SHT30数字温湿度传感器(I2C接口)(3)烟雾检测:MQ2烟雾传感器(模拟信号)(4)火焰检测:红外火焰传感器(高低电平输出)(5)有害气体检测:MQ135空气质量传感器(模拟信号)(6)通信模块:ESP8266 WiFi模块(MQTT协议接入华为云)(7)显示模块:1.44寸TFT LCD液晶屏(SPI接口)(8)风扇控制模块:继电器驱动12V直流风扇(9)报警模块:高电平触发有源蜂鸣器(10)上位机软件:Qt5 + C++可视化监控平台设计意义设计意义:该工业仓库环境智能监控系统通过集成多类传感器与智能控制模块,实现了对仓库环境的全方位实时监测与自动化管理。系统能够精准采集温湿度、烟雾、火焰及有害气体等关键参数,一旦检测到异常(如温度过高、烟雾浓度超标或可燃气体泄漏),立即触发本地蜂鸣器报警并自动启动风扇通风,快速降低环境风险,有效预防火灾、爆炸等安全事故,保障仓储物资安全与人员生命安全。借助ESP8266模块与华为云IoT平台的对接,系统实现了环境数据的远程实时上传。管理人员可通过Qt开发的上位机软件远程查看仓库状态,分析历史数据趋势,及时制定环境优化策略。这种"云端+本地"的双重监控模式大幅提升了管理效率,减少人工巡检成本,尤其适用于大型或分散式仓库的集中化管理。本地配备的TFT LCD显示屏为现场工作人员提供直观的环境状态反馈,确保即使网络中断时仍能维持基础监控功能。整体设计将环境感知、智能响应、远程监管与本地交互紧密结合,显著提升了工业仓库的安全等级与智能化管理水平,对降低企业运营风险、推动仓储数字化升级具有重要实践价值。设计思路设计思路系统以STM32F103C8T6为核心控制器,通过多传感器协同工作实现仓库环境全维度监测。温湿度数据由SHT30传感器经I2C接口实时采集,烟雾浓度与有害气体浓度分别通过MQ2和MQ135的模拟信号输入至STM32的ADC模块进行量化分析。火焰检测采用数字式红外传感器,其高低电平信号直接接入GPIO口实现快速响应。环境参数异常判定采用阈值比较机制。当任一传感器数据超过预设安全范围(如温度超限、烟雾浓度超标、火焰触发或气体泄漏),主控立即启动双重响应:通过GPIO驱动有源蜂鸣器发出声光报警,同时触发继电器控制12V直流风扇启动强制通风。所有传感器数据与报警状态实时刷新至1.44寸TFT LCD屏,SPI接口确保显示效率。数据传输通过ESP8266模块实现,STM32通过UART发送AT指令建立WIFI连接,采用MQTT协议将结构化数据(包含传感器读数、设备状态及时间戳)上传至华为云IoT平台。云端数据持久化存储为上位机提供分析基础。上位机基于Qt5框架开发,通过调用华为云API获取实时数据流及历史记录,可视化界面展示动态曲线、报警日志及环境参数分布。远程用户可通过该平台监控仓库状态,执行历史数据回溯分析,形成完整的监测-报警-远程管理闭环系统。所有功能严格遵循工业场景需求,无冗余设计。框架图系统框架图+-----------------------------------------------------------------------------------------+ | 工业仓库环境智能监控系统 | | | | +-----------------+ +-------------------+ +-----------------+ +------------+ | | | 传感器采集层 | | STM32主控 | | 执行控制层 | | 通信与云平台 | | | | +-------------+ | | +---------------+ | | +-------------+ | | +---------+ | | | | | SHT30 |----I2C----> | | | | 继电器控制 |<-----| | ESP8266 | | | | | | 温湿度传感器| | | | | | | | | 12V风扇 | | | | WiFi模块 |----MQTT---> 华为云IoT平台 | | | +-------------+ | | | | | | | +-------------+ | | | +---------+ | | | | | | | | | | STM32F103C8T6 | | | | | | | | +-------------+ | | +-------------+ | | | | | | | +-------------+ | | | +---------+ | | | 上位机软件 | | | | MQ2 |----ADC----> | | | | 有源蜂鸣器 |<-----| | | TFT LCD |<-----SPI----> (Qt5远程监控)| | | | 烟雾传感器 | | | | | 数据处理 | | | | 报警器 | | | | | 1.44寸屏 | | | | 历史数据分析| | | +-------------+ | | | | 阈值判断 | | | +-------------+ | | | +---------+ | | +-------------+ | | | | | | 逻辑控制 | | | | | | | | | | +-------------+ | | | | | | | | | | | | | | | 红外火焰 |----GPIO---> | | | | | | | | | | | 传感器 | | | | | | | | | | | | | | | +-------------+ | | | | 串口通信 |----UART----> | | | | | | | | | | +---------------+ | | | | | | | | | +-------------+ | | +-------------------+ | | | | | | | | | MQ135 |----ADC----> | | | | | | | | | 有害气体 | | | | | | | | | | | +-------------+ | | +-----------------+ | +-------------+ | | +-----------------+ +---------------------------------------------------+ | | | +-----------------------------------------------------------------------------------------+ 框架说明:传感器采集层SHT30(I2C):实时采集温湿度MQ2(ADC):检测烟雾浓度红外火焰传感器(GPIO):火焰状态检测MQ135(ADC):监测有害气体浓度STM32主控层STM32F103C8T6核心处理器功能:多接口数据采集(I2C/ADC/GPIO)环境参数阈值判断与异常检测控制逻辑决策(报警/通风)串口通信驱动(连接ESP8266)SPI驱动LCD显示执行控制层继电器模块:控制12V风扇启停(通风)有源蜂鸣器:高电平触发声光报警通信与云平台层ESP8266:通过UART接收STM32数据,MQTT协议上传至华为云IoTTFT LCD(SPI):本地实时显示环境状态华为云IoT平台:数据存储与远程访问枢纽Qt5上位机:远程监控/历史数据分析界面系统总体设计系统总体设计围绕STM32F103C8T6主控芯片构建,通过多传感器协同实现仓库环境智能监控。温湿度数据由SHT30传感器经I2C接口实时采集,烟雾浓度通过MQ2传感器模拟信号经ADC转换获取,火焰状态由红外火焰传感器数字信号直接输入GPIO,有害气体浓度则由MQ135传感器模拟信号经ADC转换监测。所有传感器数据在主控芯片进行实时融合处理。当检测到任一参数超过安全阈值时,系统立即触发两级响应:通过GPIO驱动有源蜂鸣器发出声光报警,同时控制继电器启动12V直流风扇强制通风。环境状态及参数数值通过SPI接口在1.44寸TFT LCD屏上实时显示,提供本地可视化监控。通信层面采用ESP8266 WiFi模块,通过AT指令集建立网络连接,基于MQTT协议将环境数据封装为JSON格式上传至华为云IoT平台。云平台实现数据持久化存储,为远程访问提供支持。上位机采用Qt5框架开发,通过调用华为云API接口获取实时数据流及历史数据库,构建可视化监控界面。该界面支持多参数动态曲线展示、阈值配置及异常事件记录查询,实现远程仓库环境状态分析与管理。系统功能总结系统功能主要实现模块实时监测仓库温湿度SHT30数字温湿度传感器(I2C接口)实时监测烟雾浓度MQ2烟雾传感器(模拟信号)实时监测火焰状态红外火焰传感器(高低电平输出)实时监测有害气体泄漏MQ135空气质量传感器(模拟信号)环境异常自动声光报警高电平触发有源蜂鸣器环境异常自动通风控制继电器驱动12V直流风扇数据上传至华为云平台ESP8266 WiFi模块(MQTT协议)远程监测与历史数据分析上位机软件(Qt5 + C++)本地环境状态显示1.44寸TFT LCD液晶屏(SPI接口)核心控制与数据处理STM32F103C8T6主控芯片设计的各个功能模块描述主控制器模块主控芯片采用STM32F103C8T6,负责协调所有硬件模块的运行。通过实时调度任务,完成数据采集、逻辑判断、报警控制、通信传输及显示驱动。其核心功能包括初始化外设接口(如I2C、SPI、ADC、UART)、处理传感器数据、执行异常响应策略(如启动风扇或蜂鸣器),并通过中断机制确保环境监测的实时性。环境参数采集模块该模块集成多种传感器:温湿度检测:SHT30传感器通过I2C接口与STM32通信,实时采集仓库温度与湿度数据,数字信号输出精度高且抗干扰性强。烟雾检测:MQ2传感器输出模拟信号,经STM32内部ADC转换为数字值,监测烟雾浓度变化。火焰检测:红外火焰传感器输出高低电平信号,直接接入STM32 GPIO引脚,火焰出现时触发高电平报警。有害气体检测:MQ135传感器通过模拟信号输出气体浓度,STM32的ADC模块量化数据以判断泄漏风险。报警与执行模块当任一传感器数据超出预设安全阈值时,系统立即响应:触发有源蜂鸣器(高电平驱动)发出声光报警信号。通过继电器控制12V直流风扇启动,强制通风以降低环境风险。报警状态同步更新至LCD屏与云端,确保本地及远程实时获知异常。无线通信模块ESP8266 WiFi模块通过UART串口与STM32交互,采用MQTT协议将传感器数据封装并上传至华为云IoT平台。实现远程监测功能,支持上位机实时调取仓库环境状态,同时为历史数据分析提供云端数据存储基础。本地显示模块1.44寸TFT LCD屏通过SPI接口接收STM32指令,动态显示当前环境参数(温湿度、烟雾、火焰、气体浓度数值)及系统状态(正常/报警)。界面设计简洁,关键数据高亮提示,便于现场人员快速监控。上位机软件模块基于Qt5与C++开发的可视化监控平台,从华为云IoT平台获取数据。功能包括:实时显示仓库多参数动态曲线与数值。支持历史数据查询与分析(如温湿度趋势图、报警事件记录)。提供参数阈值配置界面,增强远程管控灵活性。上位机代码设计以下是基于Qt5和C++的上位机监控系统完整代码设计,实现远程环境监控与数据分析功能:#include <QtWidgets> #include <QtMqtt> #include <QtCharts> #include <QDateTimeAxis> #include <QValueAxis> // 环境数据结构体 struct EnvData { double temperature; double humidity; int smoke; int flame; int gas; QDateTime timestamp; }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) { setupUI(); setupMQTT(); setupDatabase(); } private: // UI组件 QTabWidget *tabWidget; QMqttClient *mqttClient; QSqlDatabase db; QVector<EnvData> dataHistory; // 实时监控页 QLabel *tempLabel, *humLabel, *smokeLabel, *flameLabel, *gasLabel; // 历史数据页 QChartView *chartView; QChart *dataChart; QLineSeries *tempSeries, *humSeries; // 报警日志页 QTextEdit *alarmLog; void setupUI() { // 主窗口设置 setWindowTitle("工业仓库环境监控系统"); setGeometry(100, 100, 800, 600); // 标签页容器 tabWidget = new QTabWidget(this); setCentralWidget(tabWidget); // 1. 实时监控页 QWidget *realtimeTab = new QWidget; QGridLayout *realtimeLayout = new QGridLayout; realtimeLayout->addWidget(new QLabel("温度(℃):"), 0, 0); tempLabel = new QLabel("--"); realtimeLayout->addWidget(tempLabel, 0, 1); realtimeLayout->addWidget(new QLabel("湿度(%):"), 1, 0); humLabel = new QLabel("--"); realtimeLayout->addWidget(humLabel, 1, 1); realtimeLayout->addWidget(new QLabel("烟雾浓度:"), 2, 0); smokeLabel = new QLabel("--"); realtimeLayout->addWidget(smokeLabel, 2, 1); realtimeLayout->addWidget(new QLabel("火焰状态:"), 3, 0); flameLabel = new QLabel("--"); realtimeLayout->addWidget(flameLabel, 3, 1); realtimeLayout->addWidget(new QLabel("有害气体:"), 4, 0); gasLabel = new QLabel("--"); realtimeLayout->addWidget(gasLabel, 4, 1); realtimeTab->setLayout(realtimeLayout); tabWidget->addTab(realtimeTab, "实时监控"); // 2. 历史数据页 QWidget *historyTab = new QWidget; QVBoxLayout *historyLayout = new QVBoxLayout; // 初始化图表 dataChart = new QChart; chartView = new QChartView(dataChart); chartView->setRenderHint(QPainter::Antialiasing); // 时间轴 QDateTimeAxis *axisX = new QDateTimeAxis; axisX->setFormat("hh:mm"); dataChart->addAxis(axisX, Qt::AlignBottom); // 数值轴 QValueAxis *axisY = new QValueAxis; axisY->setRange(0, 100); dataChart->addAxis(axisY, Qt::AlignLeft); // 数据序列 tempSeries = new QLineSeries; tempSeries->setName("温度"); humSeries = new QLineSeries; humSeries->setName("湿度"); dataChart->addSeries(tempSeries); dataChart->addSeries(humSeries); tempSeries->attachAxis(axisX); tempSeries->attachAxis(axisY); humSeries->attachAxis(axisX); humSeries->attachAxis(axisY); historyLayout->addWidget(chartView); historyTab->setLayout(historyLayout); tabWidget->addTab(historyTab, "历史数据"); // 3. 报警日志页 QWidget *alarmTab = new QWidget; QVBoxLayout *alarmLayout = new QVBoxLayout; alarmLog = new QTextEdit; alarmLog->setReadOnly(true); alarmLayout->addWidget(alarmLog); QPushButton *clearBtn = new QPushButton("清空日志"); connect(clearBtn, &QPushButton::clicked, [this](){ alarmLog->clear(); }); alarmLayout->addWidget(clearBtn); alarmTab->setLayout(alarmLayout); tabWidget->addTab(alarmTab, "报警日志"); } void setupMQTT() { mqttClient = new QMqttClient(this); mqttClient->setHostname("your_huaweicloud_address"); // 华为云地址 mqttClient->setPort(1883); mqttClient->setUsername("your_username"); // 华为云用户名 mqttClient->setPassword("your_password"); // 华为云密码 connect(mqttClient, &QMqttClient::connected, [this](){ auto subscription = mqttClient->subscribe("env_data_topic", 0); if (!subscription) { QMessageBox::critical(this, "错误", "MQTT订阅失败!"); return; } }); connect(mqttClient, &QMqttClient::messageReceived, [this](const QByteArray &msg, const QMqttTopicName &){ processMessage(msg); }); connect(mqttClient, &QMqttClient::stateChanged, [](QMqttClient::ClientState state){ qDebug() << "MQTT状态:" << state; }); mqttClient->connectToHost(); } void setupDatabase() { db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("env_data.db"); if (!db.open()) { QMessageBox::critical(this, "数据库错误", "无法打开数据库!"); return; } QSqlQuery query; query.exec("CREATE TABLE IF NOT EXISTS env_data (" "id INTEGER PRIMARY KEY AUTOINCREMENT, " "timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, " "temperature REAL, " "humidity REAL, " "smoke INTEGER, " "flame INTEGER, " "gas INTEGER)"); } void processMessage(const QByteArray &msg) { QJsonDocument doc = QJsonDocument::fromJson(msg); if (!doc.isObject()) return; QJsonObject obj = doc.object(); EnvData data; data.temperature = obj["temp"].toDouble(); data.humidity = obj["hum"].toDouble(); data.smoke = obj["smoke"].toInt(); data.flame = obj["flame"].toInt(); data.gas = obj["gas"].toInt(); data.timestamp = QDateTime::currentDateTime(); // 更新实时数据 tempLabel->setText(QString::number(data.temperature)); humLabel->setText(QString::number(data.humidity)); smokeLabel->setText(QString::number(data.smoke)); flameLabel->setText(data.flame ? "有火焰!" : "正常"); gasLabel->setText(QString::number(data.gas)); // 检查报警条件 if(data.temperature > 40 || data.humidity > 85 || data.smoke > 300 || data.flame || data.gas > 200) { QString alarmMsg = QString("[%1] 报警! 温度:%2 湿度:%3 烟雾:%4 火焰:%5 气体:%6") .arg(data.timestamp.toString("yyyy-MM-dd hh:mm:ss")) .arg(data.temperature).arg(data.humidity) .arg(data.smoke).arg(data.flame ? "是" : "否").arg(data.gas); alarmLog->append(alarmMsg); } // 保存到数据库 QSqlQuery query; query.prepare("INSERT INTO env_data (timestamp, temperature, humidity, smoke, flame, gas) " "VALUES (?, ?, ?, ?, ?, ?)"); query.addBindValue(data.timestamp); query.addBindValue(data.temperature); query.addBindValue(data.humidity); query.addBindValue(data.smoke); query.addBindValue(data.flame); query.addBindValue(data.gas); query.exec(); // 更新图表 updateChart(data); } void updateChart(const EnvData &data) { // 限制数据点数量 if (tempSeries->count() > 60) { tempSeries->removePoints(0, tempSeries->count() - 60); humSeries->removePoints(0, humSeries->count() - 60); } // 添加新数据点 qint64 msecs = data.timestamp.toMSecsSinceEpoch(); tempSeries->append(msecs, data.temperature); humSeries->append(msecs, data.humidity); // 更新坐标轴范围 QDateTimeAxis *axisX = qobject_cast<QDateTimeAxis*>(dataChart->axes(Qt::Horizontal)[0]); if (axisX) { axisX->setRange( QDateTime::currentDateTime().addSecs(-300), QDateTime::currentDateTime() ); } } }; int main(int argc, char *argv[]) { QApplication app(argc, argv); // 初始化Qt图表 QApplication::setApplicationName("工业仓库监控系统"); QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); MainWindow mainWin; mainWin.show(); return app.exec(); } #include "main.moc" 上位机功能说明:多标签页界面实时监控:显示当前环境参数数值历史数据:动态折线图展示温湿度变化报警日志:记录异常事件及时间戳核心功能实现MQTT连接华为云IoT平台接收实时数据SQLite数据库存储历史数据动态图表展示(使用QtCharts)多参数异常检测报警系统数据持久化存储与检索运行要求Qt5组件:QtCharts、QtMqtt、QtSql华为云配置:替换MQTT连接参数数据库:自动创建SQLite本地数据库扩展功能支持历史数据导出(CSV/Excel)可添加阈值设置界面支持多设备管理可集成邮件/短信报警使用说明:替换MQTT连接参数后直接编译运行,系统会自动创建数据库并接收云端数据。模块代码设计STM32工业仓库环境监控系统代码设计(寄存器方式)#include "stm32f10x.h" // 引脚定义 #define SHT30_SCL_PIN GPIO_Pin_6 // PB6 #define SHT30_SDA_PIN GPIO_Pin_7 // PB7 #define FLAME_SENSOR_PIN GPIO_Pin_2 // PA2 #define BUZZER_PIN GPIO_Pin_3 // PA3 #define FAN_PIN GPIO_Pin_4 // PA4 #define LCD_CS_PIN GPIO_Pin_8 // PA8 #define LCD_DC_PIN GPIO_Pin_0 // PB0 #define LCD_RST_PIN GPIO_Pin_1 // PB1 // 报警阈值 #define TEMP_HIGH_LIMIT 40.0 #define HUMI_HIGH_LIMIT 80.0 #define SMOKE_THRESHOLD 800 #define GAS_THRESHOLD 600 #define FLAME_ALARM_LEVEL 0 // 低电平触发报警 // 全局变量 float temperature = 0; float humidity = 0; uint16_t smoke_value = 0; uint16_t gas_value = 0; uint8_t flame_state = 1; // 默认安全状态 // 系统时钟初始化 void RCC_Configuration(void) { // 开启外设时钟 RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_ADC1EN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_SPI1EN | RCC_APB2ENR_AFIOEN; RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; } // GPIO初始化 void GPIO_Configuration(void) { // I2C引脚 (PB6, PB7) GPIOB->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_CNF7); GPIOB->CRL |= GPIO_CRL_CNF6_1 | GPIO_CRL_CNF7_1; // 开漏输出 GPIOB->CRL |= GPIO_CRL_MODE6 | GPIO_CRL_MODE7; // 输出模式50MHz // ADC引脚 (PA0-MQ2, PA1-MQ135) GPIOA->CRL &= ~(GPIO_CRL_CNF0 | GPIO_CRL_CNF1 | GPIO_CRL_MODE0 | GPIO_CRL_MODE1); GPIOA->CRL |= GPIO_CRL_MODE0 | GPIO_CRL_MODE1; // 模拟输入模式 // 火焰传感器(PA2-输入), 蜂鸣器(PA3-输出), 风扇(PA4-输出) GPIOA->CRL &= ~(GPIO_CRL_CNF2 | GPIO_CRL_CNF3 | GPIO_CRL_CNF4); GPIOA->CRL |= GPIO_CRL_CNF2_0; // PA2浮空输入 GPIOA->CRL |= GPIO_CRL_MODE3 | GPIO_CRL_MODE4; // PA3/PA4输出模式50MHz // LCD控制引脚 (PB0-DC, PB1-RST, PA8-CS) GPIOB->CRL |= GPIO_CRL_MODE0 | GPIO_CRL_MODE1; // PB0/PB1推挽输出 GPIOA->CRH |= GPIO_CRH_MODE8; // PA8推挽输出 } // I2C初始化 void I2C_Configuration(void) { I2C1->CR1 &= ~I2C_CR1_PE; // 禁用I2C // 配置时钟: 72MHz PCLK1, SM模式(100kHz) I2C1->CR2 = 0x24; // FREQ = 36MHz I2C1->CCR = 0xB4; // CCR = 180 (100kHz) I2C1->TRISE = 0x25; // TRISE = 37 (1000ns) I2C1->CR1 |= I2C_CR1_PE; // 启用I2C } // SHT30温湿度读取 uint8_t SHT30_ReadData(float *temp, float *humi) { uint8_t cmd[2] = {0x2C, 0x06}; // 高精度测量命令 uint8_t data[6] = {0}; // 发送测量命令 I2C1->CR1 |= I2C_CR1_START; while(!(I2C1->SR1 & I2C_SR1_SB)); I2C1->DR = 0x44 << 1; // SHT30地址+写 while(!(I2C1->SR1 & I2C_SR1_ADDR)); (void)I2C1->SR2; // 清除ADDR标志 I2C1->DR = cmd[0]; while(!(I2C1->SR1 & I2C_SR1_TXE)); I2C1->DR = cmd[1]; while(!(I2C1->SR1 & I2C_SR1_BTF)); I2C1->CR1 |= I2C_CR1_STOP; // 延时等待测量完成 for(volatile int i=0; i<10000; i++); // 读取数据 I2C1->CR1 |= I2C_CR1_START; while(!(I2C1->SR1 & I2C_SR1_SB)); I2C1->DR = (0x44 << 1) | 0x01; // SHT30地址+读 while(!(I2C1->SR1 & I2C_SR1_ADDR)); (void)I2C1->SR2; for(int i=0; i<5; i++) { while(!(I2C1->SR1 & I2C_SR1_RXNE)); data[i] = I2C1->DR; } I2C1->CR1 &= ~I2C_CR1_ACK; I2C1->CR1 |= I2C_CR1_STOP; while(!(I2C1->SR1 & I2C_SR1_RXNE)); data[5] = I2C1->DR; // 数据转换 uint16_t rawTemp = (data[0] << 8) | data[1]; uint16_t rawHumi = (data[3] << 8) | data[4]; *temp = -45 + 175 * (rawTemp / 65535.0f); *humi = 100 * (rawHumi / 65535.0f); return 1; } // ADC初始化 void ADC_Configuration(void) { ADC1->CR2 = ADC_CR2_ADON; // 开启ADC // 校准 ADC1->CR2 |= ADC_CR2_RSTCAL; while(ADC1->CR2 & ADC_CR2_RSTCAL); ADC1->CR2 |= ADC_CR2_CAL; while(ADC1->CR2 & ADC_CR2_CAL); // 配置通道0(MQ2)和通道1(MQ135) ADC1->SMPR2 = (0x07 << (0 * 3)) | (0x07 << (1 * 3)); // 采样时间239.5周期 // 连续扫描模式 ADC1->CR1 = ADC_CR1_SCAN; ADC1->CR2 = ADC_CR2_CONT | ADC_CR2_ADON; } // 读取ADC值 uint16_t ADC_Read(uint8_t channel) { // 设置转换序列 ADC1->SQR3 = channel; // 单次转换 ADC1->CR2 |= ADC_CR2_SWSTART; // 开始转换 while(!(ADC1->SR & ADC_SR_EOC)); // 等待转换完成 return ADC1->DR; } // 火焰传感器读取 uint8_t FlameSensor_Read(void) { return GPIOA->IDR & FLAME_SENSOR_PIN ? 0 : 1; // 低电平触发 } // 蜂鸣器控制 void Buzzer_Control(uint8_t state) { if(state) GPIOA->BSRR = BUZZER_PIN; else GPIOA->BRR = BUZZER_PIN; } // 风扇控制 void Fan_Control(uint8_t state) { if(state) GPIOA->BSRR = FAN_PIN; else GPIOA->BRR = FAN_PIN; } // 报警检测逻辑 void Check_Alarm(void) { uint8_t alarm = 0; if(temperature > TEMP_HIGH_LIMIT) alarm = 1; if(humidity > HUMI_HIGH_LIMIT) alarm = 1; if(smoke_value > SMOKE_THRESHOLD) alarm = 1; if(gas_value > GAS_THRESHOLD) alarm = 1; if(flame_state) alarm = 1; if(alarm) { Buzzer_Control(1); Fan_Control(1); } else { Buzzer_Control(0); Fan_Control(0); } } // USART1初始化 (ESP8266) void USART1_Configuration(void) { // 波特率115200 USART1->BRR = 0x1D4C; // 72MHz/115200=625 USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; USART1->CR2 = 0; USART1->CR3 = 0; } // 通过ESP8266发送数据到华为云 void Send_To_HuaweiCloud(void) { char buffer[128]; sprintf(buffer, "T:%.1fC H:%.1f%% SMK:%d GAS:%d FL:%d", temperature, humidity, smoke_value, gas_value, flame_state); // 发送数据 for(char *p = buffer; *p; p++) { while(!(USART1->SR & USART_SR_TXE)); USART1->DR = *p; } } // LCD初始化 (SPI1) void SPI1_Configuration(void) { SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_BR_0 | SPI_CR1_BR_1; // 主模式, 18MHz SPI1->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI; // 软件NSS管理 SPI1->CR1 |= SPI_CR1_SPE; // 启用SPI } // LCD显示函数 void LCD_Display(void) { // 简化显示实现 LCD_SendCommand(0x2A); // 设置列地址 // ... 具体显示实现 LCD_DrawString(10, 10, "Temp:"); LCD_DrawFloat(60, 10, temperature, 1); // ... 其他数据显示 } // 主函数 int main(void) { // 系统初始化 RCC_Configuration(); GPIO_Configuration(); I2C_Configuration(); ADC_Configuration(); USART1_Configuration(); SPI1_Configuration(); // LCD初始化 LCD_Init(); while(1) { // 读取传感器数据 SHT30_ReadData(&temperature, &humidity); smoke_value = ADC_Read(0); // MQ2 gas_value = ADC_Read(1); // MQ135 flame_state = FlameSensor_Read(); // 报警检测 Check_Alarm(); // 上传数据到云平台 Send_To_HuaweiCloud(); // LCD显示 LCD_Display(); // 延时2秒 for(volatile int i=0; i<1000000; i++); } } 关键模块说明SHT30温湿度传感器:使用I2C接口(PB6/PB7)发送高精度测量命令0x2C06读取6字节数据并转换为实际温湿度值MQ2/MQ135气体传感器:使用ADC1通道0(PA0)和通道1(PA1)239.5周期采样时间保证精度返回12位ADC原始值(0-4095)火焰传感器:数字输入PA2低电平触发报警(返回1表示火焰检测)报警控制系统:蜂鸣器(PA3)和风扇(PA4)控制多参数阈值判断触发联动华为云通信:USART1(PA9/PA10)连接ESP8266通过MQTT协议传输格式化数据实际使用需配置AT指令和MQTT连接TFT LCD显示:SPI1接口(PA5/6/7)控制显示当前环境参数和报警状态需要实现底层SPI传输和显示驱动项目核心代码以下是基于STM32F103C8T6的工业仓库监控系统main.c完整代码(寄存器开发方式):#include "stm32f10x.h" #include "sht30.h" // 温湿度传感器驱动 #include "lcd_spi.h" // LCD显示驱动 #include "mqtt_cloud.h" // 华为云MQTT通信 #include <stdio.h> #include <string.h> // 硬件引脚定义 #define FLAME_SENSOR_GPIO GPIOC #define FLAME_SENSOR_PIN GPIO_Pin_0 #define BUZZER_GPIO GPIOC #define BUZZER_PIN GPIO_Pin_1 #define FAN_RELAY_GPIO GPIOC #define FAN_RELAY_PIN GPIO_Pin_2 #define MQ2_ADC_CHANNEL ADC_Channel_0 // PA0 #define MQ135_ADC_CHANNEL ADC_Channel_1 // PA1 // 报警阈值 #define TEMP_ALARM_MAX 40.0 // 温度报警值(℃) #define HUMI_ALARM_MAX 80.0 // 湿度报警值(%) #define SMOKE_ALARM_THRESHOLD 800 // 烟雾ADC报警值 #define GAS_ALARM_THRESHOLD 700 // 有害气体ADC报警值 // 全局变量 volatile uint16_t adc_mq2 = 0; // 烟雾传感器ADC值 volatile uint16_t adc_mq135 = 0; // 有害气体ADC值 float temperature = 0.0; // 温度值 float humidity = 0.0; // 湿度值 uint8_t flame_state = 0; // 火焰状态(0:正常, 1:有火焰) uint8_t alarm_flag = 0; // 综合报警标志 // 函数声明 void RCC_Configuration(void); void GPIO_Configuration(void); void ADC_Configuration(void); void TIM3_Init(void); void NVIC_Configuration(void); uint16_t Get_ADC_Value(uint8_t channel); void Check_Alarm_Condition(void); void Send_Cloud_Data(void); int main(void) { // 系统初始化 RCC_Configuration(); GPIO_Configuration(); ADC_Configuration(); TIM3_Init(); NVIC_Configuration(); LCD_Init(); // 初始化LCD SHT30_Init(); // 初始化温湿度传感器 ESP8266_Init(); // 初始化WiFi模块 MQTT_Connect(); // 连接华为云 LCD_Clear(BLACK); LCD_ShowString(10, 5, "Warehouse Monitor", WHITE, BLACK); while(1) { // 1. 读取传感器数据 SHT30_ReadData(&temperature, &humidity); flame_state = GPIO_ReadInputDataBit(FLAME_SENSOR_GPIO, FLAME_SENSOR_PIN); // 2. 检查报警条件 Check_Alarm_Condition(); // 3. LCD显示数据 char disp_buf[50]; sprintf(disp_buf, "Temp: %.1fC Humi: %.1f%%", temperature, humidity); LCD_ShowString(10, 30, disp_buf, WHITE, BLACK); sprintf(disp_buf, "Smoke: %d Gas: %d", adc_mq2, adc_mq135); LCD_ShowString(10, 50, disp_buf, WHITE, BLACK); sprintf(disp_buf, "Flame: %s", flame_state ? "DETECT!" : "Normal"); LCD_ShowString(10, 70, flame_state ? RED : GREEN, BLACK, disp_buf); sprintf(disp_buf, "Status: %s", alarm_flag ? "ALARM!" : "Normal"); LCD_ShowString(10, 90, alarm_flag ? RED : GREEN, BLACK, disp_buf); // 4. 每5秒上传数据到云端 static uint32_t cloud_timer = 0; if(HAL_GetTick() - cloud_timer > 5000) { cloud_timer = HAL_GetTick(); Send_Cloud_Data(); } } } // 系统时钟配置 void RCC_Configuration(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO | RCC_APB2Periph_ADC1, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); // ADC时钟=72MHz/6=12MHz } // GPIO配置 void GPIO_Configuration(void) { // 火焰传感器输入(PC0) GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = FLAME_SENSOR_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(FLAME_SENSOR_GPIO, &GPIO_InitStructure); // 蜂鸣器输出(PC1) GPIO_InitStructure.GPIO_Pin = BUZZER_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(BUZZER_GPIO, &GPIO_InitStructure); // 风扇继电器(PC2) GPIO_InitStructure.GPIO_Pin = FAN_RELAY_PIN; GPIO_Init(FAN_RELAY_GPIO, &GPIO_InitStructure); } // ADC配置 void ADC_Configuration(void) { ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); } // TIM3初始化(用于ADC定时采样) void TIM3_Init(void) { TIM_TimeBaseInitTypeDef TIM_InitStructure; TIM_InitStructure.TIM_Period = 999; // 1kHz TIM_InitStructure.TIM_Prescaler = 71; // 72MHz/72=1MHz TIM_InitStructure.TIM_ClockDivision = 0; TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_InitStructure); TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); TIM_Cmd(TIM3, ENABLE); } // 中断配置 void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } // ADC采样中断服务函数 void TIM3_IRQHandler(void) { if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM3, TIM_IT_Update); adc_mq2 = Get_ADC_Value(MQ2_ADC_CHANNEL); // 采样MQ2 adc_mq135 = Get_ADC_Value(MQ135_ADC_CHANNEL); // 采样MQ135 } } // 获取ADC采样值 uint16_t Get_ADC_Value(uint8_t channel) { ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_239Cycles5); ADC_SoftwareStartConvCmd(ADC1, ENABLE); while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); return ADC_GetConversionValue(ADC1); } // 报警条件检查 void Check_Alarm_Condition(void) { alarm_flag = 0; // 温度超标 if(temperature > TEMP_ALARM_MAX) { alarm_flag = 1; } // 湿度超标 if(humidity > HUMI_ALARM_MAX) { alarm_flag = 1; } // 烟雾检测 if(adc_mq2 > SMOKE_ALARM_THRESHOLD) { alarm_flag = 1; } // 有害气体检测 if(adc_mq135 > GAS_ALARM_THRESHOLD) { alarm_flag = 1; } // 火焰检测 if(flame_state) { alarm_flag = 1; } // 触发报警设备 if(alarm_flag) { GPIO_SetBits(BUZZER_GPIO, BUZZER_PIN); // 开启蜂鸣器 GPIO_SetBits(FAN_RELAY_GPIO, FAN_RELAY_PIN); // 开启风扇 } else { GPIO_ResetBits(BUZZER_GPIO, BUZZER_PIN); // 关闭蜂鸣器 GPIO_ResetBits(FAN_RELAY_GPIO, FAN_RELAY_PIN); // 关闭风扇 } } // 发送数据到华为云 void Send_Cloud_Data(void) { char json_buf[128]; snprintf(json_buf, sizeof(json_buf), "{\"temp\":%.1f,\"humi\":%.1f,\"smoke\":%d,\"gas\":%d,\"flame\":%d,\"alarm\":%d}", temperature, humidity, adc_mq2, adc_mq135, flame_state, alarm_flag); MQTT_PublishData(json_buf); // 通过MQTT协议发布数据 } 代码说明:传感器数据采集:SHT30通过I2C读取温湿度MQ2/MQ135通过ADC定时采样(TIM3触发)火焰传感器通过GPIO输入检测报警控制逻辑:温度>40℃/湿度>80%/烟雾>800/气体>700/火焰触发时触发蜂鸣器(PC1)和风扇继电器(PC2)数据显示与通信:实时在TFT LCD显示环境参数每5秒通过ESP8266以MQTT协议上传数据到华为云数据格式为JSON:{"temp":25.5,"humi":45.0,...}关键外设驱动:ADC多通道轮询采样TIM3定时器触发采样GPIO控制报警设备SPI驱动LCD显示总结本文设计的基于STM32的工业仓库环境智能监控系统,以STM32F103C8T6为核心控制器,通过多传感器协同实现了对仓库环境的全面监测。系统集成了SHT30温湿度传感器、MQ2烟雾传感器、红外火焰传感器和MQ135有害气体检测模块,构建了高可靠性的环境参数采集网络。实时数据通过SPI接口的1.44寸TFT LCD本地显示,同时利用ESP8266 WiFi模块通过MQTT协议将数据上传至华为云平台,实现了远程监控与历史数据分析的双重保障。系统具备智能响应机制,当检测到温湿度超标、烟雾浓度异常、火焰或有害气体泄漏时,STM32主控将立即触发有源蜂鸣器报警,并通过继电器驱动12V直流风扇启动强制通风。这种本地-云端联动的设计既保证了异常情况的快速处置,又通过华为云平台为上位机(基于Qt5开发的可视化平台)提供了数据支撑,实现了仓库环境的多维度安全管理。该设计充分考虑了工业场景的实际需求,硬件选型兼顾成本与性能,软件架构实现了数据采集、异常处理、云端通信的有机融合。系统不仅提升了仓库环境监控的智能化水平,其模块化设计也为未来功能扩展(如增加入侵检测或照明控制)奠定了基础,具有较高的工程应用价值。
-
引言随着物联网(IoT)技术的迅猛发展,越来越多的开发者和企业开始关注如何高效地构建和管理智能设备。物联网概览物联网通过传感器、RFID等技术实现了物品与物品、物品与人之间的信息交换与通信,构建了一个智能化网络。其架构分为感知层、网络层和应用层,各层次协同工作,实现数据采集、传输与处理。据预测,到2025年全球物联网市场规模将达到1.5万亿美元,在智能家居、智能交通等领域有广泛的应用前景。应用案例智能家居:智能音箱可通过语音控制家电,智能门锁实现远程开门,智能摄像头实时监控家庭安全。智能交通:利用传感器优化交通流量,车联网技术提升交通安全与效率。工业物联网:通过传感器监控生产设备状态,提高生产效率和产品质量。华为云IoT平台介绍华为云IoT平台提供了一套完整的设备接入解决方案,支持设备注册、状态监控、远程控制等功能模块,帮助用户快速搭建稳定的物联网应用。主要功能设备管理:包括设备注册区、设备管理列表、设备详情页等部分,支持多种设备类型的注册与批量操作。在线调试:提供详细的设备创建流程指导,简化了开发者接入设备的难度。消息跟踪:实时监控设备上报的数据,并能下发命令给设备。实例展示以智慧烟感器为例,演示了设备连接平台、上报数据到平台以及平台下发命令给设备的过程。这不仅展示了平台的功能性,还证明了其实时性和高效性。首页搜索“设备接入”,进行服务的开通随后来到控制台,点击你所开通的服务在产品里“创建产品”输入相关产品信息随后到设备页面进行注册设备相关demo案例引导可参考:https://support.huaweicloud.com/qs-iothub/iot_05_00010.html以一款虚拟的智慧烟感器为例,带您快速体验平台的三个基本功能:设备连接平台,设备上报数据到平台,平台下发命令给设备API Explorer助力开发API Explorer是华为云提供的一个强大的工具,它允许开发者快速调试API、查看文档并获取代码示例,极大地提高了开发效率。功能亮点快速上手:降低调试难度,减少开发时间。多语言支持:丰富的代码示例覆盖多种编程语言,满足不同需求。应用场景多样:适用于物联网设备开发、数据分析等多种场景。首页搜索“API Explorer”找到你想要测试的API带星号的是必填信息,填入相关信息即可调试在右侧窗口可查看代码示例复制到IDE里需要填充请求头里的token!!!具体token可使用IAM接口获取结语华为云通过一系列创新的物联网解决方案,为开发者们提供了强大而灵活的工具集,推动了物联网技术的发展。
-
近日,中国移动与华为联合申报的“5G时代算网融合标志性应用——移动云手机”入选了由工业和信息化部新闻宣传中心(人民邮电报社)组织征集的2023年ICT优秀案例,并凭借其在5G业务创新、提升用户体验、算力惠民等方面的突出价值,被授予“算力赋能创新应用”荣誉称号。 作为实体手机的云端延伸,移动云手机基于5G超宽连接通道,接入云端无限算力,突破了本地设备限制,让公众在保障安全私密的前提下实现云端算力的即取即用。其典型场景有:一是算力随身,弹性调用云端算力,突破物理手机性能限制;二是真机延伸,应用及文件上云,释放物理手机存储空间;三是公私分离,多账号绑定,实现一机多机多身份管理;四是数据安全,数据云端存储不落地,手机永不“丢”;五是多端协同,跨云终端之间同屏互动,实现远程协同。 华为基于ARM架构云底座,融合多种创新技术打造云手机极致体验:一、通过自研Monbox软件仿真架构,实现单服务器云机密度翻倍提升,端到端时延持续优化;二、超分还原+AVS3视频流,实现高清低码,大幅提升云上渲染效率;三、创新指令流分离渲染技术,在确保画质的同时进一步降低时延和流量消耗。 移动云手机作为5G用户的个人算力终端,高度契合“算网时代算力赋能数字经济高质量发展”的趋势,为广大用户带来全新的差异化体验和算力普惠服务,而中国移动作为“连接+算力+能力”新型信息服务体系的建设者,有望借此重构算力消费新体验,重构能力底座,重构用户信息服务新入口,为5G发展开辟一条全新业务赛道。
上滑加载中
推荐直播
-
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
华为云开发者AI素养直播课·第五期2026/09/04 周五 16:00-18:00
林华鼎-华为云AI开发者运营负责人;蒋春阳-华为云AI开发者案例开发专家
本期直播内容: AI工具体验营 · 第5-8课连讲。Agent-Team 多智能体协作完成毕业设计实践
回顾中 -
华为云开发者AI素养ClassRoom·第六期2026/09/08 周二 19:00-20:00
樊渊-2026华为软件挑战赛冠军
高手来了:看软挑高手解析二维排样问题—从工业难题到算法突破
回顾中
热门标签