智能温室大棚(花房)2-按键设置温湿度报警参数

本文介绍了使用STM32单片机控制智能温室大棚的温湿度报警参数,通过四个按键进行操作,包括参数确认、模式选择和增减参数值。重点讲解了如何利用外部中断提高程序实时性,详细展示了GPIO配置和EXTI中断初始化的代码实现。
摘要由CSDN通过智能技术生成

今天写智能温室大棚(花房)的第2部分,实现使用四个按键设置温湿度报警参数。

一、方案介绍

经过系统方案设计分析,使用4个按键分别做如下控制:

key1:参数确认,确认当前参数值,切换到下一个设置参数;

key2:模式选择,系统的显示模式和参数设置模式的切换;

key3:参数值减小;

key4:参数值增加。

在开始进行程序编写的时候,选择了最简单的顺序轮训方式,最终在测试过程中发现实时性很差,最终选择了外部中断的方式。

我们现简要介绍一些STM32外部中断的知识:

STM32 的每个 IO 都可以作为外部 中断的中断输入口 STM32F103 的中断控制器支持 19 个外部中
/ 事件请求。每个中断设有状态位,每个中断 /事件都有独立的触发和屏蔽设置。
STM32F103 的 19 个外部中断为:
线 0~15 :对应外部 IO 口的输入中断。
线 16 :连接到 PVD 输出。
线 17 :连接到 RTC 闹钟事件。
线 18 :连接到 USB 唤醒事件。
STM32 IO 口使用的中断线只有 16 个,但是 STM32 IO 口却远远不止 16 个, 于是 STM32 就将GPIO 的管教 GPIOx.0~GPIOx.15(x=A,B,C,D,E F,G) 分别对应中断线 15~0 。这样每个中
断线对应了最多 7 IO 口,以线 0 为例:它对应了 GPIOA.0 GPIOB.0 GPIOC.0、 GPIOD.0 、 GPIOE.0、 GPIOF.0 GPIOG.0 。而中断线每次只能连接到 1 IO 口上,这样就需要通过配置 来决定对应的中断线配置到哪个 GPIO 上了。
GPIO和中断线的映射关系如下图所示:

二、代码编写

本次使用的4个按键对应的GPIO如下:

//              KEY1   PA3
//              KEY2   PA4
//              KEY3   PA5
//              KEY4   PA6 

1. key.c

初始化key对应的DPIO模式:

//按键初始化函数 
void KEY_Init(void)
{
	
	GPIO_InitTypeDef GPIO_InitStructure;

 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能PORTA时钟

	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //关闭jtag,使能SWD,可以用SWD模式调试
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;  //PA3、PA4、PA5、PA6
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  //设置成上拉输入
 	GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PA3、PA4、PA5、PA6
	
} 

对应的key.h

#ifndef __KEY_H
#define __KEY_H	 
#include "sys.h" 	 


#define KEY1  GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3)  //读取按键0
#define KEY2  GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4) //读取按键1
#define KEY3  GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5) //读取按键1
#define KEY4  GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6) //读取按键1
 

#define KEY1_PRES	1		//KEY1  
#define KEY2_PRES	2		//KEY2 
#define KEY3_PRES	3		//KEY3 
#define KEY4_PRES	4		//KEY4

void KEY_Init(void);//IO初始化					    
#endif

2. exti.c

按键中断初始化:

//外部中断初始化函数
void EXTIX_Init(void)
{
 
 	  EXTI_InitTypeDef EXTI_InitStructure;
 	  NVIC_InitTypeDef NVIC_InitStructure;

  	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟

	  KEY_Init();//初始化按键对应io模式

    //GPIOA.7 中断线以及中断初始化配置
  	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource7);

  	EXTI_InitStructure.EXTI_Line=EXTI_Line7;
  	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);	 	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

    //GPIOA.4	  中断线以及中断初始化配置
  	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource4);

  	EXTI_InitStructure.EXTI_Line=EXTI_Line4;
  	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);	  	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

    //GPIOA.5	  中断线以及中断初始化配置
  	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource5);

   	EXTI_InitStructure.EXTI_Line=EXTI_Line5;
  	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);		//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
		
		//GPIOA.6	  中断线以及中断初始化配置
  	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource6);

   	EXTI_InitStructure.EXTI_Line=EXTI_Line6;
  	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);		//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
		
		NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;			//使能按键所在的外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2, 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;					//子优先级1
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure); 
 
   	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;			//使能按键所在的外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2, 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;					//子优先级3
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure); 
 
}

中断处理函数:

void EXTI4_IRQHandler(void)
{
  delay_ms(10);    //消抖
	if(KEY2==0)
	{	  
		key2_Hander(); 
		OLED_Clear();	
		display();
	}
	EXTI_ClearITPendingBit(EXTI_Line4);  //清除EXTI4线路挂起位
}

 void EXTI9_5_IRQHandler(void)
{			
	delay_ms(10);   //消抖			 
	if(KEY3==0)	{
		key3_Hander();
		OLED_Clear();	
		display();
	}
	else if(KEY4==0){
		key4_Hander();
		OLED_Clear();	
		display();
	}
	else if(KEY1==0){
		key1_Hander();
		OLED_Clear();	
		display();
	}
		
 	 EXTI_ClearITPendingBit(EXTI_Line5|EXTI_Line6|EXTI_Line7);    //清除LINE5/6/7上的中断标志位  
}

按键处理函数:

void key1_Hander(void)
{
	switch(mode)
	{
		case 1:break;  //显示模式
		case 2:
			{
				currentParameter += 1;
				if(currentParameter == 7)
				{
					currentParameter = 1;		
				}
			break; //设置模式
		default:break;
		}
	}
}

void key2_Hander(void)
{
	switch(mode)
	{
		case 1:
		{
			mode=2;
			currentParameter = 1;
		}
		break;
		case 2:
		{
			mode=1;
		}
		break; 
		default:break;
	}
}

void key3_Hander(void)
{
		switch(mode)
		{
		case 1:break;  //显示模式
		case 2:
			{
				if(currentParameter == 1)
				{
					temperatureThreshold_max += 1;  
				}
				else if(currentParameter == 2)
				{
					temperatureThreshold_min += 1;  
				}				
				else if(currentParameter == 3)
				{
					humidityThreshold_max += 5;  
				}
				else if(currentParameter == 4)
				{
					humidityThreshold_min += 5;  
				}
				else if(currentParameter == 5)
				{
					lightThreshold_max += 10;  
				}
				else if(currentParameter == 6)
				{
					lightThreshold_min += 10;  
				}
				
			}
			break; //设置模式
		default:break;
			
		 }
}

void key4_Hander(void)
{
		switch(mode)
		{
		case 1:break;  //显示模式
		case 2:
			{
				if(currentParameter == 1)
				{
					temperatureThreshold_max -= 1;  
				}
				else if(currentParameter == 2)
				{
					temperatureThreshold_min -= 1;  
				}				
				else if(currentParameter == 3)
				{
					humidityThreshold_max -= 5;  
				}
				else if(currentParameter == 4)
				{
					humidityThreshold_min -= 5;  
				}
				else if(currentParameter == 5)
				{
					lightThreshold_max -= 10;  
				}
				else if(currentParameter == 6)
				{
					lightThreshold_min -= 10;  
				}
				
			}
			break; //设置模式
		default:break;
			
		 }
}

显示函数:

void display()
{
	switch(mode)
	{
		case 0: display0(); break;   //开机界面(可不加)
		case 1: display1(); break;   //显示界面
		case 2:                      //设置界面
		{
				if(currentParameter == 1)
				{
					display2();    //设置温度高
				}
				else if(currentParameter == 2)
				{
					display3();    //设置温度低
				}
				else if(currentParameter == 3)
				{
					display4();    //设置湿度高
				}
				else if(currentParameter == 4)
				{
					display5();    //设置湿度低
				}
				else if(currentParameter == 5)
				{
					display6();    //设置光照高
				}
				else if(currentParameter == 6)
				{
					display7();    //设置光照低
				}				
		}
		 break;

	}
} 

//显示界面
void display0()  // 开机界面 
{
	OLED_ShowCHinese(28,0,0);   //智
	OLED_ShowCHinese(46,0,1);   //能
	OLED_ShowCHinese(64,0,2);   //大
	OLED_ShowCHinese(82,0,3);   //棚
}

void display1()  // 显示界面 
{
	OLED_ShowCHinese(0,0,4);    //温
	OLED_ShowCHinese(18,0,5);   //度
	OLED_ShowString(36,0,":",16); 
	OLED_ShowString(70,0,"C",16);  //℃	

	OLED_ShowCHinese(0,3,6);    //湿
	OLED_ShowCHinese(18,3,7);   //度 
	OLED_ShowString(36,3,":",16); 
	OLED_ShowString(70,3,"%",16);  //%		

	OLED_ShowCHinese(0,6,8);    //光
	OLED_ShowCHinese(18,6,9);   //照 
	OLED_ShowString(36,6,":",16);
	OLED_ShowString(70,6,"%",16);  //%		
	
	//显示2个数字//x,y :起点坐标	 //len :数字的位数//size:字体大小//mode:模式	0,填充模式;1,叠加模式//num:数值(0~4294967295);	
	//void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2)
	OLED_ShowNum(40,0,temp,3,16); 	
	OLED_ShowNum(40,3,humid,3,16); 
	OLED_ShowNum(40,6,light,3,16); 
}

void display2()  // 显示温度高设置界面
{
	OLED_ShowCHinese(0,0,4);    //温
	OLED_ShowCHinese(18,0,5);   //度
	OLED_ShowCHinese(36,0,10);  //高	
	OLED_ShowString(54,0,":",16);
	OLED_ShowString(88,0,"C",16);  //℃		
	OLED_ShowNum(58,0,temperatureThreshold_max,3,16); 
}

void display3()  // 显示温度低设置界面
{
	OLED_ShowCHinese(0,0,4);    //温
	OLED_ShowCHinese(18,0,5);   //度
	OLED_ShowCHinese(36,0,11);  //低	
	OLED_ShowString(54,0,":",16); 
	OLED_ShowString(88,0,"C",16);  //℃		
	OLED_ShowNum(58,0,temperatureThreshold_min,3,16); 
}

void display4()  // 显示湿度高设置界面
{	 
	OLED_ShowCHinese(0,3,6);    //湿
	OLED_ShowCHinese(18,3,7);   //度 
	OLED_ShowCHinese(36,3,10);  //高	
	OLED_ShowString(54,3,":",16); 
	OLED_ShowString(88,3,"%",16);  //%		
	OLED_ShowNum(58,3,humidityThreshold_max,3,16);	
}

void display5()  // 显示湿度低设置界面
{	 
	OLED_ShowCHinese(0,3,6);    //湿
	OLED_ShowCHinese(18,3,7);   //度
	OLED_ShowCHinese(36,3,11);  //低		
	OLED_ShowString(54,3,":",16); 
	OLED_ShowString(88,3,"%",16);  //%	
	OLED_ShowNum(58,3,humidityThreshold_min,3,16);	
}

void display6()  // 显示光照高设置界面
{
	OLED_ShowCHinese(0,6,8);    //光
	OLED_ShowCHinese(18,6,9);   //照
	OLED_ShowCHinese(36,6,10);  //高		
	OLED_ShowString(54,6,":",16);
	OLED_ShowString(88,6,"%",16);  //%		
	OLED_ShowNum(58,6,lightThreshold_max,3,16); 
}

void display7()  // 显示光照低设置界面
{
	OLED_ShowCHinese(0,6,8);    //光
	OLED_ShowCHinese(18,6,9);   //照 
	OLED_ShowCHinese(36,6,11);  //低	
	OLED_ShowString(54,6,":",16);
	OLED_ShowString(88,6,"%",16);  //%	
	OLED_ShowNum(58,6,lightThreshold_min,3,16); 
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值