基于嵌入式物联网技术的智慧病房方案设计
文章目錄
- 前言
- 一、系統(tǒng)設計要求
- 二、系統(tǒng)硬件設計
- 單片機控制電路
- AHT20模塊
- 心率脈搏采集模塊
- MOBUS通信模塊
- 三、系統(tǒng)功能分析與STM32F103基本配置
- 基本配置如下
- 四 主要代碼設計
- 溫濕度獲取代碼設計
- RTOS 進程設計
- 定時開關
- 技術總結與分析
前言
隨著社會經濟的發(fā)展和城市化的加速發(fā)展,物聯(lián)網技術已經逐步進入各個領域,在許多方面都有著重要的作用。而近些年來,物聯(lián)網技術也逐漸的進入了醫(yī)療領域。其中智慧病房作為智慧醫(yī)療的細分領域,以輔助醫(yī)療供給為目標,通過打造院內物聯(lián)網,讓患者與醫(yī)護人員的互動,通過物聯(lián)醫(yī)療設備緊密聯(lián)系。這同時也是醫(yī)院信息化程度提升的一個標志。通過病房的實體設施在線化與醫(yī)療信息系統(tǒng)數(shù)字化聯(lián)動,醫(yī)護人員不用守在病患身邊,也能提供實時服務。為醫(yī)護人員減負,利用物聯(lián)網提升醫(yī)療服務質量,改善醫(yī)患關系。
因此,設計基于嵌入式物聯(lián)網技術的智慧病房,能很好的為醫(yī)生和患者提供幫助。
一、系統(tǒng)設計要求
設計一個基于物聯(lián)網技術的智慧病房管理系統(tǒng)。假設醫(yī)院住院部的一層病房(走廊兩邊病房平行分布),病房數(shù)量最多60間,每間病房3個床位,編號從1~180號。每間病房可采用的設備如下:STM32F103開發(fā)板1塊,房間溫濕度采集模塊1套(I2C接口,AHT20模塊),房間自動燈光開關控制器(以PWM方式控制,每天早上7點漸亮,晚上22點漸滅),病人脈搏&血氧檢測儀3套(UART接口輸出脈搏+血氧的數(shù)字值),床頭緊急呼叫按鍵開關3個(按下呼叫)。
每間病房的STM32F103開發(fā)板通過UART轉485接口,以mobus組網方式(mobus協(xié)議不熟悉的話,可以直接視之為一個自定義數(shù)據(jù)包格式的串口通信)連接到護士監(jiān)控室的PC電腦上(上位機)。PC電腦上可接收每間病房的溫濕度數(shù)據(jù)(周期為5分鐘)、床頭緊急呼叫信號、病人脈搏血氧數(shù)據(jù)(正常狀態(tài)下30分鐘一次采集;當脈搏超過120或血氧值低于90時切換到危重狀態(tài)下,實時采集),顯示在屏幕上并且保存到MySQL數(shù)據(jù)庫里。
二、系統(tǒng)硬件設計
智慧病房的設計的硬件主要由以下五部分構成,即單片機控制模塊、AHT20模塊、心率脈搏采集模塊、通信模塊和上位機。單片機控制模塊負責對整體數(shù)據(jù)進行處理,并且根據(jù)指令對系統(tǒng)消息進行處理;AHT20模塊負責接收收集溫濕度信息;MOBUS通信模塊負責將信息發(fā)給PC機;MAX30102模塊負責采集病人的信息。
系統(tǒng)框圖
單片機控制電路
系統(tǒng)單片機采用了STM32F103。 STM32F103具有功耗低,性能高的優(yōu)點。STM32F1系列屬于中低端的32位ARM微控制器,該系列芯片是意法半導體(ST)公司出品,其內核是Cortex-M3。芯片集成定時器Timer,CAN,ADC,SPI,I2C,USB,UART等多種外設功能。存儲器有從16K到512K字節(jié)的閃存程序存儲器。而且內部有著睡眠、停機和待機模式。滿足了防丟失器對讀寫速度和功耗的要求。
AHT20模塊
AHT20是國內奧松生成的I2C接口的MEMS溫濕度傳感器,ADC位數(shù)為20Bit,具有體積小、精度高、成本低等優(yōu)點。AHT20 配有一個全新設計的 ASIC專用芯片、一個經過改進的MEMS半導體電容式濕度傳感元件和一個標準的片上溫度傳感元件,其性能已經大大提升甚至超出了前一代傳感器的可靠性水平,新一代溫濕度傳感器,經過改進使其在惡劣環(huán)境下的性能更穩(wěn)定。
AHT20原理圖
心率脈搏采集模塊
MAX30102是一個集成的脈搏血氧儀和心率監(jiān)測儀生物傳感器的模塊(芯片)。它集成了一個660nm紅光LED、880nm紅外光LED、光電檢測器、光器件,以及帶環(huán)境光抑制的低噪聲電子電路。可通過軟件關斷模塊,待機電流為零,實現(xiàn)電源始終維持供電狀態(tài),可運用于低功耗產品中。
MAX30102采用一個1.8V電源和一個獨立的3.3V用于內部LED的電源,標準的I2C兼容的通信接口。市面很多都將MAX30102芯片集成在一個PCB模塊上,內部增加一個1.8V和3.3V LDO穩(wěn)壓電路,可對模塊單獨供5.0V電源,方便開發(fā)者進行開發(fā)。
引腳圖
芯片內部有3.3V-5.0V的LED電源和1.8V的邏輯電源,所以模塊帶有兩路穩(wěn)壓電路,將5V電源分別轉化為3.3V和1.8V;由于LED驅動電源的供電范圍為3.3V-5.0V,3.3V穩(wěn)壓電路可省去。
由于MAX30102的邏輯電路的IIC通信電平為1.8V,這與我們常用的51單片機和STM32單片機的引腳電平不匹配。
這里有個解決方法,因為MAX30102的SDA、SCL、INT引腳為開漏,可以將模塊上的R1、R2、R3電阻去掉,對于51單片機來說,在SDA、SCL、INT引腳上分別加一個4.7-10k電阻上拉至5V;對于STM32單片機,只需要將相應的控制引腳配置為上拉模式即可。
模塊只需要接上5V電源,SDA、SCL、INT引腳與單片機連接即可;IRD、RD一般不接,以STM32單片機接線為例(單片機采用模擬IIC的控制方式)
MOBUS通信模塊
max485是美信(maxim)推出的一款常用rs485轉換器。其中5腳和8腳是引腳,6腳和7腳就是485通信中的a和b兩個引腳,而1腳和4腳分別接到我們單片機的rxd和txd引腳上,直接使用單片機uart進行數(shù)據(jù)接收和發(fā)送。而2腳和3腳就是方向引腳了,其中2腳是低電平使能接收器,3腳是高電平使能輸出驅動器。我們把這兩個引腳連到一起,平時不發(fā)送數(shù)據(jù)的時候,保持這兩個引腳是低電平,讓max485處于接收狀態(tài),當需要發(fā)送數(shù)據(jù)的時候,把這個引腳拉高,發(fā)送數(shù)據(jù),發(fā)送完畢后再拉低這個引腳就可以了。為了提高rs485的抗干擾性能,需要在靠近max485的a和b引腳之間并接一個電阻,這個電阻阻值從100歐到1k都可以。
三、系統(tǒng)功能分析與STM32F103基本配置
根據(jù)分析我們需要使用如下幾種功能:
1.使用 I2C 讀取 AHT20 模塊
2.TIM 定時器與 PWM 呼吸燈
3.按鍵信息接收與消抖
4.UART 轉 485 接口與 modbus 通信
5.MAX30102 模塊心率與血氧測量
基本配置如下
RCC 配置
SYS 配置
USART1 與 DMA 配置
I2C 配置
TIM3 配置
DMA 配置
TIM2 與 PWM 配置
NVIC 配置
GPIO 配置
時鐘配置
引腳配置
RTOS 配置
這里選擇引入 RT-Thread 輕量便捷 :
外部按鈕配置
四 主要代碼設計
溫濕度獲取代碼設計
首先我們需要引入溫濕度驅動頭文件:
#include "AHT20.h"然后我們需要在進程中對溫濕度傳感器進行初始化,這里在初始化之后,不能立即獲取溫濕度,需要等待 2 秒或以上,確保數(shù)據(jù)正確性:
MX_GPIO_Init(); MX_I2C1_Init(); MX_USART1_UART_Init(); uint32_t CT_data[2]={0,0}; // 用于獲取溫濕度數(shù)據(jù) volatile int c1,t1; rt_thread_delay(50); AHT20_Init(); rt_thread_delay(2500);然后我們需要獲取經過 CRC 驗證的溫濕度數(shù)據(jù),這里直接調用驅動函數(shù)即可:
while(1){AHT20_Read_CTdata_crc(CT_data); //經過CRC校驗,讀取AHT20的溫度和濕度數(shù)據(jù) 推薦每隔大于1S讀一次c1 = CT_data[0]*1000/1024/1024; //計算得到濕度值c1(放大了10倍)t1 = CT_data[1]*2000/1024/1024-500;//計算得到溫度值t1(放大了10倍)printf("正在檢測");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");printf("\r\n");printf("溫度:%d%d.%d",t1/100,(t1/10)%10,t1%10); // 這里需要對溫度進行計算后才能得到我們需要的溫度值printf("濕度:%d%d.%d",c1/100,(c1/10)%10,c1%10); // 這里同樣需要對適度進行計算printf("\r\n");printf("等待");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");printf("\r\n");}RTOS 進程設計
首先新建 app_rt_thread.c 文件,然后引入頭文件:
#include "rtthread.h" #include "main.h" #include "i2c.h" #include "usart.h" #include "gpio.h" #include "stdio.h" #include "AHT20.h"然后我們需要設計進程,這里主進程先設置為串口發(fā)送,子進程設置兩個,一個是獲取溫度參數(shù),另一個是控制 PC13 引腳上的板載 LED ,后續(xù)會根據(jù)系統(tǒng)進程對進行設計:
//初始化線程函數(shù) void MX_RT_Thread_Init(void) {//初始化LED1線程rt_thread_init(&led1_thread,"led1",led1_task_entry,RT_NULL,&rt_led1_thread_stack[0],sizeof(rt_led1_thread_stack),3,20);//開啟線程調度rt_thread_startup(&led1_thread);//初始化USART1線程rt_thread_init(&usart1_thread,"usart1",usart1_task_entry,RT_NULL,&rt_usart1_thread_stack[0],sizeof(rt_usart1_thread_stack),3,20);//開啟線程調度rt_thread_startup(&usart1_thread); }//主任務 void MX_RT_Thread_Process(void) {printf("Hello RT_Thread!!!\r\n");rt_thread_delay(2000); }//LED1任務 void led1_task_entry(void *parameter) {while(1){HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13, GPIO_PIN_RESET);rt_thread_delay(500);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13, GPIO_PIN_SET);rt_thread_delay(500);} } //讀取溫度任務 void usart1_task_entry(void *parameter) {MX_GPIO_Init();MX_I2C1_Init();MX_USART1_UART_Init();uint32_t CT_data[2]={0,0}; //volatile int c1,t1;rt_thread_delay(50);AHT20_Init();rt_thread_delay(2500);while(1){AHT20_Read_CTdata_crc(CT_data); //經過CRC校驗,讀取AHT20的溫度和濕度數(shù)據(jù) 推薦每隔大于1S讀一次c1 = CT_data[0]*1000/1024/1024; //計算得到濕度值c1(放大了10倍)t1 = CT_data[1]*2000/1024/1024-500;//計算得到溫度值t1(放大了10倍)printf("正在檢測");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");printf("\r\n");printf("溫度:%d%d.%d",t1/100,(t1/10)%10,t1%10); // 這里需要對溫度進行計算后才能得到我們需要的溫度值printf("濕度:%d%d.%d",c1/100,(c1/10)%10,c1%10); // 這里同樣需要對適度進行計算printf("\r\n");printf("等待");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");rt_thread_delay(100);printf(".");printf("\r\n");} }然后我們在主函數(shù)中引入 RT-Thread 必要的頭文件并引用函數(shù):
#include "rtthread.h"extern void MX_RT_Thread_Init(void); extern void MX_RT_Thread_Process(void);最后我們直接在主函數(shù)中對進程進行初始化,并運行即可,這里直接給出完整主函數(shù)
int main(void) {/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_DMA_Init();MX_I2C1_Init();MX_TIM3_Init();MX_USART1_UART_Init();MX_TIM2_Init();/* USER CODE BEGIN 2 */MX_RT_Thread_Init(); // 初始化線程/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){MX_RT_Thread_Process(); // 執(zhí)行主進程/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */ }定時開關
這里要求我們能夠實現(xiàn)在早上 7 點開燈,晚上 22 點滅燈,所以我們就要設計 RTC 系統(tǒng)時間與日歷讀取,確定我們當前的時間與日期,然后判斷時間數(shù),最終通過 PWM 實現(xiàn)燈的漸亮與漸滅
這里先設置兩個變量用于獲取時間和日期:
RTC_DateTypeDef Date;
RTC_TimeTypeDef Time;
然后我們可以通過時間進行判斷從而實現(xiàn)開關燈的效果:
void ledauto_task_entry(void *parameter){HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);while(1){HAL_RTC_GetTime(&hrtc,&Time,RTC_FORMAT_BIN);if(Time.Hours == 7&&Time.Minutes == 0&&Time.Seconds == 0){printf("開燈!");for(uint16_t i=1;i<500;i++){htim2.Instance->CCR2 = i;rt_thread_delay(5);}}else if(Time.Hours == 22&&Time.Minutes == 0&&Time.Seconds == 0){printf("關燈!");for(uint16_t i=499;i>=1;i--){htim2.Instance->CCR2 = i;rt_thread_delay(5);}}} }由于開發(fā)板掉電,時間會重置,所以這里設計時間掉電保存,如果使用外接 RTC 并有電池,則會在掉電后繼續(xù)計時,這里我設計將代碼直接寫道 RTC 初始化的函數(shù)中即可,完整初始化代碼如下:
void MX_RTC_Init(void) {/* USER CODE BEGIN RTC_Init 0 *//* USER CODE END RTC_Init 0 */RTC_TimeTypeDef sTime = {0};RTC_DateTypeDef DateToUpdate = {0};/* USER CODE BEGIN RTC_Init 1 */__HAL_RCC_BKP_CLK_ENABLE();// 開啟后背區(qū)域時鐘__HAL_RCC_PWR_CLK_ENABLE();// 開啟電源時鐘/* USER CODE END RTC_Init 1 *//** Initialize RTC Only*/hrtc.Instance = RTC;hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;hrtc.Init.OutPut = RTC_OUTPUTSOURCE_NONE;if (HAL_RTC_Init(&hrtc) != HAL_OK){Error_Handler();}/* USER CODE BEGIN Check_RTC_BKUP */if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1)!= 0x5051){/* USER CODE END Check_RTC_BKUP *//** Initialize RTC and set the Time and Date*/sTime.Hours = 0x7;sTime.Minutes = 0x0;sTime.Seconds = 0x0;if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK){Error_Handler();}DateToUpdate.WeekDay = RTC_WEEKDAY_THURSDAY;DateToUpdate.Month = RTC_MONTH_JANUARY;DateToUpdate.Date = 0x12;DateToUpdate.Year = 0x23;if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BCD) != HAL_OK){Error_Handler();}/* USER CODE BEGIN RTC_Init 2 */__HAL_RTC_SECOND_ENABLE_IT(&hrtc,RTC_IT_SEC); //開啟RTC時鐘秒中斷datebuff = DateToUpdate; //把日期數(shù)據(jù)拷貝到自己定義的data中HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0x5051);//向指定的后備區(qū)域寄存器寫入數(shù)據(jù)HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, (uint16_t)datebuff.Year);HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR3, (uint16_t)datebuff.Month);HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR4, (uint16_t)datebuff.Date);HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR5, (uint16_t)datebuff.WeekDay);}else{datebuff.Year = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR2);datebuff.Month = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR3);datebuff.Date = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR4);datebuff.WeekDay = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR5);DateToUpdate = datebuff;if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK){Error_Handler();}__HAL_RTC_SECOND_ENABLE_IT(&hrtc,RTC_IT_SEC); //開啟RTC時鐘秒中斷 }getRealTime();/* USER CODE END RTC_Init 2 */}然后我們需要在運行時,實時獲取一次時間:
void getRealTime(void) {HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BIN);HAL_RTC_GetDate(&hrtc, &datebuff, RTC_FORMAT_BIN);HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, (uint16_t)datebuff.Year);HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR3, (uint16_t)datebuff.Month);HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR4, (uint16_t)datebuff.Date);HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR5, (uint16_t)datebuff.WeekDay); }void HAL_RTCEx_RTCEventCallback(RTC_HandleTypeDef *hrtc) {if(hrtc->Instance == RTC){getRealTime(); } }這部分代碼要寫在初始化代碼前面
這樣我們就實現(xiàn)了定時開關燈
技術總結與分析
本文通過STM32較為詳細的分析了如何設計出智能病房管理系統(tǒng),該系統(tǒng)設計方案簡單清晰,所選外設電路價格適中,質量較好,易于系統(tǒng)的實現(xiàn),該系統(tǒng)設計的可執(zhí)行性還是比較高的。設計方案采用代碼清晰詳盡,較好的為系統(tǒng)的實現(xiàn)提供了技術基礎。
在生活需求已得到基本滿足的今天,人們對于醫(yī)療衛(wèi)生服務的要求也越來越高,而物聯(lián)網技術的出現(xiàn),滿足了人民群眾關注自身健康的需要,推動了醫(yī)療衛(wèi)生信息化產業(yè)的發(fā)展。物聯(lián)網技術在醫(yī)療領域的應用潛力巨大,能夠幫助醫(yī)院實現(xiàn)對人的智慧化醫(yī)療和對物的智慧化管理工作,能夠滿足醫(yī)療健康信息、醫(yī)療設備與用品、公共衛(wèi)生安全的智能化管理與監(jiān)控等方面的需求,從而解決醫(yī)療平臺支撐薄弱、醫(yī)療服務水平整體較低、醫(yī)療安全生產隱患等問題。在服務內容上,物聯(lián)網智慧病房的出現(xiàn),更是意義重大。因此,此次設計除了復習到了嵌入式的相關知識外,還對物聯(lián)網技術有了一定的了解。
總結
以上是生活随笔為你收集整理的基于嵌入式物联网技术的智慧病房方案设计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《非洲猫科》观后感
- 下一篇: 在Github上进行合作开发