STM32
直播中

世态薄凉

9年用户 1222经验值
私信 关注
[问答]

如何实现环境参数智能监测站设计?

如何实现环境参数智能监测站设计?

回帖(1)

陈茗卓

2021-12-20 10:24:50
系统总体设计

本系统具有对环境的温度、湿度、光照、空气质量、土壤水分、雨情的检测和控制等功能。系统运用STM32F103C8T6作为最小系统的中央处理器。整个系统主要从硬件电路设计和软件程序设计两部分来实现。可以将环境监控系统的硬件分为几大模块进行设计,分别为:信号采集模块、主控制模块、人机互动模块。本系统设计用DS18B20、DHT11、光敏二极管、MQ-135对温度、湿度、光照、环境质量等参数进行采集。再把采集的数据输送到STM32F103C8T6中进行处理。处理后的信息输送到OLED上进行显示。STM32F103C8T6根据键盘输入的设置参数值进行对比和判断是否有参数超过设置的范围,如有参数超标就发出声响进行警报,把环境参数通过NRF24L01模块发送到终端上。
检测节点结构框图:





总程序流程图

本系统采用单片机作为主控制部分,主程序是一个无限循环的程序,通过keil开发环境下载到单片机中工作。系统开始工作时,主程序运行,先对系统的硬件进行初始化,然后判断是否有键盘摁下,运用键盘进行环境参数的设置,然后通过传感器采集环境中的温度、湿度、光照、有害气体的参数。在OLED上显示采集到的环境参数。在与我们所设置的环境参数进行比较看是否有参数超标。
总程序流程图:





DS18B20程序流程图

温度监控的子程序也是一个循环的程序。当单片机接上电之后,单片机向DS18B20传感器发出指令,DS18b20传感器采集环境中温度参数,把温度值传输到液晶显示屏上显示出来。同时在STM32中将采集的温度参数的实际值与我们设置的参数范围进行比较。如果实际的参数值在设置的范围内,则返回重新采集。如果不在范围之内就发出警报并把数值通过蓝牙传输到终端上,同时开启相应的设备控制温度,并返回重新采集数据。
DS18B20流程图:





DHT11程序流程图

湿度监控也是一个循环的子程序。当STM32通上电之后,STM32向DHT11发出采集指令,它就采集养殖舍内的湿度参数值,把该参数值传送到OLED上显示出来。同时在STM32中将采集的湿度参数的实际值与我们设置的参数范围进行比较。如果实际的参数值在设置的范围内,则返回重新采集。如果不在范围之内就发出警报并把数值通过蓝牙传输到终端上,同时开启相应的设备控制湿度,并返回重新采集数据。
DHT11流程图:





MQ-135程序流程图

有害气体监控的子程序也是一个循环的程序。当单片机接上电之后,单片机向MQ-135传感器发出指令,MQ-135传感器采集环境中有害气体浓度,把有害气体浓度值传输到液晶显示屏上显示出来。同时有害气体浓度值在单片机中与我们设定的参数浓度值进行对比是否在设定的浓度范围之内。如果在设定的范围之内,则返回重新采集数据。如果不在范围之内发出警报把数值通过NRF传输到终端上,提醒管理人员进行人工处理降低有害气体浓度,并返回重新采集数据。
MQ-135流程图:





光照强度程序流程图

当STM32通上电之后,STM32向光照传感器发出工作指令,其通过光敏电阻采集养殖舍内的光照参数,并把该参数值传送到OLED上显示出来。同时实际的光照与系统内设定的光照范围进行比较,看实际值在哪个范围内,系统会对不同的范围开启不同的灯光数值,并返回重新采集数值。
光照流程图:





NRF 程序流程图

监测终端上电,首先NRF检测配对,检测环境检测节点是否工作正常,随后进行环境参数采集,分析处理。





土壤水分程序流程图

土壤水分传感器,AD采集传感器采集的电压信号,公式计算可得土壤水分百分比,随即传输给监测终端,并在OLED显示信息。





雨情程序流程图

雨滴传感器采集雨情信息,同其他传感器类似,单片机AD采集电压信号,并通过NRF传输给监测终端,公式计算之后得雨情信息。






核心代码
检测节点主程序


#include "stm32f10x.h"
#include "bsp_led.h"  
#include "bsp_GeneralTim.h"
#include "bsp_adc.h"
#include "OLED_I2C.h"
#include "delay.h"
#include "bsp_key.h"  
#include "beep.h"
#include "nrf24l01.h"
#include "sys.h"
#include "bsp_usart.h"
#include "bsp_dht11.h"
#include "ds18b20.h"
#define uint unsigned int
#define uchar unsigned char
///
void num_char(uint x);


uchar adc1_num[ ]="12345";
uint ADC_ConvertedValueLocal[NOFCHANEL];
extern __IO uint16_t ADC_ConvertedValue[NOFCHANEL];
char *reverse(char *s)
{
    char temp;
    char *p = s;    //p指向s的头部
    char *q = s;    //q指向s的尾部
    while(*q)
        ++q;
    q--;
   
    //交换移动指针,直到p和q交叉
    while(q > p)
    {
        temp = *p;
        *p++ = *q;
        *q-- = temp;
    }
    return s;
}
// //检测到的传感器ID存数组
extern unsigned char DS18B20_ID[8][8];
extern unsigned char DS18B20_SensorNum;
int main(void)
{
  char *string = my_itoa(12700);
uchar TEMP[]="TEMP:";/*温度 ℃*/
uchar HUM[]="HUM:";  /*湿度 %Rh*/
uchar CDQ[]="CDQ:";    /*光强 lux*/
uchar SHUM[]="SHUM:";/*土壤水分 %*/
uchar PSI[]="PSI:";/*空气质量 ppm*/
uchar RCD[]="RCD:";/*雨情 mm*/
u8 rx_buf[40];
  u16 TEMP1=0,HUM1=0,CDQ1=0,SHUM1=0,PSI1=0,RCD1=0;
int adc_A5_i,adc_A7_i,adc_A1_U,adc_B0_U;
int duty_set=10,fre_set=100;
int set_point=5000;
float Temp;
  u8 num=0,i;
  
SystemInit();

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  LED_GPIO_Config();
//BEEP_Init();
ADCx_Init();
SPI2_Init();
  NRF24L01_Init();
/* 高级定时器初始化 */
  GENERAL_TIM_Init(duty_set , fre_set);
  DelayInit();
I2C_Configuration();
OLED_Init();
OLED_CLS();
Key_GPIO_Config();
  pid_text_init();
OLED_Fill(0xFF);//全屏点亮
DelayMs(1000);
OLED_Fill(0x00);//全屏灭
DHT11_Data_TypeDef DHT11_Data;
/* 配置Systick 为1us中断一次 */

USART_Config();//初始化串口2
/*初始化DT11的引脚*/
DHT11_Init ();

/*初始化DS18b20的引脚*/
  u8 DS18B20_Init();
while(NRF24L01_Check())  //检测NRF24L01是否存在
{
  GPIO_SetBits(GPIOC,GPIO_Pin_13);
  OLED_ShowStr(0,1,(unsigned char*)"NRF Error",1);
  OLED_ShowStr(0,2,(unsigned char*)"Please chect NRF",1);
}

NRF24L01_TX_Mode();
   while (DS18B20_Init())   //检测DS18B20是否存在
  {
   OLED_ShowStr(0,1,(unsigned char*)"Ds18B20 Error",1);
  }
    while(1)
    {
    LED1_TOGGLE;
    num=DS18B20_Search_Rom(1);
    for(i=0;i   {
  TEMP1=DS18B20_Get_Temp1(i);
  }
  if( DHT11_Read_TempAndHumidity ( & DHT11_Data ) == SUCCESS)
  {
   HUM1=DHT11_Data.humi_int;
  }
  if(NRF24L01_TxPacket(rx_buf)==TX_OK)
   {
    GPIO_ResetBits(GPIOC,GPIO_Pin_13);
   }
   else
   {
       GPIO_SetBits(GPIOC,GPIO_Pin_13);
       DelayMs(100);
       GPIO_ResetBits(GPIOC,GPIO_Pin_13);
       DelayMs(100);   
       }
       rx_buf[0]=TEMP1>>8;//温度
   rx_buf[1]=TEMP1;
   rx_buf[2]=HUM1>>8;//湿度
   rx_buf[3]=HUM1;
   rx_buf[4]=adc_B0_U>>8;//光照强度
   rx_buf[5]=adc_B0_U;
   rx_buf[6]=adc_A5_i>>8;//土壤水分
   rx_buf[7]=adc_A5_i;
   rx_buf[8]=adc_A7_i>>8;//空气质量
   rx_buf[9]=adc_A7_i;
   rx_buf[10]=adc_A1_U>>8;//雨情
   rx_buf[11]=adc_A1_U;
  adc_A5_i = ADC_ConvertedValue[0]*33000/4096;
  adc_A7_i = ADC_ConvertedValue[1]*33000/4096;
  adc_A1_U = ADC_ConvertedValue[2]*33000/4096;
  adc_B0_U = ADC_ConvertedValue[3]*33000/4096;
   ///温度显示//
     string = my_itoa(TEMP1);
  OLED_ShowStr(0,0,TEMP,1);
  OLED_ShowStr(40,0,string,1);
///湿度显示//
       string = my_itoa(HUM1);
    OLED_ShowStr(0,1,HUM,1);
      OLED_ShowStr(40,1,string,1);
  
///光强显示//
//   adc_A5_i=adc_A5_i*30.3/50;  
  string = my_itoa(adc_B0_U);
  OLED_ShowStr(0,2,CDQ,1);
  OLED_ShowStr(40,2,string,1);
///土壤水分显示//
//  adc_A7_i= adc_A7_i*30.3/50;
   string = my_itoa(adc_A5_i);//32991:最干燥 (32991-采集值)/32991=水分  %
  OLED_ShowStr(0,3,SHUM,1);
  OLED_ShowStr(40,3,string,1);
  
///空气质量显示//  10--1000ppm
   string = my_itoa(adc_A7_i);      //  
  OLED_ShowStr(0,4,PSI,1);
  OLED_ShowStr(40,4,string,1);
  
///雨情显示//  
   string = my_itoa(adc_A1_U);//32991:雨情最小即未下雨  (32991-采集值)/32991=雨情 %
  OLED_ShowStr(0,5,RCD,1);
  OLED_ShowStr(40,5,string,1);
  
  OLED_ShowStr(25,6,"First node",2);
    LED2_TOGGLE;
    }
}


监测终端主程序


#include "sys.h"
#include "sysitck.h"
#include "led.h"
#include "nrf24l01.h"
#include "adc.h"
#include "OLED_I2C.h"
#include "beep.h"
#include "bsp_adc.h"
#include "bsp_GeneralTim.h"
#include "key.h"
#define uint unsigned int
#define uchar unsigned char
void num_char(uint x);


uchar adc1_num[ ]="12345";
uint ADC_ConvertedValueLocal[NOFCHANEL];  
extern __IO uint16_t ADC_ConvertedValue[NOFCHANEL];
char *reverse(char *s)
{
    char temp;
    char *p = s;    //p指向s的头部
    char *q = s;    //q指向s的尾部
    while(*q)
        ++q;
    q--;
   
    //交换移动指针,直到p和q交叉
    while(q > p)
    {
        temp = *p;
        *p++ = *q;
        *q-- = temp;
    }
    return s;
}
// //检测到的传感器ID存数
int main(void)
{
  char *string = my_itoa(12700);
uchar TEMP[]="TEMP:";/*温度 ℃*/
uchar HUM[]="HUM:";  /*湿度 %Rh*/
uchar CDQ[]="CDQ:";    /*光强 lux*/
uchar SHUM[]="SHUM:";/*土壤水分 %*/
uchar PSI[]="PSI:";/*空气质量 ppm*/
uchar RCD[]="RCD:";/*雨情 mm*/
  int adc_A5_i,adc_A7_i,adc_B0_U,adc_B1_U;
int duty_set=10,fre_set=100;
int m=0;//节点数
int i=0;
int T=0;
u8 rx_buf[40];
  u16 TEMP1=0,HUM1=0,CDQ1=0,SHUM1=0,PSI1=0,RCD1=0;//
u16 TEMP2=0,HUM2=0,CDQ2=0,SHUM2=0,PSI2=0,RCD2=0;//
  SystemInit();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
LED_GPIO_Config();
  Key_GPIO_Config();
NRF24L01_Init();
adc_init();
I2C_Configuration();
OLED_Init();
OLED_Fill(0xFF);
delay_ms(1000);
OLED_Fill(0x00);
  while(NRF24L01_Check())  //检测NRF24L01是否存在
{
  GPIO_SetBits(GPIOC,GPIO_Pin_13);
  OLED_ShowStr(0,1,(unsigned char*)"NRF Error",1);
  OLED_ShowStr(0,2,(unsigned char*)"Please chect NRF",1);
}
  while(1)
{
// key_scan();
  
  digitalToggle(LED3_GPIO_PORT,LED3_GPIO_PIN);
  delay_ms(10);
  digitalToggle(LED2_GPIO_PORT,LED2_GPIO_PIN);
      第一节点环境信息接收///
   TEMP1=rx_buf[0]<<8|rx_buf[1];//温度
   HUM1=rx_buf[2]<<8|rx_buf[3];//湿度
   CDQ1=rx_buf[4]<<8|rx_buf[5];//光照强度
   SHUM1=rx_buf[6]<<8|rx_buf[7];//土壤水分
   PSI1=rx_buf[8]<<8|rx_buf[9];//空气质量
   RCD1=rx_buf[10]<<8|rx_buf[11];//雨情
  第二节点环境信息接收///
   TEMP2=rx_buf[0]<<8|rx_buf[1];//温度
   HUM2=rx_buf[2]<<8|rx_buf[3];//湿度
   CDQ2=rx_buf[4]<<8|rx_buf[5];//光照强度
   SHUM2=rx_buf[6]<<8|rx_buf[7];//土壤水分
   PSI2=rx_buf[8]<<8|rx_buf[9];//空气质量
   RCD2=rx_buf[10]<<8|rx_buf[11];//雨情
        if(TEMP1>30|TEMP2>30)
   {
    BEEP_Init();
    Sound(50);
   }
   if(HUM1>70|HUM2>70)
   {
    BEEP_Init();
    Sound(50);
   }
     if(m==0)
{
     for(i=0;i<6;i++)
  {
   OLED_ShowCN(18+i*16,0,i);//个人信息
  }
     for(i=0;i<4;i++)
  {
   OLED_ShowCN1(26+i*16,2,i);//
  }
    for(i=0;i<3;i++)
  {
   OLED_ShowCN2(36+i*16,4,i);//
  }
  OLED_ShowStr(24,6,"1605260141",2);
}
    //第一个节点环境信息
if(m==1)
{  
  
  NRF24L01_RX_Mode();
  ///温度显示//
  string = my_itoa(TEMP1);
  OLED_ShowStr(0,0,TEMP,1);
  OLED_ShowStr(40,0,string,1);
  OLED_ShowCN3(90, 0, 0);
     ///湿度显示//
   string = my_itoa(HUM1);
  OLED_ShowStr(0,1,HUM,1);
  OLED_ShowStr(40,1,string,1);
  OLED_ShowStr(90,1,"%Rh",1);
  
  
   ///光照强度显示//   
  string = my_itoa(CDQ1);
  OLED_ShowStr(0,2,CDQ,1);
  OLED_ShowStr(40,2,string,1);
  OLED_ShowStr(90,2,"lux",1);
     ///土壤水分显示//
   string = my_itoa((32991-SHUM1)/32991.0*100);//32991:最干燥(32991-采集值)/32991=水分 %值显示
  OLED_ShowStr(0,3,SHUM,1);
  OLED_ShowStr(40,3,string,1);
  OLED_ShowStr(90,3,"%",1);
  
   ///空气质量显示//  
  
   string = my_itoa(990/32991.0*PSI1);                  //32991:最大采集电压   10-1000ppm   990/32991*采集电压值=  ppm
  OLED_ShowStr(0,4,PSI,1);
  OLED_ShowStr(40,4,string,1);
  OLED_ShowStr(90,4,"ppm",1);
  
   ///雨情显示//
  string = my_itoa((32991-RCD1)/32991.0*100);//32991:未下雨   (32991-采集值)/32991=雨情 %值显示
  OLED_ShowStr(0,5,RCD,1);
  OLED_ShowStr(40,5,string,1);
  OLED_ShowStr(90,5,"mm",1);
  
  OLED_ShowStr(25,6,"First node",2);
}
   //第二个节点环境信息
  if(m==2)
{  
  
  NRF24L01_RX_Mode1();
  ///温度显示//
  string = my_itoa(TEMP2);
  OLED_ShowStr(0,0,TEMP,1);
  OLED_ShowStr(40,0,string,1);
    OLED_ShowCN3(90, 0, 0);
  
   ///湿度显示//
   string = my_itoa(HUM2);
  OLED_ShowStr(0,1,HUM,1);
  OLED_ShowStr(40,1,string,1);
  OLED_ShowStr(90,1,"%Rh",1);
  
  
   ///光照强度显示//   
  string = my_itoa((CDQ2));
  OLED_ShowStr(0,2,CDQ,1);
  OLED_ShowStr(40,2,string,1);
  OLED_ShowStr(90,2,"lux",1);
  
   ///土壤水分显示//
   string = my_itoa((32991-SHUM2)/32991.0*100);
  OLED_ShowStr(0,3,SHUM,1);
  OLED_ShowStr(40,3,string,1);
  OLED_ShowStr(90,3,"%",1);
  
   ///空气质量显示//  
  
   string = my_itoa(990/32991.0*PSI2);
  OLED_ShowStr(0,4,PSI,1);
  OLED_ShowStr(40,4,string,1);
  OLED_ShowStr(90,4,"ppm",1);
  
  
   ///雨情显示//
  string = my_itoa((32991-RCD2)/32991.0*100);
  OLED_ShowStr(0,5,RCD,1);
  OLED_ShowStr(40,5,string,1);
  OLED_ShowStr(90,5,"mm",1);
  
  OLED_ShowStr(25,6,"Second node",2);
}
     if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6)==0)
   {
    delay_ms(20);
   if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6)==0)
     m++;
   if(m>2)m=1;
   OLED_Fill(0x00);
   while(!GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6));
   }
         if(NRF24L01_RxPacket(rx_buf)==0)
         {
         GPIO_ResetBits(GPIOC,GPIO_Pin_13);
         }
         }
         }


由于程序篇幅较长,这里不一一展示,后续会将完整代码上传此博客。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分