Fastbond活动项目3 环境监测
使用arduino 配合 max adi的相关原件完成环境温度、湿度、照度的采集和记录
标签
Arduino
老孙头
更新2021-11-25
1057

   B站视频地址https://www.bilibili.com/video/BV1L44y1Y7tK?share_source=copy_web

 

   本人是一名电气工程师,主要是搞建筑电气的也就是低压,对电子电路这些东西很感兴趣,但是工作很忙,业余时间比较少,投入在这一块的精力也比较少,只是能够利用arduino做一点点小玩意,有幸从硬禾的公众号上得知了这个fastbond活动,很感兴趣。于是就参加了。

   

     项目介绍

     我这次进行的项目是第三个主题,环境监测。出发点根据一定时间间隔监测房间的照度、温度和湿度。监控结果可以用来分析房间的温湿度随室外温度和光照情况的不同,所产生的变化。

     事实上,建筑专业研究人员,可以通过这些数据,对房屋的保温情况做出评估。也可以根据这些数据控制空调、暖气、电动窗帘等设施使得建筑环境更加舒适,更加节能环保。

     受技术和时间的限制、我并没有打板,整个装置采用的现成模块配合杜邦线连接而成。看上去比较散乱,要是能会打板就好了。这里给硬禾做个广告。因为硬禾确确实实提供了打板的设计课,而且价格特别低,也就是一条烟钱。主要我就是没时间啊,没时间。。。

   

     设计思路

      设计思路是使用温湿度测量模块、单线温度模块、光敏模块,按照一定时间间隔持续记录室内外环境,使用时钟模块确保arduino内部时间累加器溢出或电源不小心断电后后,当前的时间信息依然保留。使用TF卡模块记录数据。Arduino UNO作为主控。编程软件环境为arduino IDE。

   

    项目使用模块、器件介绍

     主控板使用arduino uno,负责收集并转换传感器信号,并发送到串口和存储至TF卡。传感器使用DHT11和DS18b20(美信公司,温度测量模块,单线接口),用来测量室内温湿度和室外温度。使用光敏电阻模块+AD620芯片(ADI公司,放大器用于放大信号)测量环境光强,使用DS1307模块(美信、时钟模块)提供脱机记录实时时间。另有一个TF卡读卡器模块,用于记录数据。

    整体搭建完是这样子的。

Fu9RWEOzBlg4QDyqhcKDyDBcoHNk

 

   项目源码及注释

#include <SPI.h>
#include <SD.h>
File dataFile ;
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>

#define DHTPIN 2 // Digital pin connected to the DHT sensor
#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT22 // DHT 22 (AM2302)
//#define DHTTYPE DHT21 // DHT 21 (AM2301)

DHT_Unified dht(DHTPIN, DHTTYPE);

#define LIGHT_PIN A0
const int chipSelect =4 ;

uint32_t delayMS;

//表示时间用的
#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>

//18b20用
#include <OneWire.h>
OneWire ds(5); // on pin 8 (a 4.7K resistor is necessary)




//下面进入setup函数----------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);


// dht传感器初始设置,Initialize device.
dht.begin();
Serial.println(F("DHTxx Unified Sensor Example"));
// Print temperature sensor details.
sensor_t sensor;
dht.temperature().getSensor(&sensor);
Serial.println(F("------------------------------------"));
Serial.println(F("Temperature Sensor"));
Serial.print (F("Sensor Type: ")); Serial.println(sensor.name);
Serial.print (F("Driver Ver: ")); Serial.println(sensor.version);
Serial.print (F("Unique ID: ")); Serial.println(sensor.sensor_id);
Serial.print (F("Max Value: ")); Serial.print(sensor.max_value); Serial.println(F("°C"));
Serial.print (F("Min Value: ")); Serial.print(sensor.min_value); Serial.println(F("°C"));
Serial.print (F("Resolution: ")); Serial.print(sensor.resolution); Serial.println(F("°C"));
Serial.println(F("------------------------------------"));
// Print humidity sensor details.
dht.humidity().getSensor(&sensor);
Serial.println(F("Humidity Sensor"));
Serial.print (F("Sensor Type: ")); Serial.println(sensor.name);
Serial.print (F("Driver Ver: ")); Serial.println(sensor.version);
Serial.print (F("Unique ID: ")); Serial.println(sensor.sensor_id);
Serial.print (F("Max Value: ")); Serial.print(sensor.max_value); Serial.println(F("%"));
Serial.print (F("Min Value: ")); Serial.print(sensor.min_value); Serial.println(F("%"));
Serial.print (F("Resolution: ")); Serial.print(sensor.resolution); Serial.println(F("%"));
Serial.println(F("------------------------------------"));
// Set delay between sensor readings based on sensor details.
delayMS = sensor.min_delay / 1000;

pinMode(10,OUTPUT);
Serial.println("Initializing SD cad");
if(!SD.begin(chipSelect))
{
Serial.println("Initializing failed!");
//while (1);
}
Serial.println("Initializing done!");


//-----------


}


//表述时间的一个尾巴,没这个 下面那个print2digits还不认
void print2digits(int number) {
if (number >= 0 && number < 10) {
Serial.write('0');
}
Serial.print(number);
}
void loop() {
//用于18b20的-----------------------------------------------------------------
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float celsius;

if ( !ds.search(addr)) {
//串口打印状态的注释掉 Serial.println("No more addresses.");
//串口打印状态的注释掉 Serial.println();
ds.reset_search();
delay(1000);
return;
}

/*串口打印状态的注释掉
Serial.print("ROM =");
for( i = 0; i < 8; i++) {
Serial.write(' ');
Serial.print(addr[i], HEX);
}

if (OneWire::crc8(addr, 7) != addr[7]) {
Serial.println("CRC is not valid!");
return;
}
Serial.println();


// the first ROM byte indicates which chip
switch (addr[0]) {
case 0x10:
Serial.println(" Chip = DS18S20"); // or old DS1820
type_s = 1;
break;
case 0x28:
Serial.println(" Chip = DS18B20");
type_s = 0;
break;
case 0x22:
Serial.println(" Chip = DS1822");
type_s = 0;
break;
default:
Serial.println("Device is not a DS18x20 family device.");
return;
}
串口打印状态的注释掉 */

ds.reset();
ds.select(addr);
ds.write(0x44, 1); // start conversion, with parasite power on at the end

delay(1000); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.

present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad

//串口打印状态的注释掉 Serial.print(" Data = ");
//串口打印状态的注释掉 Serial.print(present, HEX);
//串口打印状态的注释掉 Serial.print(" ");
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
//串口打印状态的注释掉 Serial.print(data[i], HEX);
//串口打印状态的注释掉 Serial.print(" ");
}
//串口打印状态的注释掉 Serial.print(" CRC=");
//串口打印状态的注释掉 Serial.print(OneWire::crc8(data, 8), HEX);
//串口打印状态的注释掉 Serial.println();

// Convert the data to actual temperature
// because the result is a 16 bit signed integer, it should
// be stored to an "int16_t" type, which is always 16 bits
// even when compiled on a 32 bit processor.
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// "count remain" gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[4] & 0x60);
// at lower res, the low bits are undefined, so let's zero them
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
//// default is 12 bit resolution, 750 ms conversion time
}
celsius = (float)raw / 16.0;
//华氏度注释掉 fahrenheit = celsius * 1.8 + 32.0;
//串口打印温度放到后面Serial.print(" 18b20 Temperature = ");
// Serial.print(celsius);
//Serial.print(" Celsius。 ");
//华氏度注释掉 Serial.print(fahrenheit);
//华氏度注释掉 Serial.println(" Fahrenheit");








//表示时间用的----------------------------------------------------------------------------------------------

tmElements_t tm;

if (RTC.read(tm)) {
Serial.print("Ok, Time = ");
print2digits(tm.Hour);
Serial.write(':');
print2digits(tm.Minute);
Serial.write(':');
print2digits(tm.Second);
Serial.print(", Date (D/M/Y) = ");
Serial.print(tm.Day);
Serial.write('/');
Serial.print(tm.Month);
Serial.write('/');
Serial.print(tmYearToCalendar(tm.Year));
Serial.println();
} else {
if (RTC.chipPresent()) {
Serial.println("The DS1307 is stopped. Please run the SetTime");
Serial.println("example to initialize the time and begin running.");
Serial.println();
} else {
Serial.println("DS1307 read error! Please check the circuitry.");
Serial.println();
}
delay(9000);
}
delay(1000);

//------存进去sd卡,这里是存时间
Serial.println(F("Open file and write data "));
dataFile = SD.open("datalog.txt", FILE_WRITE);

if (dataFile) {
// dataFile.print(event.temperature);
// dataFile.print(F("°C,"));


dataFile.print(" Time: ");


dataFile.print(tmYearToCalendar(tm.Year));
dataFile.print('/');
dataFile.print(tm.Month);
dataFile.print('/');
dataFile.print(tm.Day);

dataFile.print(", ");


dataFile.print(tm.Hour);
dataFile.print(':');
dataFile.print(tm.Minute);
dataFile.print(':');
dataFile.print(tm.Second);


dataFile.print(F("==>>"));



dataFile.close();
Serial.println("done.");
} else {
//if the file didn't open, print an error:
Serial.println("error opening test.txt");
}



// Get temperature event and print its value. 选择开始测量温度,我发现得测完温度就往sd卡存温度。不能温度湿度测量完以后一起存到sd卡里去。可能是因为串行输入的,且没保存
sensors_event_t event;
dht.temperature().getEvent(&event);
if (isnan(event.temperature)) {
Serial.println(F("Error reading temperature!"));
}
else {
Serial.print(F("DHT11-Temperature: "));
Serial.print(event.temperature);
Serial.println(F("°C"));
}
// Get humidity event and print its value.

//------存进去sd卡
Serial.println(F("Open file and write data "));
dataFile = SD.open("datalog.txt", FILE_WRITE);

if (dataFile) {

dataFile.print(F(" DHT11-Temperature:"));
dataFile.print(event.temperature);
dataFile.print(F("°C, "));


dataFile.close();
Serial.println("done.");
} else {
//if the file didn't open, print an error:
Serial.println("error opening test.txt");
}

//测量湿度
dht.humidity().getEvent(&event);
if (isnan(event.relative_humidity)) {
Serial.println(F("Error reading humidity!"));
}
else {
Serial.print(F("Humidity:"));
Serial.print(event.relative_humidity);
Serial.println(F("% "));
}
Serial.print(F("Read data from Light Sensor "));
int light =analogRead(LIGHT_PIN);


//------存进去sd卡
Serial.println(F("Open file and write data "));
dataFile = SD.open("datalog.txt", FILE_WRITE);

if (dataFile) {

dataFile.print(F(" Humidity:"));
dataFile.print(event.relative_humidity);
dataFile.print(F("%,"));

dataFile.close();
Serial.println("done.");
} else {
//if the file didn't open, print an error:
Serial.println("error opening test.txt");
}

//测量亮度
Serial.print(F("The Ligt: "));
Serial.println(light);


//------存进去sd卡
Serial.println(F("Open file and write data "));
dataFile = SD.open("datalog.txt", FILE_WRITE);

if (dataFile) {
dataFile.print(F(" Light:"));
dataFile.print (light);

dataFile.close();
Serial.println("done.");
} else {
//if the file didn't open, print an error:
Serial.println("error opening test.txt");
}


//----18b20的温度--先串口打印然后存进去sd卡
Serial.print(F(" 18b20 Temperature = "));
Serial.print(celsius);
Serial.println(F(" Celsius。 "));
Serial.println(F("Open file and write data "));
dataFile = SD.open("datalog.txt", FILE_WRITE);

if (dataFile) {
dataFile.print(F(" ; 18b20's Temperature: "));
dataFile.println(celsius);

dataFile.close();
Serial.println("done.");
} else {
//if the file didn't open, print an error:
Serial.println("error opening test.txt");
}


// Delay between measurements. 这个delayms怎么来的没搞懂,反正是隔1秒钟,给x了600 相当于600s记录一次,后面减1000是减去读取时间那里有个延时1000
delay(delayMS*600- 1500);

}

  记录的文件可以从我在b站上传的视频上看个大概。

 

     功能演示结果及说明

      程序上传到Arduino UNO上可以正常运行,分享一个记录文件的截图Fn8EiOHPZhEImBnVGtD5Vcp3-K3-通过截图,大家可以注意到,这个时间间隔颇短了一些,是因为在录视频的时候,想通过串口展示数据的读取过程的,按照源码的设计则要10分钟才能测一次数据,那也太长了所以监测间隔被改小了很多。编程环境是arduino IDE. 如果直接完全复制源码,但是编译失败,多半是还需要加载几个库。这些库是用来支持18b20模块、TF卡读写、DHT11模块、DS1307模块的。这些库下载后,里面还可以找到例程,我的程序就是照例程修改的,希望大家可以用的更好。搜索关键字是18b20 ;tf; 1307;dht11.

    下面的截图是串口监视器监视到的数据,里面显示文件打开错误,是因为卡拔出来放电脑里看记录了。正常运行是没有问题的。

FiQnz6jlmItD6d6aQSXorKxTpIJx

 

 

      最后说一下对本活动的心得体会

     我觉得活动非常好,就是时间太短了,而且一开始似乎还要用指定芯片或是需要打板就会劝退很大一批人,因为打板还需要更多的各种成本也提高了难度,从时间上到技术上再到金钱上。希望以后还能多多组织类似的活动。最后感谢硬禾和得捷组织了这一个活动。

附件下载
dht11-_light_18b20_test.ino
此为程序代码
团队介绍
就自己一个人啦
团队成员
老孙头
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号