【Arduino】基于Arduino单片机的小型气象站设计

要求:设计一个小型的气象监测站,检测温湿度、大气压力、空气质量等参数,并显示在1602液晶显示屏上。

设计方案:

        1、使用温湿度传感器检测温度和湿度,并在显示屏第一行上显示。

        2、使用大气压传感器测量大气压,并在显示屏第二行上显示。

        3、使用激光颗粒物传感器检测空气中PM2.5含量,并在显示屏第二行上显示。

设备选型:

主控中心:Arduino Mega 2560

        Arduino Mega 2560是基于ATmega2560的微控制板,有54路数字输入/输出端口(其中15个可以作为PWM输出),16路模拟输入端口,4路UART串口,16MHz的晶振,USB连接口,电池接口,ICSP头和复位按钮。简单地用USB连接电脑或者用交直流变压器就能使用。

温湿度传感器:DHT11

        DHT11 数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有枀高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个 NTC 测温元件,并与一个高性能 8 位单片机相连接。

          

           引脚说明

                    1、VDD 供电 3.3~5.5V DC

                    2、DATA 串行数据,单总线

                   3、NC 空脚

                   4、GND 接地,电源负极

大气压传感器:BMP085

       BMP085是德国BOSCH公司生产的一款低功耗、高精度的MEMS数字气压传感器。BMP085的供电电压为1.8 V~3.6 V,典型值为2.5 V。它由电阻式压力传感器、A/D转换器和带有E2PROM的控制单元组成,控制单元通过I2C总线与移动设备的微处理器连接。E2PROM中存储了11个校准参数,这11个校准参数涉及到参考温度下的零点漂移、零点漂移的温度系数以及灵敏度的温度系数等,用于对气压值进行温度补偿。

       BMP085的气压测量范围为300hPa~1100hPa(海拔高度-500 m~9000 m),温度测量范围为-40 ℃~+85 ℃。在低功耗模式下,BMP085精度为0.06 hPa(0.5 m),在高精度模式下其精度可以达到0.03 hPa(0.25 m),转换速率可以达到128次/s,能够满足系统对速度和精度的要求。

激光颗粒物传感器:GP2Y1051AUOF

        GP2Y1010AU0F是日本夏普公司开发的一款光学灰尘浓度检测传感器。此传感器内部成对脚分布的红外发光管和光电晶体管,利用光敏原理来工作。用于检测特别细微的颗粒,如香烟颗粒、细微灰尘。依靠输出脉冲的高度来判断颗粒浓度。

           

系统连接图:

                     

撰写代码:

ino 文件

n#include "DHT11.h"
#include <Wire.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(12,11,A4,A5,A6,A7);//1602
DHT11 myDHT11(2);//温湿度输出引脚
//气压传感器-------------------------
#define BMP180ADD 0x77  // I2C address of BMP180  
                           //write is (0xEE)     read is (0xEF)       
unsigned char OSS;                            
/**********************MSB      LSB******/
int ac1;           // 0xAA     0xAB
int ac2;           // 0xAC     0xAD
int ac3;           // 0xAE     0xAE
unsigned int ac4;  // 0xB0     0xB1
unsigned int ac5;  // 0xB2     0xB3
unsigned int ac6;  // 0xB4     0xB5
int b1;            // 0xB6     0xB7
int b2;            // 0xB8     0xB9
int mb;            // 0xBA     0xBB
int mc;            // 0xBC     0xBD
int md;            // 0xBE     0xBF
float temperature;  
double pressure;   
double pressure2;
long b5;          
double altitude;  


//PM2.5---------------------------------------------------------
#define    COV_RATIO                0.2            //ug/mmm / mv
#define    NO_DUST_VOLTAGE          400            //mv
#define    SYS_VOLTAGE              5000           //ADC参考电压    
const int vout = 5;        //pm2.5输出引脚
float density, voltage;
int   adcvalue;
int Filter(int m)
{
  static int flag_first = 0, _buff[10], sum;
  const int _buff_max = 10;
  int i;
  
  if(flag_first == 0)
  {
    flag_first = 1;

    for(i = 0, sum = 0; i < _buff_max; i++)
    {
      _buff[i] = m;
      sum += _buff[i];
    }
    return m;
  }
  else
  {
    sum -= _buff[0];
    for(i = 0; i < (_buff_max - 1); i++)
    {
      _buff[i] = _buff[i + 1];
    }
    _buff[9] = m;
    sum += _buff[9];
    
    i = sum / 10.0;
    return i;
  }
}
//-----------------------------------


void setup(void)
{
  lcd.begin(16,2);    //初始化LCD1602
  lcd.print("Welcome to use!"); //液晶显示Welcome to use!
  delay(1000);      //延时1000ms
  lcd.clear();      //液晶清屏
  Serial.begin(9600);   //send and receive at 9600 baud
   Wire.begin();
  OSS = 2;  // Oversampling Setting           0: single    1: 2 times    2: 4 times   3: 8 times 
  BMP180start();
}

void loop(void)
{
  //lcd.clear();      //液晶清屏
  Serial.print("---------\n");
  delayMicroseconds(280);
  adcvalue = analogRead(vout); 
  adcvalue = Filter(adcvalue);
 //电压
  voltage = (SYS_VOLTAGE / 1024.0) * adcvalue * 11;
  if(voltage >= NO_DUST_VOLTAGE)
  {
    voltage -= NO_DUST_VOLTAGE;
    density = voltage * COV_RATIO;
  }
  else
    density = 0;
  Serial.print("PM: ");
  Serial.print(3*density/100);
  Serial.print(" ug/m3\n");  
  lcd.setCursor(8,1);    //设置液晶开始显示的指针位置,1列,2行
  lcd.print("PM:"); //液晶显示
  lcd.print(3*density/100);
  delay(500);
   
  Serial.print("---------\n");
  myDHT11.DHT11_Read();								//读取温湿度值
  Serial.print("HUMI = ");
  Serial.print(myDHT11.HUMI_Buffer_Int);
  Serial.println(" %RH");
  Serial.print("TMEP = ");
  Serial.print(myDHT11.TEM_Buffer_Int);
  Serial.println(" C");
  lcd.setCursor(0,0);    //设置液晶开始显示的指针位置,1列,2行
  lcd.print("T:"); //液晶显示
  lcd.print(myDHT11.HUMI_Buffer_Int);
  lcd.print((char)223);    //液晶显示“°”
  lcd.print("C");   //液晶显示“C”
   delay(500);
  lcd.setCursor(7,0);    //设置液晶开始显示的指针位置,1列,2行
  lcd.print("H:"); //液晶显示
  lcd.print(myDHT11.TEM_Buffer_Int);
  lcd.print(" %RH");   //液晶显示“C”
  delay(500);			  //延时1s

  Serial.print("---------\n");
  calculate();
  show();
  delay(500);
}
//大气压
/** calculate centure **/
void calculate()
{
  temperature = bmp180GetTemperature(bmp180ReadUT());
  temperature = temperature*0.1;
  pressure = bmp180GetPressure(bmp180ReadUP());
  pressure2 = pressure/101325;
  pressure2 = pow(pressure2,0.19029496);
  altitude = 44330*(1-pressure2);                            //altitude = 44330*(1-(pressure/101325)^0.19029496);
}
 
/** print reslut **/
void show()
{
  Serial.print("Temp: ");
  Serial.print(temperature, 1);                            //10 hexadecimal
  Serial.println(" C");
  Serial.print("Pressure: ");
  Serial.print(pressure, 0);                               //10 hexadecimal
  Serial.println(" Pa");
  Serial.print("altitude:");
  Serial.print(altitude);
  Serial.println("m");
  lcd.setCursor(0,1);    //设置液晶开始显示的指针位置,1列,2行
  lcd.print("P:"); //液晶显示
  lcd.print(pressure/1000.0);
}
 
/**BMP180 satrt program**/
void BMP180start()
{                     /*MSB*/
  ac1 = bmp180ReadDate(0xAA);                      //get full data
  ac2 = bmp180ReadDate(0xAC);  
  ac3 = bmp180ReadDate(0xAE);  
  ac4 = bmp180ReadDate(0xB0);  
  ac5 = bmp180ReadDate(0xB2);  
  ac6 = bmp180ReadDate(0xB4);  
  b1  = bmp180ReadDate(0xB6);  
  b2  = bmp180ReadDate(0xB8);  
  mb  = bmp180ReadDate(0xBA);  
  mc  = bmp180ReadDate(0xBC);  
  md  = bmp180ReadDate(0xBE);
}
 
/***BMP180 temperature Calculate***/
short bmp180GetTemperature(unsigned int ut)
{
  long x1, x2;
  x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15;  //x1=((ut-ac6)*ac5)/(2^15)
  x2 = ((long)mc << 11)/(x1 + md);                //x2=(mc*2^11)/(x1+md)
  b5 = x1 + x2;                                   //b5=x1+x2
  return ((b5 + 8)>>4);                           //t=(b5+8)/(2^4)
}
 
/***BMP180 pressure Calculate***/
 
long bmp180GetPressure(unsigned long up)
{
  long x1, x2, x3, b3, b6, p;
  unsigned long b4, b7;
  
  b6 = b5 - 4000;
 
  x1 = (b2 * (b6 * b6)>>12)>>11;
  x2 = (ac2 * b6)>>11;
  x3 = x1 + x2;
  b3 = (((((long)ac1)*4 + x3)<<OSS) + 2)>>2;
  
  x1 = (ac3 * b6)>>13;
  x2 = (b1 * ((b6 * b6)>>12))>>16;
  x3 = ((x1 + x2) + 2)>>2;
  b4 = (ac4 * (unsigned long)(x3 + 32768))>>15;
  
  b7 = ((unsigned long)(up - b3) * (50000>>OSS));
  if (b7 < 0x80000000)
    p = (b7<<1)/b4;
  else
    p = (b7/b4)<<1;
    
  x1 = (p>>8) * (p>>8);
  x1 = (x1 * 3038)>>16;
  x2 = (-7357 * p)>>16;
  p += (x1 + x2 + 3791)>>4;
  
  return p;
}
 
 
/*** Read 1 bytes from the BMP180  ***/
 
int bmp180Read(unsigned char address)
{
  unsigned char data;
  
  Wire.beginTransmission(BMP180ADD);
  Wire.write(address);
  Wire.endTransmission();
  
  Wire.requestFrom(BMP180ADD, 1);
  while(!Wire.available());
    
  return Wire.read();
}
 
/*** Read 2 bytes from the BMP180 ***/
int bmp180ReadDate(unsigned char address)
{
  unsigned char msb, lsb;
  Wire.beginTransmission(BMP180ADD);
  Wire.write(address);
  Wire.endTransmission();
  Wire.requestFrom(BMP180ADD, 2);
  while(Wire.available()<2);
  msb = Wire.read();
  lsb = Wire.read();
  return (int) msb<<8 | lsb;
}
 
/*** read uncompensated temperature value ***/
unsigned int bmp180ReadUT()
{
  unsigned int ut;
  Wire.beginTransmission(BMP180ADD);
  Wire.write(0xF4);                       // Write 0x2E into Register 0xF4
  Wire.write(0x2E);                       // This requests a temperature reading
  Wire.endTransmission();  
  delay(5);                               // Wait at least 4.5ms
  ut = bmp180ReadDate(0xF6);               // read MSB from 0xF6 read LSB from (16 bit)
  return ut;
}
 
/*** Read uncompensated pressure value from BMP180 ***/
unsigned long bmp180ReadUP()
{
  unsigned char msb, lsb, xlsb;
  unsigned long up = 0;
  
  Wire.beginTransmission(BMP180ADD);
  Wire.write(0xF4);                        // Write 0x34+(OSS<<6) into register 0xF4
  Wire.write(0x34 + (OSS<<6));             // 0x34+oss*64
  Wire.endTransmission(); 
  delay(2 + (3<<OSS));                     // Wait for conversion, delay time dependent on OSS
  
  Wire.beginTransmission(BMP180ADD);
  Wire.write(0xF6);                        // Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)
  Wire.endTransmission();
  
  Wire.requestFrom(BMP180ADD, 3); 
  while(Wire.available() < 3);             // Wait for data to become available
  msb = Wire.read();
  lsb = Wire.read();
  xlsb = Wire.read();
  up = (((unsigned long) msb << 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8-OSS);//16 to 19 bit
  return up;
}

DHT11.CPP

#include "DHT11.h"

//定义变量
unsigned char HUMI_Buffer_Int = 0;
unsigned char TEM_Buffer_Int = 0;

DHT11::DHT11(int pin)
{
	DHT11_DQ = pin;
}
 
//****************************************************
//初始化DHT11
//****************************************************
void DHT11::DHT11_Init()
{
	pinMode(DHT11_DQ,OUTPUT);

	digitalWrite(DHT11_DQ,LOW);  //拉低总线,发开始信号;
	delay(30);  //延时要大于 18ms,以便 DHT11 能检测到开始信号;
	digitalWrite(DHT11_DQ,HIGH);
	delayMicroseconds(40);  //等待 DHT11 响应;
	pinMode(DHT11_DQ,INPUT_PULLUP);
	while(digitalRead(DHT11_DQ) == HIGH);
	delayMicroseconds(80);   //DHT11 发出响应,拉低总线 80us;
	if(digitalRead(DHT11_DQ) == LOW);
	delayMicroseconds(80);   //DHT11 拉高总线 80us 后开始发送数据;
}

//****************************************************
//读一个字节DHT11数据
//****************************************************
unsigned char DHT11::DHT11_Read_Byte()
{
	unsigned char i,dat = 0;
	unsigned int j;

	pinMode(DHT11_DQ,INPUT_PULLUP);
        delayMicroseconds(2);
	for( i=0; i<8; i++)
	{
			while(digitalRead(DHT11_DQ) == LOW);   //等待 50us;
			delayMicroseconds(40);   //判断高电平的持续时间,以判定数据是‘0’还是‘1’;
			if(digitalRead(DHT11_DQ) == HIGH)
				dat |= (1<<(7-i));   //高位在前,低位在后;
			while(digitalRead(DHT11_DQ) == HIGH);   //数据‘1’,等待下一位的接收;

	}
	return dat;
}

//****************************************************
//读取温湿度值,存放在TEM_Buffer和HUMI_Buffer
//****************************************************
void DHT11::DHT11_Read()
{
	DHT11_Init();

	HUMI_Buffer_Int = DHT11_Read_Byte();   		//读取湿度的整数值
	DHT11_Read_Byte();							//读取湿度的小数值
	TEM_Buffer_Int = DHT11_Read_Byte();			//读取温度的整数值
	DHT11_Read_Byte();							//读取温度的小数值
	DHT11_Read_Byte();							//读取校验和
	delayMicroseconds(50);						//DHT11拉低总线50us

	pinMode(DHT11_DQ,OUTPUT);
	digitalWrite(DHT11_DQ,HIGH);				//释放总线	


}


测试结果:

1602显示

串口数据

发布了64 篇原创文章 · 获赞 82 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_40602000/article/details/86630427