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

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

cpp 复制代码
#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_OBJECT

public:
    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

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处理。

上位机代码设计

cpp 复制代码
#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_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    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"

模块代码设计

c 复制代码
#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) {
    // 设置系统时钟为72MHz
    RCC->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: input
    GPIOA->CRL |= (0x4 << (0 * 4)); // Floating input
    
    // 配置门传感器引脚为输入带上拉
    GPIOA->CRL &= ~(0xF << (1 * 4)); // PA1: input
    GPIOA->CRL |= (0x8 << (1 * 4)); // Pull-up input
    GPIOA->ODR |= DOOR_SENSOR_PIN; // Enable pull-up
    
    // 配置DS1302引脚:CE、IO、SCLK为输出
    GPIOA->CRL &= ~(0xFF << (2 * 4)); // Clear PA2, PA3, PA4
    GPIOA->CRL |= (0x3 << (2 * 4)) | (0x3 << (3 * 4)) | (0x3 << (4 * 4)); // PA2, PA3, PA4: output, 50MHz
    GPIOA->ODR &= ~(DS1302_CE_PIN | DS1302_IO_PIN | DS1302_SCLK_PIN); // Set low initially
    
    // 配置温控和报警引脚为输出
    GPIOA->CRL &= ~(0xF << (5 * 4)); // PA5: output
    GPIOA->CRL |= (0x3 << (5 * 4)); // Output, 50MHz
    GPIOA->CRL &= ~(0xF << (6 * 4)); // PA6: output
    GPIOA->CRL |= (0x3 << (6 * 4)); // Output, 50MHz
    
    // 配置UART1引脚: PA9 as TX, PA10 as RX
    GPIOA->CRH &= ~(0xFF << 4); // Clear PA9 and PA10
    GPIOA->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 bit
    USART1->BRR = 72000000 / 9600; // Set baud rate
    USART1->CR1 |= USART_CR1_TE | USART_CR1_RE; // Enable TX and RX
    USART1->CR1 |= USART_CR1_UE; // Enable UART
}

void DHT22_Init(void) {
    // 初始化代码,设置引脚
    GPIO_ResetBits(DHT22_PORT, DHT22_PIN); // Set low initially
    Delay_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 high
        Delay_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 seconds
    time[0] = DS1302_ReadByte();
    DS1302_WriteByte(0x83); // Read minutes
    time[1] = DS1302_ReadByte();
    DS1302_WriteByte(0x85); // Read hours
    time[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();
    }
}

模块代码设计

c 复制代码
#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.5us
    while (us--) {
        __asm__("nop");
    }
}

// GPIO initialization
void GPIO_Init(void) {
    // Enable clock for GPIOA and GPIOB
    RCC_APB2ENR |= (1 << 2) | (1 << 3);  // GPIOA and GPIOB clock enable

    // Configure PA0 (DHT22) as output open-drain initially
    GPIOA_CRL &= ~(0xF << (DHT22_PIN * 4));
    GPIOA_CRL |= (0x3 << (DHT22_PIN * 4));  // Output mode, max speed 50MHz
    GPIOA_ODR |= (1 << DHT22_PIN);  // Set high

    // Configure PA1 (Door sensor) as input with pull-up
    GPIOA_CRL &= ~(0xF << (DOOR_SENSOR_PIN * 4));
    GPIOA_CRL |= (0x8 << (DOOR_SENSOR_PIN * 4));  // Input with pull-up/pull-down
    GPIOA_ODR |= (1 << DOOR_SENSOR_PIN);  // Pull-up

    // Configure PA2, PA3, PA4 for DS1302: PA2(CE) and PA4(SCLK) as output, PA3(IO) as input/output
    GPIOA_CRL &= ~(0xFFF << (DS1302_CE_PIN * 4));  // Clear bits for PA2, PA3, PA4
    GPIOA_CRL |= (0x3 << (DS1302_CE_PIN * 4)) | (0x3 << (DS1302_SCLK_PIN * 4));  // Output for CE and SCLK
    GPIOA_ODR &= ~(1 << DS1302_CE_PIN);  // CE low
    GPIOA_ODR &= ~(1 << DS1302_SCLK_PIN);  // SCLK low

    // For PA3(IO), set as input initially
    GPIOA_CRL |= (0x8 << (DS1302_IO_PIN * 4));  // Input with pull-up/pull-down
    GPIOA_ODR |= (1 << DS1302_IO_PIN);  // Pull-up

    // Configure PA5 (Temperature control) and PA6 (Alarm) as output
    GPIOA_CRL &= ~(0xFF << (TEMP_CTRL_PIN * 4));
    GPIOA_CRL |= (0x3 << (TEMP_CTRL_PIN * 4)) | (0x3 << (ALARM_PIN * 4));  // Output
    GPIOA_ODR &= ~(1 << TEMP_CTRL_PIN);  // Off initially
    GPIOA_ODR &= ~(1 << ALARM_PIN);  // Off initially

    // Configure PA9 (USART1 TX) as alternate function output, PA10 (USART1 RX) as input
    GPIOA_CRH &= ~(0xFF << ((ESP8266_TX_PIN - 8) * 4));
    GPIOA_CRH |= (0xB << ((ESP8266_TX_PIN - 8) * 4));  // AF output for TX
    GPIOA_CRH |= (0x4 << ((ESP8266_RX_PIN - 8) * 4));  // Input floating for RX
}

// USART1 initialization for ESP8266
void USART1_Init(void) {
    // Enable clock for USART1
    RCC_APB2ENR |= (1 << 14);  // USART1 clock enable

    // Configure USART1: 9600 baud, 8 data bits, no parity, 1 stop bit
    USART1_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 TXE
    USART1_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 mode
    GPIOA_ODR &= ~(1 << DHT22_PIN);  // Pull low
    Delay_ms(1);  // Wait 1ms
    GPIOA_ODR |= (1 << DHT22_PIN);  // Pull high
    Delay_us(30);  // Wait 30us
    GPIOA_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 low
        if (timeout++ > DHT22_TIMEOUT) return 0;
        Delay_us(1);
    }
    timeout = 0;
    while (!(GPIOA_IDR & (1 << DHT22_PIN))) {  Wait for high
        if (timeout++ > DHT22_TIMEOUT) return 0;
        Delay_us(1);
    }
    timeout = 0;
    while (GPIOA_IDR & (1 << DHT22_PIN)) {  Wait for low again
        if (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 high
        if (timeout++ > DHT22_TIMEOUT) return 0;
        Delay_us(1);
    }
    Delay_us(40);  // Wait 40us
    if (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();
    }
    // Checksum
    if (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 mode
    for (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 high
        Delay_us(1);
        GPIOA_ODR &= ~(1 << DS1302_SCLK_PIN);  // SCLK low
        Delay_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 mode
    for (int i = 0; i < 8; i++) {
        byte >>= 1;
        if (GPIOA_IDR & (1 << DS1302_IO_PIN)) byte |= 0x80;
        GPIOA_ODR |= (1 << DS1302_SCLK_PIN);  // SCLK high
        Delay_us(1);
        GPIOA_ODR &= ~(1 << DS1302_SCLK_PIN);  // SCLK low
        Delay_us(1);
    }
    return byte;
}

void DS1302_Write_Register(uint8_t reg, uint8_t data) {
    GPIOA_ODR |= (1 << DS1302_CE_PIN);  // CE high
    DS1302_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 high
    DS1302_Write_Byte(reg | 0x01);  // Read command
    uint8_t data = DS1302_Read_Byte();
    GPIOA_ODR &= ~(1 << DS1302_CE_PIN);  // CE low
    return data;
}

void DS1302_Init(void) {
    // Disable write protection
    DS1302_Write_Register(0x8E, 0x00);
    // Enable clock
    DS1302_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 credentials
    Delay_ms(5000);
    USART1_SendString("AT+CIPSTART=\"TCP\",\"192.168.1.100\",8080\r\n");  // Replace with Huawei Cloud IP and port
    Delay_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 interrupts
    SYST_RVR = 8000 - 1;  // Reload value for 1ms at 8MHz
    SYST_CVR = 0;
    SYST_CSR = (1 << 2) | (1 << 0);  // Processor clock, enable

    GPIO_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 control
            if (temperature > TEMP_THRESHOLD_HIGH || humidity > HUMIDITY_THRESHOLD_HIGH) {
                Temp_Ctrl_On();
                Alarm_On();
            } else {
                Temp_Ctrl_Off();
                Alarm_Off();
            }

            // Send data to cloud
            ESP8266_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 locally
                last_door状态 = door状态;
            }
        }
        Delay_ms(5000);  // Read every 5 seconds
    }
}

项目核心代码

c 复制代码
#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 clock
    RCC_APB2ENR |= (1 << 2);
    
    // Configure PA2 and PA3 as output push-pull, 50MHz
    GPIOA_CRL &= ~(0xF << 8);   // Clear bits for PA2
    GPIOA_CRL |= (0x3 << 8);    // Set PA2 to output push-pull
    GPIOA_CRL &= ~(0xF << 12);  // Clear bits for PA3
    GPIOA_CRL |= (0x3 << 12);   // Set PA3 to output push-pull
}

// USART1 initialization for ESP8266
void USART1_Init(void) {
    // Enable USART1 clock
    RCC_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 receiver
    USART1_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 hardware
    GPIO_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 sensors
        DHT22_Read(&temp, &humidity);
        door_status = DoorSensor_Read();
        DS1302_GetTime(time_str);
        
        // Control logic
        if (temp > 30.0 || humidity > 80.0) {
            Fan_On();
            Alarm_On();
        } else {
            Fan_Off();
            Alarm_Off();
        }
        
        // Prepare data string
        char 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 cloud
        ESP8266_SendData(data);
        
        // Delay
        Delay();
    }
}

总结

本系统基于STM32F103C8T6微控制器,成功设计并实现了一个智能医疗药品存储柜,核心功能包括实时监测柜内温湿度及门开关状态,确保药品存储环境符合标准,并在温湿度超标时自动启动温控设备和报警机制,从而保障药品的安全与有效性。

硬件组成上,系统采用了DHT22温湿度传感器进行环境数据采集,干簧管门磁传感器检测门状态,DS1302时钟模块记录精确时间信息,ESP8266-01S Wi-Fi模块实现与华为云平台的稳定通信,所有组件通过洞洞板焊接的信号处理电路和杜邦线连接,确保了系统的可靠性和易维护性。

软件方面,通过华为云平台集成,系统实现了环境数据和药品存取记录的上传与存储,QT上位机应用提供了友好的用户界面,支持药品管理、历史数据查询和报警信息处理,大大提升了系统的智能化水平和操作便利性。

总体而言,该系统将嵌入式硬件、云平台和上位机软件有机结合,为医疗药品存储提供了一套高效、可靠的解决方案,具有广泛的应用前景和推广价值。

项目核心代码

c 复制代码
#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  // PA3

void SystemInit(void) {
    // 启用HSE并配置PLL为72MHz
    RCC_CR |= (1 << 16);  // 启用HSE
    while (!(RCC_CR & (1 << 17)));  // 等待HSE就绪
    RCC_CFGR |= (1 << 16);  // PLL源为HSE
    RCC_CFGR |= (9 << 18);  // PLL倍频9倍,HSE 8MHz * 9 = 72MHz
    RCC_CR |= (1 << 24);  // 启用PLL
    while (!(RCC_CR & (1 << 25)));  // 等待PLL就绪
    RCC_CFGR |= (2 << 0);  // 切换系统时钟到PLL
    while ((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);    // 推挽输出,50MHz
    GPIOA_CRL &= ~(0xF << 12);  // 清除PA3配置
    GPIOA_CRL |= (0x3 << 12);   // 推挽输出,50MHz

    // 配置PA9为USART1 TX(复用推挽输出),PA10为USART1 RX(输入浮空)
    GPIOA_CRH &= ~(0xF << 4);   // 清除PA9配置
    GPIOA_CRH |= (0xB << 4);    // 复用推挽输出,50MHz
    GPIOA_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 -> 0x1D4C
    USART1_CR1 |= (1 << 13);  // 启用USART
    USART1_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上位机软件的交互,便于药品管理、历史数据查询和报警处理,增强了用户体验和操作便利性。

总体而言,该系统结合了嵌入式技术、物联网云平台和上位机软件,为医疗行业提供了一种高效、可靠的药品存储解决方案,具有较高的实用价值和推广前景。

相关推荐
lypzcgf6 小时前
Coze源码分析-API授权-删除令牌-后端源码
数据库·人工智能·后端·系统架构·开源·go·安全架构
一伦明悦დ6 小时前
jetson开发板Ubuntu系统Docker中使用 MySQL 数据库详解-安装与配置指南
数据库·mysql·ubuntu
猫猫的小茶馆7 小时前
【STM32】贪吃蛇 [阶段 8] 嵌入式游戏引擎通用框架设计
stm32·单片机·嵌入式硬件·mcu·物联网·游戏引擎·智能硬件
学Java的bb7 小时前
后端Web实战-多表操作&员工列表查询
数据库
2301_781392527 小时前
Spring框架入门:从IoC到AOP
java·数据库·spring
yBmZlQzJ8 小时前
在PostgreSQL中使用分区技术
数据库·postgresql
我有一颗五叶草8 小时前
MySQL 体系结构
数据库·mysql
久绊A9 小时前
阿里云OSS架构示意图与流程
数据库·阿里云·oss
v_for_van9 小时前
TFT屏幕:STM32硬件SPI+DMA+队列自动传输
笔记·stm32·单片机·嵌入式硬件·mcu·物联网·学习