項目開發背景
隨著現代醫療技術的快速發展,藥品的安全存儲與管理成為醫療質量控制中的重要環節。許多藥品對存儲環境的溫濕度具有嚴格的要求,一旦超出允許范圍,藥品的理化性質可能發生改變,甚至失效,直接影響患者的用藥安全與治療效果。然而,傳統的藥品存儲柜大多依賴人工巡檢和記錄,存在效率低、誤差大、實時性差等問題,難以滿足日益嚴格的藥品管理規范。
在此背景下,物聯網技術的興起為藥品存儲管理提供了新的解決方案。通過傳感器實時采集環境數據,結合無線通信技術將信息上傳至云平臺,能夠實現對藥品存儲狀態的遠程監控與智能預警。這不僅大大提高了藥品管理的自動化水平和數據準確性,也為醫療機構降低了人為管理成本與風險。
本項目基于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上位機軟件的交互,便于藥品管理、歷史數據查詢和報警處理,增強了用戶體驗和操作便利性。
總體而言,該系統結合了嵌入式技術、物聯網云平臺和上位機軟件,為醫療行業提供了一種高效、可靠的藥品存儲解決方案,具有較高的實用價值和推廣前景。