#include #include #include #include #include #include #define I2C_ADDR 0x3f #define BACKLIGHT_PIN 3 #define En_pin 2 #define Rw_pin 1 #define Rs_pin 0 #define D4_pin 4 #define D5_pin 5 #define D6_pin 6 #define D7_pin 7 LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin, BACKLIGHT_PIN, POSITIVE); int screenWidth = 20; int screenHeight = 4; int countMovement = 0; int stringStart = 0; int stringStop = 0; int scrollCursor = 0; #include // A DS3231/DS3232 library /*************************************************************************** This is a library for the BME280 humidity, temperature & pressure sensor Designed specifically to work with the Adafruit BME280 Breakout ----> http://www.adafruit.com/products/2650 These sensors supports either I2C or SPI to communicate, 2 or 4 pins are required to interface. However this sketch is using I2C for communications and only needs 2 wires for communication ***************************************************************************/ #include "cactus_io_BME280_I2C.h" // Create the BME280 object // BME280_I2C bme; // I2C using default 0x77 BME280_I2C bme(0x76); // I2C using address 0x76 double ALTITUDE = 423.0; // Altitude of sensor in meters double Lw = 9; double Ln = 49; #include dht DHT; #define DHT22_PIN 5 const char compile_date[] = __DATE__ "-" __TIME__; const char compile_file[] = __FILE__ ; // ---------------------- int pwmPin = 10; // fan PWM -> connected to digital pin 9 int pwmVal = 0; int DEBUG = 1; // DEBUG counter; if set to 1, will write values back via serial // Definition of Arduino type #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) #define IS_MEGA (1) #define IS_UNO (0) #else #define IS_MEGA (0) #define IS_UNO (1) #endif // Analog output (i.e PWM) pins. These must be chosen so that we can change the PWM frequency without affecting the millis() // function or the MsTimer2 library. So don't use timer/counter 1 or 2. See comment in setup() function. // THESE PIN NUMBERS MUST NOT BE CHANGED UNLESS THE CODE IN setup(), setTransistorFanSpeed() AND setDiodeFanSpeed() IS CHANGED TO MATCH! #if IS_UNO // On the Uno we can only use the OC1B pin, so these pin numbers are both 10 const int transistorFanPin = 10; // OC1B const int diodeFanPin = 10; // OC1B #else // On the Mega we use OC1B and OC1C const int transistorFanPin = 12; // OC1B const int diodeFanPin = 13; // OC1C #endif // Definitions for PWM fan control const unsigned char maxFanSpeed = 80; // this is calculated as 16MHz divided by 8 (prescaler), divided by 25KHz (target PWM frequency from Intel specification) char cb[100]; //Central European Time (Frankfurt, Paris) TimeChangeRule CEST = { "CEST", Last, Sun, Mar, 2, 120}; //Central European Summer Time TimeChangeRule CET = { "CET ", Last, Sun, Oct, 3, 60}; //Central European Standard Time Timezone CE(CEST, CET); TimeChangeRule *tcr; //pointer to the time change rule, use to get TZ abbrev time_t utc, local; char* weekdays[] = { "So", "Mo", "Di", "Mi", "Do", "Fr", "Sa" }; int osec = -1; // phases of the moon (0 is new moon, p1-waxing crescent, p5-first quarter, p10-full moon, etc.) #define d 0xFF // delimeter const char phases[][11] PROGMEM = { { 24,28,38,42,50,61,65,73,77,87,91 }, // p1 { 16,29,43,60,72,86,99,d }, // p2 { 12,17,30,44,59,71,85,98,103,d }, // p3 { 1,18,31,58,84,97,9,d }, // p4 { 2,3,4,6,7,8,d }, // p5 first / last quarter { 96,83,57,32,19,d }, // p6 { 102,95,82,33,20,13,d }, // p7 { 70,56,45,20,d }, // p8 { 94,81,69,55,46,34,21,d }, // p9 { 90,80,76,68,64,54,51,47,39,35,25 } // p10 }; // Set the transistor fan speed, where 0 <= fanSpeed <= maxFanSpeed void setTransistorFanSpeed(unsigned char fanSpeed) { OCR1BH = 0; OCR1BL = fanSpeed; } // Set the diode fan speed, where 0 <= fanSpeed <= maxFanSpeed void setDiodeFanSpeed(unsigned char fanSpeed) { #if IS_UNO OCR1BH = 0; OCR1BL = fanSpeed; #else OCR1CH = 0; OCR1CL = fanSpeed; #endif } void setup() { Serial.begin(9600); // Set up the PWM pins for a PWM frequency close to the recommended 25KHz for the Intel fan spec. // We can't get this frequency using the default TOP count of 255, so we have to use a custom TOP value. #if IS_UNO // Only timer/counter 1 is free because TC0 is used for system timekeeping (i.e. millis() function), // and TC2 is used for our 1-millisecond tick. TC1 controls the PWM on Arduino pins 9 and 10. // However, we can only get PWM on pin 10 (controlled by OCR1B) because we are using OCR1A to define the TOP value. // Using a prescaler of 8 and a TOP value of 80 gives us a frequency of 16000/(8 * 80) = 25KHz exactly. TCCR1A = (1 << COM1B1) | (1 << COM1B0) | (1 << WGM11) | (1 << WGM10); // OC1A (pin 9) disconnected, OC1B (pin 10) = inverted fast PWM #ifdef FAN_AUDIO_TEST // test code to get 440Hz output (= concert A) to test the logic OCR1AH = 0; OCR1BL = 71; // 50% duty cycle TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12); // TOP = OCRA, prescaler = 256 OCR1AL = 141; // TOP = 141, 16000000 / (256 * 142) = 440.014 OCR1BH = 0; #else OCR1AH = 0; OCR1AL = 79; // TOP = 79 TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); // TOP = OCR0A, prescaler = 8 OCR1BH = 0; OCR1BL = maxFanSpeed; // max fan speed (i.e. pin 5 initially low all the time) #endif TCNT1H = 0; TCNT1L = 0; #else // On the Mega we use TC1 and OCR1B, OCR1C TCCR1A = (1 << COM1B1) | (1 << COM1B0) | (1 << COM1C1) | (1 << COM1C1) | (1 << WGM11) | (1 << WGM10); // OC1A disconnected, OC1B = OC1C inverted fast PWM TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); // TOP = OCR1A, prescaler = 8 TCCR1C = 0; OCR1AH = 0; OCR1AL = 79; // TOP = 79 OCR1BH = 0; OCR1BL = maxFanSpeed; OCR1CH = 0; OCR1CL = maxFanSpeed; TCNT1H = 0; TCNT1L = 0; #endif // We have to enable the ports as outputs before PWM will work. pinMode(transistorFanPin, OUTPUT); pinMode(diodeFanPin, OUTPUT); // ------------------------------ lcd.begin(screenWidth, screenHeight); // LCD Hintergrundbeleuchtung aktivieren lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE); lcd.clear(); lcd.setCursor(0, 0); // ------- Quick 3 blinks of backlight ------------- for(int i = 0; i< 3; i++) { lcd.backlight(); delay(250); lcd.noBacklight(); delay(250); } lcd.backlight(); // finish with backlight on Serial.println(compile_date); roop(0, compile_date, 100); Serial.println(compile_file); roop(1, compile_file, 100); delay(1000); lcd.clear(); //Clear screen lcd.noCursor(); //disable cursor, enable cursore use: enableCursor(); lcd.setCursor(0, 0); // Initialize the sensor (it is important to get calibration values stored on the device). if (bme.begin()) { Serial.println(F("BME280 init success")); lcd.print(F("BME280 init success")); } else { // Oops, something went wrong, this is usually a connection problem, // see the comments at the top of this sketch for the proper connections. Serial.println(F("BME280 init fail\n\n")); lcd.print(F("BME280 init fail")); while(1); // Pause forever. } float temp = bme.getTemperature_C(); delay(1000); lcd.setCursor(0, 1); setSyncProvider(RTC.get); // the function to get the time from the RTC if(timeStatus()!= timeSet) { lcd.println(F("RTC sync Error")); } else { lcd.print(F("RTC sync OK")); } delay(1000); lcd.clear(); //Clear screen lcd.setCursor(0, 0); delay(1000); setTime(hour(),minute(),second(),day(),month(),(year()-2000) ); // set time to Saturday 8:29:00am Jan 1 2011 digitalClockDisplay(); // FanTest(); } // ===================================================================================================== void loop() { if (second() != osec) { switch (second()) { case 0: BME_DisplayTempHumDew(); break; case 10: DHT_DisplayTempHumDew(); break; case 20: DisplayPressure(); break; case 30: BME_DisplayTempHumDew(); break; case 40: DHT_DisplayTempHumDew(); break; case 50: DisplayPressure(); break; } osec = second(); digitalClockDisplay(); CheckClockSet(); delay(500); // wait one second between clock display } } // =========================================================== void DisplayPressure() { double bme_abs, rel_pres ; char string_rel_pressure[8]; char string_abs_pressure[8]; char string_elevation[8]; bme_abs = bme.getPressure()/100; rel_pres = bme_abs / pow((1.0 - ( ALTITUDE / 44330.0 )), 5.255); dtostrf(bme_abs, 4, 1, string_abs_pressure); dtostrf(rel_pres, 4, 1, string_rel_pressure); dtostrf(ALTITUDE, 3, 1, string_elevation); sprintf(cb, "Absoluter Luftdruck: %shPa\tLuftdruck auf Meereshoehe: %shPa\tHoehe: %sm", string_abs_pressure, string_rel_pressure, string_elevation ); Serial.println(cb); lcd.clear(); lcd.setCursor(0, 0); sprintf(cb, "Luftdruck %shPa", string_rel_pressure); lcd.print(cb); lcd.setCursor(0, 1); sprintf(cb, "Luftdruck %shPa", string_abs_pressure); lcd.print(cb); lcd.setCursor(0, 2); sprintf(cb, "H%che %sm", char(0xef), string_elevation); lcd.print(cb); /* ------------------------------------------------------- */ digitalClockDisplay(); } // =============================================================== // BME280 related // Display Temp./Hum./Dew // void BME_DisplayTempHumDew() { double bme_temp, bme_humidity, bme_dew; char string_bme_temp[10]; char string_bme_humidity[10]; char string_bme_dew[10]; bme_temp = bme.getTemperature_C(); bme_humidity = bme.getHumidity(); bme_dew = dewPointFast(bme_temp, bme_humidity); dtostrf(bme_temp, 3, 1, string_bme_temp); dtostrf(bme_humidity, 3, 1, string_bme_humidity); dtostrf(bme_dew, 3, 1, string_bme_dew); sprintf(cb, "BME-Temperature: %s°C\tBME-Humidity: %s%%rH\tBME-Dewpoint: %s°C\t", string_bme_temp, string_bme_humidity, string_bme_dew ); Serial.println(cb); lcd.clear(); //Clear screen lcd.setCursor(0, 0); sprintf(cb, "Luftfeuchte %s%%rH", string_bme_humidity); lcd.print(cb); lcd.setCursor(0, 1); sprintf(cb, "Temperatur %s%cC", string_bme_temp, char(0xdf) ); lcd.print(cb); lcd.setCursor(0, 2); sprintf(cb, "Taupunkt %s%cC", string_bme_dew, char(0xdf)); lcd.print(cb); /* ------------------------------------------------------- */ // 40 values from 60%rH to 100%rH int RPM[] = { 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; int hum, fan_speed; hum=bme_humidity; // convert to integer if ((hum) > 60) { hum=hum-60; fan_speed=(RPM[hum]); setTransistorFanSpeed(fan_speed); } else { fan_speed=0; setTransistorFanSpeed(70); } sprintf(cb, "Hum = %2d\tfan_speed = %2d", hum, fan_speed); Serial.println(cb); // lcd.setCursor(10, 1); // lcd.print("Fan "); // lcd.print(fan_speed); /* ------------------------------------------------------- */ digitalClockDisplay(); } // =============================================================== // DHT related // Display Temp./Hum./Dew // void DHT_DisplayTempHumDew() { double dht_humidity, dht_temperature, dht_dew; char string_temp[10]; char string_hum[10]; char string_dew[10]; // READ DHT DATA uint32_t start = micros(); int chk = DHT.read22(DHT22_PIN); uint32_t stop = micros(); Serial.println(); Serial.print(F("Read sensor: ")); switch (chk) { case 0: Serial.println("OK"); break; case -1: Serial.println("Checksum error"); break; case -2: Serial.println("Time out error"); break; default: Serial.println("Unknown error"); break; } // DISPLAY DATA dht_humidity = DHT.humidity; dht_temperature = DHT.temperature; dht_dew = dewPointFast(dht_temperature, dht_humidity); dtostrf(dht_humidity, 3, 1, string_hum); dtostrf(dht_temperature, 3, 1, string_temp); dtostrf(dht_dew, 3, 1, string_dew); lcd.clear(); //Clear screen lcd.setCursor(0, 0); sprintf(cb, "Luftfeuchte %s%%rH", string_hum); lcd.print(cb); lcd.setCursor(0, 1); sprintf(cb, "Temperatur %s%cC", string_temp, char(0xdf)); lcd.print(cb); lcd.setCursor(0, 2); sprintf(cb, "Taupunkt %s%cC", string_dew, char(0xdf)); lcd.print(cb); sprintf(cb, "Humidity: %s%%rH\tTemperatur: %s°C\r\nTaupunkt: %s°C\tConversion time: %4dµs", string_hum, string_temp, string_dew, (stop - start)); Serial.println(cb); /* ------------------------------------------------------- */ digitalClockDisplay(); } // ================================================================= void digitalClockDisplay() { utc = now(); local = CE.toLocal(utc, &tcr); printTimeLCD(local, tcr -> abbrev); } void printTimeLCD(time_t t, char *tz) { // Da in dem vierzeiligen Display noch eine Zeile Platz hatte // hier eine Art von Sekundenzeiger sprintf(cb, "%s %02d.%02d.%02d %02d:%02d:%02d", (weekdays[weekday(t) - 1]), day(t), month(t),year(t)-2000, hour(t), minute(t), second(t)) ; lcd.setCursor(0, 3); lcd.print(cb); Serial.println(); utc = now(); printTime(utc, "UTC"); local = CE.toLocal(utc, &tcr); printTime(local, tcr -> abbrev); } //Function to print time with time zone void printTime(time_t t, char *tz) { sprintf(cb, "%s, %02d.%02d.%04d %02d:%02d:%02d %s", (weekdays[weekday(t) - 1]), day(t), month(t),year(t), hour(t), minute(t), second(t), tz ) ; Serial.println(cb); } // -----( Declare User-written Functions )----- //Celsius to Fahrenheit conversion double Fahrenheit(double celsius) { return 1.8 * celsius + 32; } //Celsius to Kelvin conversion double Kelvin(double celsius) { return celsius + 273.15; } // dewPoint function NOAA // reference: http://wahiduddin.net/calc/density_algorithms.htm double dewPoint(double celsius, double humidity) { double A0= 373.15/(273.15 + celsius); double SUM = -7.90298 * (A0-1); SUM += 5.02808 * log10(A0); SUM += -1.3816e-7 * (pow(10, (11.344*(1-1/A0)))-1) ; SUM += 8.1328e-3 * (pow(10,(-3.49149*(A0-1)))-1) ; SUM += log10(1013.246); double VP = pow(10, SUM-3) * humidity; double T = log(VP/0.61078); // temp var return (241.88 * T) / (17.558-T); } // delta max = 0.6544 wrt dewPoint() // 5x faster than dewPoint() // reference: http://en.wikipedia.org/wiki/Dew_point double dewPointFast(double celsius, double humidity) { double a = 17.271; double b = 237.7; double temp = (a * celsius) / (b + celsius) + log(humidity/100); double Td = (b * temp) / (a - temp); return Td; } void CheckClockSet() { if (Serial.available()) { time_t t = processSyncMessage(); if (t > 0) { RTC.set(t); // set the RTC and the system time to the received value setTime(t); Serial.println("New Tiime has been set"); utc = now(); printTime(utc, "UTC"); local = CE.toLocal(utc, &tcr); printTime(local, tcr -> abbrev); } } // if no input, just return } /* code to process time sync messages from the serial port */ #define TIME_MSG_LEN 11 // time sync to PC is HEADER followed by unix time_t as ten ascii digits #define TIME_HEADER 'T' // Header tag for serial time sync message time_t processSyncMessage() { // return the time if a valid sync message is received on the serial port. while (Serial.available() >= TIME_MSG_LEN ) { // time message consists of a header and ten ascii digits char c = Serial.read() ; Serial.print(c); if ( c == TIME_HEADER ) { time_t pctime = 0; for (int i = 0; i < TIME_MSG_LEN - 1; i++) { c = Serial.read(); if ( c >= '0' && c <= '9') { pctime = (10 * pctime) + (c - '0') ; // convert digits to a number } } return pctime; } } return 0; } // =================================== // =================================== void DisplayMoonPhase() { local = CE.toLocal(utc, &tcr); Serial.println("MoonPhase:\t"); Serial.println(MoonPhase(local, tcr -> abbrev)); lcd.setCursor(0, 0); lcd.print("Mondphase: "); lcd.setCursor(11, 0); lcd.print(MoonPhase(local, tcr -> abbrev)); lcd.setCursor(0, 1); lcd.print("Aufgang: "); lcd.setCursor(0, 2); lcd.print("Untergang: "); lcd.setCursor(0, 3); lcd.println(" "); } float MoonPhase(time_t t, char *tz) { return GetPhase(year(t), month(t), day(t) ); } float GetPhase(int nYear, int nMonth, int nDay) // calculate the current phase of the moon { float phase; double AG, IP; long YY, MM, K1, K2, K3, JD; YY = nYear - floor((12 - nMonth) / 10); MM = nMonth + 9; if (MM >= 12) { MM = MM - 12; } K1 = floor(365.25 * (YY + 4712)); K2 = floor(30.6 * MM + 0.5); K3 = floor(floor((YY / 100) + 49) * 0.75) - 38; JD = K1 + K2 + nDay + 59; if (JD > 2299160) { JD = JD - K3; } IP = MyNormalize((JD - 2451550.1) / 29.530588853); AG = IP*29.53; phase = 0; if ((AG < 1.84566) && (phase == 0)) { phase = 0; //new; 0% illuminated } if ((AG < 5.53699) && (phase == 0)) { phase = .25; //Waxing crescent; 25% illuminated } if ((AG < 9.922831) && (phase == 0)) { phase = .50; //First quarter; 50% illuminated } if ((AG < 12.91963) && (phase == 0)) { phase = .75; //Waxing gibbous; 75% illuminated } if ((AG < 16.61096) && (phase == 0)) { phase = 1; //Full; 100% illuminated } if ((AG < 20.30228) && (phase == 0)) { phase = .75; //Waning gibbous; 75% illuminated } if ((AG < 23.99361) && (phase == 0)) { phase = .50; //Last quarter; 50% illuminated } if ((AG < 27.68493) && (phase == 0)) { phase = .25; //Waning crescent; 25% illuminated } if (phase == 0) { phase = 0; //default to new; 0% illuminated } return phase; } double MyNormalize(double v) { v = v - floor(v); if (v < 0) v = v + 1; return v; } // ================ from: // http://reefsanctuary.com/forum/index.php?threads/show-your-arduino-controller-sketch.71063/ // ============= int moonPhase(int moonYear, int moonMonth, int moonDay) { int dayFromYear, dayFromMonth; double julianDay; int phase; if (moonMonth < 3) //keep the month before march { moonYear--; //take away a year moonMonth += 12; //add an extra 12 months (the year taken away from before) } ++moonMonth; dayFromYear = 365.25 * moonYear; //get days from current year dayFromMonth = 30.6 * moonMonth; //get number of days from the current month julianDay = dayFromYear + dayFromMonth + moonDay - 694039.09; //add them all julianDay /= 29.53; //divide by the length of lunar cycle phase = julianDay; //take integer part julianDay -= phase; //get rid of the int part phase = julianDay*8 + 0.5; //get it between 0-8 and round it by adding .5 phase = phase & 7; //get a number between 1-7 return phase; //1 == new moon, 4 == full moon } void FanTest() { setTransistorFanSpeed(0); delay(5000); // run for 30 seconds at maximum fan speed setTransistorFanSpeed(10); delay(5000); // run for 30 seconds at maximum fan speed setTransistorFanSpeed(20); delay(5000); // run for 30 seconds at low fan speed setTransistorFanSpeed(30); delay(5000); // run for 30 seconds at low fan speed setTransistorFanSpeed(40); delay(5000); // run for 30 seconds at low fan speed setTransistorFanSpeed(50); // delay(5000); // run for 30 seconds at low fan speed } // ========================================== void roop(int Reihe, String line2, int speed) { countMovement = 0; stringStart = 0; stringStop = 0; scrollCursor = 0; // Serial.print(countMovement); Serial.print("-"); Serial.println(line2.length() + 1); while ( ( countMovement ) < (line2.length() + 2 ) ) { lcd.setCursor(scrollCursor, Reihe); // Serial.print("Cursor: "); Serial.print(scrollCursor); Serial.print(" "); Serial.println(Reihe); lcd.print(line2.substring(stringStart, stringStop)); // Serial.println( line2.substring(stringStart, stringStop) ); delay(speed); if (stringStart == 0 && scrollCursor > 0) { // Serial.println(scrollCursor); scrollCursor--; stringStop++; } else if (stringStart == stringStop) { stringStart = stringStop = 0; scrollCursor = screenWidth; } else if (stringStop == line2.length() && scrollCursor == 0) { stringStart++; } else { stringStart++; stringStop++; } countMovement++; } } void ClearLine(int line) { }