Temp logger
Submitted by ok4bx on Sun, 2016-02-07 14:49
- /*
- * Author: Tomas Borovicka, ok4bx
- * Date: February 2016
- *
- * ====Resources:
- * DS18B20 file://C:/Users/Tomas/Desktop/Datasheets/DS18B20.pdf
- * DS3231 file://C:/Users/Tomas/Desktop/Datasheets/DS3231-DS3231S.pdf
- * AT24C32 file://C:/Users/Tomas/Desktop/Datasheets/AT24C32.pdf
- * ATMega328 file://C:/Users/Tomas/Desktop/Datasheets/atmega328.pdf
- * Pinout file://C:/Users/Tomas/Desktop/Datasheets/nanopdf.png
- * RTC schematic http://i0.wp.com/woodsgood.ca/projects/wp-content/uploads/RTC-schematic.jpg
- *
- * ====Pin assigment:
- * D7 - DS18B20
- * A4 - SDA <> DS3231
- * A5 - SCL -> DS3231
- * D2 - INT0 <- DS3231 SQW
- * D3 - INT1 --/\/\/\--+ 220Ohm jumper
- * D0 - RX0 ----------+ Wake on serial
- *
- * ====Notes:
- * Drain - Modry, Source - Cerveny, Gate - Zluty
- *
- * ===Temp:
- * raw + 880
- * 0xFFFF = -1 =
- * -2
- * -3
- */
- #include <Wire.h>
- #include <OneWire.h>
- #include <EEPROM.h>
- #include <avr/sleep.h>
- #include "morse.h"
- #define INTERNAL_EEPROM 0x00
- #define DS3231_I2C_ADDRESS 0x68
- #define AT24C32_I2C_ADDRESS 0x57
- #define CW_PIN A0
- #define LED_PIN 13
- #define RTC_POWER_PIN 9
- #define ADC_PIN A1
- #define ADC_CONTROL_PIN 8
- #define ADDRESS_16BIT 1
- #define ADDRESS_8BIT 0
- #define TIMEOUT_TIME 90000
- const char hextable[] PROGMEM = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
- OneWire ds(7);
- String buffer;
- String msg;
- byte x,rx;
- int ch,i;
- int cwspeed = SPEED_WPM27;
- int eepPtr = 0;
- long activityTime = millis();
- struct Mydatetime {
- byte second;
- byte minute;
- byte hour;
- byte day;
- byte month;
- byte year;
- byte dow;
- } datetime;
- typedef struct {
- byte day;
- byte month;
- int year;
- } Mydate;
- #define storageLen 5
- int16_t storage[storageLen];
- volatile int state = LOW;
- byte decToBcd(byte val){
- return( (val/10*16) + (val%10) );
- }
- byte bcdToDec(byte val){
- return( (val/16*10) + (val%16) );
- }
- // Print withing leading 0
- void print0(byte b) {
- if(b<10)
- Serial.print(F("0"));
- Serial.print(b);
- }
- void printHex(byte n) {
- Serial.print((char)pgm_read_byte(hextable + (n >> 4)));
- Serial.print((char)pgm_read_byte(hextable + (n & 0x0F)));
- }
- void eraseEeprom(int address, int pages) {
- for(int page=0; page<pages; page++) {
- Serial.println(page);
- Wire.beginTransmission(address);
- Wire.write(highByte(page*16));
- Wire.write(lowByte(page*16));
- for(int xx=0;xx<16;xx++)
- Wire.write(0xFF);
- Serial.flush();
- Wire.endTransmission();
- delay(25);
- }
- }
- void dump(int deviceAddress, int address, int length, int adrWord) {
- int requestSize;
- int tmpLength;
- int curAddress;
- Serial.println(F(" 0 1 2 3 4 5 6 7 8 9 A B C D E F"));
- address &= 0xFFF0;
- for(int block=0; block <= length/16; block++) {
- tmpLength = (block+1)*16;
- requestSize = (tmpLength<length) ? 16 : 16 - (tmpLength - length);
- if(requestSize) {
- //print address
- curAddress = address + block*16;
- printHex(highByte(curAddress));
- printHex(lowByte(curAddress));
- Serial.print(F(": "));
- //I2C device, 0 = Internal EEPROM
- if(deviceAddress) {
- //I2C set address
- Wire.beginTransmission(deviceAddress);
- if(adrWord==HIGH)
- Wire.write(highByte(curAddress));
- Wire.write(lowByte(curAddress));
- Wire.endTransmission();
- //I2C read data
- Wire.requestFrom(deviceAddress, requestSize);
- Wire.endTransmission();
- }
- for(int adr=0; adr < requestSize; adr++) {
- printHex((deviceAddress) ? Wire.read() : EEPROM.read(curAddress + adr));
- Serial.print( (adr != 7) ? F(" ") : F("|") ); //print | after 8 bytes
- }
- Serial.println();
- }
- Serial.flush();
- }
- }
- void setRtcAlarm() {
- Wire.beginTransmission(DS3231_I2C_ADDRESS);
- Wire.write(0x07);
- /* Wire.write(0x00); // each minute
- Wire.write(0x80);
- Wire.write(0x80);
- Wire.write(0x80); */
- Wire.write(0x05); // XX:00:05
- Wire.write(0x00);
- Wire.write(0x80);
- Wire.write(0x80);
- Wire.endTransmission();
- Wire.beginTransmission(DS3231_I2C_ADDRESS);
- Wire.write(0x0E);
- Wire.write(0x05);
- Wire.endTransmission();
- }
- void clearRtcAlarm() {
- Wire.beginTransmission(DS3231_I2C_ADDRESS);
- Wire.write(0x0F);
- Wire.write(0x00);
- Wire.endTransmission();
- }
- void getRtcTime(struct Mydatetime *dt) {
- Wire.beginTransmission(DS3231_I2C_ADDRESS);
- Wire.write(0);
- Wire.endTransmission();
- Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
- dt->second = bcdToDec(Wire.read());
- dt->minute = bcdToDec(Wire.read());
- dt->hour = bcdToDec(Wire.read() & 0x3f);
- dt->dow = Wire.read();
- dt->day = bcdToDec(Wire.read());
- dt->month = bcdToDec(Wire.read() & 0x1f);
- dt->year = bcdToDec(Wire.read());
- }
- void setRtcTime(struct Mydatetime *dt) {
- Wire.beginTransmission(DS3231_I2C_ADDRESS);
- Wire.write(0);
- Wire.write(decToBcd(dt->second & 0x7F));
- Wire.write(decToBcd(dt->minute & 0x7F));
- Wire.write(decToBcd(dt->hour & 0x3F));
- Wire.write(dt->dow & 0x07);
- Wire.write(decToBcd(dt->day & 0x3F));
- Wire.write(decToBcd(dt->month & 0x1F));
- Wire.write(decToBcd(dt->year));
- Wire.endTransmission();
- }
- int16_t getTemp() {
- byte i;
- byte present = 0;
- byte type_s = 0; //sensor type 0=DS18B20
- byte data[12];
- byte addr[8] = { 0x28, 0xE3, 0x7E, 0xE4, 0x00, 0x00, 0x00, 0xE6}; //sensor ID
- float celsius;
- if (OneWire::crc8(addr, 7) != addr[7]) //Address CRC is not valid!
- return -2;
- 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
- for ( i = 0; i < 9; i++) { // we need 9 data bytes
- data[i] = ds.read();
- }
- if(OneWire::crc8(data,8) != data[8]) //Data CRC is not valid
- return -3;
- int16_t raw = (data[1] << 8) | data[0];
- byte cfg = (data[4] & 0x60);
- 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;
- Serial.print(F("Temperature = "));
- Serial.print(celsius);
- Serial.println();
- return raw + 880;
- }
- int getVoltage(void) {
- int voltage;
- digitalWrite(ADC_CONTROL_PIN,LOW); //connect source
- delay(5);
- voltage = analogRead(ADC_PIN);
- voltage = analogRead(ADC_PIN);
- delay(10);
- ADCSRA &= ~(1<<ADEN); //disable ADC
- digitalWrite(ADC_CONTROL_PIN,HIGH); //disconnect source
- return 4400*x/1024;
- }
- long JulianDate(int year, int month, int day) {
- //1)http://quasar.as.utexas.edu/BillInfo/JulianDatesG.html
- //2) http://forum.arduino.cc/index.php?topic=94925.0
- //3) OK http://netcdf4-python.googlecode.com/svn/trunk/docs/netcdftime.netcdftime-pysrc.html
- year = 2000 + year;
- if(month < 3) {
- month += 12;
- year -= 1;
- }
- long centuries = year/100;
- long leaps = centuries/4;
- long leapDays = 2 - centuries + leaps; // note is negative!!
- long yearDays = 365.25 * (year + 4716); // days until 1 jan this year
- long monthDays = 30.6001 * (month + 1); // days until 1st month
- long jd = leapDays + day + monthDays + yearDays -1524.5;
- jd += 1; //correction due wrong "round" of .5
- return jd;
- }
- void GregorianDate(long jd, Mydate *d) {
- //http://php.net/manual/en/function.jdtogregorian.php
- long calc1, calc2, calc3;
- long year, month, day;
- jd = jd - 1721119;
- calc1 = 4 * jd - 1;
- year = (calc1 / 146097);
- jd = (calc1 - 146097 * year);
- day = (jd / 4);
- calc2 = 4 * day + 3;
- jd = (calc2 / 1461);
- day = calc2 - 1461 * jd;
- day = ((day + 4) / 4);
- calc3 = 5 * day - 3;
- month = (calc3 / 153);
- day = calc3 - 153 * month;
- day = ((day + 5) / 5);
- year = 100 * year + jd;
- if (month < 10) {
- month = month + 3;
- }
- else {
- month = month - 9;
- year = year + 1;
- }
- /* Serial.print(year);
- print0(month);
- print0(day);
- //Serial.println(); */
- d->day = day;
- d->month = month;
- d->year = year;
- }
- void intAlarm() {
- state = HIGH;
- return;
- }
- void intWakeSerial() {
- detachInterrupt(digitalPinToInterrupt(3));
- return;
- }
- void cwOn() {
- digitalWrite(LED_PIN,HIGH);
- digitalWrite(CW_PIN,LOW);
- }
- void cwOff() {
- digitalWrite(LED_PIN,LOW);
- digitalWrite(CW_PIN,HIGH);
- }
- void sendCW(byte letter) {
- int bits = 16;
- int mode;
- word signs = pgm_read_word(morse + letter);
- if(signs!=0) {
- Serial.println(signs,BIN);
- mode = signs >> 14;
- signs &= 0x3FFF;
- //Serial.println(mode);
- while(!(signs & 0x8000) && bits) {
- signs <<= 1;
- bits--;
- }
- signs <<= 1;
- bits--;
- switch(mode) {
- case 0:
- while(bits) {
- cwOn();
- if (signs & 0x8000)
- delay(DAH*cwspeed);
- else
- delay(DIT*cwspeed);
- cwOff();
- signs <<= 1;
- bits--;
- if (bits>0) delay(DIT*cwspeed);
- }
- delay(CHAR_DELAY*cwspeed);
- break;
- case 2:
- signs >>= 3;
- cwOn();
- delay(signs*100);
- cwOff();
- break;
- case 3:
- while(bits) {
- Serial.println(signs,BIN);
- if (signs & 0x8000)
- cwOn();
- else
- cwOff();
- delay(DIT*cwspeed);
- signs <<= 1;
- bits--;
- }
- }
- }
- }
- void sendData() {
- String message = F("*** QTC DE OK1RIG/B VVV VVV VVV = ");
- for(int cnt=0; cnt<message.length(); cnt++)
- sendCW(message[cnt]);
- int cnt = 0;
- while (cnt<storageLen and storage[cnt]>-2000) {
- Serial.println(storage[cnt],DEC);
- long cTemp = (long)storage[cnt]*625/1000;
- if(storage[0]<0)
- msg = String("m" + cTemp);
- else
- msg = String(cTemp);
- for(int t=0; t<msg.length(); t++)
- sendCW(msg[t]);
- sendCW(' ');
- sendCW(' ');
- sendCW(' ');
- cnt++;
- }
- sendCW('.');
- }
- void rtcOn() {
- pinMode(RTC_POWER_PIN,OUTPUT);
- digitalWrite(RTC_POWER_PIN, HIGH);
- }
- void rtcOff() {
- pinMode(RTC_POWER_PIN, INPUT);
- digitalWrite(RTC_POWER_PIN, LOW);
- }
- void sleepBaby() {
- rtcOff();
- attachInterrupt(digitalPinToInterrupt(3), intWakeSerial, LOW );
- set_sleep_mode(SLEEP_MODE_PWR_DOWN);
- sleep_enable();
- sleep_bod_disable();
- sei();
- sleep_cpu();
- sleep_disable();
- rtcOn();
- }
- int readTemperature(int day, byte hour) {
- int address = day * 50 + hour * 2 + 2;
- int temp;
- Wire.beginTransmission(AT24C32_I2C_ADDRESS);
- Wire.write(highByte(address));
- Wire.write(lowByte(address));
- Wire.endTransmission();
- Wire.requestFrom(AT24C32_I2C_ADDRESS, 2);
- temp = Wire.read();
- return Wire.read() << 8 | temp;
- }
- void pastValues(int samples) {
- struct Mydatetime dt;
- long start,today;
- int hour;
- getRtcTime(&dt);
- today = JulianDate(dt.year, dt.month, dt.day);
- EEPROM.get(0, start);
- start = today - start;
- hour = dt.hour;
- while(samples && start) {
- Serial.println(readTemperature(start, hour)-880);
- hour--;
- if (hour<0) { //or if(--hour < 0) {
- hour = 23;
- start--;
- }
- samples--;
- }
- }
- void setup() {
- rtcOn(); //power RTC On
- //CW
- pinMode(LED_PIN, OUTPUT); //onboard Led
- digitalWrite(LED_PIN, LOW);
- pinMode(CW_PIN, OUTPUT); //Buzzer
- digitalWrite(CW_PIN,HIGH);
- //ADC
- pinMode(ADC_CONTROL_PIN, OUTPUT); //connect Voltage on ADC
- digitalWrite(ADC_CONTROL_PIN,HIGH);
- pinMode(ADC_PIN, INPUT); //Battery meassure
- analogReference(INTERNAL);
- Serial.begin(19200);
- Wire.begin();
- while (!Serial); // wait for serial port to connect. Needed for native USB port only
- for(int x=storageLen-1; x>=0; x--) //loop down is less code in ASM
- storage[x] = 0x8000; // 0°C is valid value !
- //Serial.setTimeout(50);
- buffer = "";
- Serial.println(F("Console ready."));
- attachInterrupt(digitalPinToInterrupt(2), intAlarm, FALLING );
- clearRtcAlarm();
- setRtcAlarm();
- }
- void loop() {
- long jd;
- Mydate date;
- if (Serial.available() > 0) {
- activityTime = millis(); //timeout handling
- ch = Serial.read();
- if (ch==8) { //BS
- if (buffer.length()>0) { //if something in buffer
- Serial.write(127); //echo backspace 127 in PuTTY
- }
- }
- else if (ch==13) {
- Serial.println();
- if(buffer.equals(F("clear"))) {
- clearRtcAlarm();
- }
- else if(buffer.equals(F("temps"))) {
- for(int x=0; x<storageLen; x++)
- Serial.println((float)storage[x]/16);
- }
- else if(buffer.equals(F("cw"))) {
- sendData();
- }
- /*else if(buffer.equals(F("st"))) {
- for(int y=1; y!=10; y++) {
- Wire.beginTransmission(AT24C32_I2C_ADDRESS);
- Wire.write(0);
- Wire.write(30);
- Wire.endTransmission(false); //FLUSH, STOP and continue
- Wire.requestFrom(AT24C32_I2C_ADDRESS, 1, true); //STOP
- rx = Wire.read();
- Serial.println(rx);
- Serial.flush();
- }
- } */
- else if(buffer.equals(F("dumprtc"))) {
- dump(DS3231_I2C_ADDRESS, 0, 19, ADDRESS_8BIT);
- }
- else if(buffer.startsWith(F("dumpeep"))) {
- int addr = 0;
- buffer.trim();
- if (buffer.length()>0 and buffer.length()<=4) {
- for(int lp=0; lp<buffer.length();lp++) {
- if (buffer[lp]>='A' and buffer[lp]<='F')
- addr = (addr << 4) | ((byte)buffer[lp]-55);
- else if(buffer[lp]>='a' and buffer[lp]<='f')
- addr = (addr << 4) | ((byte)buffer[lp]-87);
- else if(buffer[lp]>='0' and buffer[lp]<='9')
- addr = (addr << 4) | ((byte)buffer[lp]-48);
- }
- }
- dump(AT24C32_I2C_ADDRESS, addr, 256, ADDRESS_16BIT);
- }
- else if(buffer.startsWith(F("dumpint"))) {
- dump(INTERNAL_EEPROM, 0, 256, ADDRESS_8BIT);
- }
- else if(buffer.equals(F("volt"))) {
- Serial.print(F("Analog value:"));
- Serial.println(getVoltage());
- }
- /*else if(buffer.equals(F("jd"))){
- Serial.println(JulianDate(16, 1 , 1));
- Serial.println(JulianDate(16, 12 , 31));
- Serial.println(JulianDate(15, 1 , 1));
- Serial.println(JulianDate(15, 12 , 31));
- } */
- else if(buffer.equals(F("temprtc"))) {
- Wire.beginTransmission(DS3231_I2C_ADDRESS);
- Wire.write(0x11);
- Wire.endTransmission();
- Wire.requestFrom(DS3231_I2C_ADDRESS, 2);
- int temp2 = Wire.read();
- temp2 <<= 2;
- temp2 |= (Wire.read() >> 6);
- Serial.println((float)temp2/4);
- }
- else if(buffer.equals(F("cleareep"))) {
- eraseEeprom(AT24C32_I2C_ADDRESS, 256);
- Serial.println(F("Eeprom erased."));
- }
- else if(buffer.equals(F("time"))) {
- getRtcTime(&datetime);
- print0(datetime.year); Serial.print(F("-"));
- print0(datetime.month); Serial.print(F("-"));
- print0(datetime.day); Serial.print(F(" "));
- print0(datetime.hour); Serial.print(F(":"));
- print0(datetime.minute); Serial.print(F(":"));
- print0(datetime.second); Serial.print(F(" "));
- print0(datetime.dow);
- Serial.println();
- }
- else if(buffer.startsWith(F("settime "))) {
- buffer.trim();
- if(buffer.length() == 6) {
- getRtcTime(&datetime);
- datetime.hour = (buffer[0]-48) * 10 + (buffer[1]-48);
- datetime.minute = (buffer[2]-48) * 10 + (buffer[3]-48);
- datetime.second = (buffer[4]-48) * 10 + (buffer[5]-48);
- setRtcTime(&datetime);
- } else Serial.println(F("Bad format, should be HHMMSS"));
- }
- else if(buffer.startsWith(F("setdate "))) {
- buffer.trim();
- if(buffer.length() == 6) {
- getRtcTime(&datetime);
- datetime.year = (buffer[0]-48) * 10 + (buffer[1]-48);
- datetime.month = (buffer[2]-48) * 10 + (buffer[3]-48);
- datetime.day = (buffer[4]-48) * 10 + (buffer[5]-48);
- setRtcTime(&datetime);
- } else Serial.println(F("Bad format, should be YYMMDD"));
- }
- else if(buffer.startsWith(F("setdow "))) {
- buffer.trim();
- if(buffer.length() == 1) {
- getRtcTime(&datetime);
- datetime.dow = buffer[0]-48;
- setRtcTime(&datetime);
- } else Serial.println(F("Bad format, should be D"));
- }
- /* else if(buffer.equals(F("rtcon"))) {
- rtcOn();
- }
- else if(buffer.equals(F("rtcoff"))) {
- rtcOff();
- } */
- else if(buffer.equals(F("storedate"))) {
- getRtcTime(&datetime);
- jd = JulianDate(datetime.year, datetime.month, datetime.day);
- EEPROM.put(0, jd);
- }
- else if(buffer.equals(F("loaddate"))) {
- EEPROM.get(0, jd);
- Serial.println(jd);
- GregorianDate(jd, &date);
- Serial.print(date.year);
- print0(date.month);
- print0(date.day);
- }
- /* else if(buffer.equals(F("greg"))) {
- EEPROM.get(0, jd);
- Serial.println(jd);
- GregorianDate(jd);
- GregorianDate(2457389);
- GregorianDate(2457754);
- GregorianDate(2457024);
- GregorianDate(2457388);
- } */
- else if(buffer.equals(F("list"))) {
- EEPROM.get(0, jd);
- getRtcTime(&datetime);
- long today = JulianDate(datetime.year, datetime.month, datetime.day);
- Serial.println(today);
- long toDay = today - jd;
- Serial.println(toDay);
- int fromDay = toDay - 2;
- if (fromDay<0) fromDay = 0;
- Serial.println(fromDay);
- for(int d=fromDay; d<=toDay; d++) {
- for(int h=0; h < 24; h++) {
- GregorianDate(jd+d, &date);
- Serial.print(date.year);
- print0(date.month);
- print0(date.day);
- Serial.print(F(" "));
- print0(h);
- Serial.print(F(":00"));
- Serial.print(F(" "));
- int tmpTemp = readTemperature(d,h);
- if (tmpTemp>0 and tmpTemp<2880) {
- Serial.println((float)(tmpTemp-880)/16.0);
- }
- else Serial.println();
- }
- }
- }
- else if (buffer.equals("")) {
- //nil - avoid error message on enter
- }
- else Serial.println(F("Error."));
- Serial.print(F(">>"));
- buffer = "";
- } else {
- buffer.concat((char)ch);
- Serial.write(ch);
- }
- }
- //In case if millis overflow (once per ~50 days)
- if(activityTime>millis())
- activityTime = millis();
- //Timeout - sleep
- if(millis() > (activityTime + TIMEOUT_TIME)) {
- sleepBaby();
- activityTime = millis();
- }
- if (state==HIGH) {
- rtcOn();
- Serial.println(F("Interrupt invoked"));
- getRtcTime(&datetime);
- Serial.print(F("Day offset:"));
- int tmpDayOffset = JulianDate(datetime.year,datetime.month,datetime.day) - EEPROM.get(0, jd);
- Serial.println(tmpDayOffset);
- Serial.print(F("In day add:"));
- Serial.println((datetime.hour*2)+2);
- /* delay(50);
- for(int x=storageLen-1; x>0; x--) //shift data
- storage[x] = storage[x-1];
- storage[0] = getTemp();
- */
- if (datetime.minute == 0) {
- int temperature = getTemp();
- eepPtr = (tmpDayOffset * 50) + (datetime.hour * 2) + 2;
- Serial.println(eepPtr);
- Serial.println(temperature);
- Wire.beginTransmission(AT24C32_I2C_ADDRESS);
- Wire.write(highByte(eepPtr));
- Wire.write(lowByte(eepPtr));
- Wire.write(lowByte(temperature));
- Wire.write(highByte(temperature));
- Wire.endTransmission();
- }
- Serial.flush(); //wait until all serial data are out before sleep
- clearRtcAlarm();
- state=LOW;
- sleepBaby();
- }
- }