#include <Time.h>
#include <Timezone.h>
#include <string.h>
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#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 <DS3232RTC.h> // 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.h>
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)
{
}
Comments