void sleep_until_switch_press() { // This routine takes up a lot of program memory :( // Turn the WDT off so it doesn't wake us from sleep // Will also ensure interrupts are on or we will never wake up WDT_off(); // Need to reset press duration since a button release wasn't recorded press_duration = 0; // Enable a pin change interrupt to wake us up // However, we have to make sure the switch is released otherwise we will wake when the user releases the switch while (is_pressed()) { _delay_ms(16); } PCINT_on(); // turn red+green LEDs off DDRB = (1 << PWM_PIN); // note the lack of red/green pins here // with this commented out, the LEDs dim instead of turning off entirely //PORTB &= 0xff ^ ((1 << RED_PIN) | (1 << GREEN_PIN)); // red+green off // Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command. //set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Now go to sleep sleep_mode(); // Hey, someone must have pressed the switch!! // Disable pin change interrupt because it's only used to wake us up PCINT_off(); // Turn the WDT back on to check for switch presses WDT_on(); // Go back to main program }
void sleep_until_switch_press() { // This routine takes up a lot of program memory :( // Turn the WDT off so it doesn't wake us from sleep // Will also ensure interrupts are on or we will never wake up WDT_off(); // Need to reset press duration since a button release wasn't recorded press_duration = 0; // Enable a pin change interrupt to wake us up // However, we have to make sure the switch is released otherwise we will wake when the user releases the switch while (is_pressed()) { _delay_ms(16); } PCINT_on(); // Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command. //set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Now go to sleep sleep_mode(); // Hey, someone must have pressed the switch!! // Disable pin change interrupt because it's only used to wake us up PCINT_off(); // Turn the WDT back on to check for switch presses WDT_on(); // Go back to main program }
void sleep_until_eswitch_pressed() { WDT_off(); ADC_off(); // make sure switch isn't currently pressed while (button_is_pressed()) {} empty_event_sequence(); // cancel pending input on suspend //PCINT_since_WDT = 0; // ensure PCINT won't ignore itself PCINT_on(); // wake on e-switch event // configure sleep mode set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); sleep_bod_disable(); sleep_cpu(); // wait here // something happened; wake up sleep_disable(); #ifdef USE_THERMAL_REGULATION // forget what the temperature was last time we were on reset_thermal_history = 1; #endif // go back to normal running mode //PCINT_on(); // should be on already // FIXME? if button is down, make sure a button press event is added to the current sequence ADC_on(); WDT_on(); }
int main(void) { DDRB = (1 << PWM_PIN); // Set PWM pin to output ACSR |= (1<<7); // AC (Analog Comparator) off TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) set_sleep_mode(SLEEP_MODE_IDLE); // Will allow us to go idle between WDT interrupts ADC_ctrl(); // Battery monitoring WDT_on(); // Start watchdogtimer set_output(0, 1); // Set phase pwm as default get_mode(); // Get mode identifier and store with short press indicator if (mypwm == MODE_PROGRAM) { mode_program(); } else if (mypwm == MODE_STROBE) { mode_strobe(); } else { set_output(mypwm, 1); } while(1) { sleep_mode(); // Enter sleep mode } return 0; }
int main(void) { uint8_t i; WDT_off(); setup(); PORTB |= (1<<PB7);//DONE _delay_ms(1000); PORTB &= ~(1<<PB7);//DONE // insert a startup delay of 20s to prevent interference with redboot // interrupts are already enabled at this stage // so the pulses are counted but not sent to the deamon // for (i=0; i<4; i++) _delay_ms(5000); serialFlush(); printString("\n"); WDT_on(); for (;;) loop(); return 0; }
int main(void) { // Set all ports to input, and turn pull-up resistors on for the inputs we are using DDRB = 0x00; PORTB = (1 << SWITCH_PIN) | (1 << STAR2_PIN) | (1 << STAR3_PIN); // Set the switch as an interrupt for when we turn pin change interrupts on PCMSK = (1 << SWITCH_PIN); // Set PWM pin to output DDRB = (1 << PWM_PIN); // Set timer to do PWM for correct output pin and set prescaler timing TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23 TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) // Turn features on or off as needed #ifdef VOLTAGE_MON ADC_on(); #else ADC_off(); #endif ACSR |= (1<<7); //AC off // Determine if we are going L-H, or H-L based on STAR 2 if ((PINB & (1 << STAR2_PIN)) == 0) { // High to Low low_to_high = 0; } else { low_to_high = 1; } // Not soldered (1) should enable memory memory = ((PINB & (1 << STAR3_PIN)) > 0) ? 1 : 0; // Don't think we want to ever go to sleep // Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command. //set_sleep_mode(SLEEP_MODE_PWR_DOWN); //sleep_until_switch_press(); WDT_on(); // Determine what mode we should fire up // Read the last mode that was saved if (memory) { read_mode_idx(); } else { if (low_to_high) { mode_idx = 0; } else { mode_idx = sizeof(modes); } } PWM_LVL = modes[mode_idx]; uint8_t last_mode_idx = mode_idx; while(1) { // We will never leave this loop. The WDT will interrupt to check for switch presses and // will change the mode if needed. If this loop detects that the mode has changed, run the // logic for that mode while continuing to check for a mode change. if (mode_idx != last_mode_idx) { // Save the new mode last_mode_idx = mode_idx; // The WDT changed the mode. PWM_LVL = modes[mode_idx]; } } return 0; // Standard Return Code }
int main(void) { uint8_t short_click = 0; // All ports default to input, but turn pull-up resistors on for the stars (not the ADC input! Made that mistake already) PORTB = (1 << STAR2_PIN) | (1 << STAR3_PIN); // Start up ADC for capacitor pin DIDR0 |= (1 << CAP_DIDR); // disable digital input on ADC pin to reduce power consumption ADMUX = (1 << REFS0) | (1 << ADLAR) | CAP_CHANNEL; // 1.1v reference, left-adjust, ADC3/PB3 ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL; // enable, start, prescale // Wait for completion while (ADCSRA & (1 << ADSC)) ; // Start again as datasheet says first result is unreliable ADCSRA |= (1 << ADSC); // Wait for completion while (ADCSRA & (1 << ADSC)) ; if(ADCH > CAP_THRESHOLD) short_click = 1; // Turn off ADC ADC_off(); // Charge up the capacitor by setting CAP_PIN to output DDRB |= (1 << CAP_PIN); // Output PORTB |= (1 << CAP_PIN); // High // Set PWM pin to output DDRB = (1 << PWM_PIN); // Set timer to do PWM for correct output pin and set prescaler timing TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23 TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) // Turn features on or off as needed #ifdef ENABLE_VOLTAGE_MONITORING ADC_on(); #else ADC_off(); #endif ACSR |= (1<<7); //AC off #ifdef ENABLE_TURNING_OFF_TURBO_TIMER turbo_timer_enabled = ((PINB & (1 << STAR2_PIN)) > 0) ? 1 : 0; #endif #ifdef ENABLE_SINGLE_MODE if((PINB & (1 << STAR2_PIN)) == 0) { modes[0] = modes[1] = #ifdef FOUR_MODES modes[2] = #endif MODE_TURBO; // Last basic mode is already MODE_TURBO - no need to waste bytes changing that } #endif #ifdef ENABLE_HIGH_TO_LOW #ifdef HIGH_TO_LOW_ON_BY_DEFAULT if((PINB & (1 << STAR3_PIN)) > 0) #else if((PINB & (1 << STAR3_PIN)) == 0) #endif revert_modes(); #endif #ifdef ENABLE_TACTICAL_MODE #ifdef TACTICAL_MODE_ON_BY_DEFAULT if((PINB & (1 << STAR2_PIN)) > 0) #else if((PINB & (1 << STAR2_PIN)) == 0) #endif { modes[1] = MODE_TURBO; if(modes[0] == MODE_TURBO) // Single mode { modes[2] = #ifdef FOUR_MODES modes[3] = #endif MODE_TURBO; } else { modes[0] = MODE_STROBE; modes[2] = MODE_LOW; #ifdef FOUR_MODES modes[3] = MODE_LOWLOW; #endif } } #endif // Enable sleep mode set to Idle that will be triggered by the sleep_mode() command. // Will allow us to go idle between WDT interrupts set_sleep_mode(SLEEP_MODE_IDLE); // Mode memory handling block { uint8_t n_short_clicks = 0; // Determine what mode we should fire up // Read the last mode that was saved mode_idx = read_stored_idx(); // Handle short press counter n_short_clicks = (mode_idx & 0xf0); mode_idx &= 0x0f; if(short_click) // This click was short { if(n_short_clicks == MODE_INDEX_TURBO_RAMPDOWN) // TODO: Test if this logic works in practice, or do we need to use always double tap from turbo? n_short_clicks = 0; // Keep turbo, reset counter else next_mode(n_short_clicks); // Will handle wrap arounds store_mode_idx(mode_idx | ((n_short_clicks < HIDDEN_MODE_THRESHOLD) ? n_short_clicks+0x10 : n_short_clicks)); } else // Didn't have a short press, keep the same mode, stored without short click counter { if((PINB & (1 << STAR2_PIN)) == 0) // Tactical or Single or No memory, reset to 1st mode mode_idx = 0; store_mode_idx(mode_idx); } } // Start watchdog timer (used for storing the mode after delay, turbo timer, and voltage monitoring) WDT_on(); // Now just fire up the mode selected_pwm = modes[mode_idx]; // Note: Actual PWM can be less than selected PWM (e.g. in case of low voltage) if(selected_pwm < PWM_MIN) // Hidden blinky modes adjusted_pwm = PWM_MAX; // All blinky modes initially with full power else adjusted_pwm = selected_pwm; // block for main loop { uint8_t ii = 0; // Loop counter, used by multiple branches #ifdef ENABLE_BEACONS uint8_t beacon_background = PWM_OFF; #endif while(1) { #ifdef ENABLE_VOLTAGE_MONITORING if(adjusted_pwm == PWM_OFF) // Voltage monitoring signaled us to turn off the light -> break out of the main loop break; #endif PWM_LVL = adjusted_pwm; // must be set inside loop, is volatile & might have changed because of voltage monitoring switch(selected_pwm) { case MODE_STROBE: // Disorienting alternating strobe #ifdef NORMAL_STROBE // 51ms = ~19.5Hz, ~60% DC _delay_ms(25); PWM_LVL = 0; _delay_ms(26); #endif #ifdef ALTERNATING_STROBE _delay_ms(31); PWM_LVL = 0; if(ii < 19) // 51ms = ~19.5Hz, ~60% DC _delay_ms(20); else if(ii < 32) // 77ms = ~13Hz, ~40% DC _delay_ms(46); else ii = 255; #endif #ifdef RANDOM_STROBE { // 77ms = 13Hz, 51ms = 19.5Hz / 40-60% DC ii = (5 * ii) + 128; _delay_ms(31); PWM_LVL = 0; _delay_ms(ii > 127 ? 46 : 20); } #endif break; case MODE_MOTION_STOPPING_STROBE: // 8Hz, 1.6% DC _delay_ms(2); PWM_LVL = 0; _delay_ms(123); break; #ifdef ENABLE_SOS case MODE_SOS: if(ii / 3 == 1) _delay_ms(600); // Dash for 'O' (3xDot) else _delay_ms(200); // Dot for 'S' PWM_LVL = 0; switch(ii) { default: _delay_ms(200); // Pause inside a letter (1xDot) break; case 2: case 5: _delay_ms(600); // Pause between letters (3xDot) break; case 8: _delay_ms(2500); // Pause between "words" (should be 7xDot, but I like it longer) ii = 255; break; } break; #endif #ifdef ENABLE_BEACONS case MODE_BEACON_WITH_BACKGROUND: beacon_background = PWM_BEACON_BACKGROUND; goto beacon_common; case MODE_SLOW_BEACON_WITH_BACKGROUND: beacon_background = PWM_SLOW_BEACON_BACKGROUND; // no break - fall through to beacon code case MODE_BEACON: case MODE_ALPINE_DISTRESS_BEACON: beacon_common: _delay_ms(50); PWM_LVL = beacon_background; _delay_ms(950); if(selected_pwm == MODE_ALPINE_DISTRESS_BEACON) { if(ii > 5) { _delay_ms(59000); ii = 255; } else _delay_ms(9000); } else if(selected_pwm == MODE_SLOW_BEACON_WITH_BACKGROUND) _delay_ms(1500); #endif break; default: sleep_mode(); break; } ii++; // Loop counter, used by multiple branches } } #ifdef ENABLE_VOLTAGE_MONITORING // // Critically low voltage -> Turn off the light // // Disable WDT so it doesn't wake us up from sleep WDT_off(); // Would be nice to blink a couple of times with lowest brightness to notify the user, but not implemented due space restrictions // Turn the light off PWM_LVL = 0; // Disable ADC so it doesn't consume power ADC_off(); // Power down as many components as possible set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Deep sleep until powered off - consumes ~110uA during the deep sleep while(1) sleep_mode(); #endif return 0; // Standard Return Code -> would return to idle loop with interrupts disabled. }
int main(void) { // All ports default to input, but turn pull-up resistors on for the stars (not the ADC input! Made that mistake already) PORTB = (1 << STAR2_PIN) | (1 << STAR3_PIN) | (1 << STAR4_PIN); // Set PWM pin to output DDRB = (1 << PWM_PIN); // Set timer to do PWM for correct output pin and set prescaler timing TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23 TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) // Turn features on or off as needed #ifdef ENABLE_VOLTAGE_MONITORING ADC_on(); #else ADC_off(); #endif ACSR |= (1<<7); //AC off #ifdef ENABLE_TURNING_OFF_MEMORY // Soldering Star 4 disables memory #ifdef MEMORY_ON_BY_DEFAULT memory_enabled = ((PINB & (1 << STAR4_PIN)) > 0) ? 1 : 0; #else memory_enabled = ((PINB & (1 << STAR4_PIN)) == 0) ? 1 : 0; #endif #endif #ifdef ENABLE_TURNING_OFF_TURBO_TIMER turbo_timer_enabled = ((PINB & (1 << STAR2_PIN)) > 0) ? 1 : 0; #endif #ifdef ENABLE_SINGLE_MODE if((PINB & (1 << STAR2_PIN)) == 0) { modes[0] = modes[1] = #ifdef FOUR_MODES modes[2] = #endif MODE_TURBO; // Last basic mode is already MODE_TURBO - no need to waste bytes changing that } #endif #ifdef ENABLE_TACTICAL_MODE #ifdef TACTICAL_MODE_ON_BY_DEFAULT if((PINB & (1 << STAR2_PIN)) > 0) #else if((PINB & (1 << STAR2_PIN)) == 0) #endif { #ifdef ENABLE_TURNING_OFF_MEMORY if(memory_enabled) // Single mode { modes[0] = modes[1] = #ifdef FOUR_MODES modes[2] = #endif MODE_TURBO; // Last basic mode is already MODE_TURBO - no need to waste bytes changing that } else #endif { modes[0] = MODE_STROBE; modes[1] = MODE_TURBO; modes[2] = MODE_LOW; #ifdef FOUR_MODES modes[3] = MODE_LOWLOW; #endif wdt_timeout = 1; } } #endif #ifdef ENABLE_HIGH_TO_LOW #ifdef HIGH_TO_LOW_ON_BY_DEFAULT if((PINB & (1 << STAR3_PIN)) > 0) #else if((PINB & (1 << STAR3_PIN)) == 0) #endif revert_modes(); #endif // Enable sleep mode set to Idle that will be triggered by the sleep_mode() command. // Will allow us to go idle between WDT interrupts set_sleep_mode(SLEEP_MODE_IDLE); // Mode memory handling block { uint8_t short_clicks = 0; // Determine what mode we should fire up // Read the last mode that was saved mode_idx = read_stored_idx(); // Handle short press indicator short_clicks = (mode_idx & 0xf0); mode_idx &= 0x0f; if(short_clicks) // One or more short clicks { // Indicates we did a short press last time, go to the next mode next_mode(short_clicks); // Will handle wrap arounds } // else: Didn't have a short press, keep the same mode, nothing to do // Store mode with short press indicator store_mode_idx(mode_idx | ((short_clicks < HIDDEN_MODE_THRESHOLD) ? short_clicks+0x10 : short_clicks)); } // Start watchdog timer (used for storing the mode after delay, turbo timer, and voltage monitoring) WDT_on(); // Now just fire up the mode selected_pwm = modes[mode_idx]; // Note: Actual PWM can be less than selected PWM (e.g. in case of low voltage) if(selected_pwm < PWM_MIN) // Hidden blinky modes adjusted_pwm = PWM_MAX; // All blinky modes initially with full power else adjusted_pwm = selected_pwm; // block for main loop { uint8_t ii = 0; // Loop counter, used by multiple branches #ifdef ENABLE_BEACONS uint8_t beacon_background = PWM_OFF; #endif while(1) { #ifdef ENABLE_VOLTAGE_MONITORING if(adjusted_pwm == PWM_OFF) // Voltage monitoring signaled us to turn off the light -> break out of the main loop break; #endif PWM_LVL = adjusted_pwm; // must be set inside loop, is volatile & might have changed because of voltage monitoring switch(selected_pwm) { case MODE_STROBE: // Disorienting alternating strobe #ifdef NORMAL_STROBE _delay_ms(20); PWM_LVL = 0; _delay_ms(40); #endif #ifdef ALTERNATING_STROBE _delay_ms(20); PWM_LVL = 0; if(ii < 22) // 60ms = ~16.7Hz, ~33% DC _delay_ms(40); else if(ii < 36) // 111ms = ~9Hz, ~18% DC _delay_ms(90); else ii = 255; #endif #ifdef RANDOM_STROBE { // 77ms = 13Hz, 51ms = 19.5Hz / 40-60% DC ii = (5 * ii) + 128; _delay_ms(31); PWM_LVL = 0; _delay_ms(ii > 127 ? 46 : 20); } #endif break; case MODE_MOTION_STOPPING_STROBE: // 10Hz, 2% DC _delay_ms(2); PWM_LVL = 0; _delay_ms(98); break; #ifdef ENABLE_SOS case MODE_SOS: if(ii / 3 == 1) _delay_ms(600); // Dash for 'O' (3xDot) else _delay_ms(200); // Dot for 'S' PWM_LVL = 0; switch(ii) { default: _delay_ms(200); // Pause inside a letter (1xDot) break; case 2: case 5: _delay_ms(600); // Pause between letters (3xDot) break; case 8: _delay_ms(2500); // Pause between "words" (should be 7xDot, but I like it longer) ii = 255; break; } break; #endif #ifdef ENABLE_BEACONS case MODE_BEACON_WITH_BACKGROUND: case MODE_SLOW_BEACON_WITH_BACKGROUND: #ifdef FOUR_MODES beacon_background = PWM_SLOW_BEACON_BACKGROUND; #else switch(selected_pwm) { case MODE_BEACON_WITH_BACKGROUND: beacon_background = PWM_BEACON_BACKGROUND; break; case MODE_SLOW_BEACON_WITH_BACKGROUND: beacon_background = PWM_SLOW_BEACON_BACKGROUND; break; } #endif // no break - fall through to beacon code case MODE_BEACON: case MODE_ALPINE_DISTRESS_BEACON: _delay_ms(50); PWM_LVL = beacon_background; _delay_ms(950); if(selected_pwm == MODE_ALPINE_DISTRESS_BEACON) { if(ii > 5) { _delay_ms(59000); ii = 255; } else _delay_ms(9000); } else if(selected_pwm == MODE_SLOW_BEACON_WITH_BACKGROUND) _delay_ms(1500); #endif break; default: sleep_mode(); break; } ii++; // Loop counter, used by multiple branches } } #ifdef ENABLE_VOLTAGE_MONITORING // // Critically low voltage -> Turn off the light // // Disable WDT so it doesn't wake us up from sleep WDT_off(); // Would be nice to blink a couple of times with lowest brightness to notify the user, but not implemented due space restrictions // Turn the light off PWM_LVL = 0; // Disable ADC so it doesn't consume power ADC_off(); // Power down as many components as possible set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Deep sleep until powered off - consumes ~110uA during the deep sleep while(1) sleep_mode(); #endif return 0; // Standard Return Code -> would return to idle loop with interrupts disabled. }