当前位置: 首页 > news >正文

毕业设计 单片机stm32智能大棚监控护理系统 - lora 远程通信

文章目录

  • 0 前言
  • 1 简介
  • 2 主要器件
  • 3 实现效果
  • 4 设计原理
    • 4.1 lora无线通信
    • 4.2 MG812二氧化碳监测模块
    • 4.3 MQ-2烟雾传感器
  • 5 部分核心代码
  • 6 最后


0 前言

🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。

为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天要分享的是

🚩 单片机stm32智能大棚监控护理系统

🥇学长这里给一个题目综合评分(每项满分5分)

  • 难度系数:3分
  • 工作量:3分
  • 创新点:4分

🧿 选题指导, 项目分享:

https://gitee.com/dancheng-senior/project-sharing-1/blob/master/%E6%AF%95%E8%AE%BE%E6%8C%87%E5%AF%BC/README.md


1 简介

基于STM32单片机的lora大棚系统,可检测烟雾浓度,二氧化碳浓度,温湿度,当烟雾浓度超过阈值风扇开启,通过lora无线通信把数据传输到主机。

2 主要器件

  • STM32F103C8T6主控芯片
  • DHT11温湿度模块
  • MQ2烟雾检测模块
  • 二氧化碳监测模块
  • lora无线通信
  • OLED屏

3 实现效果

在这里插入图片描述

4 设计原理

4.1 lora无线通信

简介

LoRa就是远距离无线电(Long Range Radio),是semtech公司创建的低功耗局域网无线标准,它最大特点就是在同样的功耗条件下比其他无线方式传播的距离更远,实现了低功耗和远距离的统一,它在同样的功耗下比传统的无线射频通信距离扩大3-5倍。

LoRa是一种基于扩频技术的远距离无线传输技术,其实也是是诸多LPWAN通信技术中的一种,最早由美国Semtech公司采用和推广。这一方案为用户提供一种简单的能实现远距离、低功耗无线通信手段。目前,LoRa主要在ISM频段运行,主要包括433、868、915 MHz等。

LoRa是物理层或无线调制用于建立长距离通信链路。许多传统的无线系统使用频移键控(FSK)调制作为物理层,因为它是一种实现低功耗的非常有效的调制。LoRa是基于线性调频扩频调制,它保持了像FSK调制相同的低功耗特性,但明显地增加了通信距离。线性扩频已在军事和空间通信领域使用了数十年, 由于其可以实现长通信距离和干扰的鲁棒性,但是LoRa是第一个用于商业用途的低成本实现。

LoRa的优势在于技术方面的长距离能力。单个网关或基站可以覆盖整个城市或数百平方公里范围。在一个给定的位置,距离在很大程度上取决于环境或障碍物,但LoRa和LoRaWAN有一个链路预算优于其他任何标准化的通信技术。

LoRa的特性

  • 传输距离:城镇可达2-5Km ,郊区可达15 Km ;

  • 工作频率:ISM 频段,包括433、868、915 MH等;

  • 容量:一个LoRa网关可以连接上千上万个LoRa节点;

  • 传输速率:几百到几十Kbps,速率越低传输距离越长;

  • 调制方式:基于扩频技术,线性调制扩频的一个变种,具有前向纠错能力。

实物图

在这里插入图片描述
引脚描述如下
在这里插入图片描述
接线
在这里插入图片描述

4.2 MG812二氧化碳监测模块

CO2浓度MG-812 是采用固体电解质池原理来检测 CO2 的半导体氧化物学传感器。当传感器保持在一定的工作温度,置于 CO2 气氛中时,电池正负极发生电极反应,传感器敏感电极和参考电极之间产生电动势,输出信号压与 CO2 浓度的对数成反比例线性关系,通过测试信号电压的变化可检到 CO2 浓度的变化。
在这里插入图片描述
模块只有4个接口,VCC接电源,GND,AO接MCU的ADC引脚,得到模块输出电压,再根据输出电压信号与CO2浓度线性关系来算出环境的CO2浓度。

4.3 MQ-2烟雾传感器

简介
MQ-2常用于家庭和工厂的气体泄漏监测装置,适宜于液化气、苯、烷、酒精、氢气、烟雾等的探测。故因此,MQ-2可以准确来说是一个多种气体探测器。
MQ-2的探测范围极其的广泛。它的优点:灵敏度高、响应快、稳定性好、寿命长、驱动电路简单。
在这里插入图片描述
二、MQ-2的工作原理
MQ-2型烟雾传感器属于二氧化锡半导体气敏材料,属于表面离子式N型半导体。处于200~300摄氏度时,二氧化锡吸附空气中的氧,形成氧的负离子吸附,使半导体中的电子密度减少,从而使其电阻值增加。当与烟雾接触时,如果晶粒间界处的势垒收到烟雾的调至而变化,就会引起表面导电率的变化。利用这一点就可以获得这种烟雾存在的信息,烟雾的浓度越大,导电率越大,输出电阻越低,则输出的模拟信号就越大。
在这里插入图片描述

MQ-2应用电路

MQ-2常用的电路有两种,一种使用采用比较器电路监控,另一种为ADC电路检测。

比较器电路
在这里插入图片描述
MQ-2的4脚输出随烟雾浓度变化的直流信号,被加到比较器U1A的2脚,Rp构成比较器的门槛电压。当烟雾浓度较高输出电压高于门槛电压时,比较器输出低电平(0v),此时LED亮报警;当浓度降低传感器的输出电压低于门槛电压时,比较器翻转输出高电平(Vcc),LED熄灭。调节Rp,可以调节比较器的门槛电压,从而调节报警输出的灵敏度。
R1串入传感器的加热回路,可以保护加热丝免受冷上电时的冲击。

ADC转换电路
MQ-2传感器另外一个采集方法为AD信号采集,即将电压信号转化为数字信号,进而转化为精确的烟雾浓度值。
在这里插入图片描述MQ-2传感器的4脚、6脚的电压为输出信号,Rs为传感器的本体电阻。其中若气体浓度上升,必导致Rs下降。而Rs的下降则会导致MQ-2的4脚、6脚对地输出的电压增大。所以气体浓度增大,其输出的电压也会增大,最终通过ADC0832转换后数值增大。

5 部分核心代码

#include "lora.h"
#include "sys.h"
#include "delay.h"
#include "usart3.h"
#include "string.h"
#include "stdio.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "lcd.h"
 
//设备参数初始化(具体设备参数见lora_cfg.h定义)
_LoRa_CFG LoRa_CFG=
{
	.addr = LORA_ADDR,       //设备地址
	.power = LORA_POWER,     //发射功率
	.chn = LORA_CHN,         //信道
	.wlrate = LORA_RATE,     //空中速率
	.wltime = LORA_WLTIME,   //睡眠时间
	.mode = LORA_MODE,       //工作模式
	.mode_sta = LORA_STA,    //发送状态
	.bps = LORA_TTLBPS ,     //波特率设置
	.parity = LORA_TTLPAR    //校验位设置
};
 
//全局参数
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
 
//设备工作模式(用于记录设备状态)
u8 Lora_mode=0;//0:配置模式 1:接收模式 2:发送模式
//记录中断状态
static u8 Int_mode=0;//0:关闭 1:上升沿 2:下降沿
 
 
//usmart支持部分
//将收到的AT指令应答数据返回给电脑串口
//mode:0,不清零USART3_RX_STA;
//     1,清零USART3_RX_STA;
void lora_at_response(u8 mode)
{
	if(USART3_RX_STA&0X8000)		//接收到一次数据了
	{ 
		USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
		printf("%s",USART3_RX_BUF);	//发送到串口
		if(mode)USART3_RX_STA=0;
	} 
}
//lora发送命令后,检测接收到的应答
//str:期待的应答结果
//返回值:0,没有得到期待的应答结果
//其他,期待应答结果的位置(str的位置)
u8* lora_check_cmd(u8 *str)
{
	char *strx=0;
	if(USART3_RX_STA&0X8000)		//接收到一次数据了
	{ 
		USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
		strx=strstr((const char*)USART3_RX_BUF,(const char*)str);
	} 
	return (u8*)strx;
}
//lora发送命令
//cmd:发送的命令字符串(不需要添加回车了),当cmd<0XFF的时候,发送数字(比如发送0X1A),大于的时候发送字符串.
//ack:期待的应答结果,如果为空,则表示不需要等待应答
//waittime:等待时间(单位:10ms)
//返回值:0,发送成功(得到了期待的应答结果)
//       1,发送失败
u8 lora_send_cmd(u8 *cmd,u8 *ack,u16 waittime)
{
	u8 res=0; 
	USART3_RX_STA=0;
	if((u32)cmd<=0XFF)
	{
		while((USART3->SR&0X40)==0);//等待上一次数据发送完成  
		USART3->DR=(u32)cmd;
	}else u3_printf("%s\r\n",cmd);//发送命令
	
	if(ack&&waittime)		//需要等待应答
	{
	   while(--waittime)	//等待倒计时
	   { 
		  delay_ms(10);
		  if(USART3_RX_STA&0X8000)//接收到期待的应答结果
		  {
			  if(lora_check_cmd(ack))break;//得到有效数据 
			  USART3_RX_STA=0;
		  } 
	   }
	   if(waittime==0)res=1; 
	}
	return res;
}
 
 
//AUX中断设置
//mode:配置的模式 0:关闭 1:上升沿 2:下降沿
void Aux_Int(u8 mode)
{
    if(!mode)
	{
		EXTI_InitStructure.EXTI_LineCmd = DISABLE;//关闭中断
		NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;	
	}else
	{
		if(mode==1)
			 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿
	    else if(mode==2)
			 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿
		
		EXTI_InitStructure.EXTI_LineCmd = ENABLE;
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;		
	}
	Int_mode = mode;//记录中断模式
	EXTI_Init(&EXTI_InitStructure);
	NVIC_Init(&NVIC_InitStructure);  
    
}
 
//LoRa模块初始化
//返回值: 0,检测成功
//        1,检测失败
u8 LoRa_Configure(void)
{
	 u8 retry=0;
	 u8 temp=1;
	
	 GPIO_InitTypeDef  GPIO_InitStructure;
		
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//使能PA端口时钟
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	//使能复用功能时钟
 
     GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//禁止JTAG,从而PA15可以做普通IO使用,否则PA15不能做普通IO!!!	
	
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;	    		 //LORA_MD0
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
	 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
	 GPIO_Init(GPIOA, &GPIO_InitStructure);	  				 //推挽输出 ,IO口速度为50MHz
	
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;				 //LORA_AUX
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; 		     //下拉输入
	 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
	 GPIO_Init(GPIOA, &GPIO_InitStructure);					 //根据设定参数初始化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_Rising;  //上升沿触发
  	 EXTI_InitStructure.EXTI_LineCmd = DISABLE;              //中断线关闭(先关闭后面再打开)
  	 EXTI_Init(&EXTI_InitStructure);//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
	
	 NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;			//LORA_AUX
  	 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级2, 
  	 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;		//子优先级3
  	 NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE; //关闭外部中断通道(后面再打开)
   	 NVIC_Init(&NVIC_InitStructure); 
	 
	 LORA_MD0=0;
	 LORA_AUX=0;
	
	 while(LORA_AUX)//确保LORA模块在空闲状态下(LORA_AUX=0)
	 {
		 delay_ms(600); 
	 }
	 usart3_init(115200);//初始化串口3
	 
	 LORA_MD0=1;//进入AT模式
	 delay_ms(40);
	 retry=3;
	 while(retry--)
	 {
		 if(!lora_send_cmd("AT","OK",70))
		 {
			 temp=0;//检测成功
			 break;
		 }	
	 }
	 if(retry==0) temp=1;//检测失败
	 return temp;
}
void LoRa_Init(void)
{
	while(LoRa_Configure())//初始化ATK-LORA-01模块
	{	
		delay_ms(300);
	}
	LoRa_Set();
}
 
//Lora模块参数配置
void LoRa_Set(void)
{
	u8 sendbuf[20];
	u8 lora_addrh,lora_addrl=0;
	
	usart3_set(LORA_TTLBPS_115200,LORA_TTLPAR_8N1);//进入配置模式前设置通信波特率和校验位(115200 8位数据 1位停止 无数据校验)
	usart3_rx(1);//开启串口3接收
	
	while(LORA_AUX);//等待模块空闲
	LORA_MD0=1; //进入配置模式
	delay_ms(40);
	Lora_mode=0;//标记"配置模式"
	
	lora_addrh =  (LoRa_CFG.addr>>8)&0xff;
	lora_addrl = LoRa_CFG.addr&0xff;
	
	sprintf((char*)sendbuf,"AT+ADDR=%02x,%02x",lora_addrh,lora_addrl);//设置设备地址
	lora_send_cmd(sendbuf,"OK",50);
	
	sprintf((char*)sendbuf,"AT+WLRATE=%d,%d",LoRa_CFG.chn,LoRa_CFG.wlrate);//设置信道和空中速率
	lora_send_cmd(sendbuf,"OK",50);
	
	sprintf((char*)sendbuf,"AT+TPOWER=%d",LoRa_CFG.power);//设置发射功率
	lora_send_cmd(sendbuf,"OK",50);
	
	sprintf((char*)sendbuf,"AT+CWMODE=%d",LoRa_CFG.mode);//设置工作模式
	lora_send_cmd(sendbuf,"OK",50);
	
	sprintf((char*)sendbuf,"AT+TMODE=%d",LoRa_CFG.mode_sta);//设置发送状态
	lora_send_cmd(sendbuf,"OK",50);
	
	sprintf((char*)sendbuf,"AT+WLTIME=%d",LoRa_CFG.wltime);//设置睡眠时间
	lora_send_cmd(sendbuf,"OK",50);
	
	sprintf((char*)sendbuf,"AT+UART=%d,%d",LoRa_CFG.bps,LoRa_CFG.parity);//设置串口波特率、数据校验位
	lora_send_cmd(sendbuf,"OK",50);
 
	LORA_MD0=0;//退出配置,进入通信
	delay_ms(40);
	while(LORA_AUX);//判断是否空闲(模块会重新配置参数)
	USART3_RX_STA=0;
	Lora_mode=1;//标记"接收模式"
	usart3_set(LoRa_CFG.bps,LoRa_CFG.parity);//返回通信,更新通信串口配置(波特率、数据校验位)
	Aux_Int(1);//设置LORA_AUX上升沿中断	
	
}
 
u8 Dire_Date[]={0x11,0x22,0x33,0x44,0x55};//定向传输数据
u8 date[30]={0};//定向数组
 
 
 
u32 obj_addr = 0;//记录用户输入目标地址
u8 obj_chn = 0;//记录用户输入目标信道
 
u8 wlcd_buff[10]={0}; //LCD显示字符串缓冲区
//Lora模块发送数据
void LoRa_SendData(u8 Data[])
{      
	static u8 num=0;
    u16 addr;
	u8 chn;
	u16 i=0; 
		
	if(LoRa_CFG.mode_sta == LORA_STA_Tran)//透明传输
	{
		u3_printf("%s\r\n",Data);
		num++;
		if(num==255) num=0;
		
	}else if(LoRa_CFG.mode_sta == LORA_STA_Dire)//定向传输
	{
		
		addr = (u16)obj_addr;//目标地址
		chn = obj_chn;//目标信道
		
		date[i++] =(addr>>8)&0xff;//高位地址
		date[i++] = addr&0xff;//低位地址
		date[i] = chn;//无线信道
		
		for(i=0;i<Dire_DateLen;i++)//数据写到发送BUFF
		{
			date[3+i] = Dire_Date[i];
		}	
		for(i=0;i<(Dire_DateLen+3);i++)
		{
			while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET);//循环发送,直到发送完毕   
			USART_SendData(USART3,date[i]); 
		}	
		
        //将十六进制的数据转化为字符串打印在lcd_buff数组
		sprintf((char*)wlcd_buff,"%x %x %x %x %x %x %x %x",
				date[0],date[1],date[2],date[3],date[4],date[5],date[6],date[7]);
	    Dire_Date[4]++;//Dire_Date[4]数据更新		
	}
			
}
 
u8 rlcd_buff[10]={0}; //LCD显示字符串缓冲区
//Lora模块接收数据
u8* LoRa_ReceData(void)
{
 
    u16 len=0;
   
	//有数据来了
	if(USART3_RX_STA&0x8000)
	{
		LED1 =0;
		memset((char*)USART3_RX_BUF,0x00,len);//串口接收缓冲区清0
		len = USART3_RX_STA&0X7FFF;
		USART3_RX_BUF[len]=0;//添加结束符
		USART3_RX_STA=0;
 
		if(LoRa_CFG.mode_sta==LORA_STA_Tran)//透明传输
		{	
 
		}else if(LoRa_CFG.mode_sta==LORA_STA_Dire)//定向传输
		{
			//将十六进制的数据转化为字符串打印在lcd_buff数组
			sprintf((char*)rlcd_buff,"%x %x %x %x %x",
			USART3_RX_BUF[0],USART3_RX_BUF[1],USART3_RX_BUF[2],USART3_RX_BUF[3],USART3_RX_BUF[4]);
		}
		
	}
	return USART3_RX_BUF;
 
}
 
 
 
//LORA_AUX中断服务函数
void EXTI4_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line4))
	{  
	   if(Int_mode==1)//上升沿(发送:开始发送数据 接收:数据开始输出)     
	   {
		  if(Lora_mode==1)//接收模式
		  {
			 USART3_RX_STA=0;//数据计数清0
		  }
		  Int_mode=2;//设置下降沿触发
		  LED0=0;//DS0亮
	   }
       else if(Int_mode==2)//下降沿(发送:数据已发送完 接收:数据输出结束)	
	   {
		  if(Lora_mode==1)//接收模式
		  {
			 USART3_RX_STA|=1<<15;//数据计数标记完成
		  }else if(Lora_mode==2)//发送模式(串口数据发送完毕)
		  {
			 Lora_mode=1;//进入接收模式
		  }
		  Int_mode=1;//设置上升沿触发
          LED0=1;//DS0灭		   
	   }
       Aux_Int(Int_mode);//重新设置中断边沿
	   EXTI_ClearITPendingBit(EXTI_Line4); //清除LINE4上的中断标志位  
	}	
}
 
 
// MQ-2烟雾传感器

unsigned char GetYanWuValue(void)
{
		unsigned int sum=0;
		unsigned char m,value=0;
		for(m=0;m<20;m++)			//读50次AD值
			sum = adc0832(0)+sum;		//读到的AD值,将读到的数据累加到sum
		value=(unsigned char)(sum/20);				//跳出上面的for循环后,将累加的总数除以50得到平均值value
	
		if(value > ADC_Zero) 
				value = value - ADC_Zero;              //首先减去零点漂移
			else
				value = 0;
	
		return value;

}


6 最后

相关文章:

  • 关于QCefView的一些事
  • b站pink老师JavaScript的jQuery 案例代码——电梯导航案例
  • Python快速实现简易飞机大战小游戏
  • PowerWorld仿真与电力系统潮流计算(牛顿拉夫逊法和高斯赛德尔法)(Matlab实现)
  • VSCode自动更新后关闭,重新打开后版本自动降级
  • Google Earth Engine(GEE)——如何处理阈值筛选后的结果没发生变化,以青藏高原NDBI为例
  • 数字验证学习笔记——SystemVerilog芯片验证4 ——数据类型
  • 行为树BT设计与实现
  • 基于神经网络的指纹识别,指纹比对技术何时出现
  • 【图像分割】基于差分进化算法优化模糊熵实现多级图像阈值分割附matlab代码
  • LeetCode 0817. 链表组件
  • 27、Java——超市会员管理系统(对象+IO流)
  • 嵌入式分享合集74
  • 布尔模型,向量空间模型
  • 详解数商云采购协同系统供应商准入流程,加强汽修供应商管理革新企业采购渠道
  • $translatePartialLoader加载失败及解决方式
  • 【node学习】协程
  • angular2开源库收集
  • ECMAScript入门(七)--Module语法
  • express + mock 让前后台并行开发
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • tab.js分享及浏览器兼容性问题汇总
  • 从零搭建Koa2 Server
  • 动态魔术使用DBMS_SQL
  • 面试总结JavaScript篇
  • 深度学习在携程攻略社区的应用
  • 微信小程序--------语音识别(前端自己也能玩)
  • 一起参Ember.js讨论、问答社区。
  • Salesforce和SAP Netweaver里数据库表的元数据设计
  • ​软考-高级-系统架构设计师教程(清华第2版)【第20章 系统架构设计师论文写作要点(P717~728)-思维导图】​
  • # 睡眠3秒_床上这样睡觉的人,睡眠质量多半不好
  • (+4)2.2UML建模图
  • (3)llvm ir转换过程
  • (HAL)STM32F103C6T8——软件模拟I2C驱动0.96寸OLED屏幕
  • (react踩过的坑)Antd Select(设置了labelInValue)在FormItem中initialValue的问题
  • (vue)页面文件上传获取:action地址
  • (笔试题)分解质因式
  • (力扣记录)235. 二叉搜索树的最近公共祖先
  • .bat批处理(九):替换带有等号=的字符串的子串
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
  • .net 反编译_.net反编译的相关问题
  • .net 验证控件和javaScript的冲突问题
  • .net与java建立WebService再互相调用
  • @SentinelResource详解
  • @Transactional 详解
  • [ vulhub漏洞复现篇 ] Apache Flink目录遍历(CVE-2020-17519)
  • [Android]如何调试Native memory crash issue
  • [Asp.net mvc]国际化
  • [AutoSar]工程中的cpuload陷阱(三)测试
  • [AX]AX2012开发新特性-禁止表或者表字段
  • [codeforces]Recover the String
  • [CSS]盒子模型
  • [Linux内存管理-分页机制]—把一个虚拟地址转换为物理地址
  • [Perl] Find Shell on your Wordpress site
  • [poj 3461]Oulipo[kmp]