毕设-基于LoRa的智能农业大棚(一)

任务目标

实现功能:
(1)能够实时检测显示土壤湿度,当需要浇水的时候自动打开灌溉系统,土壤湿度满足要求后,关闭灌溉系统;
(2)检测显示二氧化碳浓度,过高时,通过继电器打开通风排气扇,同时将二氧化碳浓度数值传输到终端进行提示;
(3)能够实时检测显示土壤酸碱度,超标时候能给出报警并提示;
(4)远程异地和检测与控制:传感器所采集到的信息,通过LoRa模块发送给网关,网关以有线连接的方式通过WiFi模块发送给云端,APP可以随时查看大棚内的二氧化碳浓度、土壤湿度与酸碱度的情况;
(5)系统平时可以处于自动模式工作,当需要修改参数时,可以进行手动模式,手动控制可以通过手机和前端按键进行修改,并设置阈值。修改后,将按照新的参数进行工作。

系统设计方案

本系统由LoRa节点,LoRa网关,智能手机3部分组成,整体结构如图2-1所示。两个大棚通过LoRa模块传输数据到网关,网关将所有数据整理后上传到云端。
毕设-基于LoRa的智能农业大棚(一)_第1张图片

三块LoRa模块通信逻辑设计

本次使用的是正点原子的LoRa模块,具体配置可以参考手册进行。为了方便我使用的模式为广播,只需要将三个LoRa模块地址、信道、速率相同就可以通信了。由于处于广播模式下,当一个模块发送指令时其他另外两个模块都会接受到信息,所以在开发板接受到数据的时候需要做一下验证处理。为了防止数据冲突采用轮询的方式,轮询发送数据。例如:将终端节点A1和A2的关键字设置为‘DataA1’和‘DataA2’,网关发送关键字‘DataA1’给终端节点A1和A2同时接受到了关键字‘DataA1’,此时终端节点都进入串口中断中判断关键字是否需要回复,终端A1判断为是则回复采集的数据到网关。

LoRa转WiFi网关设计与实现

网关的主要功能就是接受终端节点的数据、通过WiFi模块发送数据到云端、下发阈值到终端节点。使用STMF407作为核心的开发板,需要的资源:定时器中断,外部中断,串口接受中断。
按键的任务就是负责增加或者减少下发的阈值
毕设-基于LoRa的智能农业大棚(一)_第2张图片
串口2中断接受和处理LoRa模块发送的数据,串口3中断是接受和处理WiFi模块发送的数据(设计思路同串口2)。
毕设-基于LoRa的智能农业大棚(一)_第3张图片
定时器4负责轮询发送关键字给LoRa模块,并由LoRa发送给各终端节点的LoRa模块。定时器3负责定时发送数据给WiFi模块,WiFi模块发送数据到云端。
毕设-基于LoRa的智能农业大棚(一)_第4张图片

代码

LoRa模块初始化(部分)
#include "lora.h"
void LoRa_Init(void)
{

	
	  GPIO_InitTypeDef  GPIO_InitStructure;
	  NVIC_InitTypeDef NVIC_InitStructure;

	  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOF, ENABLE);//使能GPIOC,GPIOF时钟
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟
	
	    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //MD0引脚
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//输出模式
	    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;//下拉
      GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOE2,3,4
	
	    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //AUX引脚
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;//下拉
      GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化
	
	
	  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOF, EXTI_PinSource6);//PC0 连接到中断线0
	
	  /* 配置EXTI_Line0 */

	
	
	  NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;//外部中断0
       NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;//抢占优先级0
	  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
	  NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;//使能外部中断通道
	  NVIC_Init(&NVIC_InitStructure);//配置
	 
	 LORA_MD0=0;
	  LORA_AUX=0;
	
	
	  while(LORA_AUX)//确保LORA模块在空闲状态下(LORA_AUX=0)
	  {
		 delay_ms(100);	 
	  }
	  Lora_uart_init(115200);//初始化串口3
	 
	  LORA_MD0=1;//进入AT模式
	  delay_ms(15);
		while(Lora_setCmd("AT\r\n","OK",0))
			;
	  delay_ms(5);
		Lora_Clear();
		delay_ms(5);
		while(Lora_setCmd("AT+ADDR=01,23\r\n","OK",0))
			;
		delay_ms(5);
		while(Lora_setCmd("AT+WLRATE=24,5\r\n","OK",0))
			;
		delay_ms(5);
	  LORA_MD0=0; //进入透传模式
		Lora_uart_init(9600);
		delay_ms(10);
}
串口三接受中断
void USART3_IRQHandler()                	//串口3中断服务程序
{
	u8 Res;
	if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
	{
		Res =USART_ReceiveData(USART3);//(USART1->DR);	//读取接收到的数据
		//printf("%d",Res);
		if(counts == 0)
		{
			Lora_Clear();
		}
		read_bufs[counts++] = Res;
		//判断格式
			if(Res == 0xfe)
			{
				counts = 0;
			}
			else if(Res == '}')
			{
				counts = 0;
				USART_Cmd(USART3, DISABLE);//关闭
				#if 0
				printf("%s\r\n",read_bufs);
				#endif
				Lora_Rx_data();//解析数据
				USART_Cmd(USART3, ENABLE);//打开
			}
		if(counts>500)
		{
			counts = 0;
		}
		USART_ClearFlag(USART3, USART_IT_RXNE);
  }	
} 
串口二接受中断
void USART2_IRQHandler(void)                	//串口2中断服务程序
{
	u8 Res;
	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
	{
		Res =USART_ReceiveData(USART2);//(USART1->DR);	//读取接收到的数据
		if(counts_2 == 0)
		{
			wifi_Clear();
		}
		read_bufs_HC[counts_2++] = Res;
		//判断数据格式
		if(Res == '{')
		{
			counts_2 = 0;
		}
		else if(Res == '}')
		{
			counts_2 = 0;
			USART_Cmd(USART2, DISABLE);//关闭
			printf("%s\r\n",read_bufs_HC);
			HC25_Rx_Data();           //解析数据
			USART_Cmd(USART2, ENABLE);//开启
		}


		if(counts_2>200)
		{
			counts_2 = 0;
		}
		USART_ClearFlag(USART2, USART_IT_RXNE);		 
  } 
}
定时器三中断
void TIM3_IRQHandler(void){
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断
	{
		if(STA==0){
			//Jason数据格式
				sprintf(jason," {\n "
          "\"CO2_1\":%d,"
          "\"CO2pre_1\":%d,"
          "\"PH_1\":%d,"
          "\"PHpre_1\":%d,"
          "\"SoilHum_1\":%d,"
          "\"SoilHumpre_1\":%d,"
          "\"CO2_2\":%d,"
          "\"CO2pre_2\":%d,"
          "\"PH_2\":%d,"
          "\"PHpre_2\":%d,"
          "\"SoilHum_2\":%d,"
          "\"SoilHumpre_2\":%d"
             "\n}",data.CO2_data,data.CO2_data_Pre,data.PH,data.PH_Pre,data.Soil,data.Soil_Pre
		,data1.CO2_data,data1.CO2_data_Pre,data1.PH,data1.PH_Pre,data1.Soil,data1.Soil_Pre);
		
			HC25_setData(jason); //发数据
		}
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  //清除中断标志位
}
定时器四中断
void TIM4_IRQHandler(void)
{
	char tx_buff[80];
	char tx_buf2[80];
	if(TIM_GetITStatus(TIM4,TIM_IT_Update)==SET) //溢出中断
	{
		TX_time++; //轮询标志位
		
		switch(TX_time){
			case TX_TIME://等于1
				if(TX_1){//判断预设值发送标志位
					sprintf(tx_buff,"0xfeDATA:%d:%d:%d:%d:%d:%d}",CO2Pre1,SoilPre1,PHPre1,Water_IT1,Fan_IT1,Beef_IT1);
					Lora_setData(tx_buff);
					TX_1=0;
					TXcope1=1;
				}else
				Lora_setData("0xfeTX1:A}\r\n");//轮询关键字1
				break;
			case TX_TIME+TIME_ADD://等于2
				if(TX_2){//判断预设值发送标志位
				     sprintf(tx_buf2,"0xfedataer:%d:%d:%d:%d:%d:%d}",CO2Pre2,SoilPre2,PHPre2,Water_IT2,Fan_IT2,Beef_IT2);
					Lora_setData(tx_buf2);
					TX_2=0;
					TXcope2=1;
				}
			     else 
					Lora_setData("0xfetxer:b}\r\n");
				
			     TX_time=0;//轮询标志位
				
				break;
			default:
				  break;
		}
	}
	TIM_ClearITPendingBit(TIM4,TIM_IT_Update);  //清除中断标志位
}

有问题私信或评论区-_- 讨论群985432073

你可能感兴趣的:(毕设教学,stm32,嵌入式,物联网)