#include "LedControl.h" #include #include // ************************* DECLARATIONS ************************* const int theDeviceAddress = 80; // set the address of the EEPROM chip // ***** DELAY BEFORE SLEEP ******** const long idleBeforeSleep=60000; // 300000 milliseconds = 5 minutes, 60000=1 minute long nextSleepMillis; // **** CONFIGURE THE LED DISPLAY **** // Pin 12 is connected to the DATA IN-pin (1) of the MAX7219 // Pin 11 is connected to the LOAD(/CS)-pin (12) of the MAX7219 // Pin 10 is connected to the CLK-pin (13) of the MAX7219 LedControl lc=LedControl(12,10,11,1); // **** CONFIGURE THE ROTARY SWITCH **** //switch 8 to pin 4, switch 4 to pin 5, switch 2 to pin 6, switch 1 to pin 7, const int rotaryPins[] = { 4, 5, 6, 7}; //Rotary Switch Pins // **** INITIALIZE THE COUNTERS AND MISC VARS**** volatile long countSum; // the number displayed on the LED long lastSum; // used by the loop to tell if the number has changed volatile long plusCount=0; // the number of times the increment button has been pressed volatile long minusCount=0; // the number of times the decrement button has been pressed long maxNumber=0; // the highest number reached long minNumber=0; // the lowest number reached int eraseConfirm=0; // used by printEraseConfirm() to determine which message to display int mode=0; /* mode -1 = DELETE mode 0 = NORMAL mode 1 = STATS maximum number mode 2 = STATS minimum number mode 3 = STATS increment button presses mode 4 = STATS decrement button presses */ // ************************* END DECLARATIONS ************************* // **** THE ADD FUNCTION CALLED BY INTERRUPT 0 (pin 2) **** void increment(){ if (mode==0){ countSum += getSwitchValue(); plusCount++; //increment the count of increment button pushes nextSleepMillis= millis() + idleBeforeSleep;// reset the idle timer } else { //if system is in STATS mode it will step through the stats //if system is in DELETE mode it will switch to NORMAL mode mode++; } } // **** THE SUBTRACT FUNCTION CALLED BY INTERRUPT 1 (pin 3) **** void decrement(){ if (mode==-1){ // if system is in DELETE mode countSum=0; // reset the counter mode=0; // return to NORMAL mode } else{ countSum -= getSwitchValue(); minusCount++; // increment the count of decrement button pushes nextSleepMillis= millis() + idleBeforeSleep;// reset the idle timer } } // **** GET THE VALUE OF THE ROTARY SWITCH **** // Creates a value from DIP Switch (4 positions used) // Switch is complement coded // pin 4 = 0001, pin 5 = 0010, pin 6 = 0100, pin 7 = 1000 // Switch data sheet = http://www.nkkswitches.com/pdf/FR01.pdf byte getSwitchValue(){ int i,j=0; //Get the switch's state for(i=0; i<=3; i++){ j = (j << 1) | (digitalRead(rotaryPins[i])); // read the input pin } int dec=j; if (dec==0){ dec=10; // we don't want 0 value, so change it to 10 } return dec; //return switch value } void setup() { //Serial.begin(9600); Wire.begin(); // read the stored values of the counters countSum = WireEepromReadLong(theDeviceAddress, 0); plusCount = WireEepromReadLong(theDeviceAddress, 4); minusCount =WireEepromReadLong(theDeviceAddress, 8); maxNumber = WireEepromReadLong(theDeviceAddress, 12); minNumber = WireEepromReadLong(theDeviceAddress, 16); // to reset the stored values after development /* WireEepromWriteLong(theDeviceAddress,0, 0); WireEepromWriteLong(theDeviceAddress,4, 0); WireEepromWriteLong(theDeviceAddress,8, 0); WireEepromWriteLong(theDeviceAddress,12, 0); WireEepromWriteLong(theDeviceAddress,16, 0); */ lastSum=countSum; nextSleepMillis= millis() + idleBeforeSleep;// reset the idle timer /* Set up the MAX7219 The MAX72XX is in power-saving mode on startup, we have to do a wakeup call */ lc.shutdown(0,false); /* Set the brightness to a medium values */ lc.setIntensity(0,15); /* and clear the display */ lc.clearDisplay(0); // prep the pins of the rotary switch int i; for(i = 0; i<=3; i++){ pinMode(rotaryPins[i], INPUT); // sets the digital pin 4-7 as input digitalWrite(rotaryPins[i], HIGH); // Set pullup resistor on } //Check for RESET request, by rotary switch = 8 and decrement button being pressed if(getSwitchValue()==8) { pinMode(3, INPUT); if (digitalRead(3)==1){ mode=-1; // mode -1= DELETE } } //Check for STATS request, by rotary switch = 3 and increment button being pressed if(getSwitchValue()==3) { pinMode(2, INPUT); if (digitalRead(2)==1){ mode=1; // mode > 0 = STATS } } // Configure the Interrupts attachInterrupt(0, increment, RISING); attachInterrupt(1, decrement, RISING); } void printNumber(long v) { if(v < -9999999 || v > 99999999) { v=0; countSum=0; } /* ones 00000001 max dig 0 pin 2, led dig 4 pin 6 tens 00000010 max dig 1 pin 11, led dig 3 pin 8 hundreds 00000100 max dig 2 pin 6, led dig 2 pin 9 thousands 00001000 max dig 3 pin 7, led dig 1 pin 12 tenthousands 00010000 max dig 4 pin 3, led dig 4 pin 6 hundredthousands 00100000 max dig 5 pin 10, led dig 3 pin 8 millions 01000000 max dig 6 pin 5, led dig 2 pin 9 tenmillions 10000000 max dig 7 pin 8, led dig 1 pin 12 */ int digitArray[8]; boolean negative; long originalV=v; if(v<0) { v=v*-1; } int i; //chew through the number and break it into digits for(i = 0; i<=6; i++){ digitArray[i]=v%10; v=v/10; } digitArray[7]=v; /* long version of the above function ones=v%10; digitArray[0]=ones; v=v/10; tens=v%10; digitArray[1]=tens; v=v/10; hundreds=v%10; digitArray[2]=hundreds; v=v/10; thousands=v%10; digitArray[3]=thousands; v=v/10; tenthousands=v%10; digitArray[4]=tenthousands; v=v/10; hundredthousands=v%10; digitArray[5]=hundredthousands; v=v/10; millions=v%10; digitArray[6]=millions; v=v/10; tenmillions=v; digitArray[7]=tenmillions; */ // blank out zeroes to the left. long numberPlace=10000000; int lastBlank; for(i = 7; i>=1; i--){ if(abs(originalV)>(numberPlace-1)){ lc.setDigit(0,i,digitArray[i],false); } else { lc.setChar(0,i,' ',false); lastBlank=i; } numberPlace /= 10; } lc.setDigit(0,0,digitArray[0],false); // if negative, set the right-most blank to a minus sign if (originalV < 0){ lc.setChar(0,lastBlank,'-',false); } } void printEraseConfirm(int eraseMode){ if (eraseMode==1){ lc.setChar(0,7,'e',false); // E lc.setRow(0,6,0x05); // r lc.setChar(0,5,'a',false); // A lc.setDigit(0,4,5,false); // S (5) lc.setChar(0,3,'e',false); // E lc.setChar(0,1,' ',false); // blank lc.setChar(0,0,' ',false); // blank } else{ //"YES" over the red button lc.setDigit(0,7,4,false); // y (4) lc.setChar(0,6,'e',false); // e lc.setDigit(0,5,5,false); // S (5) lc.setChar(0,4,' ',false); // blank lc.setChar(0,3,' ',false); // blank //"no" over the green button lc.setRow(0,1,0x15); // n lc.setRow(0,0,0x1D); // O (0) } } void loop() { // *** debugging stuff *** // delay(1000); // Serial.print("countSum:"); // Serial.println(countSum); switch (mode){ case -1: // DELETE mode: alternate display between "Erase" & "Yes No" for 5 seconds eraseConfirm++; printEraseConfirm(eraseConfirm%2); delay(1000); if (eraseConfirm>5){ mode=0; // if erase isn't confirmed in 5 seconds, revert to normal ops } break; case 0: // NORMAL Mode: display count printNumber(countSum); break; case 1: // STATS Mode: display highest number reached printNumber(maxNumber); break; case 2: // STATS Mode: display lowest number reached printNumber(minNumber); break; case 3: // STATS Mode: display number of times increment button pushed printNumber(plusCount); break; case 4: // STATS Mode: display number of times decrement button pushed printNumber(minusCount); break; default: mode=0; } //if the number has changed we write it to memory if (lastSum != countSum){ WireEepromWriteLong(theDeviceAddress,0, countSum); if (countSum > lastSum){ //store plusCount WireEepromWriteLong(theDeviceAddress,4, plusCount); // if the new number > previous maximum number, store it if (countSum > maxNumber){ WireEepromWriteLong(theDeviceAddress,12, countSum); maxNumber=countSum; } } else { //store minusCount WireEepromWriteLong(theDeviceAddress,8, minusCount); // if the number < previous minimum number, store it if (countSum < minNumber){ WireEepromWriteLong(theDeviceAddress,16, countSum); minNumber=countSum; } } lastSum=countSum; } // if it's been longer than the timeout period, go to sleep if (millis() > nextSleepMillis){ sleepNow(); } } void sleepNow() // here we put the arduino to sleep { // http://www.arduino.cc/playground/Learning/ArduinoSleepCode /* Now is the time to set the sleep mode. In the Atmega8 datasheet * http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf on page 35 * there is a list of sleep modes which explains which clocks and * wake up sources are available in which sleep mode. * * In the avr/sleep.h file, the call names of these sleep modes are to be found: * * The 5 different modes are: * SLEEP_MODE_IDLE -the least power savings * SLEEP_MODE_ADC * SLEEP_MODE_PWR_SAVE * SLEEP_MODE_STANDBY * SLEEP_MODE_PWR_DOWN -the most power savings * * For now, we want as much power savings as possible, so we * choose the according * sleep mode: SLEEP_MODE_PWR_DOWN * */ set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here sleep_enable(); // enables the sleep bit in the mcucr register // so sleep is possible. just a safety pin /* Now it is time to enable an interrupt. We do it here so an * accidentally pushed interrupt button doesn't interrupt * our running program. if you want to be able to run * interrupt code besides the sleep function, place it in * setup() for example. * * In the function call attachInterrupt(A, B, C) * A can be either 0 or 1 for interrupts on pin 2 or 3. * * B Name of a function you want to execute at interrupt for A. * * C Trigger mode of the interrupt pin. can be: * LOW a low level triggers * CHANGE a change in level triggers * RISING a rising edge of a level triggers * FALLING a falling edge of a level triggers * * In all but the IDLE sleep modes only LOW can be used. */ attachInterrupt(0,wakeUpNow, RISING); // use interrupt 0 (pin 2) and run function // wakeUpNow when pin 2 gets RISING attachInterrupt(1,wakeUpNow, RISING); // use interrupt 1 (pin 3) and run function // wakeUpNow when pin 3 gets RISING lc.shutdown(0,true); sleep_mode(); // here the device is actually put to sleep!! // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP sleep_disable(); // first thing after waking from sleep: // disable sleep... detachInterrupt(0); // disables interrupt 0 on pin 2 detachInterrupt(1); // and interrupt 1 on pin 3 so the // wakeUpNow code will not be executed // during normal running time. //reattach increment & decrement to interrupt pins attachInterrupt(0, increment, RISING); attachInterrupt(1, decrement, RISING); } void wakeUpNow() // here the interrupt is handled after wakeup { lc.shutdown(0,false); // wake up the display nextSleepMillis= millis() + idleBeforeSleep; //reset the idle sleep timer // execute code here after wake-up before returning to the loop() function // timers and code using timers (serial.print and more...) will not work here. // we don't really need to execute any special functions here, since we // just want the thing to wake up } //--------- Memory Functions -------------- // adapted from http://www.arduino.cc/playground/Code/I2CEEPROM24LC512 long WireEepromReadLong(int theDeviceAddress, unsigned int theMemoryAddress) { byte theByteArray[sizeof(long)]; WireEepromRead(theDeviceAddress, theMemoryAddress, sizeof(long), theByteArray); return((long )theByteArray[0]) << 24 | ((long )theByteArray[1]) << 16 | ((long )theByteArray[2]) << 8 | (long )theByteArray[3]; } void WireEepromWriteLong(int theDeviceAddress, unsigned int theMemoryAddress, long theLong) { byte theByteArray[sizeof(long)] = { (byte)(theLong >> 24), (byte)(theLong >> 16), (byte)(theLong >> 8), (byte)(theLong >> 0) }; WireEepromWrite(theDeviceAddress, theMemoryAddress, sizeof(long), theByteArray); } void WireEepromRead(int theDeviceAddress, unsigned int theMemoryAddress, int theByteCount, byte* theByteArray) { for (int theByteIndex = 0; theByteIndex < theByteCount; theByteIndex++) { Wire.beginTransmission(theDeviceAddress); Wire.send((byte)((theMemoryAddress + theByteIndex) >> 8)); Wire.send((byte)((theMemoryAddress + theByteIndex) >> 0)); Wire.endTransmission(); delay(5); Wire.requestFrom(theDeviceAddress, sizeof(byte)); theByteArray[theByteIndex] = Wire.receive(); } } void WireEepromWrite(int theDeviceAddress, unsigned int theMemoryAddress, int theByteCount, byte* theByteArray) { for (int theByteIndex = 0; theByteIndex < theByteCount; theByteIndex++) { Wire.beginTransmission(theDeviceAddress); Wire.send((byte)((theMemoryAddress + theByteIndex) >> 8)); Wire.send((byte)((theMemoryAddress + theByteIndex) >> 0)); Wire.send(theByteArray[theByteIndex]); Wire.endTransmission(); delay(5); } }