预警器件控制思考

预警器件控制思考

最小示例思想

当读取到环境信息与环境阈值的时候, 我们预警系统就要根据这些信息做出判断,是否要启动器件。

image-20240801174851481

最简单的就是, 举温度temp的例子, temp(温度)与temp_th(阈值), 通过判断, 得出是否要启动器件.

image-20240802061601931

如果在一段时间内, 一直是环境异常, 我们那只需要启动一次器件就可以了, 按照上面的方法, 就会一直重复启动器件. 所以我们在启动器件前, 需要判断一下, 器件的状态, 如果要切换状态的话, 那么我们就操作硬件.

image-20240801173412942

(1)当temp > temp_th 时, 当环境刚异常, 并且器件没有启动的时候, 此时我们判断出此状态, 那么我们就启动硬件.

那下一次判断的时候, 环境仍然异常, 但是器件刚才已经启动了, 那么通过判断, 我们就不用启动了.

(2)当temp < temp_th 时, 当环境刚恢复正常时, 并且器件启动的时候, 此时我们判断出此状态, 那么我们就可以关闭硬件了.

那下一次判断的时候, 环境仍然正常, 但是器件刚才已经关闭了, 那么通过判断, 我们就不用重复关闭了.

(3) 所以, 当我们要切换器件状态的时候, 我们首先判断器件当前的状态是否和我们所需一致, 如果一致, 那么我们就不进行切换即可.

(4)最小例程的代码, 是用 red_led 和 blue_led 来存储温湿度应急器件的状态的, 并且这个标志位是和器件io口绑定状态, 我们在操作io口后,我们都要更新这个状态。只是为了避免频繁操作器件,我们在判断预警操作器件的时候,都需要判断当前器件状态,是否已经符合, 如果符合,那么就不操作。我们这里功能不是太复杂,所以就用这种方法来实现。

后续如果加入操作系统的思想的话,尤其是硬件的操作,需要多级容错判断,来保证绝对的安全,这里只做简单分析。

image-20240801175047736

器件状态绑定

我们通过观察发现 ,red_led和 PBout(3)深度绑定, 所以直接新建一个文件, 然后新建一个结构体, 来保存器件的状态, 操作器件开关.

我们先观察下面示例, 然后分析学习, 构建我们的工程:

image-20240801180144618

(1)观察, 这个函数,是操作器件的, 然后每次操作的时候, 都会传入一个status, 就是我们所需的状态,

​ 但是 传入状态并不代表着我们就要频繁操作io口, 因为在一段时间内环境一直异常,我们100ms钟检测一次,当我们检测到异常, 我们就启动器件, 因为要保证预警系统的实时性, 所以下一个100ms检测的时候, 器件已经运行了,我们就无需重复启动了. 所以当我们传入状态后, 想开器件, 就判断一下器件是否已经启动, 如果启动, 就说明在上一个100ms的时候, 就已经启动了,我们这次进入只是为了保证实时性, 从而重复确认.

​ 同理, 关闭器件也一样, 如果我们检测到 环境 从 异常->正常后,

我们就关闭器件,操作io口前, 也同样判断一下, 器件是否已经处于关闭状态, 如果关闭,则无需操作. (注意我们上图运用的是结构体变量, 其函数状态和io口状态深度绑定, 所以通过判断变量,就可以判断出我们所处的状态,从而操作io口)

image-20240801173412942

代码实操:

在加dht11和oled最小例程的基础上,手把手改写代码, 加思路导向

改前的工程:

https://ww0.lanzoul.com/i1jH22680p3a

修改完预警的工程:

https://ww0.lanzoul.com/ihhjp26avqub

失效联系qq:2958360390 回复关键词 最小例程系统预警系统构建

(1) 我们解压打开改之前的工程

image-20240802071443939

(2)然后去锁定预警处理部分的代码

会发现, 我们这里是直接在main函数里面访问temp和humi的, 直接做出预警判断

image-20240802071703229

(3)并且, 和上述说的一样, red_led和 PBout(3) 并没有深度绑定, 所以我们先去 构建一下, 操作器件的函数, 我们构建两个文件一个是temp预警器件, 一个是 humi预警器件。

​ 首先,还和之前一样, 在品字哪里, 新建一个alarm的文件夹, 来存放预警器件的文件, 然后再去add, 逐个创建文件, 我们起名, temp_led.c 和 temp_led.h , humi_led.c和 humi_led.h吧。

详细步骤:(为了避免篇幅过长)

https://blog.csdn.net/qq_57484399/article/details/140862473

(4)如下图,我们先做temp_led.c的预警,

这里我们不谈c语言格式, 只谈随心写代码, 甚至我们可以用中文来代替, 至于格式问题, 是编译器和al的事情, 我们只谈逻辑.

image-20240802081906579

(5)先看之前原始的预警的时候, 操作器件的时候, 是怎么操作的

image-20240802082109921

我们是先判断状态, 让着当状态切换的时候, 我们才操作器件.

但是这些好像和我们用户没什么关系, 我们用户, 只是想, 在报警的时候, 你操作器件就行了, 至于启动不启动器件, 是我们底层控制启动器件的代码通过判断, 才做的事情, 所以, 我们此处进行替换.

image-20240802082426300

(6)至于启动不启动器件, 是函数内部通过判断器件是否处于运行状态, 才操作io口的.我们这里复制 temp_led_Set, 然后直接跳转temp_led.c函数

image-20240802082630432

(7)看到这个是传入的状态, 所以我们还得给led_red绑定一个结构体状态, 通过调用判断这个状态, 再确定是否需要操作io口,

我们去temp_led.h去定义状态结构体

image-20240802124853840
#define red_led_ON	1

#define red_led_OFF	0


typedef struct
{

	_Bool red_led_Status;

} TEMP_ALARM_INFO;

(8)定义完, 之后, 去temp_led.c里面去创建一个temp_alarm_info的变量, 然后 再去构造函数. 相当于定一个了一个状态了

image-20240802125209534

TEMP_ALARM_INFO temp_info = {0};

(9) 然后我们接着构造控制函数

传入的状态, 我们修改为 _Bool status

void temp_led_Set(_Bool status)
{
	
}

(10)还是根据流程图所示, 我们传入的状态, 就是我们想要的状态, 目前如果 机器是此状态, 我们就跳过不操作io口, 相当于我们切换状态的时候, 我们才操作io口

image-20240802130517065

(11)直接上代码, 如果需要开预警设备, 并且当前状态不是开,则操作io口

如果需要关应急设备, 并且当前状态不是关,则操作io口.

(为什么要判断切换状态呢? 因为我们并不能确保这是 第一次从正常->应急, 或者从应急->预警, 第一次操作,当然可以直接操作io口, 因为在一段时间内, 我们只需要操作一次io口,就行了, 但是为了保证实时性, 我们会一直操作判断器件状态, 从而达到实时性, 后续我们采用操作系统思想解决, 我们这里比较简单粗暴.)

image-20240802190849869

下面我把完善的代码奉上, 请直接复制黏贴即可

temp_led.c
//单片机头文件
#include "stm32f10x.h"

#include "temp_led.h"
#include "sys.h"

TEMP_ALARM_INFO temp_info = {0};

void temp_led_Init(void)
{
	//初始化小灯, PB3(温度) PB4(湿度) PB5(烟雾浓度)
	GPIO_InitTypeDef GPIO_InitStructure;
	//开启硬件时钟	PB5
	/* GPIOD Periph clock enable */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	//开启AFIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	//禁用JTAGD端口
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);	
   //配置 pB 3 4 5 GPIO工作模式(推挽输出)
	/* Configure PD0 and PD2 in output pushpull mode */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOB, &GPIO_InitStructure);	//配置端口
	//控制端口寄存器GPIO输出电平
	PBout(3) = 0;//temp_led	
	
}	

void temp_led_Set(_Bool status)
{
	if(status == red_led_ON && temp_info.red_led_Status != red_led_ON)	
	{
		//操作小灯开
		PBout(3) = 1;//temp_led
		//状态设置为开
		temp_info.red_led_Status = status;
	}
	else
	if(status == red_led_OFF && temp_info.red_led_Status != red_led_OFF)
	{
		//操作小灯关
		PBout(3) = 0;//temp_led
		//状态设置为关
		temp_info.red_led_Status = status;
	}
}

temp_led.h
#ifndef _TEMP_LED_H_
#define _TEMP_LED_H_


#define red_led_ON	1

#define red_led_OFF	0



typedef struct
{

	_Bool red_led_Status;

} TEMP_ALARM_INFO;

extern TEMP_ALARM_INFO temp_info;


void temp_led_Init(void);
void temp_led_Set(_Bool status);

#endif

humi_led.c
//单片机头文件
#include "stm32f10x.h"

#include "humi_led.h"
#include "sys.h"

HUMI_ALARM_INFO humi_info = {0};

void humi_led_Init(void)
{
	//初始化小灯, PB3(温度) PB4(湿度) PB5(烟雾浓度)
	GPIO_InitTypeDef GPIO_InitStructure;
	//开启硬件时钟	PB5
	/* GPIOD Periph clock enable */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	//开启AFIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	//禁用JTAGD端口
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);	
   //配置 pB 3 4 5 GPIO工作模式(推挽输出)
	/* Configure PD0 and PD2 in output pushpull mode */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOB, &GPIO_InitStructure);	//配置端口
	//控制端口寄存器GPIO输出电平
	PBout(4) = 0;//humi_led	
	
}	

void humi_led_Set(_Bool status)
{
	if(status == blue_led_ON && humi_info.blue_led_Status != blue_led_ON)	
	{
		//操作小灯开
		PBout(4) = 1;//blue_led
		//状态设置为开
		humi_info.blue_led_Status = status;
	}
	else
	if(status == blue_led_OFF && humi_info.blue_led_Status != blue_led_OFF)
	{
		//操作小灯关
		PBout(4) = 0;//blue_led
		//状态设置为关
		humi_info.blue_led_Status = status;
	}
}

humi_led.h
#ifndef _HUMI_LED_H_
#define _HUMI_LED_H_


#define blue_led_ON	  1

#define blue_led_OFF  0



typedef struct
{

	_Bool blue_led_Status;

} HUMI_ALARM_INFO;

extern HUMI_ALARM_INFO humi_info;


void humi_led_Init(void);
void humi_led_Set(_Bool status);

#endif


main.c
#include "stm32f10x.h"                  // Device header
#include "sys.h"
#include "delay.h"
#include "dht11.h"
#include "OLED.h"

#include "humi_led.h"
#include "temp_led.h"


uint8_t temp;	//读取的环境温度
uint8_t humi;	//读取的环境湿度

uint8_t temp_th;	//设置的温度阈值
uint8_t humi_th;	//设置的湿度阈值

_Bool red_led;	//(温度指示灯)

_Bool blue_led;	//(湿度指示灯)

_Bool set_limit;	//管理员是否设置阈值


led小灯初始化
//void led_init(void);


int main()
{

	unsigned short timeCount = 0;	//发送间隔变量
    //手动设置环境温度(模拟上帝)
	temp = 66;	//温度是28度
	humi = 60;	//湿度是60%	
    //手动设置阈值(代替远程)
    temp_th = 30;	//温度阈值是30度
	humi_th = 60;		//湿度阈值是60%
    //小灯状态初始化
    red_led = 0;
    blue_led = 0;   
	//测试变量: 管理设置阈值符号位
	set_limit = 1;
//	//小灯初始化
//	led_init();
	//滴答定时器
	Delay_Init();
	//dht11初始化
	DHT11_Init();
//	while(DHT11_Init())
//	{
		printf("DHT11 Error \r\n");
//		OLED_ShowString(0,48, "DHT11 Error", 8);
//		OLED_Update();	
//		DelayMs(2000);
//	}
	//oled初始化
	OLED_Init();
	humi_led_Init();
	temp_led_Init();
	
	while(1)
	{

		//(1)设置环境信息阈值(手动输入代替远程控制)
		if(set_limit == 1)
		{
			temp_th = 29;
			humi_th = 88;
			//设置完阈值就清零,下次不设置了, 直到set_limit被管理员置1
			//然后再次进入此功能函数里,进行设置阈值
			set_limit = 0;
		}
		//(2)读取环境信息 (手动输入代替器件读取)
		//if(过了100毫秒) 每隔100毫秒,读取一次, 保证实时性,减轻负担
		if(++timeCount >= 10)
		{
			DHT11_Read_Data(&temp,&humi);
//			temp = 99;	//人手输入,代替器件,忽略底层,重视逻辑
//			humi = 99;	
			OLED_Clear();
			OLED_ShowChinese(0, 0, "温度");
			OLED_ShowChinese(0, 24, "湿度:");
			OLED_Printf(48,0,OLED_8X16,"%2d",temp);
			OLED_Printf(48,24,OLED_8X16,"%2d",humi);	
			OLED_ShowChinese(80,0 , "℃");
			OLED_ShowChinese(80,24 , "%");		
			OLED_Update();
			timeCount = 0; 	//从新计时`		
		}
		DelayXms(10);	//10*10 = 100ms
		//后面跟 1ms的延时, 我们一切从简,先留着
		
		//(3)每时每刻判断环境信息是否异常
		if(temp >= temp_th)
		{
			//启动器件
			temp_led_Set(red_led_ON);
			
		}
		else	//同理,环境正常时候
		{     
			temp_led_Set(red_led_OFF);
		}      
		//判断湿度是否报警
		//每时每刻判断环境信息是否异常
		if(humi >= humi_th)
		{
			humi_led_Set(blue_led_ON);
			
//			if(blue_led == 0)	//如果是关闭状态则启动,开启则无操作
//			{
//				blue_led = 1; 
//				PBout(4) = 1;
//			}
		}
		else	//同理,环境正常时候
		{
			humi_led_Set(blue_led_OFF);
//			if(blue_led == 1)	//如果是开启状态则启动,关闭则无操作
//			{
//				blue_led = 0;
//				PBout(4) = 0;
//			}        
		}       
	}	

}

///**************************************************
//函数名: led_init
//功  能: 温湿度,烟雾浓度小灯初始化
//参  数: 无
//配置参数: PB3(温度) PB4(湿度) PB5(烟雾浓度)
//		  推挽输出
//		 小灯正极接io口, 负极接地
//返回值: 无
//**************************************************/
//void led_init(void)
//{
//	//初始化小灯 , PB3(温度) PB4(湿度) PB5(烟雾浓度)
//	GPIO_InitTypeDef GPIO_InitStructure;
//	//开启硬件时钟	PB5
//	/* GPIOD Periph clock enable */
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//	//开启AFIO时钟
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//	//禁用JTAGD端口
//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);	
//   //配置 pB 3 4 5 GPIO工作模式(推挽输出)
//	/* Configure PD0 and PD2 in output pushpull mode */
//	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
//	GPIO_Init(GPIOB, &GPIO_InitStructure);	//配置端口

//	//控制端口寄存器GPIO输出电平
//	PBout(3) = 0;//temp_led
//	PBout(4) = 0;	//humi_led
	PBout(5) = 0;	//mq2_led	
//	
//}

  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值