基于物联网技术的智慧病房管理系统(二)—— RTOS、AHT20 与 按钮功能实现

基于物联网技术的智慧病房管理系统(二)—— RTOS、AHT20 与 按钮功能实现

这里 RTOS 代码修改,AHT20 驱动代码移植可以参考前面博客内容:

  1. STM32 —— IIC 读取 ATH20(DTH20)温度传感器

  2. STM32 —— RT-Thread Nano 移植

这里主要介绍使用和按键相关内容

温湿度获取代码设计

首先我们需要引入温湿度驱动头文件:

#include "AHT20.h"

然后我们需要在进程中对温湿度传感器进行初始化,这里在初始化之后,不能立即获取温湿度,需要等待 2 秒或以上,确保数据正确性:

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);

然后我们需要获取经过 CRC 验证的温湿度数据,这里直接调用驱动函数即可:

	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 进程设计

首先新建 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"

然后我们需要设计进程,这里主进程先设置为串口发送,子进程设置两个,一个是获取温度参数,另一个是控制 PC13 引脚上的板载 LED ,后续会根据系统进程对进行设计:

//初始化线程函数
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");
	}
}

这里直接给出完整代码如下:

点击查看完整 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"
 
struct rt_thread led1_thread;
struct rt_thread usart1_thread;
rt_uint8_t rt_led1_thread_stack[128];
rt_uint8_t rt_usart1_thread_stack[256];
void led1_task_entry(void *parameter);
void usart1_task_entry(void *parameter);

int fputc(int ch,FILE *f)
{
    HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);    
		//等待发送结束	
		while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_TC)!=SET){
		}		
    return ch;
}
 
//初始化线程函数
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");
	}
}

然后我们在主函数中引入 RT-Thread 必要的头文件并引用函数:

#include "rtthread.h"

extern void MX_RT_Thread_Init(void);
extern void MX_RT_Thread_Process(void);

最后我们直接在主函数中对进程进行初始化,并运行即可,这里直接给出完整主函数:

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 */
}

按钮的使用与消抖

首先我们设计按钮在 PA3 引脚,然后在设置 PA4 引脚上外接一个 LED ,这里先令按钮按下反转 PA4 引脚电平,即按下小灯泡点亮,再次按下,小灯泡熄灭,这里直接设计为一个新进程:

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&&(KEY1==0))
	{
		HAL_Delay(10);//去抖动
		key_up=0;
		if(KEY1==0)return KEY1_PRES;
	}
	else if(KEY1==1)key_up=1;
 	return 0;//无按键按下
}

由于我们整个系统是通过仿真模拟的形式进行测试,所以这里使用常规按键输入判断在 Proteus 中反应不够灵敏,所以这里采用中断的形式来实现按钮的效果,即按键触发外部中断:

这里我们需要将按钮设置好的 GPIO_Input 改为 GPIO_EXIT :


然后设计相关代码:

首先需要重写中断函数,这里可以看我们前面的博客:

STM32 —— 中断1 点灯

这里直接给出代码:

__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(GPIO_Pin);
  /* NOTE: This function Should not be modified, when the callback is needed,
           the HAL_GPIO_EXTI_Callback could be implemented in the user file
   */
	
	if(GPIO_Pin == GPIO_PIN_3){
		if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_3) == 0){
			HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_4);
		}
	}
}

现在我们的按键就灵敏好用了,这里要求是获取病人按下紧急呼叫按钮的信息,这里我们将按钮控制灯亮扩展到三个按钮和三个灯:


__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(GPIO_Pin);
  /* NOTE: This function Should not be modified, when the callback is needed,
           the HAL_GPIO_EXTI_Callback could be implemented in the user file
   */
	switch(GPIO_Pin){
		case GPIO_PIN_3:{
			HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_13);
			break;
		}
		case GPIO_PIN_4:{
			HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_14);
			break;
		}
		case GPIO_PIN_5:{
			HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_15);
			break;
		}
	}
}

这样我们就完成了对 RTOS 移植,AHT20 温湿度数据获取和按键功能的实现。

posted @ 2023-01-12 01:20  ppqppl  阅读(73)  评论(0编辑  收藏  举报