STM32F103C8T6的智能医疗药品存储柜系统设计与华为云实现
项目开发背景
随着现代医疗技术的快速发展,药品的安全存储与管理成为医疗质量控制中的重要环节。许多药品对存储环境的温湿度具有严格的要求,一旦超出允许范围,药品的理化性质可能发生改变,甚至失效,直接影响患者的用药安全与治疗效果。然而,传统的药品存储柜大多依赖人工巡检和记录,存在效率低、误差大、实时性差等问题,难以满足日益严格的药品管理规范。
在此背景下,物联网技术的兴起为药品存储管理提供了新的解决方案。通过传感器实时采集环境数据,结合无线通信技术将信息上传至云平台,能够实现对药品存储状态的远程监控与智能预警。这不仅大大提高了药品管理的自动化水平和数据准确性,也为医疗机构降低了人为管理成本与风险。
本项目基于STM32F103C8T6主控制器,融合温湿度传感、门状态检测、时钟记录与Wi-Fi通信等技术,构建了一套智能药品存储柜系统,并通过华为云实现数据的集中管理与分析。该系统具备环境监测、自动调控、数据追溯和远程管理等功能,旨在为医疗机构提供一种可靠、高效的药品存储管理手段,提升药品管理的智能化水平和医疗安全质量。
设计实现的功能
(1)实时监测药品柜内温湿度及门开关状态。
(2)温湿度超标时自动启动温控设备并报警。
(3)药品存取记录及环境数据上传至华为云平台。
(4)QT上位机实现药品管理、环境数据查询及报警信息处理。
项目开发背景
随着医疗行业的快速发展,药品的安全存储成为保障患者用药安全和治疗效果的关键环节。许多药品对存储环境有严格的温湿度要求,例如疫苗、胰岛素等生物制剂需要在特定温度范围内保存,否则容易失效甚至产生有害物质。然而,传统的药品存储柜往往依赖人工定期检查,这种方式效率低下且容易因疏忽导致环境参数超标,无法实现实时监控和及时干预,从而增加了药品变质和医疗风险的可能性。
此外,医疗机构的药品管理还面临着记录不完整、追溯困难等问题。手动记录药品存取信息不仅耗时耗力,还容易出现错误或遗漏,这在紧急情况下可能影响药品的快速调配和使用。随着物联网和云计算技术的兴起,智能化的药品存储解决方案逐渐成为趋势,它能够通过自动化监测、数据远程传输和智能报警,显著提升药品管理的效率和可靠性。
本项目旨在设计并实现一个基于STM32F103C8T6微控制器的智能医疗药品存储柜系统,结合华为云平台,实现对柜内温湿度、门开关状态的实时监测,并在环境参数超标时自动启动温控设备并发出报警。通过集成Wi-Fi模块,系统将药品存取记录和环境数据上传至云平台,便于远程监控和数据分析;同时,QT上位机软件提供友好的用户界面,支持药品管理、历史查询和报警处理,从而为医疗机构提供一套高效、安全且可扩展的智能存储解决方案。
项目硬件模块组成
(1)STM32F103C8T6最小系统核心板作为主控制器。
(2)DHT22温湿度传感器监测柜内环境。
(3)干簧管门磁传感器检测柜门开关状态。
(4)DS1302时钟模块记录药品存取时间。
(5)ESP8266-01S Wi-Fi模块实现云平台通信。
(6)洞洞板焊接信号处理电路,杜邦线连接各传感器。
设计意义
该智能医疗药品存储柜系统设计基于STM32F103C8T6主控制器,实现了对药品存储环境的精准监控与管理,具有重要的实际应用价值。系统通过集成温湿度传感器和门状态检测,确保了药品在适宜的环境中存储,防止因温湿度波动导致的药品变质或失效,从而保障医疗用药的安全性和有效性。
系统具备自动温控和报警功能,在环境参数超标时及时响应,减少了人为干预的需求,提高了运维效率。这不仅降低了药品损失的风险,还增强了医疗机构的应急处理能力,为日常药品管理提供了可靠的技术支持。
通过华为云平台实现数据上传和QT上位机进行远程管理,系统实现了药品存取记录的数字化和环境的实时可追溯。这便于医护人员查询历史数据、处理报警信息,并支持大数据分析,为优化药品存储策略和提升医疗服务质量奠定了基础。整体设计提升了医疗资源管理的智能化水平,符合现代医疗信息化的发展趋势。
设计实现的功能
(1)实时监测药品柜内温湿度及门开关状态。
(2)温湿度超标时自动启动温控设备并报警。
(3)药品存取记录及环境数据上传至华为云平台。
(4)QT上位机实现药品管理、环境数据查询及报警信息处理。
项目硬件模块组成
(1)STM32F103C8T6最小系统核心板作为主控制器。
(2)DHT22温湿度传感器监测柜内环境。
(3)干簧管门磁传感器检测柜门开关状态。
(4)DS1302时钟模块记录药品存取时间。
(5)ESP8266-01S Wi-Fi模块实现云平台通信。
(6)洞洞板焊接信号处理电路,杜邦线连接各传感器。
设计思路
系统设计以STM32F103C8T6最小系统核心板作为主控制器,负责协调整个系统的运行。该控制器通过GPIO接口连接各传感器模块,初始化外设并设置中断处理,确保实时性。系统上电后,STM32进入主循环,持续采集传感器数据并执行控制逻辑,同时通过串口与Wi-Fi模块通信,实现数据上传和命令接收。
温湿度监测由DHT22传感器完成,STM32通过单总线协议读取传感器数据,定期采样柜内环境参数。门开关状态检测使用干簧管门磁传感器,连接至STM32的GPIO引脚并配置为输入模式,利用中断或轮询方式实时监测门状态变化,确保任何开门或关门事件都能及时捕获。
数据处理部分包括温湿度阈值判断,当检测到温度或湿度超出预设范围时,STM32自动启动温控设备如风扇或加热器,并通过蜂鸣器或LED进行报警提示。控制逻辑基于简单比较算法,确保响应快速且可靠,避免误动作。
时间记录依靠DS1302时钟模块,STM32通过SPI或类似接口读取当前时间,为药品存取事件添加时间戳。这些时间数据与传感器数据一起存储到本地缓冲区,并在需要时上传,保证记录的准确性和完整性。
云平台通信通过ESP8266-01S Wi-Fi模块实现,STM32通过串口AT指令与模块交互,连接至华为云平台。系统定期将温湿度数据、门状态事件以及药品存取记录打包为JSON格式,通过MQTT或HTTP协议上传,同时支持从云平台接收配置更新或查询指令。
QT上位机作为用户界面,运行于PC端,通过TCP/IP协议与云平台或直接与STM32通信(需网络配置)。它提供药品管理功能如录入和查询存取记录,实时显示环境数据曲线,并处理报警信息,允许用户确认和日志导出,增强系统的可管理性和可视化。
设计意义
智能医疗药品存储柜系统基于STM32F103C8T6主控制器设计,旨在提升药品存储的安全性和管理效率。该系统通过实时监测柜内温湿度及门开关状态,确保药品处于适宜环境中,防止因温湿度波动导致的药品变质或失效,从而保障医疗用药的有效性和患者安全。
温湿度超标时自动启动温控设备并报警功能,能够及时响应环境异常,减少人工干预的需求,避免药品损坏风险。这种自动化控制不仅提高了系统的可靠性,还降低了医疗机构的运营成本,通过即时报警机制确保问题得到快速处理。
药品存取记录及环境数据上传至华为云平台,实现了数据的远程存储和可追溯性。这使得医护人员能够通过云平台随时访问历史数据,进行分析和审计,支持合规性管理和决策制定,同时增强了药品管理的透明度和 accountability。
QT上位机软件提供了友好的用户界面,简化了药品管理、环境数据查询和报警信息处理流程。它使操作人员能够直观地监控系统状态,快速响应报警,并高效管理药品库存,提升了整体工作效率和用户体验。
硬件组成如DHT22传感器、干簧管门磁和DS1302时钟模块,确保了数据采集的准确性和时序记录的真实性。ESP8266-01S Wi-Fi模块实现了稳定的云平台通信,而洞洞板焊接和杜邦线连接则体现了系统的灵活性和成本效益,适用于各种医疗环境部署。
框架图
+-------------------+ +-----------------+ +-----------------+
| | | | | |
| DHT22 Sensor |----->| | | |
| (温湿度监测) | | | | |
+-------------------+ | | | || STM32F103C8T6 | | ESP8266-01S |
+-------------------+ | (主控制器) |----->| (Wi-Fi通信) |
| | | | | |
| Dry Reed Sensor |----->| | | |
| (门开关状态检测) | | | | |
+-------------------+ | | | || | | |
+-------------------+ | | | |
| | | | | |
| DS1302 Clock |----->| | | |
| (时间记录) | | | | |
+-------------------+ +-----------------+ +-----------------+| || |v v+-----------------+ +-----------------+| | | || 温控设备 | | 华为云平台 || (风扇/加热器) | | (数据存储) || | | |+-----------------+ +-----------------+| || |v v+-----------------+ +-----------------+| | | || 报警设备 | | QT上位机 || (蜂鸣器/LED) | | (药品管理) || | | |+-----------------+ +-----------------+
设计思路
设计思路基于STM32F103C8T6最小系统核心板作为主控制器,负责协调整个系统的运行。该系统通过集成多种传感器和执行器,实现智能医疗药品存储柜的自动化管理。核心板处理来自传感器的数据,执行控制逻辑,并通过Wi-Fi模块与云平台通信,同时上位机软件提供用户界面进行监控和管理。
系统首先通过DHT22温湿度传感器实时监测柜内环境参数,传感器数据通过GPIO引脚读取,STM32进行ADC转换或数字信号处理,确保数据的准确性。干簧管门磁传感器用于检测柜门开关状态,通过中断或轮询方式读取状态变化,从而记录门的开闭事件。DS1302时钟模块提供实时时间戳,用于标记药品存取和环境数据的时间,确保记录的可追溯性。
当温湿度数据超出预设阈值时,STM32触发控制逻辑,自动启动温控设备如风扇或加热器,以调节环境条件,同时通过声光报警装置(如蜂鸣器和LED)发出警报,提醒用户及时处理。这一过程基于软件中的比较算法,实时监控数据并做出响应,确保药品存储环境的安全。
ESP8266-01S Wi-Fi模块负责与华为云平台通信,STM32通过UART接口与ESP8266交互,使用AT指令或自定义协议建立Wi-Fi连接。环境数据、门状态事件和药品存取记录被封装成JSON格式,通过MQTT或HTTP协议上传到云平台,实现数据的远程存储和监控。云平台配置为接收和处理这些数据,支持后续的数据分析和告警推送。
QT上位机应用程序运行在PC端,通过串口或网络与STM32系统通信,实现药品管理功能,如添加、删除和查询药品信息,同时可以实时查看环境数据历史记录和报警信息。上位机提供图形化界面,方便用户处理报警事件和生成报告,增强了系统的可用性和管理效率。整个系统的硬件连接采用洞洞板焊接信号处理电路,杜邦线连接各传感器和模块,确保电路的稳定性和可维护性。
系统总体设计
该系统基于STM32F103C8T6最小系统核心板作为主控制器,实现智能医疗药品存储柜的监控与管理。系统通过DHT22温湿度传感器实时采集柜内环境数据,并结合干簧管门磁传感器检测柜门的开关状态,确保环境参数和门状态得到持续监测。
当温湿度数据超出预设阈值时,系统自动启动温控设备(如风扇或加热器)进行调节,并触发报警机制,例如通过蜂鸣器或LED指示,以提醒用户及时处理异常情况,保障药品存储安全。
药品存取记录和环境数据通过DS1302时钟模块标记时间戳,并通过ESP8266-01S Wi-Fi模块将数据上传至华为云平台,实现远程数据存储和访问。硬件连接采用洞洞板焊接信号处理电路,并使用杜邦线灵活连接各传感器和模块,确保系统稳定性和可维护性。
此外,QT上位机软件提供药品管理、环境数据查询和报警信息处理功能,用户可以通过图形界面直观地查看历史记录、处理报警事件,并管理药品库存,提升系统的实用性和用户体验。整个设计注重实际应用,确保功能可靠且易于扩展。
框架图
+-----------------------------+
| 传感器层 |
| +-----------------------+ |
| | DHT22温湿度传感器 |---+
| +-----------------------+ | +-----------------------------+
| | | 控制层 |
| +-----------------------+ | | +-----------------------+ |
| | 干簧管门磁传感器 |---|-->| | STM32F103C8T6主控制器 | |
| +-----------------------+ | | +-----------------------+ |
| | | |
| +-----------------------+ | | +-----------------------+ |
| | DS1302时钟模块 |---|-->| | 信号处理电路(洞洞板)| |
| +-----------------------+ | | +-----------------------+ |
+-----------------------------+ +-----------------------------+|| (控制信号)v
+-----------------------------+ +-----------------------------+
| 执行层 | | 通信层 |
| +-----------------------+ | | +-----------------------+ |
| | 温控设备(如风扇) |<---|--| | ESP8266-01S Wi-Fi模块 | |
| +-----------------------+ | | +-----------------------+ |
| | | |
| +-----------------------+ | | (通过UART通信) |
| | 报警设备(如蜂鸣器) |<---|--| |
| +-----------------------+ | +-----------------------------+
+-----------------------------+ || (Wi-Fi)v+-----------------------------+| 云平台层 || +-----------------------+ || | 华为云平台 | || +-----------------------+ |+-----------------------------+|| (数据API)v+-----------------------------+| 应用层 || +-----------------------+ || | QT上位机应用程序 | || +-----------------------+ |+-----------------------------+
系统功能总结
功能描述 | 实现方式 |
---|---|
实时监测柜内温湿度 | DHT22温湿度传感器 |
实时监测柜门开关状态 | 干簧管门磁传感器 |
温湿度超标自动控制与报警 | 通过STM32控制温控设备(如风扇/加热器)并触发报警装置 |
记录药品存取时间 | DS1302时钟模块 |
上传药品存取记录及环境数据至华为云平台 | ESP8266-01S Wi-Fi模块 |
药品管理、环境数据查询及报警信息处理 | QT上位机软件 |
系统主控制与数据处理 | STM32F103C8T6最小系统核心板 |
系统总体设计
系统总体设计基于STM32F103C8T6最小系统核心板作为主控制器,负责协调整个智能医疗药品存储柜的运行。该系统通过集成多种传感器和执行器,实现药品存储环境的实时监控和数据管理。硬件组成包括DHT22温湿度传感器用于采集柜内环境数据,干簧管门磁传感器检测门开关状态,DS1302时钟模块提供准确的时间记录,ESP8266-01S Wi-Fi模块处理与华为云平台的通信,所有电路通过洞洞板焊接和杜邦线连接确保稳定性和灵活性。
传感器数据采集由STM32主控制器定期轮询完成。DHT22传感器实时测量温湿度数值,干簧管门磁传感器输出门状态信号,这些数据通过ADC和GPIO接口读入STM32进行处理。DS1302时钟模块为每次事件提供时间戳,确保药品存取记录的准确性。主控制器对采集到的数据进行初步滤波和校验,以消除噪声并提高可靠性。
当温湿度数据超出预设阈值时,系统自动触发控制逻辑。STM32通过GPIO输出信号启动温控设备(如风扇或加热器),以调节柜内环境,同时激活报警装置(如蜂鸣器或LED指示灯)进行本地警示。这一过程确保药品存储条件始终符合要求,防止环境异常导致的药品变质。
所有环境数据和事件记录(包括温湿度、门状态和时间戳)通过ESP8266-01S Wi-Fi模块上传至华为云平台。STM32通过串口与Wi-Fi模块通信,使用MQTT或HTTP协议将数据打包发送,实现远程监控和存储。云平台负责数据持久化和分析,为上位机提供查询基础。
QT上位机软件作为用户界面,实现药品管理、环境数据查询和报警信息处理。它通过云平台API获取数据,显示实时温湿度曲线、门状态历史记录和报警事件,并允许用户配置阈值和管理药品信息。上位机与STM32系统间接交互,通过云平台同步数据,确保系统的远程可管理性和用户体验。
设计的各个功能模块描述
STM32F103C8T6最小系统核心板作为主控制器,负责协调整个系统的运行,包括采集传感器数据、处理逻辑判断、控制外部设备以及管理通信模块。它通过GPIO接口连接各传感器和执行器,实现实时数据采集和控制输出。
DHT22温湿度传感器用于实时监测药品柜内的温度和湿度环境,其数字输出信号直接连接到STM32的GPIO引脚,STM32定期读取传感器数据以进行环境监测和超标判断。
干簧管门磁传感器检测柜门的开关状态,当门打开或关闭时,传感器状态变化通过GPIO输入到STM32,系统据此记录门状态事件并可能触发相关操作如记录存取时间。
DS1302时钟模块提供实时时间信息,用于精确记录药品存取事件的时间戳,STM32通过串行通信接口读取时钟数据,确保记录准确性并支持时间相关功能。
ESP8266-01S Wi-Fi模块实现与华为云平台的通信,STM32通过串口将温湿度数据、门状态事件和存取记录发送给ESP8266,由后者通过Wi-Fi网络上传数据到云平台,同时接收可能的云指令。
洞洞板焊接的信号处理电路用于接口和信号调理,例如可能包括电平转换或滤波电路,以确保传感器信号稳定可靠地传输到STM32,杜邦线用于灵活连接各组件。
温控设备在温湿度超标时由STM32控制启动,例如通过继电器驱动风扇或加热器,以调节柜内环境,同时系统会触发报警机制如声音或光指示,确保及时处理异常情况。
系统功能总结
功能 | 实现方式 |
---|---|
实时监测药品柜内温湿度 | 使用DHT22温湿度传感器 |
实时监测门开关状态 | 使用干簧管门磁传感器 |
温湿度超标时自动启动温控设备并报警 | STM32F103C8T6控制温控设备,触发报警机制 |
记录药品存取时间 | 使用DS1302时钟模块 |
药品存取记录及环境数据上传至华为云平台 | 通过ESP8266-01S Wi-Fi模块实现通信 |
QT上位机实现药品管理、环境数据查询及报警信息处理 | 基于QT开发的上位机软件 |
设计的各个功能模块描述
STM32F103C8T6最小系统核心板作为主控制器,负责协调整个系统的运行。它通过读取传感器数据、处理逻辑控制指令以及管理外设模块来实现功能需求。主控制器实时采集温湿度传感器和门状态传感器的信号,根据预设阈值判断是否启动温控设备或触发报警,同时记录时间信息并通过Wi-Fi模块上传数据到云平台。
DHT22温湿度传感器用于监测药品柜内的环境参数,实时检测温度和湿度值。传感器将采集到的数据以数字信号形式传输给主控制器,主控制器据此进行监控和决策,确保柜内环境符合药品存储要求,并在超标时采取相应措施。
干簧管门磁传感器检测柜门的开关状态,当门打开或关闭时,传感器会产生信号变化并通知主控制器。这一功能用于记录药品存取事件,并结合时钟模块提供时间戳,确保门状态变化的准确记录和报警触发。
DS1302时钟模块提供实时时钟功能,用于记录药品存取的具体时间。模块与主控制器连接,确保时间数据的准确性和一致性,为上传到云平台的数据添加时间标签,便于后续查询和分析。
ESP8266-01S Wi-Fi模块实现与华为云平台的通信功能,负责将采集到的温湿度数据、门状态记录以及报警信息上传到云。模块通过串口与主控制器交互,配置网络参数并处理数据传输,确保数据的可靠性和实时性。
洞洞板焊接的信号处理电路用于稳定和调理传感器信号,确保数据采集的准确性。电路可能包括滤波、电平转换或保护元件,以适应不同传感器的输出特性,并通过杜邦线连接到主控制器和其他模块。
杜邦线用于灵活连接各传感器和模块到主控制器,便于系统的组装、调试和维护。这种连接方式提供了良好的可扩展性和可靠性,确保信号传输的稳定性。
上位机代码设计
以下是基于Qt C++开发的智能医疗药品存储柜系统上位机代码。代码包括主窗口类,实现药品管理、环境数据查询和报警信息处理功能。使用QNetworkAccessManager与华为云平台通信,假设API端点为硬编码值(实际应用中应配置化)。
文件结构:
main.cpp
:应用程序入口。MainWindow.h
:主窗口头文件。MainWindow.cpp
:主窗口实现文件。Medicine.h
:药品数据模型头文件(可选,简化处理)。Medicine.cpp
:药品数据模型实现文件(可选,简化处理)。
由于篇幅限制,这里提供核心代码。药品数据模型简化处理,直接使用QList存储药品名称。
main.cpp
#include "MainWindow.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QTabWidget>
#include <QListWidget>
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QDateTime>class MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void onAddMedicine();void onDeleteMedicine();void onRefreshEnvironment();void onRefreshAlarms();void onEnvironmentReplyFinished(QNetworkReply *reply);void onAlarmsReplyFinished(QNetworkReply *reply);private:void setupUI();void fetchEnvironmentData();void fetchAlarmsData();QTabWidget *tabWidget;QListWidget *medicineList;QLineEdit *medicineInput;QPushButton *addButton;QPushButton *deleteButton;QListWidget *environmentList;QPushButton *refreshEnvButton;QListWidget *alarmsList;QPushButton *refreshAlarmsButton;QNetworkAccessManager *networkManager;QString baseUrl = "http://example.com/api/"; // 假设的API基URL,实际应配置
};#endif // MAINWINDOW_H
MainWindow.cpp
#include "MainWindow.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QMessageBox>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), networkManager(new QNetworkAccessManager(this))
{setupUI();connect(networkManager, &QNetworkAccessManager::finished, this, &MainWindow::onEnvironmentReplyFinished);connect(networkManager, &QNetworkAccessManager::finished, this, &MainWindow::onAlarmsReplyFinished);fetchEnvironmentData();fetchAlarmsData();
}MainWindow::~MainWindow()
{
}void MainWindow::setupUI()
{setWindowTitle("智能医疗药品存储柜系统");setGeometry(100, 100, 800, 600);tabWidget = new QTabWidget(this);setCentralWidget(tabWidget);// 药品管理标签QWidget *medicineTab = new QWidget;QVBoxLayout *medicineLayout = new QVBoxLayout;medicineList = new QListWidget;medicineInput = new QLineEdit;medicineInput->setPlaceholderText("输入药品名称");QHBoxLayout *inputLayout = new QHBoxLayout;addButton = new QPushButton("添加");deleteButton = new QPushButton("删除");inputLayout->addWidget(medicineInput);inputLayout->addWidget(addButton);inputLayout->addWidget(deleteButton);medicineLayout->addWidget(medicineList);medicineLayout->addLayout(inputLayout);medicineTab->setLayout(medicineLayout);tabWidget->addTab(medicineTab, "药品管理");// 环境数据标签QWidget *envTab = new QWidget;QVBoxLayout *envLayout = new QVBoxLayout;environmentList = new QListWidget;refreshEnvButton = new QPushButton("刷新");envLayout->addWidget(environmentList);envLayout->addWidget(refreshEnvButton);envTab->setLayout(envLayout);tabWidget->addTab(envTab, "环境数据");// 报警信息标签QWidget *alarmsTab = new QWidget;QVBoxLayout *alarmsLayout = new QVBoxLayout;alarmsList = new QListWidget;refreshAlarmsButton = new QPushButton("刷新");alarmsLayout->addWidget(alarmsList);alarmsLayout->addWidget(refreshAlarmsButton);alarmsTab->setLayout(alarmsLayout);tabWidget->addTab(alarmsTab, "报警信息");// 连接信号和槽connect(addButton, &QPushButton::clicked, this, &MainWindow::onAddMedicine);connect(deleteButton, &QPushButton::clicked, this, &MainWindow::onDeleteMedicine);connect(refreshEnvButton, &QPushButton::clicked, this, &MainWindow::onRefreshEnvironment);connect(refreshAlarmsButton, &QPushButton::clicked, this, &MainWindow::onRefreshAlarms);
}void MainWindow::onAddMedicine()
{QString medicine = medicineInput->text().trimmed();if (!medicine.isEmpty()) {medicineList->addItem(medicine);medicineInput->clear();// 这里应添加代码将药品上传到云平台,假设通过API POST// 简化处理,仅本地添加}
}void MainWindow::onDeleteMedicine()
{QList<QListWidgetItem*> selected = medicineList->selectedItems();for (QListWidgetItem *item : selected) {delete item;// 这里应添加代码从云平台删除药品,假设通过API DELETE}
}void MainWindow::onRefreshEnvironment()
{fetchEnvironmentData();
}void MainWindow::onRefreshAlarms()
{fetchAlarmsData();
}void MainWindow::fetchEnvironmentData()
{QUrl url(baseUrl + "environment");QNetworkRequest request(url);networkManager->get(request);
}void MainWindow::fetchAlarmsData()
{QUrl url(baseUrl + "alarms");QNetworkRequest request(url);networkManager->get(request);
}void MainWindow::onEnvironmentReplyFinished(QNetworkReply *reply)
{if (reply->error() == QNetworkReply::NoError) {QByteArray response = reply->readAll();QJsonDocument jsonDoc = QJsonDocument::fromJson(response);QJsonArray jsonArray = jsonDoc.array();environmentList->clear();for (const QJsonValue &value : jsonArray) {QJsonObject obj = value.toObject();QString temp = obj["temperature"].toString();QString humidity = obj["humidity"].toString();QString time = obj["timestamp"].toString();environmentList->addItem(QString("温度: %1°C, 湿度: %2%%, 时间: %3").arg(temp).arg(humidity).arg(time));}} else {QMessageBox::warning(this, "错误", "获取环境数据失败: " + reply->errorString());}reply->deleteLater();
}void MainWindow::onAlarmsReplyFinished(QNetworkReply *reply)
{if (reply->error() == QNetworkReply::NoError) {QByteArray response = reply->readAll();QJsonDocument jsonDoc = QJsonDocument::fromJson(response);QJsonArray jsonArray = jsonDoc.array();alarmsList->clear();for (const QJsonValue &value : jsonArray) {QJsonObject obj = value.toObject();QString message = obj["message"].toString();QString time = obj["timestamp"].toString();alarmsList->addItem(QString("报警: %1, 时间: %2").arg(message).arg(time));}} else {QMessageBox::warning(this, "错误", "获取报警数据失败: " + reply->errorString());}reply->deleteLater();
}
说明:
- 此代码是一个基本框架,实际应用中需要根据华为云API的具体细节调整URL和JSON解析逻辑。
- 药品管理功能目前仅本地操作,应添加云同步代码(例如,在onAddMedicine和onDeleteMedicine中实现网络请求)。
- 环境数据和报警数据通过HTTP GET请求获取,假设API返回JSON数组。
- 使用Qt的网络和JSON模块,确保在.pro文件中添加
QT += network
。
编译和运行此代码需要Qt开发环境。根据实际API调整基URL和JSON处理。
上位机代码设计
#include <QApplication>
#include <QMainWindow>
#include <QTabWidget>
#include <QTableWidget>
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
#include <QTextEdit>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QChartView>
#include <QLineSeries>
#include <QValueAxis>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QMessageBox>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QDialog>
#include <QFormLayout>
#include <QDialogButtonBox>QT_CHARTS_USE_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void onAddMedicine();void onDeleteMedicine();void onRefreshData();void onNetworkReply(QNetworkReply *reply);private:void setupUI();void fetchDataFromCloud();QTabWidget *tabWidget;QTableWidget *medicineTable;QTableWidget *envDataTable;QTextEdit *alarmTextEdit;QNetworkAccessManager *networkManager;
};MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)
{setupUI();networkManager = new QNetworkAccessManager(this);connect(networkManager, &QNetworkAccessManager::finished, this, &MainWindow::onNetworkReply);fetchDataFromCloud();
}MainWindow::~MainWindow()
{
}void MainWindow::setupUI()
{setWindowTitle("智能医疗药品存储柜管理系统");setGeometry(100, 100, 800, 600);tabWidget = new QTabWidget(this);// 药品管理标签QWidget *medicineTab = new QWidget;QVBoxLayout *medicineLayout = new QVBoxLayout;QHBoxLayout *buttonLayout = new QHBoxLayout;QPushButton *addButton = new QPushButton("添加药品");QPushButton *deleteButton = new QPushButton("删除药品");QPushButton *refreshButton = new QPushButton("刷新数据");connect(addButton, &QPushButton::clicked, this, &MainWindow::onAddMedicine);connect(deleteButton, &QPushButton::clicked, this, &MainWindow::onDeleteMedicine);connect(refreshButton, &QPushButton::clicked, this, &MainWindow::onRefreshData);buttonLayout->addWidget(addButton);buttonLayout->addWidget(deleteButton);buttonLayout->addWidget(refreshButton);medicineTable = new QTableWidget;medicineTable->setColumnCount(4);medicineTable->setHorizontalHeaderLabels(QStringList() << "药品ID" << "药品名称" << "数量" << "生产日期");medicineLayout->addLayout(buttonLayout);medicineLayout->addWidget(medicineTable);medicineTab->setLayout(medicineLayout);tabWidget->addTab(medicineTab, "药品管理");// 环境数据标签QWidget *envDataTab = new QWidget;QVBoxLayout *envLayout = new QVBoxLayout;envDataTable = new QTableWidget;envDataTable->setColumnCount(3);envDataTable->setHorizontalHeaderLabels(QStringList() << "时间" << "温度" << "湿度");envLayout->addWidget(envDataTable);QChart *chart = new QChart;QLineSeries *tempSeries = new QLineSeries;QLineSeries *humiditySeries = new QLineSeries;chart->addSeries(tempSeries);chart->addSeries(humiditySeries);chart->setTitle("温湿度历史数据");chart->createDefaultAxes();QChartView *chartView = new QChartView(chart);chartView->setRenderHint(QPainter::Antialiasing);envLayout->addWidget(chartView);envDataTab->setLayout(envLayout);tabWidget->addTab(envDataTab, "环境数据");// 报警信息标签QWidget *alarmTab = new QWidget;QVBoxLayout *alarmLayout = new QVBoxLayout;alarmTextEdit = new QTextEdit;alarmTextEdit->setReadOnly(true);alarmLayout->addWidget(alarmTextEdit);alarmTab->setLayout(alarmLayout);tabWidget->addTab(alarmTab, "报警信息");setCentralWidget(tabWidget);
}void MainWindow::onAddMedicine()
{QDialog dialog(this);dialog.setWindowTitle("添加药品");QFormLayout form(&dialog);QLineEdit *nameEdit = new QLineEdit;QLineEdit *quantityEdit = new QLineEdit;QLineEdit *dateEdit = new QLineEdit;form.addRow("药品名称:", nameEdit);form.addRow("数量:", quantityEdit);form.addRow("生产日期:", dateEdit);QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog);form.addRow(&buttonBox);connect(&buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);connect(&buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);if (dialog.exec() == QDialog::Accepted) {int row = medicineTable->rowCount();medicineTable->insertRow(row);medicineTable->setItem(row, 0, new QTableWidgetItem(QString::number(row + 1)));medicineTable->setItem(row, 1, new QTableWidgetItem(nameEdit->text()));medicineTable->setItem(row, 2, new QTableWidgetItem(quantityEdit->text()));medicineTable->setItem(row, 3, new QTableWidgetItem(dateEdit->text()));}
}void MainWindow::onDeleteMedicine()
{int currentRow = medicineTable->currentRow();if (currentRow >= 0) {medicineTable->removeRow(currentRow);} else {QMessageBox::warning(this, "警告", "请选择要删除的药品行");}
}void MainWindow::onRefreshData()
{fetchDataFromCloud();
}void MainWindow::fetchDataFromCloud()
{QUrl url("https://your-huawei-cloud-api.com/data");QNetworkRequest request(url);networkManager->get(request);
}void MainWindow::onNetworkReply(QNetworkReply *reply)
{if (reply->error() == QNetworkReply::NoError) {QByteArray data = reply->readAll();QJsonDocument doc = QJsonDocument::fromJson(data);if (doc.isArray()) {QJsonArray array = doc.array();envDataTable->setRowCount(0);for (int i = 0; i < array.size(); ++i) {QJsonObject obj = array[i].toObject();QString time = obj["time"].toString();double temperature = obj["temperature"].toDouble();double humidity = obj["humidity"].toDouble();int row = envDataTable->rowCount();envDataTable->insertRow(row);envDataTable->setItem(row, 0, new QTableWidgetItem(time));envDataTable->setItem(row, 1, new QTableWidgetItem(QString::number(temperature)));envDataTable->setItem(row, 2, new QTableWidgetItem(QString::number(humidity)));}}// 假设报警数据也在回复中if (doc.isObject()) {QJsonObject obj = doc.object();if (obj.contains("alarms")) {QJsonArray alarms = obj["alarms"].toArray();alarmTextEdit->clear();for (const QJsonValue &value : alarms) {QJsonObject alarm = value.toObject();QString alarmMsg = alarm["message"].toString();alarmTextEdit->append(alarmMsg);}}}} else {QMessageBox::critical(this, "错误", "获取数据失败: " + reply->errorString());}reply->deleteLater();
}int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}#include "main.moc"
模块代码设计
#include "stm32f10x.h"// 引脚定义
#define DHT22_PIN GPIO_Pin_0
#define DHT22_PORT GPIOA#define DOOR_SENSOR_PIN GPIO_Pin_1
#define DOOR_SENSOR_PORT GPIOA#define DS1302_CE_PIN GPIO_Pin_2
#define DS1302_CE_PORT GPIOA
#define DS1302_IO_PIN GPIO_Pin_3
#define DS1302_IO_PORT GPIOA
#define DS1302_SCLK_PIN GPIO_Pin_4
#define DS1302_SCLK_PORT GPIOA#define TEMP_CONTROL_PIN GPIO_Pin_5
#define TEMP_CONTROL_PORT GPIOA
#define ALARM_PIN GPIO_Pin_6
#define ALARM_PORT GPIOA// UART1 for ESP8266
#define ESP8266_UART USART1// 温湿度阈值
#define TEMP_HIGH_THRESHOLD 30.0
#define TEMP_LOW_THRESHOLD 2.0
#define HUMIDITY_HIGH_THRESHOLD 80.0// 函数声明
void SystemInit(void);
void GPIO_Init(void);
void UART1_Init(void);
void DHT22_Init(void);
float DHT22_ReadTemperature(void);
float DHT22_ReadHumidity(void);
uint8_t DHT22_ReadByte(void);
void DS1302_Init(void);
void DS1302_WriteByte(uint8_t data);
uint8_t DS1302_ReadByte(void);
void DS1302_GetTime(uint8_t *time);
void DoorSensor_Init(void);
uint8_t DoorSensor_Read(void);
void ESP8266_Init(void);
void ESP8266_SendCmd(char *cmd);
void ESP8266_SendData(char *data);
void Delay_ms(uint32_t nTime);
void Delay_us(uint32_t nTime);int main(void) {SystemInit();GPIO_Init();UART1_Init();DHT22_Init();DS1302_Init();DoorSensor_Init();ESP8266_Init();while (1) {// 读取温湿度float temp = DHT22_ReadTemperature();float humidity = DHT22_ReadHumidity();// 读取门状态uint8_t door_state = DoorSensor_Read();// 读取时间uint8_t time[7];DS1302_GetTime(time);// 检查温湿度阈值if (temp > TEMP_HIGH_THRESHOLD || temp < TEMP_LOW_THRESHOLD || humidity > HUMIDITY_HIGH_THRESHOLD) {GPIO_SetBits(TEMP_CONTROL_PORT, TEMP_CONTROL_PIN); // 启动温控设备GPIO_SetBits(ALARM_PORT, ALARM_PIN); // 报警} else {GPIO_ResetBits(TEMP_CONTROL_PORT, TEMP_CONTROL_PIN);GPIO_ResetBits(ALARM_PORT, ALARM_PIN);}// 准备数据上传到华为云char data_str[100];sprintf(data_str, "temp=%.2f&humidity=%.2f&door=%d&time=%02d:%02d:%02d", temp, humidity, door_state, time[2], time[1], time[0]);ESP8266_SendData(data_str);Delay_ms(5000); // 每5秒上传一次}
}void SystemInit(void) {// 设置系统时钟为72MHzRCC->CFGR |= RCC_CFGR_PLLMULL9;RCC->CFGR |= 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_PLL));
}void GPIO_Init(void) {// 启用GPIOA和UART1时钟RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN;// 配置DHT22引脚为输入GPIOA->CRL &= ~(0xF << (0 * 4)); // PA0: inputGPIOA->CRL |= (0x4 << (0 * 4)); // Floating input// 配置门传感器引脚为输入带上拉GPIOA->CRL &= ~(0xF << (1 * 4)); // PA1: inputGPIOA->CRL |= (0x8 << (1 * 4)); // Pull-up inputGPIOA->ODR |= DOOR_SENSOR_PIN; // Enable pull-up// 配置DS1302引脚:CE、IO、SCLK为输出GPIOA->CRL &= ~(0xFF << (2 * 4)); // Clear PA2, PA3, PA4GPIOA->CRL |= (0x3 << (2 * 4)) | (0x3 << (3 * 4)) | (0x3 << (4 * 4)); // PA2, PA3, PA4: output, 50MHzGPIOA->ODR &= ~(DS1302_CE_PIN | DS1302_IO_PIN | DS1302_SCLK_PIN); // Set low initially// 配置温控和报警引脚为输出GPIOA->CRL &= ~(0xF << (5 * 4)); // PA5: outputGPIOA->CRL |= (0x3 << (5 * 4)); // Output, 50MHzGPIOA->CRL &= ~(0xF << (6 * 4)); // PA6: outputGPIOA->CRL |= (0x3 << (6 * 4)); // Output, 50MHz// 配置UART1引脚: PA9 as TX, PA10 as RXGPIOA->CRH &= ~(0xFF << 4); // Clear PA9 and PA10GPIOA->CRH |= (0xB << 4) | (0x4 << 8); // PA9: AF output, 50MHz; PA10: input floating
}void UART1_Init(void) {// 配置UART1: 9600 baud, 8 data bits, no parity, 1 stop bitUSART1->BRR = 72000000 / 9600; // Set baud rateUSART1->CR1 |= USART_CR1_TE | USART_CR1_RE; // Enable TX and RXUSART1->CR1 |= USART_CR1_UE; // Enable UART
}void DHT22_Init(void) {// 初始化代码,设置引脚GPIO_ResetBits(DHT22_PORT, DHT22_PIN); // Set low initiallyDelay_ms(1000);
}float DHT22_ReadTemperature(void) {uint8_t data[5];// 启动信号GPIO_SetBits(DHT22_PORT, DHT22_PIN);Delay_us(30);GPIO_ResetBits(DHT22_PORT, DHT22_PIN);Delay_ms(1);GPIO_SetBits(DHT22_PORT, DHT22_PIN);Delay_us(40);// 等待响应while (GPIO_ReadInputDataBit(DHT22_PORT, DHT22_PIN));while (!GPIO_ReadInputDataBit(DHT22_PORT, DHT22_PIN));// 读取数据for (int i = 0; i < 5; i++) {data[i] = DHT22_ReadByte();}// 校验和检查if (data[4] == (data[0] + data[1] + data[2] + data[3])) {float temp = (data[2] & 0x7F) * 256 + data[3];temp /= 10.0;if (data[2] & 0x80) temp = -temp;return temp;}return -1.0;
}float DHT22_ReadHumidity(void) {uint8_t data[5];// 类似ReadTemperature,但返回湿度// 启动信号GPIO_SetBits(DHT22_PORT, DHT22_PIN);Delay_us(30);GPIO_ResetBits(DHT22_PORT, DHT22_PIN);Delay_ms(1);GPIO_SetBits(DHT22_PORT, DHT22_PIN);Delay_us(40);while (GPIO_ReadInputDataBit(DHT22_PORT, DHT22_PIN));while (!GPIO_ReadInputDataBit(DHT22_PORT, DHT22_PIN));for (int i = 0; i < 5; i++) {data[i] = DHT22_ReadByte();}if (data[4] == (data[0] + data[1] + data[2] + data[3])) {float humidity = data[0] * 256 + data[1];humidity /= 10.0;return humidity;}return -1.0;
}uint8_t DHT22_ReadByte(void) {uint8_t byte = 0;for (int i = 0; i < 8; i++) {while (!GPIO_ReadInputDataBit(DHT22_PORT, DHT22_PIN)); // Wait for highDelay_us(30);if (GPIO_ReadInputDataBit(DHT22_PORT, DHT22_PIN)) {byte |= (1 << (7 - i));}while (GPIO_ReadInputDataBit(DHT22_PORT, DHT22_PIN)); // Wait for low}return byte;
}void DS1302_Init(void) {GPIO_ResetBits(DS1302_CE_PORT, DS1302_CE_PIN);GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);
}void DS1302_WriteByte(uint8_t data) {for (int i = 0; i < 8; i++) {GPIO_WriteBit(DS1302_IO_PORT, DS1302_IO_PIN, (data & (1 << i)) ? Bit_SET : Bit_RESET);GPIO_SetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);Delay_us(1);GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);Delay_us(1);}
}uint8_t DS1302_ReadByte(void) {uint8_t byte = 0;for (int i = 0; i < 8; i++) {if (GPIO_ReadInputDataBit(DS1302_IO_PORT, DS1302_IO_PIN)) {byte |= (1 << i);}GPIO_SetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);Delay_us(1);GPIO_ResetBits(DS1302_SCLK_PORT, DS1302_SCLK_PIN);Delay_us(1);}return byte;
}void DS1302_GetTime(uint8_t *time) {GPIO_SetBits(DS1302_CE_PORT, DS1302_CE_PIN);DS1302_WriteByte(0x81); // Read secondstime[0] = DS1302_ReadByte();DS1302_WriteByte(0x83); // Read minutestime[1] = DS1302_ReadByte();DS1302_WriteByte(0x85); // Read hourstime[2] = DS1302_ReadByte();GPIO_ResetBits(DS1302_CE_PORT, DS1302_CE_PIN);
}void DoorSensor_Init(void) {// 已在GPIO_Init中初始化
}uint8_t DoorSensor_Read(void) {return GPIO_ReadInputDataBit(DOOR_SENSOR_PORT, DOOR_SENSOR_PIN);
}void ESP8266_Init(void) {ESP8266_SendCmd("AT+RST\r\n");Delay_ms(1000);ESP8266_SendCmd("AT+CWMODE=1\r\n");Delay_ms(1000);ESP8266_SendCmd("AT+CWJAP=\"YourSSID\",\"YourPassword\"\r\n");Delay_ms(5000);ESP8266_SendCmd("AT+CIPSTART=\"TCP\",\"华为云地址\",端口号\r\n");Delay_ms(1000);
}void ESP8266_SendCmd(char *cmd) {while (*cmd) {USART_SendData(ESP8266_UART, *cmd++);while (USART_GetFlagStatus(ESP8266_UART, USART_FLAG_TC) == RESET);}
}void ESP8266_SendData(char *data) {char cmd[50];sprintf(cmd, "AT+CIPSEND=%d\r\n", strlen(data));ESP8266_SendCmd(cmd);Delay_ms(100);ESP8266_SendCmd(data);ESP8266_SendCmd("\r\n");
}void Delay_ms(uint32_t nTime) {for (uint32_t i = 0; i < nTime * 1000; i++) {__NOP();}
}void Delay_us(uint32_t nTime) {for (uint32_t i = 0; i < nTime; i++) {__NOP();}
}
模块代码设计
#include <stdint.h>// Register definitions for STM32F103C8T6
#define GPIOA_BASE 0x40010800
#define GPIOA_CRL (*((volatile uint32_t *)(GPIOA_BASE + 0x00)))
#define GPIOA_CRH (*((volatile uint32_t *)(GPIOA_BASE + 0x04)))
#define GPIOA_IDR (*((volatile uint32_t *)(GPIOA_BASE + 0x08)))
#define GPIOA_ODR (*((volatile uint32_t *)(GPIOA_BASE + 0x0C)))#define GPIOB_BASE 0x40010C00
#define GPIOB_CRL (*((volatile uint32_t *)(GPIOB_BASE + 0x00)))
#define GPIOB_CRH (*((volatile uint32_t *)(GPIOB_BASE + 0x04)))
#define GPIOB_IDR (*((volatile uint32_t *)(GPIOB_BASE + 0x08)))
#define GPIOB_ODR (*((volatile uint32_t *)(GPIOB_BASE + 0x0C)))#define RCC_BASE 0x40021000
#define RCC_APB2ENR (*((volatile uint32_t *)(RCC_BASE + 0x18)))#define USART1_BASE 0x40013800
#define USART1_SR (*((volatile uint32_t *)(USART1_BASE + 0x00)))
#define USART1_DR (*((volatile uint32_t *)(USART1_BASE + 0x04)))
#define USART1_BRR (*((volatile uint32_t *)(USART1_BASE + 0x08)))
#define USART1_CR1 (*((volatile uint32_t *)(USART1_BASE + 0x0C)))#define SYSTICK_BASE 0xE000E010
#define SYST_CSR (*((volatile uint32_t *)(SYSTICK_BASE + 0x00)))
#define SYST_RVR (*((volatile uint32_t *)(SYSTICK_BASE + 0x04)))
#define SYST_CVR (*((volatile uint32_t *)(SYSTICK_BASE + 0x08)))// Pin definitions
#define DHT22_PIN 0 // PA0
#define DOOR_SENSOR_PIN 1 // PA1
#define DS1302_CE_PIN 2 // PA2
#define DS1302_IO_PIN 3 // PA3
#define DS1302_SCLK_PIN 4 // PA4
#define TEMP_CTRL_PIN 5 // PA5 (e.g., relay for fan)
#define ALARM_PIN 6 // PA6 (e.g., LED)
#define ESP8266_TX_PIN 9 // PA9
#define ESP8266_RX_PIN 10 // PA10// Constants
#define SYSTEM_CORE_CLOCK 8000000 // 8MHz
#define DHT22_TIMEOUT 10000
#define TEMP_THRESHOLD_HIGH 30.0 // Example temperature threshold
#define HUMIDITY_THRESHOLD_HIGH 80.0 // Example humidity threshold// Global variables
volatile uint32_t msTicks = 0;// SysTick interrupt handler
void SysTick_Handler(void) {msTicks++;
}// Delay in milliseconds
void Delay_ms(uint32_t ms) {uint32_t startTicks = msTicks;while ((msTicks - startTicks) < ms);
}// Delay in microseconds (approximate for 8MHz)
void Delay_us(uint32_t us) {us = us * 2; // Adjust for 8MHz, each loop ~0.5uswhile (us--) {__asm__("nop");}
}// GPIO initialization
void GPIO_Init(void) {// Enable clock for GPIOA and GPIOBRCC_APB2ENR |= (1 << 2) | (1 << 3); // GPIOA and GPIOB clock enable// Configure PA0 (DHT22) as output open-drain initiallyGPIOA_CRL &= ~(0xF << (DHT22_PIN * 4));GPIOA_CRL |= (0x3 << (DHT22_PIN * 4)); // Output mode, max speed 50MHzGPIOA_ODR |= (1 << DHT22_PIN); // Set high// Configure PA1 (Door sensor) as input with pull-upGPIOA_CRL &= ~(0xF << (DOOR_SENSOR_PIN * 4));GPIOA_CRL |= (0x8 << (DOOR_SENSOR_PIN * 4)); // Input with pull-up/pull-downGPIOA_ODR |= (1 << DOOR_SENSOR_PIN); // Pull-up// Configure PA2, PA3, PA4 for DS1302: PA2(CE) and PA4(SCLK) as output, PA3(IO) as input/outputGPIOA_CRL &= ~(0xFFF << (DS1302_CE_PIN * 4)); // Clear bits for PA2, PA3, PA4GPIOA_CRL |= (0x3 << (DS1302_CE_PIN * 4)) | (0x3 << (DS1302_SCLK_PIN * 4)); // Output for CE and SCLKGPIOA_ODR &= ~(1 << DS1302_CE_PIN); // CE lowGPIOA_ODR &= ~(1 << DS1302_SCLK_PIN); // SCLK low// For PA3(IO), set as input initiallyGPIOA_CRL |= (0x8 << (DS1302_IO_PIN * 4)); // Input with pull-up/pull-downGPIOA_ODR |= (1 << DS1302_IO_PIN); // Pull-up// Configure PA5 (Temperature control) and PA6 (Alarm) as outputGPIOA_CRL &= ~(0xFF << (TEMP_CTRL_PIN * 4));GPIOA_CRL |= (0x3 << (TEMP_CTRL_PIN * 4)) | (0x3 << (ALARM_PIN * 4)); // OutputGPIOA_ODR &= ~(1 << TEMP_CTRL_PIN); // Off initiallyGPIOA_ODR &= ~(1 << ALARM_PIN); // Off initially// Configure PA9 (USART1 TX) as alternate function output, PA10 (USART1 RX) as inputGPIOA_CRH &= ~(0xFF << ((ESP8266_TX_PIN - 8) * 4));GPIOA_CRH |= (0xB << ((ESP8266_TX_PIN - 8) * 4)); // AF output for TXGPIOA_CRH |= (0x4 << ((ESP8266_RX_PIN - 8) * 4)); // Input floating for RX
}// USART1 initialization for ESP8266
void USART1_Init(void) {// Enable clock for USART1RCC_APB2ENR |= (1 << 14); // USART1 clock enable// Configure USART1: 9600 baud, 8 data bits, no parity, 1 stop bitUSART1_BRR = 0x341; // 8MHz / 9600 = 833.33 -> 0x341 (mantissa 52, fraction 1)USART1_CR1 |= (1 << 13) | (1 << 3) | (1 << 2); // UE, TE, RE
}// USART1 send character
void USART1_SendChar(char c) {while (!(USART1_SR & (1 << 7))); // Wait for TXEUSART1_DR = c;
}// USART1 send string
void USART1_SendString(const char *str) {while (*str) {USART1_SendChar(*str++);}
}// DHT22 functions
void DHT22_Start(void) {GPIOA_CRL &= ~(0xF << (DHT22_PIN * 4));GPIOA_CRL |= (0x3 << (DHT22_PIN * 4)); // Output modeGPIOA_ODR &= ~(1 << DHT22_PIN); // Pull lowDelay_ms(1); // Wait 1msGPIOA_ODR |= (1 << DHT22_PIN); // Pull highDelay_us(30); // Wait 30usGPIOA_CRL &= ~(0xF << (DHT22_PIN * 4));GPIOA_CRL |= (0x8 << (DHT22_PIN * 4)); // Input mode
}uint8_t DHT22_Check_Response(void) {uint32_t timeout = 0;while (GPIOA_IDR & (1 << DHT22_PIN)) { Wait for lowif (timeout++ > DHT22_TIMEOUT) return 0;Delay_us(1);}timeout = 0;while (!(GPIOA_IDR & (1 << DHT22_PIN))) { Wait for highif (timeout++ > DHT22_TIMEOUT) return 0;Delay_us(1);}timeout = 0;while (GPIOA_IDR & (1 << DHT22_PIN)) { Wait for low againif (timeout++ > DHT22_TIMEOUT) return 0;Delay_us(1);}return 1;
}uint8_t DHT22_Read_Bit(void) {uint32_t timeout = 0;while (!(GPIOA_IDR & (1 << DHT22_PIN))) { Wait for highif (timeout++ > DHT22_TIMEOUT) return 0;Delay_us(1);}Delay_us(40); // Wait 40usif (GPIOA_IDR & (1 << DHT22_PIN)) return 1;else return 0;
}uint8_t DHT22_Read_Byte(void) {uint8_t byte = 0;for (int i = 0; i < 8; i++) {byte <<= 1;byte |= DHT22_Read_Bit();}return byte;
}int DHT22_Read(float *temperature, float *humidity) {uint8 data[5] = {0};DHT22_Start();if (!DHT22_Check_Response()) return 0;for (int i = 0; i < 5; i++) {data[i] = DHT22_Read_Byte();}// Checksumif (data[4] != (data[0] + data[1] + data[2] + data[3])) return 0;*humidity = (data[0] * 256 + data[1]) / 10.0;*temperature = (data[2] * 256 + data[3]) / 10.0;return 1;
}// DS1302 functions
void DS1302_Write_Byte(uint8_t byte) {GPIOA_CRL &= ~(0xF << (DS1302_IO_PIN * 4));GPIOA_CRL |= (0x3 << (DS1302_IO_PIN * 4)); // Output modefor (int i = 0; i < 8; i++) {if (byte & 0x01) GPIOA_ODR |= (1 << DS1302_IO_PIN);else GPIOA_ODR &= ~(1 << DS1302_IO_PIN);GPIOA_ODR |= (1 << DS1302_SCLK_PIN); // SCLK highDelay_us(1);GPIOA_ODR &= ~(1 << DS1302_SCLK_PIN); // SCLK lowDelay_us(1);byte >>= 1;}
}uint8_t DS1302_Read_Byte(void) {uint8_t byte = 0;GPIOA_CRL &= ~(0xF << (DS1302_IO_PIN * 4));GPIOA_CRL |= (0x8 << (DS1302_IO_PIN * 4)); // Input modefor (int i = 0; i < 8; i++) {byte >>= 1;if (GPIOA_IDR & (1 << DS1302_IO_PIN)) byte |= 0x80;GPIOA_ODR |= (1 << DS1302_SCLK_PIN); // SCLK highDelay_us(1);GPIOA_ODR &= ~(1 << DS1302_SCLK_PIN); // SCLK lowDelay_us(1);}return byte;
}void DS1302_Write_Register(uint8_t reg, uint8_t data) {GPIOA_ODR |= (1 << DS1302_CE_PIN); // CE highDS1302_Write_Byte(reg);DS1302_Write_Byte(data);GPIOA_ODR &= ~(1 << DS1302_CE_PIN); // CE low
}uint8_t DS1302_Read_Register(uint8_t reg) {GPIOA_ODR |= (1 << DS1302_CE_PIN); // CE highDS1302_Write_Byte(reg | 0x01); // Read commanduint8_t data = DS1302_Read_Byte();GPIOA_ODR &= ~(1 << DS1302_CE_PIN); // CE lowreturn data;
}void DS1302_Init(void) {// Disable write protectionDS1302_Write_Register(0x8E, 0x00);// Enable clockDS1302_Write_Register(0x80, 0x00); // Ensure clock is running
}void DS1302_Get_Time(uint8_t *year, uint8_t *month, uint8_t *day, uint8_t *hour, uint8_t *minute, uint8_t *second) {*second = DS1302_Read_Register(0x81);*minute = DS1302_Read_Register(0x83);*hour = DS1302_Read_Register(0x85);*day = DS1302_Read_Register(0x87);*month = DS1302_Read_Register(0x89);*year = DS1302_Read_Register(0x8D);
}// Door sensor read
uint8_t Door_Read(void) {return (GPIOA_IDR & (1 << DOOR_SENSOR_PIN)) ? 1 : 0; // 1 means door closed? depends on wiring
}// Control functions
void Temp_Ctrl_On(void) {GPIOA_ODR |= (1 << TEMP_CTRL_PIN); // Turn on temp control device
}void Temp_Ctrl_Off(void) {GPIOA_ODR &= ~(1 << TEMP_CTRL_PIN); // Turn off
}void Alarm_On(void) {GPIOA_ODR |= (1 << ALARM_PIN); // Turn on alarm
}void Alarm_Off(void) {GPIOA_ODR &= ~(1 << ALARM_PIN); // Turn off
}// ESP8266 functions for Huawei Cloud
void ESP8266_Init(void) {USART1_SendString("AT+RST\r\n");Delay_ms(1000);USART1_SendString("AT+CWMODE=1\r\n");Delay_ms(1000);USART1_SendString("AT+CWJAP=\"SSID\",\"PASSWORD\"\r\n"); // Replace with your WiFi credentialsDelay_ms(5000);USART1_SendString("AT+CIPSTART=\"TCP\",\"192.168.1.100\",8080\r\n"); // Replace with Huawei Cloud IP and portDelay_ms(2000);
}void ESP8266_Send_Data(float temp, float hum, uint8_t door状态, uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {char buffer[100];sprintf(buffer, "AT+CIPSEND=%d\r\n", strlen("Temp: XX.X, Hum: XX.X, Door: X, Time: YYYY-MM-DD HH:MM:SS"));USART1_SendString(buffer);Delay_ms(100);sprintf(buffer, "Temp: %.1f, Hum: %.1f, Door: %d, Time: 20%02d-%02d-%02d %02d:%02d:%02d\r\n", temp, hum, door状态, year, month, day, hour, minute, second);USART1_SendString(buffer);Delay_ms(500);
}// Main function
int main(void) {// Initialize SysTick for 1ms interruptsSYST_RVR = 8000 - 1; // Reload value for 1ms at 8MHzSYST_CVR = 0;SYST_CSR = (1 << 2) | (1 << 0); // Processor clock, enableGPIO_Init();USART1_Init();DS1302_Init();ESP8266_Init();float temperature, humidity;uint8_t door状态;uint8_t year, month, day, hour, minute, second;while (1) {if (DHT22_Read(&temperature, &humidity)) {door状态 = Door_Read();DS1302_Get_Time(&year, &month, &day, &hour, &minute, &second);// Check thresholds and controlif (temperature > TEMP_THRESHOLD_HIGH || humidity > HUMIDITY_THRESHOLD_HIGH) {Temp_Ctrl_On();Alarm_On();} else {Temp_Ctrl_Off();Alarm_Off();}// Send data to cloudESP8266_Send_Data(temperature, humidity, door状态, year, month, day, hour, minute, second);// Log access if door state changed (simple example)static uint8_t last_door状态 = 0;if (door状态 != last_door状态) {// Record access event, e.g., send to cloud or store locallylast_door状态 = door状态;}}Delay_ms(5000); // Read every 5 seconds}
}
项目核心代码
#include <stdint.h>// Register definitions for STM32F103
#define RCC_APB2ENR (*(volatile uint32_t*)0x40021018)
#define GPIOA_CRL (*(volatile uint32_t*)0x40010800)
#define GPIOA_CRH (*(volatile uint32_t*)0x40010804)
#define GPIOA_ODR (*(volatile uint32_t*)0x4001080C)
#define USART1_SR (*(volatile uint32_t*)0x40013800)
#define USART1_DR (*(volatile uint32_t*)0x40013804)
#define USART1_BRR (*(volatile uint32_t*)0x40013808)
#define USART1_CR1 (*(volatile uint32_t*)0x4001380C)// External function declarations
extern void DHT22_Init(void);
extern void DHT22_Read(float *temp, float *humidity);
extern void DoorSensor_Init(void);
extern uint8_t DoorSensor_Read(void);
extern void DS1302_Init(void);
extern void DS1302_GetTime(char *timeBuffer);
extern void ESP8266_Init(void);
extern void ESP8266_SendData(const char *data);// Pin definitions
#define FAN_PIN 2 // PA2
#define ALARM_PIN 3 // PA3// GPIO initialization
void GPIO_Init(void) {// Enable GPIOA clockRCC_APB2ENR |= (1 << 2);// Configure PA2 and PA3 as output push-pull, 50MHzGPIOA_CRL &= ~(0xF << 8); // Clear bits for PA2GPIOA_CRL |= (0x3 << 8); // Set PA2 to output push-pullGPIOA_CRL &= ~(0xF << 12); // Clear bits for PA3GPIOA_CRL |= (0x3 << 12); // Set PA3 to output push-pull
}// USART1 initialization for ESP8266
void USART1_Init(void) {// Enable USART1 clockRCC_APB2ENR |= (1 << 14);// Configure PA9 as alternative push-pull output (TX)GPIOA_CRH &= ~(0xF << 4);GPIOA_CRH |= (0xB << 4);// Configure PA10 as input floating (RX)GPIOA_CRH &= ~(0xF << 8);GPIOA_CRH |= (0x4 << 8);// Set baud rate to 9600 (72MHz clock)USART1_BRR = 0x1D4C;// Enable USART1, transmitter, and receiverUSART1_CR1 |= (1 << 13) | (1 << 3) | (1 << 2);
}// Control functions
void Fan_On(void) {GPIOA_ODR |= (1 << FAN_PIN);
}void Fan_Off(void) {GPIOA_ODR &= ~(1 << FAN_PIN);
}void Alarm_On(void) {GPIOA_ODR |= (1 << ALARM_PIN);
}void Alarm_Off(void) {GPIOA_ODR &= ~(1 << ALARM_PIN);
}// Simple delay function
void Delay(void) {for (volatile int i = 0; i < 500000; i++);
}int main(void) {// Initialize hardwareGPIO_Init();USART1_Init();DHT22_Init();DoorSensor_Init();DS1302_Init();ESP8266_Init();float temp, humidity;uint8_t door_status;char time_str[20];while (1) {// Read sensorsDHT22_Read(&temp, &humidity);door_status = DoorSensor_Read();DS1302_GetTime(time_str);// Control logicif (temp > 30.0 || humidity > 80.0) {Fan_On();Alarm_On();} else {Fan_Off();Alarm_Off();}// Prepare data stringchar data[100];int len = 0;len += sprintf(data + len, "Time: %s, Temp: %.2f C, Humidity: %.2f%%, Door: %s", time_str, temp, humidity, door_status ? "Open" : "Closed");// Send data to cloudESP8266_SendData(data);// DelayDelay();}
}
总结
本系统基于STM32F103C8T6微控制器,成功设计并实现了一个智能医疗药品存储柜,核心功能包括实时监测柜内温湿度及门开关状态,确保药品存储环境符合标准,并在温湿度超标时自动启动温控设备和报警机制,从而保障药品的安全与有效性。
硬件组成上,系统采用了DHT22温湿度传感器进行环境数据采集,干簧管门磁传感器检测门状态,DS1302时钟模块记录精确时间信息,ESP8266-01S Wi-Fi模块实现与华为云平台的稳定通信,所有组件通过洞洞板焊接的信号处理电路和杜邦线连接,确保了系统的可靠性和易维护性。
软件方面,通过华为云平台集成,系统实现了环境数据和药品存取记录的上传与存储,QT上位机应用提供了友好的用户界面,支持药品管理、历史数据查询和报警信息处理,大大提升了系统的智能化水平和操作便利性。
总体而言,该系统将嵌入式硬件、云平台和上位机软件有机结合,为医疗药品存储提供了一套高效、可靠的解决方案,具有广泛的应用前景和推广价值。
项目核心代码
#include <stdint.h>// 寄存器定义
#define RCC_BASE 0x40021000
#define GPIOA_BASE 0x40010800
#define USART1_BASE 0x40013800#define RCC_CR (*((volatile uint32_t *)(RCC_BASE + 0x00)))
#define RCC_CFGR (*((volatile uint32_t *)(RCC_BASE + 0x04)))
#define RCC_APB2ENR (*((volatile uint32_t *)(RCC_BASE + 0x18)))#define GPIOA_CRL (*((volatile uint32_t *)(GPIOA_BASE + 0x00)))
#define GPIOA_CRH (*((volatile uint32_t *)(GPIOA_BASE + 0x04)))
#define GPIOA_IDR (*((volatile uint32_t *)(GPIOA_BASE + 0x08)))
#define GPIOA_ODR (*((volatile uint32_t *)(GPIOA_BASE + 0x0C)))#define USART1_SR (*((volatile uint32_t *)(USART1_BASE + 0x00)))
#define USART1_DR (*((volatile uint32_t *)(USART1_BASE + 0x04)))
#define USART1_BRR (*((volatile uint32_t *)(USART1_BASE + 0x08)))
#define USART1_CR1 (*((volatile uint32_t *)(USART1_BASE + 0x0C)))// 假设其他模块函数原型
extern void DHT22_Init(void);
extern float DHT22_ReadTemperature(void);
extern float DHT22_ReadHumidity(void);
extern void DoorSensor_Init(void);
extern int DoorSensor_Read(void);
extern void DS1302_Init(void);
extern void DS1302_GetTime(char *timeStr);
extern void ESP8266_Init(void);
extern void ESP8266_SendData(const char *data);// 引脚定义
#define HEATER_PIN 2 // PA2
#define ALARM_PIN 3 // PA3void SystemInit(void) {// 启用HSE并配置PLL为72MHzRCC_CR |= (1 << 16); // 启用HSEwhile (!(RCC_CR & (1 << 17))); // 等待HSE就绪RCC_CFGR |= (1 << 16); // PLL源为HSERCC_CFGR |= (9 << 18); // PLL倍频9倍,HSE 8MHz * 9 = 72MHzRCC_CR |= (1 << 24); // 启用PLLwhile (!(RCC_CR & (1 << 25))); // 等待PLL就绪RCC_CFGR |= (2 << 0); // 切换系统时钟到PLLwhile ((RCC_CFGR & 0x0C) != 0x08); // 等待切换完成
}void GPIO_Init(void) {// 启用GPIOA时钟RCC_APB2ENR |= (1 << 2); // IOPAEN// 配置PA1为输入(门传感器),假设带上拉GPIOA_CRL &= ~(0xF << 4); // 清除PA1配置GPIOA_CRL |= (0x8 << 4); // 输入模式,带上拉/下拉// 配置PA2和PA3为推挽输出(温控设备和报警)GPIOA_CRL &= ~(0xF << 8); // 清除PA2配置GPIOA_CRL |= (0x3 << 8); // 推挽输出,50MHzGPIOA_CRL &= ~(0xF << 12); // 清除PA3配置GPIOA_CRL |= (0x3 << 12); // 推挽输出,50MHz// 配置PA9为USART1 TX(复用推挽输出),PA10为USART1 RX(输入浮空)GPIOA_CRH &= ~(0xF << 4); // 清除PA9配置GPIOA_CRH |= (0xB << 4); // 复用推挽输出,50MHzGPIOA_CRH &= ~(0xF << 8); // 清除PA10配置GPIOA_CRH |= (0x4 << 8); // 输入浮空
}void USART1_Init(void) {// 启用USART1时钟RCC_APB2ENR |= (1 << 14); // USART1EN// 配置USART1波特率为9600,72MHz时钟USART1_BRR = 0x1D4C; // 72MHz / 9600 = 7500 -> 0x1D4CUSART1_CR1 |= (1 << 13); // 启用USARTUSART1_CR1 |= (1 << 3) | (1 << 2); // 启用TX和RX
}void Delay_ms(uint32_t ms) {for (uint32_t i = 0; i < ms * 1000; i++) {__asm__("nop"); // 无操作指令实现延迟}
}int main(void) {SystemInit();GPIO_Init();USART1_Init();DHT22_Init();DoorSensor_Init();DS1302_Init();ESP8266_Init();float temperature, humidity;int doorStatus;char timeStr[20];while (1) {temperature = DHT22_ReadTemperature();humidity = DHT22_ReadHumidity();doorStatus = DoorSensor_Read();DS1302_GetTime(timeStr);// 温湿度阈值检查(示例阈值:温度>25°C或湿度>60%)if (temperature > 25.0 || humidity > 60.0) {GPIOA_ODR |= (1 << HEATER_PIN); // 开启温控设备GPIOA_ODR |= (1 << ALARM_PIN); // 开启报警} else {GPIOA_ODR &= ~(1 << HEATER_PIN); // 关闭温控设备GPIOA_ODR &= ~(1 << ALARM_PIN); // 关闭报警}// 准备数据并上传到华为云char data[100];sprintf(data, "Time: %s, Temp: %.2f, Humidity: %.2f, Door: %d", timeStr, temperature, humidity, doorStatus);ESP8266_SendData(data);Delay_ms(5000); // 每5秒执行一次}
}
总结
本系统基于STM32F103C8T6微控制器核心板,成功设计并实现了一个智能医疗药品存储柜系统,能够实时监测柜内温湿度及门开关状态,并在温湿度超标时自动启动温控设备并触发报警,确保了药品存储环境的安全与稳定。该系统通过集成多种传感器和执行器,实现了高效的本地控制与数据处理。
硬件组成包括DHT22温湿度传感器用于环境监测、干簧管门磁传感器检测门状态、DS1302时钟模块记录精确时间、以及ESP8266-01S Wi-Fi模块负责云平台通信。所有组件通过洞洞板焊接的信号处理电路和杜邦线连接,确保了系统的可靠性和扩展性,为后续功能升级提供了基础。
数据上传至华为云平台,实现了药品存取记录和环境数据的远程存储与访问,用户可以通过云服务实时监控柜内状态并接收报警信息,提升了医疗药品管理的智能化和远程化水平。此外,系统支持与QT上位机软件的交互,便于药品管理、历史数据查询和报警处理,增强了用户体验和操作便利性。
总体而言,该系统结合了嵌入式技术、物联网云平台和上位机软件,为医疗行业提供了一种高效、可靠的药品存储解决方案,具有较高的实用价值和推广前景。