一、绪论
1.项目背景
为解决因国家政策开放后,部分中老年人因抵抗力下降且疫情迅速传播导致的医院人数爆满的问题,现基于stm32开发板以及物联网嵌入式开发等相关技术,研发一款智慧病房项目,可以实时监控病人的生命体征和身体情况,以及病人紧急呼叫和方便管理的定时开关等系统,从而达到减轻医务人员压力的目的。
2.项目需求
设计一个基于物联网技术的智慧病房管理系统。假设医院住院部的一层病房(走廊两边病房平行分布),病房数量最多60间,每间病房3个床位,编号从1~180号。每间病房可采用的设备如下:STM32F103开发板1块,房间温湿度采集模块1套(I2C接口,AHT20模块),房间自动灯光开关控制器(以PWM方式控制,每天早上7点渐亮,晚上22点渐灭),病人脉搏&血氧检测仪3套(UART接口输出脉搏+血氧的数字值),床头紧急呼叫按键开关3个(按下呼叫)。每间病房的STM32F103开发板通过UART转485接口,以mobus组网方式,连接到护士监控室的PC电脑上(上位机)。PC电脑上可接收每间病房的温湿度数据(周期为5分钟)、床头紧急呼叫信号、病人脉搏血氧数据(正常状态下30分钟一次采集;当脉搏超过120或血氧值低于90时切换到危重状态下,实时采集),显示在屏幕上并且保存到MySQL数据库里。
注意:考虑到硬件设备不齐全,联网资源不具备,只须撰写较为完整,合理的系统设计方案,不须编程实现整个系统。各模块接口协议,通信参数(如任务周期数、串口波特率、modbus数据格式均可以自定义,合理即可),主要模块实现代码可以利用之前课程作业的完成代码进行阐述。
3.设计要求:
1、写出系统设计方案,画出系统功能图
2、画出病房stm32f103控制模块的电路原理图。
3、设计各功能模块的模拟实现软件,给出主要源代码
4、总结本系统方案的技术优势和代码特点
二、设计方案及系统功能图
1.每间病房的STM32F103开发板通过UART转485接口,以mobus组网方式,连接到护士监控室的PC电脑上:这需要得功能是UART转485接口并与modbus进行通信。
2.PC 电脑上可接收每间病房的温湿度数据(周期为 5 分钟):这需要使用I2C完成AHT20模块也就是温湿度读取模块。
3.床头紧急呼叫信号:这需要完成的功能是按键消息得接收。
4.病人脉搏血氧数据:这需要完成的是血氧和心率采集模块。
三、实验过程
1.CubeMX基本配置
RCC配置
SYS配置
USART1 与 DMA 配置
I2C配置
TIM3配置
TM2与 PWM配置
NVIC配置
GPIO配置
时钟配置
RTOS 配置
引入 RT-Thread
外部按钮配置
2.源代码
温湿度检测模块:
在这里需要引入温度驱动头文件:
#include "AHT20.h"
其次我们进行温度模块的初始化
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的温度和湿度数据 推荐每隔大于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 进程设计
引入头文件
#include “rtthread.h”
#include “main.h”
#include “i2c.h”
#include “usart.h”
#include “gpio.h”
#include “stdio.h”
#include “AHT20.h”
设计进程
//初始化线程函数
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的温度和湿度数据 推荐每隔大于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");
}
}
主函数
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(); // 执行主进程
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
按钮操作:
struct rt_thread btnclick_thread;
rt_uint8_t rt_btnclick_thread_stack[128];
void btnclick_task_entry(void *parameter);
void btnclick_task_entry(void *parameter){
while(1){
switch(KEY_Scan(0))
{
case KEY1_PRES:
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_4);
break;
default:
break;
}
}
}
初始化线程:
rt_thread_init(&btnclick_thread,“btnclick”,btnclick_task_entry,RT_NULL,&rt_btnclick_thread_stack[0],sizeof(rt_btnclick_thread_stack),3,20);
//开启线程调度
rt_thread_startup(&btnclick_thread);
按键消抖:
#define KEY1 HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) //读取按键1
#define KEY1_PRES 1 //KEY1按下
uint8_t KEY_Scan(uint8_t mode)
{
static uint8_t key_up=1;//按键松开标志位
if(key_up&&(KEY10))
{
HAL_Delay(10);//去抖动
key_up=0;
if(KEY10)return KEY1_PRES;
}
else if(KEY1==1)key_up=1;
return 0;//无按键按下
}
定时开关灯模块:
首先设置占空比
unit16_t pwm=0;
然后打开pwm通道:
HAL_TIM__PwM__start(&htim3,TIM_CHANNEL_1);
然后通过内部时钟读取来控制led灯的亮灭
HAL_RTC_GetDate(&hrtc,&GetData,RTC_FORMAT_BIN);
(GetTime. Hours==7 && pwm < 500 )
pwm++;
__HAL_TIM_Setcompare(&htim3,TIM_CHANNEL_1,pwm);
HAL_Delay(1);
}
while (GetTime. Hours==22 &&pwm )
{
pwm--;
__HAL_TIM_setcompare(&htim3,TIM_CHANNEL_1,pwm);
HAL_Delay(1);
}
紧急呼叫模块:
通过设置一个按钮和一个led灯,当按钮按下时反转led灯的电平,由按钮来控制led灯的亮灭,从而达到紧急呼叫的作用。
struct rt_thread btnclick_thread;
rt_uint8_t rt_btnclick_thread_stack[128];
void btnclick_task_entry(void *parameter);
void btnclick_task_entry(void *parameter){
while(1){
switch(KEY_Scan(0))
{
case KEY1_PRES:
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_4);
break;
default:
break;
}
}
}
五、总结
本系统的硬件部分由AHT20温湿度采集设备和脉搏血样检测仪组成,实现了对房间灯光的定时控制,对病房的温湿度采集和紧急呼叫模块的功能。,本系统是基于stm32的智慧病房系统,STM32的优势在于:高性能;低成本;低功耗;拓展性强。由于stm32开发板的拓展性强,因此还可以添加其他功能,如实时监测病人体温等。
本次实验运用了本学期嵌入式课程所学到的很多重要内容,例如RTC的使用,串口通信等,但由于本项目是设计方案,并不能切实完成系统设计,因此在功能设计以及代码部分仍然有许多可改进的地方。虽然未做出一个完整的系统,但本次项目也锻炼了我的综合实践能力,使我本学期所学得到了充分运用。