Untitled diff

Created Diff never expires
90 removals
444 lines
134 additions
491 lines
/* STAR_momentary version 1.6
/* MTN_momentary_temp version 1.0
*
*
* Changelog
* Changelog
*
*
* 1.0 Initial version
* 1.0 First stab at this based on STAR_momentary v1.6
* 1.1 Added ability for star 2 to change mode order
* 1.2 Fix for newer version of AVR Studio
* 1.3 Added support for dual PWM outputs and selection of PWM mode per output level
* 1.4 Added ability to switch to a momentary mode
* 1.5 Added ability to set mode to 0 but not have it turn off
* 1.6 Added ability to debounce the press
*
*
*/
*/


/*
/*
* NANJG 105C Diagram
* NANJG 105C Diagram
* ---
* ---
* -| |- VCC
* -| |- VCC
* Star 4 -| |- Voltage ADC
* Star 4 -| |- Voltage ADC
* Star 3 -| |- PWM
* Star 3 -| |- PWM
* GND -| |- Star 2
* GND -| |- Star 2
* ---
* ---
*
*
* FUSES
* FUSES
* I use these fuse settings
* I use these fuse settings
* Low: 0x75 (4.8MHz CPU without 8x divider, 9.4kHz phase-correct PWM or 18.75kHz fast-PWM)
* Low: 0x75 (4.8MHz CPU without 8x divider, 9.4kHz phase-correct PWM or 18.75kHz fast-PWM)
* High: 0xff
* High: 0xff
*
*
* For more details on these settings, visit http://github.com/JCapSolutions/blf-firmware/wiki/PWM-Frequency
* For more details on these settings, visit http://github.com/JCapSolutions/blf-firmware/wiki/PWM-Frequency
*
*
* STARS
* STARS
* Star 2 = Not used
* Star 2 = Alt PWM output
* Star 3 = H-L if connected, L-H if not
* Star 3 = Charger on? input
* Star 4 = Switch input
* Star 4 = Switch input
*
*
* VOLTAGE
* VOLTAGE
* Resistor values for voltage divider (reference BLF-VLD README for more info)
* Resistor values for voltage divider (reference BLF-VLD README for more info)
* Reference voltage can be anywhere from 1.0 to 1.2, so this cannot be all that accurate
* Reference voltage can be anywhere from 1.0 to 1.2, so this cannot be all that accurate
*
*
* VCC
* VCC
* |
* |
* Vd (~.25 v drop from protection diode)
* Vd (~.25 v drop from protection diode)
* |
* |
* 1912 (R1 19,100 ohms)
* 1912 (R1 19,100 ohms)
* |
* |
* |---- PB2 from MCU
* |---- PB2 from MCU
* |
* |
* 4701 (R2 4,700 ohms)
* 4701 (R2 4,700 ohms)
* |
* |
* GND
* GND
*
*
* ADC = ((V_bat - V_diode) * R2 * 255) / ((R1 + R2 ) * V_ref)
* ADC = ((V_bat - V_diode) * R2 * 255) / ((R1 + R2 ) * V_ref)
* 125 = ((3.0 - .25 ) * 4700 * 255) / ((19100 + 4700) * 1.1 )
* 125 = ((3.0 - .25 ) * 4700 * 255) / ((19100 + 4700) * 1.1 )
* 121 = ((2.9 - .25 ) * 4700 * 255) / ((19100 + 4700) * 1.1 )
* 121 = ((2.9 - .25 ) * 4700 * 255) / ((19100 + 4700) * 1.1 )
*
*
* Well 125 and 121 were too close, so it shut off right after lowering to low mode, so I went with
* Well 125 and 121 were too close, so it shut off right after lowering to low mode, so I went with
* 130 and 120
* 130 and 120
*
*
* To find out what value to use, plug in the target voltage (V) to this equation
* To find out what value to use, plug in the target voltage (V) to this equation
* value = (V * 4700 * 255) / (23800 * 1.1)
* value = (V * 4700 * 255) / (23800 * 1.1)
*
*
*/
*/
#define F_CPU 4800000UL
#define F_CPU 4800000UL


// PWM Mode
// PWM Mode
#define PHASE 0b00000001
#define PHASE 0b00000001
#define FAST 0b00000011
#define FAST 0b00000011


/*
/*
* =========================================================================
* =========================================================================
* Settings to modify per driver
* Settings to modify per driver
*/
*/


#define VOLTAGE_MON // Comment out to disable - ramp down and eventual shutoff when battery is low
//#define VOLTAGE_MON // Comment out to disable - ramp down and eventual shutoff when battery is low
#define MODES 0,3,14,39,125,255 // Must be low to high, and must start with 0
#define CHARGER_MON // Comment out to disable - is charging cable connected
#define ALT_MODES 0,3,14,39,125,255 // Must be low to high, and must start with 0, the defines the level for the secondary output. Comment out if no secondary output
#define MODES 0,3,32,125,255 // Must be low to high, and must start with 0
#define MODE_PWM 0,PHASE,FAST,FAST,FAST,PHASE // Define one per mode above. 0 tells the light to go to sleep
//#define ALT_MODES 0,3,32,125,255 // Must be low to high, and must start with 0, the defines the level for the secondary output. Comment out if no secondary output
#define TURBO // Comment out to disable - full output with a step down after n number of seconds
#define MODE_PWM 0,PHASE,FAST,FAST,FAST // Define one per mode above. 0 tells the light to go to sleep
//#define TURBO // Comment out to disable - full output with a step down after n number of seconds
// If turbo is enabled, it will be where 255 is listed in the modes above
// If turbo is enabled, it will be where 255 is listed in the modes above
#define TURBO_TIMEOUT 5625 // How many WTD ticks before before dropping down (.016 sec each)
//#define TURBO_TIMEOUT 5625 // How many WTD ticks before before dropping down (.016 sec each)
// 90 = 5625
// 90 = 5625
// 120 = 7500
// 120 = 7500
#define ADC_LOW 130 // When do we start ramping
#define BATT_LOW 145 // When do we start ramping
#define ADC_CRIT 120 // When do we shut the light off
#define BATT_CRIT 135 // When do we shut the light off
#define ADC_DELAY 188 // Delay in ticks between low-bat rampdowns (188 ~= 3s)
#define CHARGER_HIGH 120 // When we should lower the output
#define CHARGER_LOW 100 // When we should raise the output
#define BATT_ADC_DELAY 188 // Delay in ticks between low-bat rampdowns (188 ~= 3s)
#define CHARGER_ADC_DELAY 15 // Delay in ticks before checking for charging cable (188 ~= 3s)


//#define MOM_ENTER_DUR 128 // .16ms each. Comment out to disable this feature
//#define MOM_ENTER_DUR 128 // 16ms each. Comment out to disable this feature
#define MOM_EXIT_DUR 128 // .16ms each
//#define MOM_EXIT_DUR 128 // 16ms each


#define MOM_MODE_IDX 4 // The index of the mode to use in MODES above if momementary feature enabled, starting at index of 0
//#define MOM_MODE_IDX 4 // The index of the mode to use in MODES above, starting at index of 0


/*
/*
* =========================================================================
* =========================================================================
*/
*/


#include <avr/pgmspace.h>
#include <avr/pgmspace.h>
#include <avr/io.h>
#include <avr/io.h>
#include <util/delay.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <avr/wdt.h>
#include <avr/eeprom.h>
#include <avr/eeprom.h>
#include <avr/sleep.h>
#include <avr/sleep.h>
//#include <avr/power.h>
//#include <avr/power.h>


#define STAR3_PIN PB4 // If not connected, will cycle L-H. Connected, H-L
#define SWITCH_PIN PB3 // what pin the switch is connected to, which is Star 4
#define SWITCH_PIN PB3 // what pin the switch is connected to, which is Star 4
#define PWM_PIN PB1
#define PWM_PIN PB1
#define ALT_PWM_PIN PB0
#define ALT_PWM_PIN PB0
#define VOLTAGE_PIN PB2
#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2
#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2
#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2
#define ADC_PRSCL 0x06 // clk/64
#define ADC_PRSCL 0x06 // clk/64


#define PWM_LVL OCR0B // OCR0B is the output compare register for PB1
#define PWM_LVL OCR0B // OCR0B is the output compare register for PB1
#define ALT_PWM_LVL OCR0A // OCR0A is the output compare register for PB0
#define ALT_PWM_LVL OCR0A // OCR0A is the output compare register for PB0


//#define DEBOUNCE_BOTH // Comment out if you don't want to debounce the PRESS along with the RELEASE
//#define DEBOUNCE_BOTH // Comment out if you don't want to debounce the PRESS along with the RELEASE
// PRESS debounce is only needed in special cases where the switch can experience errant signals
// PRESS debounce is only needed in special cases where the switch can experience errant signals
#define DB_PRES_DUR 0b00000001 // time before we consider the switch pressed (after first realizing it was pressed)
#define DB_PRES_DUR 0b00000001 // time before we consider the switch pressed (after first realizing it was pressed)
#define DB_REL_DUR 0b00001111 // time before we consider the switch released
#define DB_REL_DUR 0b00001111 // time before we consider the switch released
// each bit of 1 from the right equals 16ms, so 0x0f = 64ms
// each bit of 1 from the right equals 16ms, so 0x0f = 64ms


// Switch handling
// Switch handling
#define LONG_PRESS_DUR 32 // How many WDT ticks until we consider a press a long press
#define LONG_PRESS_DUR 32 // How many WDT ticks until we consider a press a long press
// 32 is roughly .5 s
// 32 is roughly .5 s
#define BEACON
#define BEACON_DUR 70 // How many WDT ticks until we enter the hold-to-BEACON mode


/*
/*
* The actual program
* The actual program
* =========================================================================
* =========================================================================
*/
*/


/*
/*
* global variables
* global variables
*/
*/
const uint8_t modes[] = { MODES };
const uint8_t modes[] = { MODES };
#ifdef ALT_MODES
#ifdef ALT_MODES
const uint8_t alt_modes[] = { ALT_MODES };
const uint8_t alt_modes[] = { ALT_MODES };
#endif
#endif
const uint8_t mode_pwm[] = { MODE_PWM };
const uint8_t mode_pwm[] = { MODE_PWM };
volatile uint8_t mode_idx = 0;
volatile uint8_t mode_idx = 0;
volatile uint8_t press_duration = 0;
volatile uint8_t press_duration = 0;
volatile uint8_t low_to_high = 0;
volatile uint8_t in_momentary = 0;
volatile uint8_t in_momentary = 0;
#ifdef VOLTAGE_MON
volatile uint8_t adc_channel = 1; // MUX 01 corresponds with PB2, 02 for PB4. Will switch back and forth
#else
volatile uint8_t adc_channel = 2; // MUX 01 corresponds with PB2, 02 for PB4. Will switch back and forth
#endif


// Debounce switch press value
// Debounce switch press value
#ifdef DEBOUNCE_BOTH
#ifdef DEBOUNCE_BOTH
int is_pressed()
int is_pressed()
{
{
static uint8_t pressed = 0;
static uint8_t pressed = 0;
// Keep track of last switch values polled
// Keep track of last switch values polled
static uint8_t buffer = 0x00;
static uint8_t buffer = 0x00;
// Shift over and tack on the latest value, 0 being low for pressed, 1 for pulled-up for released
// Shift over and tack on the latest value, 0 being low for pressed, 1 for pulled-up for released
buffer = (buffer << 1) | ((PINB & (1 << SWITCH_PIN)) == 0);
buffer = (buffer << 1) | ((PINB & (1 << SWITCH_PIN)) == 0);
if (pressed) {
if (pressed) {
// Need to look for a release indicator by seeing if the last switch status has been 0 for n number of polls
// Need to look for a release indicator by seeing if the last switch status has been 0 for n number of polls
pressed = (buffer & DB_REL_DUR);
pressed = (buffer & DB_REL_DUR);
} else {
} else {
// Need to look for pressed indicator by seeing if the last switch status was 1 for n number of polls
// Need to look for pressed indicator by seeing if the last switch status was 1 for n number of polls
pressed = ((buffer & DB_PRES_DUR) == DB_PRES_DUR);
pressed = ((buffer & DB_PRES_DUR) == DB_PRES_DUR);
}
}


return pressed;
return pressed;
}
}
#else
#else
int is_pressed()
int is_pressed()
{
{
// Keep track of last switch values polled
// Keep track of last switch values polled
static uint8_t buffer = 0x00;
static uint8_t buffer = 0x00;
// Shift over and tack on the latest value, 0 being low for pressed, 1 for pulled-up for released
// Shift over and tack on the latest value, 0 being low for pressed, 1 for pulled-up for released
buffer = (buffer << 1) | ((PINB & (1 << SWITCH_PIN)) == 0);
buffer = (buffer << 1) | ((PINB & (1 << SWITCH_PIN)) == 0);
return (buffer & DB_REL_DUR);
return (buffer & DB_REL_DUR);
}
}
#endif
#endif


inline void next_mode() {
void next_mode() {
if (++mode_idx >= sizeof(modes)) {
if (++mode_idx >= sizeof(modes)) {
// Wrap around
// Wrap around
mode_idx = 0;
mode_idx = 1;
}
}
}
}


inline void prev_mode() {
void prev_mode() {
if (mode_idx == 0) {
if (mode_idx == 1) {
// Wrap around
// Wrap around
mode_idx = sizeof(modes) - 1;
mode_idx = sizeof(modes) - 1;
} else {
} else {
--mode_idx;
--mode_idx;
}
}
}
}


inline void PCINT_on() {
inline void PCINT_on() {
// Enable pin change interrupts
// Enable pin change interrupts
GIMSK |= (1 << PCIE);
GIMSK |= (1 << PCIE);
}
}


inline void PCINT_off() {
inline void PCINT_off() {
// Disable pin change interrupts
// Disable pin change interrupts
GIMSK &= ~(1 << PCIE);
GIMSK &= ~(1 << PCIE);
}
}


// Need an interrupt for when pin change is enabled to ONLY wake us from sleep.
// Need an interrupt for when pin change is enabled to ONLY wake us from sleep.
// All logic of what to do when we wake up will be handled in the main loop.
// All logic of what to do when we wake up will be handled in the main loop.
EMPTY_INTERRUPT(PCINT0_vect);
EMPTY_INTERRUPT(PCINT0_vect);


inline void WDT_on() {
inline void WDT_on() {
// Setup watchdog timer to only interrupt, not reset, every 16ms.
// Setup watchdog timer to only interrupt, not reset, every 16ms.
cli(); // Disable interrupts
cli(); // Disable interrupts
wdt_reset(); // Reset the WDT
wdt_reset(); // Reset the WDT
WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
WDTCR = (1<<WDTIE); // Enable interrupt every 16ms
WDTCR = (1<<WDTIE); // Enable interrupt every 16ms
sei(); // Enable interrupts
sei(); // Enable interrupts
}
}


inline void WDT_off()
inline void WDT_off()
{
{
cli(); // Disable interrupts
cli(); // Disable interrupts
wdt_reset(); // Reset the WDT
wdt_reset(); // Reset the WDT
MCUSR &= ~(1<<WDRF); // Clear Watchdog reset flag
MCUSR &= ~(1<<WDRF); // Clear Watchdog reset flag
WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
WDTCR = 0x00; // Disable WDT
WDTCR = 0x00; // Disable WDT
sei(); // Enable interrupts
sei(); // Enable interrupts
}
}


inline void ADC_on() {
void ADC_on() {
ADMUX = (1 << REFS0) | (1 << ADLAR) | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2
ADMUX = (1 << REFS0) | (1 << ADLAR) | adc_channel; // 1.1v reference, left-adjust, ADC1/PB2 or ADC2/PB3
DIDR0 |= (1 << ADC_DIDR); // disable digital input on ADC pin to reduce power consumption
DIDR0 |= (1 << ADC_DIDR); // disable digital input on ADC pin to reduce power consumption
ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL; // enable, start, prescale
ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL; // enable, start, prescale, Single Conversion mode
}
}


inline void ADC_off() {
void ADC_off() {
ADCSRA &= ~(1<<7); //ADC off
ADCSRA &= ~(1 << ADSC); //ADC off
}
}


void sleep_until_switch_press()
void sleep_until_switch_press()
{
{
// This routine takes up a lot of program memory :(
// This routine takes up a lot of program memory :(
// Turn the WDT off so it doesn't wake us from sleep
// Turn the WDT off so it doesn't wake us from sleep
// Will also ensure interrupts are on or we will never wake up
// Will also ensure interrupts are on or we will never wake up
WDT_off();
WDT_off();
// Need to reset press duration since a button release wasn't recorded
// Need to reset press duration since a button release wasn't recorded
press_duration = 0;
press_duration = 0;
// Enable a pin change interrupt to wake us up
// 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
// However, we have to make sure the switch is released otherwise we will wake when the user releases the switch
while (is_pressed()) {
while (is_pressed()) {
_delay_ms(16);
_delay_ms(16);
}
}
PCINT_on();
PCINT_on();
// Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command.
// Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command.
//set_sleep_mode(SLEEP_MODE_PWR_DOWN);
//set_sleep_mode(SLEEP_MODE_PWR_DOWN);
// Now go to sleep
// Now go to sleep
sleep_mode();
sleep_mode();
// Hey, someone must have pressed the switch!!
// Hey, someone must have pressed the switch!!
// Disable pin change interrupt because it's only used to wake us up
// Disable pin change interrupt because it's only used to wake us up
PCINT_off();
PCINT_off();
// Turn the WDT back on to check for switch presses
// Turn the WDT back on to check for switch presses
WDT_on();
WDT_on();
// Go back to main program
// Go back to main program
}
}


// The watchdog timer is called every 16ms
// The watchdog timer is called every 16ms
ISR(WDT_vect) {
ISR(WDT_vect) {


//static uint8_t press_duration = 0; // Pressed or not pressed
//static uint8_t press_duration = 0; // Pressed or not pressed
static uint16_t turbo_ticks = 0;
static uint16_t turbo_ticks = 0;
static uint8_t adc_ticks = ADC_DELAY;
static uint16_t batt_adc_ticks = BATT_ADC_DELAY;
static uint16_t charger_adc_ticks = CHARGER_ADC_DELAY;
static uint8_t lowbatt_cnt = 0;
static uint8_t lowbatt_cnt = 0;
static uint8_t high_charger_cnt = 0;
static uint8_t low_charger_cnt = 0;
static uint8_t highest_mode_idx = 255;


if (is_pressed()) {
if (is_pressed()) {
if (press_duration < 255) {
if (press_duration < 255) {
press_duration++;
press_duration++;
}
}
#ifdef MOM_ENTER_DUR
#ifdef MOM_ENTER_DUR
if (in_momentary) {
if (in_momentary) {
// Turn on full output
// Turn on full output
mode_idx = MOM_MODE_IDX;
mode_idx = MOM_MODE_IDX;
if (press_duration == MOM_EXIT_DUR) {
if (press_duration == MOM_EXIT_DUR) {
// Turn light off and disable momentary
// Turn light off and disable momentary
mode_idx = 0;
mode_idx = 0;
in_momentary = 0;
in_momentary = 0;
}
}
return;
return;
}
}
#endif
#endif


if (press_duration == LONG_PRESS_DUR) {
if (press_duration == LONG_PRESS_DUR) {
// Long press
// Long press
if (low_to_high) {
prev_mode();
prev_mode();
} else {
highest_mode_idx = mode_idx;
next_mode();
}
}
}
#ifdef BEACON //Is BEACON turned on
if (press_duration == BEACON_DUR) {
PWM_LVL = 0;
while(is_pressed()){
//Exit loop once switch is let go
PWM_LVL = 255;
_delay_ms(500);
PWM_LVL=0;
_delay_ms(5000);
//Can alter values to change BEACON duration
}
}
#endif
#ifdef MOM_ENTER_DUR
#ifdef MOM_ENTER_DUR
if (press_duration == MOM_ENTER_DUR) {
if (press_duration == MOM_ENTER_DUR) {
in_momentary = 1;
in_momentary = 1;
press_duration = 0;
press_duration = 0;
}
}
#endif
#endif
// Just always reset turbo timer whenever the button is pressed
// Just always reset turbo timer whenever the button is pressed
turbo_ticks = 0;
turbo_ticks = 0;
// Same with the ramp down delay
// Same with the ramp down delay
adc_ticks = ADC_DELAY;
batt_adc_ticks = BATT_ADC_DELAY;
charger_adc_ticks = CHARGER_ADC_DELAY;
} else {
} else {
#ifdef MOM_ENTER_DUR
#ifdef MOM_ENTER_DUR
if (in_momentary) {
if (in_momentary) {
// Turn off the light
// Turn off the light
mode_idx = 0;
mode_idx = 0;
return;
return;
}
}
#endif
#endif
// Not pressed
// Not pressed
if (press_duration > 0 && press_duration < LONG_PRESS_DUR) {
if (press_duration > 0 && press_duration < LONG_PRESS_DUR) {
// Short press
// Short press
if (low_to_high) {
next_mode();
next_mode();
} else {
highest_mode_idx = mode_idx;
prev_mode();
}
} else {
} else {
// Only do turbo check when switch isn't pressed
// Only do turbo check when switch isn't pressed
#ifdef TURBO
#ifdef TURBO
if (modes[mode_idx] == 255) {
if (modes[mode_idx] == 255) {
turbo_ticks++;
turbo_ticks++;
if (turbo_ticks > TURBO_TIMEOUT) {
if (turbo_ticks > TURBO_TIMEOUT) {
// Go to the previous mode
// Go to the previous mode
prev_mode();
prev_mode();
}
}
}
}
#endif
#endif
// Only do voltage monitoring when the switch isn't pressed
// Only do voltage monitoring when the switch isn't pressed
#ifdef VOLTAGE_MON
// See if conversion is done. We moved this up here because we want to stay on
if (adc_ticks > 0) {
// the current ADC input until the conversion is done, and then switch to the new
--adc_ticks;
// input, start the monitoring
if (batt_adc_ticks > 0) {
--batt_adc_ticks;
}
}
if (adc_ticks == 0) {
if (charger_adc_ticks > 0) {
// See if conversion is done
--charger_adc_ticks;
if (ADCSRA & (1 << ADIF)) {
}
// See if voltage is lower than what we were looking for
if (ADCSRA & (1 << ADIF)) {
if (ADCH < ((mode_idx == 1) ? ADC_CRIT : ADC_LOW)) {
if (adc_channel == 0x01) {
++lowbatt_cnt;
} else {
if (batt_adc_ticks == 0) {
lowbatt_cnt = 0;
// See if voltage is lower than what we were looking for
if (ADCH < ((mode_idx == 1) ? BATT_CRIT : BATT_LOW)) {
++lowbatt_cnt;
} else {
lowbatt_cnt = 0;
}
// See if it's been low for a while
if (lowbatt_cnt >= 4) {
prev_mode();
highest_mode_idx = mode_idx;
lowbatt_cnt = 0;
// If we reach 0 here, main loop will go into sleep mode
// Restart the counter to when we step down again
batt_adc_ticks = BATT_ADC_DELAY;
charger_adc_ticks = CHARGER_ADC_DELAY;
}
}
}
}
// Switch ADC to temp monitoring
adc_channel = 0x02;
ADMUX = ((ADMUX & 0b11111100) | adc_channel);
} else if (adc_channel == 0x02) {
if (charger_adc_ticks == 0) {
// See if temp is higher than the high threshold
if (ADCH > ((mode_idx == 1) ? 255 : CHARGER_HIGH)) {
++high_charger_cnt;
// See if it's lower that the low threshold, but not at or above the batt-adjusted mode
} else {
high_charger_cnt = 0;
low_charger_cnt = 0;
}
// See if it's been low for a while
// See if it's been low for a while
if (lowbatt_cnt >= 4) {
if (high_charger_cnt >= 1) {
prev_mode();
// TODO - step down half
lowbatt_cnt = 0;
mode_idx = 0;
// If we reach 0 here, main loop will go into sleep mode
high_charger_cnt = 0;
// Restart the counter to when we step down again
low_charger_cnt = 0;
adc_ticks = ADC_DELAY;
// If we reach 0 here, main loop will go into sleep mode
// Restart the counter to when we step down again
charger_adc_ticks = CHARGER_ADC_DELAY;
} else {
// TODO - step up half
mode_idx;
high_charger_cnt = 0;
low_charger_cnt = 0;
// TODO - CHARGER_ADC_DELAY?? Might jump up and cause it to overheat waiting too long
charger_adc_ticks = CHARGER_ADC_DELAY;
}
}
#ifdef VOLTAGE_MON
// Switch ADC to battery monitoring
adc_channel = 0x01;
ADMUX = ((ADMUX & 0b11111100) | adc_channel);
#endif;
}
}
// Make sure conversion is running for next time through
ADCSRA |= (1 << ADSC);
}
}
#endif
// Start conversion for next time through
ADCSRA |= (1 << ADSC);
}
}
press_duration = 0;
press_duration = 0;
}
}
}
}


int main(void)
int main(void)
{
{
// Set all ports to input, and turn pull-up resistors on for the inputs we are using
// Set all ports to input, and turn pull-up resistors on for the inputs we are using
DDRB = 0x00;
DDRB = 0x00;
PORTB = (1 << SWITCH_PIN) | (1 << STAR3_PIN);
PORTB = (1 << SWITCH_PIN);


// Set the switch as an interrupt for when we turn pin change interrupts on
// Set the switch as an interrupt for when we turn pin change interrupts on
PCMSK = (1 << SWITCH_PIN);
PCMSK = (1 << SWITCH_PIN);
// Set PWM pin to output
// Set PWM pin to output
#ifdef ALT_MODES
#ifdef ALT_MODES
DDRB = (1 << PWM_PIN) | (1 << ALT_PWM_PIN);
DDRB = (1 << PWM_PIN) | (1 << ALT_PWM_PIN);
#else
#else
DDRB = (1 << PWM_PIN);
DDRB = (1 << PWM_PIN);
#endif
#endif


// Set timer to do PWM for correct output pin and set prescaler timing
// 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
//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...)
TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
// Turn features on or off as needed
// Turn features on or off as needed
#ifdef VOLTAGE_MON
ADC_on();
ADC_on();
#else
ADC_off();
#endif
ACSR |= (1<<7); //AC off
ACSR |= (1<<7); //AC off
// Determine if we are going L-H, or H-L based on Star 3
if ((PINB & (1 << STAR3_PIN)) == 0) {
// High to Low
low_to_high = 0;
} else {
low_to_high = 1;
}
// Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command.
// Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command.
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_until_switch_press();
sleep_until_switch_press();
uint8_t last_mode_idx = 0;
uint8_t last_mode_idx = 0;
while(1) {
while(1) {
// We will never leave this loop. The WDT will interrupt to check for switch presses and
// 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
// 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.
// logic for that mode while continuing to check for a mode change.
if (mode_idx != last_mode_idx) {
if (mode_idx != last_mode_idx) {
// The WDT changed the mode.
// The WDT changed the mode.
if (mode_idx > 0) {
if (mode_idx > 0) {
// No need to change the mode if we are just turning the light off
// No need to change the mode if we are just turning the light off
// Check if the PWM mode is different
// Check if the PWM mode is different
if (mode_pwm[last_mode_idx] != mode_pwm[mode_idx]) {
if (mode_pwm[last_mode_idx] != mode_pwm[mode_idx]) {
#ifdef ALT_MODES
#ifdef ALT_MODES
TCCR0A = mode_pwm[mode_idx] | 0b10100000; // Use both outputs
TCCR0A = mode_pwm[mode_idx] | 0b10100000; // Use both outputs
#else
#else
TCCR0A = mode_pwm[mode_idx] | 0b00100000; // Only use the normal output
TCCR0A = mode_pwm[mode_idx] | 0b00100000; // Only use the normal output
#endif
#endif
}
}
}
}
PWM_LVL = modes[mode_idx];
PWM_LVL = modes[mode_idx];
#ifdef ALT_MODES
#ifdef ALT_MODES
ALT_PWM_LVL = alt_modes[mode_idx];
ALT_PWM_LVL = alt_modes[mode_idx];
#endif
#endif
last_mode_idx = mode_idx;
last_mode_idx = mode_idx;
if (mode_pwm[mode_idx] == 0) {
if (mode_pwm[mode_idx] == 0) {
_delay_ms(1); // Need this here, maybe instructions for PWM output not getting executed before shutdown?
_delay_ms(1); // Need this here, maybe instructions for PWM output not getting executed before shutdown?
// Go to sleep
// Go to sleep
sleep_until_switch_press();
sleep_until_switch_press();
}
}
}
}
}
}


return 0; // Standard Return Code
return 0; // Standard Return Code
}
}