// the big project //uses DHT22 temp sensor and some weird particle sensor (KS0196 i think) // also uses a 24x2 VFD display for real time read out ! //Egress. //TODO: // make sd card renaming work #include #include #include #include #include #include #include "SdFat.h" #include "sdios.h" #define DHTPIN 22 //sets up DHT stuff #define DHTTYPE DHT22 const int rs = 16, en = 17, d4 = 15, d5 = 2, d6 = 0, d7 = 4; LiquidCrystal lcd(rs, en, d4, d5, d6, d7); //VFD display setup int measurePin = 32; int ledPower = 21; //PM2.5 sensor stuff int samplingTime = 280; int deltaTime = 40; int sleepTime = 9680; float voMeasured = 0; float calcVoltage = 0; float dustDensity; float tempf,humid, tempmax, tempmin, humax, humin, dustmax, dustmin; //ALL OF THE VARIABLES unsigned long startMillis; unsigned long currentMillis; unsigned long sec,mint,hour,day; int i = 600; //makes it so it begins with adding a datapoint to the averages, avoids not-a-number things int d = 0; int screen = 1; const unsigned long period = 1000; LCDGraph graph(6,1,0); RunningAverage radustsensor(10); //ten second average to iron out inconsistencies RunningAverage tenminutetemp(600); //10 minute averages RunningAverage tenminutehumidity(600); RunningAverage tenminutedust(600); RunningAverage daytemp(144); //24 hour averages (based off of day averages) RunningAverage dayhumidity(144); RunningAverage daydust(144); DHT dht(DHTPIN, DHTTYPE); //initializes dht library with proper pins & stuff uint32_t delayMS; #define SD_FAT_TYPE 3 // SDCARD_SS_PIN is defined for the built-in SD on some boards. #ifndef SDCARD_SS_PIN const uint8_t SD_CS_PIN = SS; #else // SDCARD_SS_PIN // Assume built-in SD is used. const uint8_t SD_CS_PIN = SDCARD_SS_PIN; #endif // SDCARD_SS_PIN // Try max SPI clock for an SD. Reduce SPI_CLOCK if errors occur. #define SPI_CLOCK SD_SCK_MHZ(30) // Try to select the best SD card configuration. #if HAS_SDIO_CLASS #define SD_CONFIG SdioConfig(FIFO_SDIO) #elif ENABLE_DEDICATED_SPI #define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(16)) #else // HAS_SDIO_CLASS #define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(16)) #endif // HAS_SDIO_CLASS #if SD_FAT_TYPE == 0 SdFat sd; File file; #elif SD_FAT_TYPE == 1 SdFat32 sd; File32 file; #elif SD_FAT_TYPE == 2 SdExFat sd; ExFile file; #elif SD_FAT_TYPE == 3 SdFs sd; FsFile file; #else // SD_FAT_TYPE #error Invalid SD_FAT_TYPE #endif // SD_FAT_TYPE #define error(s) sd.errorHalt(&Serial, F(s)) void temphummeasure(){ //reads DHT22 and prints value to display tempf = dht.readTemperature(true); //reads temp in fahrenheit (can also do celcius) humid = dht.readHumidity(); //returns humidity as % if (isnan(tempf) || isnan(humid)) { Serial.println(F("Failed to read from DHT sensor!")); lcd.setCursor(5,0); lcd.print("check"); lcd.setCursor(18,0); //if sensor is not connected, notify user lcd.print("sensr"); return; } tenminutetemp.addValue(tempf); //adds values to averages tenminutehumidity.addValue(humid); Serial.print("current temp is "); Serial.print(tempf); Serial.println(" Degrees Fahrenheit"); //adds temp and humidity to serial Serial.print("current humidity is "); Serial.print(humid); Serial.println("%"); //graph.add(tempf); //select to use temp data on graph } void particulatemeasure(){ //reads particulate sensor and prints value to display digitalWrite(ledPower,LOW); // power on the LED delayMicroseconds(samplingTime); voMeasured = analogRead(measurePin); // read the dust value delayMicroseconds(deltaTime); digitalWrite(ledPower,HIGH); // turn the LED off delayMicroseconds(sleepTime); // 0 - 5V mapped to 0 - 1023 integer values // recover voltage calcVoltage = voMeasured * (5.0 / 1024.0); dustDensity = 170 * calcVoltage - 0.1; radustsensor.add(dustDensity); tenminutedust.add(dustDensity); //adds data to averages Serial.print("current dust concentration is "); Serial.print(radustsensor.getAverage()); Serial.println(" ug/m3"); graph.add(radustsensor.getAverage()); } void minmaxer(){ //calculates min and max if(tempmax < tempf){ tempmax = tempf; } if(tempmin > tempf){ tempmin = tempf; } if(humax < humid){ humax = humid; } if(humin > humid){ humin = humid; } if(dustmax < dustDensity){ dustmax = dustDensity; } if(dustmin > dustDensity){ dustmin = dustDensity; } } void screenoperator(){ //writes data to lcd display and allows user to select between screens 1 2 and 3 //defaults to current data screen if(digitalRead(14) == HIGH){ screen = 1; //screen 1 is default - displays real time info lcd.clear(); lcd.setCursor(8,0); lcd.print("Realtime"); lcd.setCursor(10,1); lcd.print("Data"); return; } else if(digitalRead(27) == HIGH){ screen = 2; //display 2 displays 10 minute averages lcd.clear(); lcd.setCursor(7,0); lcd.print("Ten Minute"); lcd.setCursor(6,1); lcd.print("Average Data"); return; } else if(digitalRead(26) == HIGH){ screen = 3; //display 3 displays 24 hour averages + overall min/max data + elapsed time since starting d = 0; lcd.clear(); lcd.setCursor(4,0); lcd.print("Twenty Four Hour"); lcd.setCursor(10,1); lcd.print("Data"); return; } if(screen == 1){ lcd.clear(); //lays out and displays info for screen 1 lcd.setCursor(0,0); lcd.print("Temp:"); lcd.setCursor(11,0); lcd.print("|Humid:"); lcd.setCursor(0,1); lcd.print("Dust:"); lcd.setCursor(5, 0); lcd.print(tempf); lcd.setCursor(10,0); lcd.print("F"); lcd.setCursor(18,0); lcd.print(humid); lcd.setCursor(23,0); lcd.print("%"); lcd.setCursor(5,1); lcd.print(radustsensor.getAverage()); lcd.setCursor(11,1); lcd.print(" ug/m3"); graph.autoRescale(false); graph.setRegisters(); graph.display(18,1); return; } else if(screen == 2){ //ten minute averages screen lcd.clear(); lcd.setCursor(0,0); lcd.print("Temp:"); lcd.setCursor(11,0); lcd.print("|Humid:"); lcd.setCursor(0,1); lcd.print("Dust:"); lcd.setCursor(5, 0); lcd.print(tenminutetemp.getAverage()); lcd.setCursor(10,0); lcd.print("F"); lcd.setCursor(18,0); lcd.print(tenminutehumidity.getAverage()); lcd.setCursor(23,0); lcd.print("%"); lcd.setCursor(5,1); lcd.print(tenminutedust.getAverage()); lcd.setCursor(11,1); lcd.print(" ug/m3"); return; } else if(screen == 3){ //this code cycles through several different screens, to display more info than would be possible with only 1 screen if(d == 0){ lcd.clear(); lcd.setCursor(0,0); lcd.print("Max Temp:"); lcd.setCursor(9,0); lcd.print(tempmax); lcd.setCursor(14,0); lcd.print((char)223); lcd.print("F"); lcd.setCursor(0,1); lcd.print("Min Temp:"); lcd.setCursor(9,1); lcd.print(tempmin); lcd.setCursor(14,1); lcd.print((char)223); lcd.print("F"); } else if(d == 3){ lcd.clear(); lcd.setCursor(0,0); lcd.print("Max Humidity:"); lcd.setCursor(13,0); lcd.print(humax); lcd.setCursor(18,0); lcd.print("%"); lcd.setCursor(0,1); lcd.print("Min Humidity:"); lcd.setCursor(13,1); lcd.print(humin); lcd.setCursor(18,1); lcd.print("%"); } else if(d == 6){ lcd.clear(); lcd.setCursor(0,0); lcd.print("Max Dust:"); lcd.setCursor(9,0); lcd.print(dustmax); lcd.setCursor(15,0); lcd.print(" ug/m3"); lcd.setCursor(0,1); lcd.print("Min Dust:"); lcd.setCursor(9,1); lcd.print(dustmin); lcd.setCursor(15,1); lcd.print(" ug/m3"); } else if(d == 9){ lcd.clear(); lcd.setCursor(0,0); lcd.print("Average Temp:"); lcd.setCursor(13,0); lcd.print(daytemp.getAverage()); lcd.print((char)223); lcd.print("F"); lcd.setCursor(0,1); lcd.print("Average Humidity:"); lcd.setCursor(17,1); lcd.print(dayhumidity.getAverage()); lcd.print("%"); } else if(d == 12){ lcd.clear(); lcd.setCursor(0,0); lcd.print("Average Dust:"); lcd.setCursor(13,0); lcd.print(daydust.getAverage()); lcd.setCursor(19,0); lcd.print("ug/m3"); lcd.setCursor(0,1); lcd.print("time:"); lcd.setCursor(6,1); lcd.print(day); lcd.print("D"); lcd.print(hour); lcd.print("H"); lcd.print(mint); lcd.print("M"); lcd.print(sec); lcd.print("S"); } d++; if(d == 16){ d = 0; } return; } } void requestaverages(){ //runs if the user pushes the request averages button - prints out averages + mins and maxes to serial port if(digitalRead(12) == HIGH){ Serial.print("10 minute average temp is:"); Serial.print(tenminutetemp.getAverage()); Serial.println("F"); Serial.print("10 minute average humidity is:"); Serial.print(tenminutehumidity.getAverage()); Serial.println("%"); Serial.print("10 minute dust concentration average is:"); Serial.print(tenminutedust.getAverage()); Serial.println(" ug/m3"); Serial.print("1 day average temp is:"); Serial.print(daytemp.getAverage()); Serial.println("F"); Serial.print("1 day average humidity is:"); Serial.print(dayhumidity.getAverage()); Serial.println("%"); Serial.print("1 day dust concentration average is:"); Serial.print(daydust.getAverage()); Serial.println(" ug/m3"); Serial.print("overall maximum temperature is:"); Serial.println(tempmax); Serial.print("overall minimum temperature is:"); Serial.println(tempmin); Serial.print("overall maximum humidity is:"); Serial.print(humax); Serial.println("%"); Serial.print("overall minimum humidity is:"); Serial.print(humin); Serial.println("%"); Serial.print("overall maximum dust concentration is:"); Serial.print(dustmax); Serial.println(" ug/m3"); Serial.print("overall minimum dust concentration is:"); Serial.print(dustmin); Serial.println(" ug/m3"); } } void timetimer(){ //sec,min,hour,day sec++; if(sec == 60){ sec = 0; mint++; } if(mint == 60){ mint = 0; hour++; } if(hour == 24){ hour = 0; day++; } } void filewrite(){ if(!file.open("data.csv", O_WRONLY | O_APPEND)){ Serial.println("that also wasn't supposed to happen"); delay(10000); } unsigned long secs = millis()/1000; file.print(secs); file.print(", "); file.print(tempf); file.print(", "); file.print(humid); file.print(", "); file.println(radustsensor.getAverage()); //file.sync(); file.close(); //Serial.println("attempted file write"); } void dayaverage(){ //Serial.println(i); if(i == 600){ daytemp.addValue(tenminutetemp.getAverage()); dayhumidity.addValue(tenminutehumidity.getAverage()); daydust.addValue(tenminutedust.getAverage()); i = 0; i++; } } void setup() { pinMode(32, INPUT); //sets pinmodes for dust sensor pinMode(21, OUTPUT); pinMode(12, INPUT_PULLDOWN); pinMode(14, INPUT_PULLDOWN); pinMode(27, INPUT_PULLDOWN); pinMode(26, INPUT_PULLDOWN); sec = 0; mint = 0; hour = 0; day = 0; dustmax = 250; dustmin = 250; lcd.begin(24, 2);//sets up VFD display with temp humidity and dust labels lcd.setCursor(0,0); lcd.print("Temp:"); lcd.setCursor(11,0); lcd.print("|Humid:"); lcd.setCursor(0,1); lcd.print("Dust:"); Serial.begin(115200); //starts serial connection to computer dht.begin(); //begins communication with the DHT22 sensor startMillis = millis(); graph.begin(&lcd); graph.filled = false; graph.yMin = 100; graph.yMax = 1000; if(!sd.begin(SD_CONFIG)){ Serial.println("Thats not supposed to happen!?"); delay(10000); } if (sd.exists("data.csv")) { file.rename("dataold.csv"); } if(!file.open("data.csv", O_WRONLY | O_CREAT)){ Serial.println("that also wasn't supposed to happen"); delay(10000); } file.println("seconds, temp, humidity, dust"); //file.close(); tempmax = dht.readTemperature(true); tempmin = dht.readTemperature(true); humax = dht.readHumidity(); humin = dht.readHumidity(); } void loop() { currentMillis = millis(); //get the current "time" (actually the number of milliseconds since the program started) if (currentMillis - startMillis >= period) //test whether the period has elapsed { temphummeasure(); particulatemeasure(); dayaverage(); minmaxer(); timetimer(); requestaverages(); screenoperator(); filewrite(); startMillis = currentMillis; //IMPORTANT to save } }