/* * Home Brain with ARDUINO Uno * * Serves as wireles alarm for gardenhouse, where is PIR, light and fire sensors, connected * to Atmel ATtiny2313A and 433 MHz radio transmitter * * I2C port I2C_PCF8574_PORT1 for keyboard and alarm: * * Low 4 bits: b0-b3: adresses keyboard 74HC151 multiplexer, b4: input from 74HC151 - HIGH signalizes pressed button * High 4 bits: b4-b6: output to 433 MHz radio coder, b7: input from radio signal */ #include #include #include // Peripheral addresses #define GREEN_LED 13 // Arduino onboard LED on pin 13 #define BEEPER 9 // Piezo Buzzer on pin 9 #define I2C_LCD 0x20 // LCD 16x2 driven by HD44780, connected to I2C module PCF8574T (7bit I2C address) #define I2C_PCF8574_PORT1 0x21 // I2C expander PCF8574P for keyboard and 433 MHz radio receiver (7bit I2C address) #define I2C_PCF8574_PORT2 0x38 // I2C expander PCF8574AP on expand shield, driving 8 FLUX LEDs (7bit I2C address) #define I2C_PCF8583_RTC1 0xA2 // PCF8583 RTC via I2C interface, A0 pin connected to Vdd, which will change the I2C address to 0xA2 (8bit I2C address) #define I2C_PCF8583_RTC2 0xA0 // PCF8583 RTC via I2C interface, A0 pin connected to GND #define I2C_PCF8591_DAC (0x92 >> 1) // PCF8591 8-bit A/D and D/A (7bit I2C address) /* * LCD connected via PCF8574T */ #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_LCD, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin, BACKLIGHT_PIN, POSITIVE); /* * Two PCF8583 real time Clock/calendar's with 240 x 8-bit RAM */ PCF8583 rtc1(I2C_PCF8583_RTC1); // Used to Keeping actual datetime, and fire 'daily alarm' to interrupt0 PCF8583 rtc2(I2C_PCF8583_RTC2); // Used to fire 'timer alarm' to interrupt1 /* * Some global variables */ volatile boolean ledStatus = false; byte port2data = 0; // content of I2C expander PCF8574AP on expand shield, driving 8 FLUX LEDs // Watchdog support #define WATCHDOG_TIMEOUT 20 volatile int watchdogCounter = 0; volatile boolean wasWatchdogWarning; // Alarm support volatile byte alarmCode = 0; // For speed reason, in one Main loop is checked only one alarm code; volatile int lastAlarmNumber = 0; // Last occured alarm, that's not acknowledged: 2-7 (0 means nothing, 1 is not alarm but watchdog signal) // Menu support #define MENU_ITEMS 24 int currentMenuItem = 1; // Backlight auto-off support #define BACKLIGHT_TIMEOUT 25 volatile int backlightCounter = 0; volatile boolean isBacklightOn; #define LED_DELAY 150 // delay for playing with FLUX LED's // Flags signalized interrupts volatile bool wasInterrupt0Triggered = false; volatile bool wasInterrupt1Triggered = false; /* * Setup ARDUINO and it's peripherals */ void setup() { /* * Initialize the LCD */ lcd.begin(16, 2); // 16 chars, 2 lines /* * Initialize ports */ pinMode(GREEN_LED, OUTPUT); // Initialize the onboard LED digital pin as an output. digitalWrite(GREEN_LED, HIGH); pinMode(BEEPER, OUTPUT); // Declare pin 9 to be an output analogWrite(BEEPER, 0); // 0 turns beeper off /* * Set port D pins 0 to 6 as inputs without changing the value of pins 0 & 1, which are RX & TX */ DDRD = DDRD | B00000000; PORTD = PORTD | B01111100; // The pullups /* * Initialize watchdog */ watchdogCounter = 0; wasWatchdogWarning = false; /* * Initialize alarm */ alarmCode = 0; lastAlarmNumber = 0; /* * Backlight */ isBacklightOn = true; /* * Hello message */ sayHello(); /* * Setup two PCF8583 RTCs and their Interrupt handlers */ rtc1.secondAlarm = 0; rtc1.minuteAlarm = 54; rtc1.hourAlarm = 17; rtc1.setClockAlarm(CLOCK_DAILY_ALARM); // Trigger interrupt0 once per day rtc2.setTimerAlarm(5, TIMER_SECONDS); // Trigger interrupt1 every 5 seconds attachInterrupt(0, interrupt0, FALLING); attachInterrupt(1, interrupt1, FALLING); } /* * Interrupt handler 0, from PCF8583 RTC #1 */ void interrupt0() { wasInterrupt0Triggered = true; } /* * Interrupt handler 1, from PCF8583 RTC #2 */ void interrupt1() { wasInterrupt1Triggered = true; } /* * Hello message and 3 beeps */ void sayHello() { lcd.clear(); lcd.home (); lcd.print("Arduino Uno"); lcd.setCursor(0, 1); lcd.print("Home Brain v 0.8"); delay (500); beep(50); delay (500); beep(50); delay (500); beep(50); digitalWrite(GREEN_LED, LOW); lcd.clear(); lcd.home (); } /* * Main loop */ void loop() { /* * Scan keyboard, all 6 buttons */ int keyNumber = getKey(); if(keyNumber > 0) // key pressed ? { if(!isBacklightOn) { isBacklightOn = true; lcd.backlight(); } backlightCounter = 0; // reset counter switch(keyNumber) { case 1: // Acknowledge alarm, set initial state sayHello(); watchdogCounter = 0; wasWatchdogWarning = false; lastAlarmNumber = 0; alarmCode = 0; break; /*case 2: lcd.backlight(); break;*/ case 3: lcd.scrollDisplayLeft(); break; case 4: // Menu printMenu(); keyNumber = getKey(); while(keyNumber != 1) // Key 1: Escape menu { switch(keyNumber) { case 2: if(currentMenuItem > 1) // Key 2: go previous menu item currentMenuItem--; else currentMenuItem = MENU_ITEMS; printMenu(); break; case 3: currentMenuItem -= 5; // Key 3: go back 5 menu items if(currentMenuItem < 1) currentMenuItem = 1; printMenu(); break; case 4: executeMenu(); // Key 4: Execute current menu item break; case 5: if(currentMenuItem < MENU_ITEMS) // Key 2: go next menu item currentMenuItem++; else currentMenuItem = 1; printMenu(); break; case 6: currentMenuItem += 5; // Key 3: go forward 5 menu items if(currentMenuItem > MENU_ITEMS) currentMenuItem = MENU_ITEMS; printMenu(); break; } delay (30); keyNumber = getKey(); } lcd.clear(); break; /*case 5: lcd.noBacklight(); break;*/ case 6: lcd.scrollDisplayRight(); break; default: { String num = String(keyNumber); lcd.setCursor(0, 1); lcd.print("Key " + num + " pressed "); longDelay(500); } break; } } /* * Check if alarm in global variable 'alarmCode' is signalled * For speed reason, in one Main loop is checked only one alarm code * For this reason alarmCode is declared in global scope */ int alarmNumber = getAlarm(); if(alarmNumber > 0) // alarm signalled ? { if(alarmNumber > 1) // don't save watchdog signal { lastAlarmNumber = alarmNumber; // save Alarm number if(!isBacklightOn) { isBacklightOn = true; lcd.backlight(); } backlightCounter = 0; // reset counter } switch(alarmNumber) { case 1: watchdogCounter = 0; // reset counter if(wasWatchdogWarning) { wasWatchdogWarning = false; lcd.setCursor(0, 1); lcd.print("Remote alarm alive now"); } break; case 2: lcd.setCursor(0, 1); lcd.print("Fire ALARM !!! "); beeps(5); break; case 3: lcd.setCursor(0, 1); lcd.print("PIR ALARM !!! "); beeps(3); break; case 4: lcd.setCursor(0, 1); lcd.print("Light ALARM !!! "); beeps(2); break; default: { String num = String(alarmNumber); lcd.setCursor(0, 1); lcd.print("Alarm " + num + " signalled "); } break; } } else { if(alarmCode == 0) // Every 8-th cycle blink onboard LED and check watchdog { digitalWrite(GREEN_LED, ledStatus); ledStatus = !ledStatus; if(watchdogCounter++ >= WATCHDOG_TIMEOUT) // counter exceed, remote station is not live { lcd.setCursor(0, 1); lcd.print("Watchdog warning "); watchdogCounter = 0; wasWatchdogWarning = true; } else { printDateTimeShort(); } // turn LCD backlight off, if alarm not occured after timeout if((isBacklightOn) && (lastAlarmNumber == 0) && (backlightCounter++ >= BACKLIGHT_TIMEOUT)) { isBacklightOn = false; lcd.noBacklight(); backlightCounter = 0; } } } /* * Handle daily interrupt, turn FLUX LED'd off if nothing to do */ if(!handleInterrupt0()) { setPort2(0x00, false); } } /* * Append spaces to rest of line to fit LCD 24 chars */ void padRight(String &line) { while(line.length() < 24) { line = line + " "; } } /* * Scan keyboard and return key number 1 - 6, if pressed * Otherwise return 0 */ int getKey() { for(byte keyCode = 0; keyCode <= 5; keyCode++) // 6 buttons are connected to inputs of 74HC151 multiplexer - scan them sequentially { byte portData = keyCode | B11111000; // I2C Port-1 bits 0-3 (B11111xxx) adresses 74HC151 multiplexer Wire.beginTransmission(I2C_PCF8574_PORT1); Wire.write(portData); Wire.endTransmission(); delay (20); Wire.requestFrom(I2C_PCF8574_PORT1, 1); if (Wire.available()) { byte c = Wire.read(); if((c & B00001000) != 0) // Test bit 4 IN, connected to output of 74HC151 multiplexer { int keyNumber = keyCode + 1; // Pressed ! beep(50); while(true) // Wait for key release { Wire.requestFrom(I2C_PCF8574_PORT1, 1); if (Wire.available()) { c = Wire.read(); // Test bit 4 IN, connected to output of 74HC151 multiplexer if((c & B00001000) == 0) { return keyNumber; // Released, return key number } // Released ? } // if (Wire.available()) } // while(true) } // Pressed ? } // if (Wire.available()) } // for 0 .. 5 return 0; // Nothing pressed } /* * Check if 'alarmCode' is signalled. * Return alarm number 1 - 8, if signalled, otherwise return 0 */ int getAlarm() { lcd.setCursor(0, 0); String alarmCodeAsString = String(alarmCode); if(wasWatchdogWarning) alarmCodeAsString += " !!!"; lcd.print("Checking: " + alarmCodeAsString); // UM3758-120A decoder have addresses A0-A9 hardcoded, A10-A12 leaved for 8 alarm numbers byte portData = (alarmCode << 4) | B10001111; // I2C Port-1 bits 4-6 (B1xxx1111) adresses UM3758-120A decoder A10-A12 bits Wire.beginTransmission(I2C_PCF8574_PORT1); Wire.write(portData); Wire.endTransmission(); longDelay(200); // delay for stabilize address on decoder Wire.requestFrom(I2C_PCF8574_PORT1, 1); if (Wire.available()) { byte c = Wire.read(); // Test bit 7 IN, connected to output of UM3758-120A decoder // UM3758-120A decoder TX pin will switch to LOW if comparsion is OK if((c & B10000000) == 0) { int alarmNumber = alarmCode + 1; // Alarm signalled ! if(alarmNumber > 1) // Don't care about watchdog signal { analogWrite(BEEPER, 128); // Start beeping ASAP String num = String(alarmNumber); lcd.setCursor(0, 1); lcd.print("Alarm " + num + " signalled"); } watchdogCounter = 0; // reset counter while(true) // Wait for alarm unsignalled { Wire.requestFrom(I2C_PCF8574_PORT1, 1); if (Wire.available()) { c = Wire.read(); // Test bit 7 IN, connected to output of UM3758-120A decoder from 433MHz radio if((c & B10000000) != 0) { return alarmNumber; // Alarm inactive, return alarm number } // Unsignalled ? } // if (Wire.available()) handleInterrupt1(); } // while(true) } // Alarm signalled ? } // if (Wire.available()) if(++alarmCode > 7) alarmCode = 0; return 0; // Nothing received } /* * Print current menu item to display */ void printMenu() { lcd.setCursor(0, 0); // Line 1 is reserved for menu item String menu = String(currentMenuItem); switch(currentMenuItem) { case 1: menu += " Print Port 1"; break; case 2: menu += " Print Port D"; break; case 3: menu += " P2: set 0x01"; break; case 4: menu += " P2: set 0x00"; break; case 5: menu += " P2: rotate <<"; break; case 6: menu += " P2: rotate >>"; break; case 7: menu += " P2: invert"; break; case 8: menu += " P2: B01010101"; break; case 9: menu += " P2: test 1"; break; case 10: menu += " P2: test 2"; break; case 11: menu += " RTC1 Minute--"; break; case 12: menu += " RTC1 Minute++"; break; case 13: menu += " RTCs Set datetime"; break; case 14: menu += " Date + time 1"; break; case 15: menu += " Date + time 2"; break; case 16: menu += " RTC1 NVRAM test"; break; case 17: menu += " Daily alarm test"; break; case 18: menu += " Weekday alarm test"; break; case 19: menu += " Dated alarm test"; break; case 20: menu += " Timer alarm test"; break; case 21: menu += " Print RTC 1"; break; case 22: menu += " Print RTC 2"; break; case 23: menu += "Test ext. DAC"; break; case 24: menu += "Print ext. ADCs"; break; } padRight(menu); lcd.print(menu); } /* * Execute current menu item */ void executeMenu() { switch(currentMenuItem) { case 1: printPort1(); break; case 2: printPortD(); break; case 3: setPort2(B00000001, true); break; case 4: setPort2(B00000000, true); break; case 5: port2data = port2data << 1; setPort2(true); break; case 6: port2data = port2data >> 1; setPort2(true); break; case 7: port2data = ~port2data; setPort2(true); break; case 8: setPort2(B01010101, true); break; case 9: test1_Port2(65535); break; case 10: test2_Port2(65535); break; case 11: rtc1.getTime(); rtc1.second = 0; rtc1.minute--; if(rtc1.minute < 0) { rtc1.minute = 59; rtc1.hour--; } rtc1.setTime(); printDateTimeFull_1(); break; case 12: rtc1.getTime(); rtc1.second = 0; rtc1.minute++; if(rtc1.minute > 59) { rtc1.minute = 0; rtc1.hour++; } rtc1.setTime(); printDateTimeFull_1(); break; case 13: setDateTime(); break; case 14: printDateTimeFull_1(); break; case 15: printDateTimeFull_2(); break; case 16: testRtcNvRam(); break; case 17: rtc1.getTime(); rtc1.secondAlarm = 0; rtc1.minuteAlarm = rtc1.minute + 1; rtc1.hourAlarm = rtc1.hour; rtc1.setClockAlarm(CLOCK_DAILY_ALARM); break; case 18: rtc1.getTime(); rtc1.secondAlarm = 0; rtc1.minuteAlarm = rtc1.minute + 1; rtc1.hourAlarm = rtc1.hour; rtc1.weekdayAlarm = B00000100; // Tuesday rtc1.setClockAlarm(CLOCK_WEEKDAY_ALARM); break; case 19: rtc1.getTime(); rtc1.secondAlarm = 0; rtc1.minuteAlarm = rtc1.minute + 1; rtc1.hourAlarm = rtc1.hour; rtc1.dayAlarm = rtc1.day; rtc1.monthAlarm = rtc1.month; rtc1.setClockAlarm(CLOCK_DATED_ALARM); break; case 20: rtc2.setTimerAlarm(5, TIMER_SECONDS); break; case 21: printRtc1Controls(); break; case 22: printRtc2Controls(); break; case 23: test1_DAC(); break; case 24: printADCs(); break; } } /////////////////////////////////////////////////////////////////////////// // // Arduino internal port D support // /////////////////////////////////////////////////////////////////////////// /* * Print Arduino Port D */ void printPortD() { byte c = PIND; // PORTD covers Arduino pin numbers 0-7. String thisString = String(c, BIN); while(thisString.length() < 8) { thisString = "0" + thisString; } thisString.setCharAt(6, 'x'); // replace RX & TX with xx thisString.setCharAt(7, 'x'); thisString = "Port D: " + thisString; padRight(thisString); lcd.setCursor(0, 1); lcd.print (thisString); } /////////////////////////////////////////////////////////////////////////// // // PCF8574 I2C Port 1 (keyboard & alarm) support // /////////////////////////////////////////////////////////////////////////// /* * Read data from external I2C PCF8574 Port 1 */ byte getPort1Status() { byte c = 0; Wire.requestFrom(I2C_PCF8574_PORT1, 1); if (Wire.available()) { c = Wire.read(); } return c; } /* * Print external I2C PCF8574 Port 1 */ void printPort1() { byte c = getPort1Status(); String thisString = String(c, BIN); while(thisString.length() < 8) { thisString = "0" + thisString; } thisString = "Port 1: " + thisString; padRight(thisString); lcd.setCursor(0, 1); lcd.print (thisString); } /////////////////////////////////////////////////////////////////////////// // // PCF8574 I2C Port 2 (FLUX LED's) support // /////////////////////////////////////////////////////////////////////////// /* * Set global variable 'port2data' to external I2C PCF8574 Port 2 */ void setPort2(boolean printIt) { Wire.beginTransmission(I2C_PCF8574_PORT2); Wire.write(port2data); Wire.endTransmission(); if(printIt) printPort2(); } /* * Set global variable 'port2data' to external I2C PCF8574 Port 2 */ void setPort2(byte _port2data, boolean printIt) { port2data = _port2data; Wire.beginTransmission(I2C_PCF8574_PORT2); Wire.write(port2data); Wire.endTransmission(); if(printIt) printPort2(); } /* * Print external I2C PCF8574 Port 2 (global variable 'port2data') */ void printPort2() { String thisString = String(port2data, BIN); while(thisString.length() < 8) { thisString = "0" + thisString; } thisString = "Port 2: " + thisString; padRight(thisString); lcd.setCursor(0, 1); lcd.print (thisString); } /////////////////////////////////////////////////////////////////////////// // // PCF8583 I2C RTC's support // /////////////////////////////////////////////////////////////////////////// /* * Print control registers on RTC #1 */ void printRtc1Controls() { byte c = rtc1.read(0x00); String thisString = String(c, BIN); while(thisString.length() < 8) { thisString = "0" + thisString; } thisString = "0x00: " + thisString; padRight(thisString); lcd.setCursor(0, 0); lcd.print (thisString); c = rtc1.read(0x08); thisString = String(c, BIN); while(thisString.length() < 8) { thisString = "0" + thisString; } thisString = "0x08: " + thisString; padRight(thisString); lcd.setCursor(0, 1); lcd.print (thisString); } /* * Print control registers on RTC #2 */ void printRtc2Controls() { byte c = rtc2.read(0x00); String thisString = String(c, BIN); while(thisString.length() < 8) { thisString = "0" + thisString; } thisString = "0x00: " + thisString; padRight(thisString); lcd.setCursor(0, 0); lcd.print (thisString); c = rtc2.read(0x08); thisString = String(c, BIN); while(thisString.length() < 8) { thisString = "0" + thisString; } thisString = "0x08: " + thisString; padRight(thisString); lcd.setCursor(0, 1); lcd.print (thisString); } /* * Set hardcoded datetime to boths RTC's */ void setDateTime() { rtc1.year = 2013; rtc1.month = 10; rtc1.day = 30; rtc1.hour = 21; rtc1.minute = 16; rtc1.second = 0; rtc1.weekday = 3; rtc2.year = rtc1.year; rtc2.month = rtc1.month; rtc2.day = rtc1.day; rtc2.hour = rtc1.hour; rtc2.minute = rtc1.minute; rtc2.second = 0; rtc2.weekday = rtc1.weekday; rtc1.setTime(); rtc2.setTime(); } const char weekday_names[7][4] = { {"Sun"}, {"Mon"}, {"Tue"}, {"Wed"}, {"Thu"}, {"Fri"}, {"Sat"} }; /* * Print date and time: DD.MM. HH.MM.SS */ void printDateTimeShort() { rtc1.getTime(); lcd.setCursor(13, 0); // Print weekday name to 1st line, right side lcd.print(weekday_names[rtc1.weekday]); char buf[25]; sprintf(buf, "%02d.%02d. %02d:%02d:%02d", rtc1.day, rtc1.month, rtc1.hour, rtc1.minute, rtc1.second); String dateTime = String(buf); padRight(dateTime); lcd.setCursor(0, 1); lcd.print(dateTime); } /* * Print date and time from RTC #1: * * WKD DD.MM.YYYY * HH.MM.SS */ void printDateTimeFull_1() { lcd.clear(); lcd.home (); rtc1.getTime(); char date[15]; sprintf(date, "%s %02d.%02d.%04d", weekday_names[rtc1.weekday], rtc1.day, rtc1.month, rtc1.year); lcd.setCursor(0, 0); lcd.print(date); char time[9]; sprintf(time, "%02d:%02d:%02d", rtc1.hour, rtc1.minute, rtc1.second); lcd.setCursor(0, 1); lcd.print(time); } /* * Print date and time from RTC #2: * * WKD DD.MM.YYYY * HH.MM.SS */ void printDateTimeFull_2() { lcd.clear(); lcd.home (); rtc2.getTime(); char date[15]; sprintf(date, "%s %02d.%02d.%04d", weekday_names[rtc2.weekday], rtc2.day, rtc2.month, rtc2.year); lcd.setCursor(0, 0); lcd.print(date); char time[9]; sprintf(time, "%02d:%02d:%02d", rtc2.hour, rtc2.minute, rtc2.second); lcd.setCursor(0, 1); lcd.print(time); } /////////////////////////////////////////////////////////////////////////// // // PCF8591 I2C 8-bit DAC and ADC's support // /////////////////////////////////////////////////////////////////////////// /* * Set given value to PCF8591 DAC #1 */ void setDAC(byte value) { Wire.beginTransmission(I2C_PCF8591_DAC); Wire.write(0x40); // control byte - turn on DAC (binary 1000000) Wire.write(value); Wire.endTransmission(); } /* * Read and print values from external I2C PCF8591 ADC inputs */ void printADCs() { byte values[4]; while(true) { for(byte adc = 0; adc <= 3; adc++) { Wire.beginTransmission(I2C_PCF8591_DAC); // wake up PCF8591 byte controlByte = 0x40 | (adc & B00000011); // Mask bits 0-2: A/D channel number Wire.write(controlByte); // control byte - read ADC0 - 3 Wire.endTransmission(); // end tranmission Wire.requestFrom(I2C_PCF8591_DAC, 2); values[adc] = Wire.read(); // PCF8591 returns the previously measured value first ... values[adc] = Wire.read(); // ... then the current byte } char line[25]; sprintf(line, "0: %d, 1: %d", values[0], values[1]); String thisString = String(line); padRight(thisString); lcd.setCursor(0, 0); lcd.print(thisString); sprintf(line, "2: %d, 3: %d", values[2], values[3]); thisString = String(line); padRight(thisString); lcd.setCursor(0, 1); lcd.print(thisString); delay(50); if(getKey() > 0) return; } } /////////////////////////////////////////////////////////////////////////// // // Beeper support // /////////////////////////////////////////////////////////////////////////// /* * Single Beep. Because Beeper not have generator, send PWM wave to a pin. */ void beep(unsigned char delayms) { analogWrite(BEEPER, 128); // Almost any value can be used except 0 and 255 delay(delayms); // wait for a delayms ms analogWrite(BEEPER, 0); // 0 turns it off } /* * Multiple Beeps. */ void beeps(int count) { for(int i = 0; i < count; i++) { longDelay (500); digitalWrite(GREEN_LED, HIGH); beep(500); longDelay (500); digitalWrite(GREEN_LED, LOW); beep(500); } } /////////////////////////////////////////////////////////////////////////// // // Interrupt support // /////////////////////////////////////////////////////////////////////////// /* * Divide long delay to small chunks and handle interrupt 1 between them */ void longDelay(long ms) { long remainder = ms; const int maxDelay = 100; // threshold do { if(remainder > maxDelay) { delay(maxDelay); } else { delay(remainder); } handleInterrupt1(); remainder -= maxDelay; } while(remainder > 0); } /* * Handle interrupt 0 * * interrupt0 - fired daily from RTC1 * return true if interupt is handled, otherwise return false */ boolean handleInterrupt0() { if(wasInterrupt0Triggered) { wasInterrupt0Triggered = false; // clear flag setPort2(B11001100, false); beep(150); delay (500); setPort2(B00110011, false); beep(150); delay (500); setPort2(B11001100, false); beep(150); delay (500); setPort2(B00110011, false); beep(150); rtc1.restartClockAlarm(); return true; } return false; } /* * Handle interrupt 1 * * interrupt1 - fired periodicaly from RTC2 - flash FLUX LED's on Port2 with regards of state flags * return true if any interupt is handled, otherwise return false */ boolean handleInterrupt1() { if(wasInterrupt1Triggered) { wasInterrupt1Triggered = false; // clear flag // Turn ON bits for according LED's in upper line port2data = B01000000; // green FLUX LED- indicate that we are alive if(wasWatchdogWarning) { port2data |= B00010000; // yellow FLUX LED - signalize watchdog warning } if(lastAlarmNumber == 3) // PIR ? { port2data |= B00000001; // red FLUX LED - indicate PIR alarm } if((lastAlarmNumber == 2) || (lastAlarmNumber == 4)) // Light or fire ? { port2data |= B00000100; // blue FLUX LED - indicate Lingh or fire sensor alarm } // Port2 have 8 LEDs are arranged in two lines: // RED(bit0)|BLUE(bit2)|YELLOW(bit4)|GREEN(bit6) // RED(bit1)|BLUE(bit3)|YELLOW(bit5)|GREEN(bit7) setPort2(false); // flash upper LED's line delay (50); port2data = port2data << 1; // move ON bits to lower line setPort2(false); // flash lower LED's line delay (50); setPort2(0x00, false); // turn all LED's OFF rtc2.restartTimerAlarm(); return true; } return false; } /////////////////////////////////////////////////////////////////////////// // // Various testing procedures, called fom menu // /////////////////////////////////////////////////////////////////////////// /* * Test external I2C PCF8574 Port 2 - play with FLUX LED's */ void test1_Port2(unsigned int nCount) { while((getKey() == 0) && (nCount-- > 0)) { port2data = 0x00; do { port2data = port2data << 1; port2data |= B00000001; setPort2(true); delay(LED_DELAY); if(getKey() != 0) return; } while(port2data != 0xFF); do { port2data = port2data << 1; port2data &= B11111110; setPort2(true); delay(LED_DELAY); if(getKey() != 0) return; } while(port2data != 0x00); } } /* * Test external I2C PCF8574 Port 2 - play with FLUX LED's */ void test2_Port2(unsigned int nCount) { while((getKey() == 0) && (nCount-- > 0)) { port2data = B00000001; do { setPort2(true); delay(LED_DELAY); if(getKey() != 0) return; port2data = port2data << 1; } while(port2data != 0x00); port2data = B10000000; do { setPort2(true); delay(LED_DELAY); if(getKey() != 0) return; port2data = port2data >> 1; } while(port2data != 0x00); } } /* * Test writes and reads into/from NVRAM in RTC1 */ void testRtcNvRam() { lcd.setCursor(0, 1); for(byte writed = 0x12; writed < 0xff; writed++) // 0x10-11 is used by PCF8583 for storing year ! { port2data = writed; setPort2(false); delay (20); rtc1.write(writed, writed); // write this same value to address byte readed = rtc1.read(writed); if(writed != readed) { String address = String(writed); lcd.print("Test failed: " + address); return; } } lcd.print("Test passed "); } /* * Send triangle wawe to external I2C PCF8591 DAC output * * http://tronixstuff.com/2013/06/17/tutorial-arduino-and-pcf8591-adc-dac-ic/ */ void test1_DAC() { for(int j = 0; j < 256; j++) { { for (int i = 0; i < 256; i++) { setDAC(i); } for (int i = 255; i >= 0; --i) { setDAC(i); } } if(getKey() > 0) return; } }