实现功能:
(1)能够实时检测显示土壤湿度,当需要浇水的时候自动打开灌溉系统,土壤湿度满足要求后,关闭灌溉系统;
(2)检测显示二氧化碳浓度,过高时,通过继电器打开通风排气扇,同时将二氧化碳浓度数值传输到终端进行提示;
(3)能够实时检测显示土壤酸碱度,超标时候能给出报警并提示;
(4)远程异地和检测与控制:传感器所采集到的信息,通过LoRa模块发送给网关,网关以有线连接的方式通过WiFi模块发送给云端,APP可以随时查看大棚内的二氧化碳浓度、土壤湿度与酸碱度的情况;
(5)系统平时可以处于自动模式工作,当需要修改参数时,可以进行手动模式,手动控制可以通过手机和前端按键进行修改,并设置阈值。修改后,将按照新的参数进行工作。
本系统由LoRa节点,LoRa网关,智能手机3部分组成,整体结构如图2-1所示。两个大棚通过LoRa模块传输数据到网关,网关将所有数据整理后上传到云端。
本次使用的是正点原子的LoRa模块,具体配置可以参考手册进行。为了方便我使用的模式为广播,只需要将三个LoRa模块地址、信道、速率相同就可以通信了。由于处于广播模式下,当一个模块发送指令时其他另外两个模块都会接受到信息,所以在开发板接受到数据的时候需要做一下验证处理。为了防止数据冲突采用轮询的方式,轮询发送数据。例如:将终端节点A1和A2的关键字设置为‘DataA1’和‘DataA2’,网关发送关键字‘DataA1’给终端节点A1和A2同时接受到了关键字‘DataA1’,此时终端节点都进入串口中断中判断关键字是否需要回复,终端A1判断为是则回复采集的数据到网关。
网关的主要功能就是接受终端节点的数据、通过WiFi模块发送数据到云端、下发阈值到终端节点。使用STMF407作为核心的开发板,需要的资源:定时器中断,外部中断,串口接受中断。
按键的任务就是负责增加或者减少下发的阈值
串口2中断接受和处理LoRa模块发送的数据,串口3中断是接受和处理WiFi模块发送的数据(设计思路同串口2)。
定时器4负责轮询发送关键字给LoRa模块,并由LoRa发送给各终端节点的LoRa模块。定时器3负责定时发送数据给WiFi模块,WiFi模块发送数据到云端。
#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