5
* Star 4 -| |- Voltage ADC
10
* CPU speed is 4.8Mhz without the 8x divider when low fuse is 0x75
12
* define F_CPU 4800000 CPU: 4.8MHz PWM: 9.4kHz ####### use low fuse: 0x75 #######
13
* /8 PWM: 1.176kHz ####### use low fuse: 0x65 #######
14
* define F_CPU 9600000 CPU: 9.6MHz PWM: 19kHz ####### use low fuse: 0x7a #######
15
* /8 PWM: 2.4kHz ####### use low fuse: 0x6a #######
17
* !!Above PWM speeds are for phase-correct PWM. This program uses Fast-PWM, which when the CPU is 4.8MHz will be 18.75 kHz
20
* I use these fuse settings
25
* Star 2 = Moon if connected //changed moon is now standard if not soldered
26
* Star 3 = H-L if connected, L-H if not //changed H-L is now standard...more POWER!!!
27
* Star 4 = Capacitor for off-time PB3 is leg #2
30
* Resistor values for voltage divider (reference BLF-VLD README for more info)
31
* Reference voltage can be anywhere from 1.0 to 1.2, so this cannot be all that accurate
35
* Vd (~.25 v drop from protection diode)
37
* 1912 (R1 19,100 ohms)
41
* 4701 (R2 4,700 ohms)
45
* ADC = ((V_bat - V_diode) * R2 * 255) / ((R1 + R2 ) * V_ref)
46
* 125 = ((3.0 - .25 ) * 4700 * 255) / ((19100 + 4700) * 1.1 )
47
* 121 = ((2.9 - .25 ) * 4700 * 255) / ((19100 + 4700) * 1.1 )
49
* Well 125 and 121 were too close, so it shut off right after lowering to low mode, so I went with
52
* To find out what value to use, plug in the target voltage (V) to this equation
53
* value = (V * 4700 * 255) / (23800 * 1.1)
63
#define F_CPU 4800000UL
65
//#define F_CPU 9600000
70
* =========================================================================
71
* Settings to modify per driver
74
#define VOLTAGE_MON // Comment out to disable
76
#define MEMORY // Comment out to disable
78
// Levels should start around 10 with Fast PWM
80
#define MODE_MOON 10 // Can comment out to remove mode, but should be set through soldering stars
81
#define MODE_LOW 65//35 // Can comment out to remove mode
82
//#define MODE_MED 130 // Can comment out to remove mode
83
#define MODE_HIGH_W_TURBO 150 // MODE_HIGH value when turbo is enabled
84
#define MODE_HIGH 255 // Can comment out to remove mode
85
#define MODE_TURBO 255 // Can comment out to remove mode
86
#define TURBO_TIMEOUT 180 // How many WTD ticks before before dropping down (.5 sec each)
88
#define ADC_LOW 130 // When do we start ramping
89
#define ADC_CRIT 124 // When do we shut the light off
91
#define CAP_THRESHOLD 200 // Value between 1 and 255 corresponding with cap voltage (0 - 1.1v) where we consider it a short press to move to the next mode
92
// Not sure the lowest you can go before getting bad readings, but with a value of 70 and a 1uF cap, it seemed to switch sometimes
93
// even when waiting 10 seconds between presses.
96
* =========================================================================
101
#define MODE_HIGH MODE_HIGH_W_TURBO
104
//#include <avr/pgmspace.h>
106
#include <util/delay.h>
107
#include <avr/interrupt.h>
109
#include <avr/eeprom.h>
110
#include <avr/sleep.h>
111
//#include <avr/power.h>
113
#define STAR2_PIN PB0
114
#define STAR3_PIN PB4
116
#define CAP_CHANNEL 0x03 // MUX 03 corresponds with PB3 (Star 4)
117
#define CAP_DIDR ADC3D // Digital input disable bit corresponding with PB3
119
#define VOLTAGE_PIN PB2
120
#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2
121
#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2
122
#define ADC_PRSCL 0x06 // clk/64
124
#define PWM_LVL OCR0B // OCR0B is the output compare register for PB1
135
// Modes (gets set when the light starts up based on stars)
136
static uint8_t modes[10]; // Don't need 10, but keeping it high enough to handle all
137
volatile uint8_t mode_idx = 0;
138
int mode_dir = 0; // 1 or -1. Determined when checking stars. Do we increase or decrease the idx when moving up to a higher mode.
139
uint8_t mode_cnt = 0;
141
uint8_t lowbatt_cnt = 0;
143
void store_mode_idx(uint8_t lvl) { //central method for writing (with wear leveling)
144
uint8_t oldpos=eepos;
145
eepos=(eepos+1)&31; //wear leveling, use next cell
146
// Write the current mode
147
EEARL=eepos; EEDR=lvl; EECR=32+4; EECR=32+4+2; //WRITE //32:write only (no erase) 4:enable 2:go
148
while(EECR & 2); //wait for completion
149
// Erase the last mode
150
EEARL=oldpos; EECR=16+4; EECR=16+4+2; //ERASE //16:erase only (no write) 4:enable 2:go
152
inline void read_mode_idx() {
153
eeprom_read_block(&eep, 0, 32);
154
while((eep[eepos] == 0xff) && (eepos < 32)) eepos++;
155
if (eepos < 32) mode_idx = eep[eepos];//&0x10; What the?
159
inline void next_mode() {
160
if (mode_idx == 0 && mode_dir == -1) {
162
mode_idx = mode_cnt - 1;
164
mode_idx += mode_dir;
165
if (mode_idx > (mode_cnt - 1)) {
172
inline void check_stars() {
173
// Load up the modes based on stars
174
// Always load up the modes array in order of lowest to highest mode
175
// 0 being low for soldered, 1 for pulled-up for not soldered
178
if ((PINB & (1 << STAR2_PIN)) == 1) { //changed MOON is standard
179
modes[mode_cnt++] = MODE_MOON;
183
modes[mode_cnt++] = MODE_LOW;
186
modes[mode_cnt++] = MODE_MED;
189
modes[mode_cnt++] = MODE_HIGH;
192
modes[mode_cnt++] = MODE_TURBO;
194
if ((PINB & (1 << STAR3_PIN)) == 0) {
196
mode_dir = 1; //changed
198
mode_dir = -1; //changed H_L is standard now
202
inline void WDT_on() {
203
// Setup watchdog timer to only interrupt, not reset, every 500ms.
204
cli(); // Disable interrupts
205
wdt_reset(); // Reset the WDT
206
WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
207
WDTCR = (1<<WDTIE) | (1<<WDP2) | (1<<WDP0); // Enable interrupt every 500ms
208
sei(); // Enable interrupts
211
inline void WDT_off()
213
cli(); // Disable interrupts
214
wdt_reset(); // Reset the WDT
215
MCUSR &= ~(1<<WDRF); // Clear Watchdog reset flag
216
WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
217
WDTCR = 0x00; // Disable WDT
218
sei(); // Enable interrupts
221
inline void ADC_on() {
222
DIDR0 |= (1 << ADC_DIDR); // disable digital input on ADC pin to reduce power consumption
223
ADMUX = (1 << REFS0) | (1 << ADLAR) | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2
224
ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL; // enable, start, prescale
227
inline void ADC_off() {
228
ADCSRA &= ~(1<<7); //ADC off
232
uint8_t low_voltage(uint8_t voltage_val) {
234
ADCSRA |= (1 << ADSC);
235
// Wait for completion
236
while (ADCSRA & (1 << ADSC));
237
// See if voltage is lower than what we were looking for
238
if (ADCH < voltage_val) {
239
// See if it's been low for a while
240
if (++lowbatt_cnt > 8) {
252
static uint8_t ticks = 0;
253
if (ticks < 255) ticks++;
256
//if (ticks == TURBO_TIMEOUT && modes[mode_idx] == MODE_TURBO) { // Doesn't make any sense why this doesn't work
257
if (ticks == TURBO_TIMEOUT && mode_idx == (mode_cnt - 1)) {
258
// Turbo mode is always at end
259
PWM_LVL = modes[--mode_idx];
260
store_mode_idx(mode_idx);
268
// All ports default to input, but turn pull-up resistors on for the stars (not the ADC input! Made that mistake already)
269
PORTB = (1 << STAR2_PIN) | (1 << STAR3_PIN);
271
// Determine what mode we should fire up
272
// Read the last mode that was saved
275
check_stars(); // Moving down here as it might take a bit for the pull-up to turn on?
277
// Start up ADC for capacitor pin
278
DIDR0 |= (1 << CAP_DIDR); // disable digital input on ADC pin to reduce power consumption
279
ADMUX = (1 << REFS0) | (1 << ADLAR) | CAP_CHANNEL; // 1.1v reference, left-adjust, ADC3/PB3
280
ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL; // enable, start, prescale
282
// Wait for completion
283
while (ADCSRA & (1 << ADSC));
284
// Start again as datasheet says first result is unreliable
285
ADCSRA |= (1 << ADSC);
286
// Wait for completion
287
while (ADCSRA & (1 << ADSC));
288
if (ADCH > CAP_THRESHOLD) {
289
// Indicates they did a short press, go to the next mode
290
next_mode(); // Will handle wrap arounds
291
store_mode_idx(mode_idx);
293
// Didn't have a short press, keep the same mode
295
// Reset to the first mode
296
mode_idx = ((mode_dir == 1) ? 0 : (mode_cnt - 1));
297
store_mode_idx(mode_idx);
303
// Charge up the capacitor by setting CAP_PIN to output
304
DDRB |= (1 << CAP_PIN); // Output
305
PORTB |= (1 << CAP_PIN); // High
307
// Set PWM pin to output
308
DDRB |= (1 << PWM_PIN);
310
// Set timer to do PWM for correct output pin and set prescaler timing
311
TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
312
TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
314
// Turn features on or off as needed
320
ACSR |= (1<<7); //AC off
322
// Enable sleep mode set to Idle that will be triggered by the sleep_mode() command.
323
// Will allow us to go idle between WDT interrupts
324
set_sleep_mode(SLEEP_MODE_IDLE);
326
uint8_t prev_mode_idx = mode_idx;
330
// Now just fire up the mode
331
PWM_LVL = modes[mode_idx];
337
#ifdef VOLTAGE_MON ///VOLTAGE MONITOR!!!
338
if (low_voltage(ADC_LOW))
340
// We need to go to a lower level
341
if (mode_idx == 0 && PWM_LVL <= modes[mode_idx])
343
// Can't go any lower than the lowest mode
344
// Wait until we hit the critical level before flashing 10 times and turning off
345
while (!low_voltage(ADC_CRIT)); //low_voltage(x) 1 if longer low zero is normal
353
// Turn off the light
355
// Disable WDT so it doesn't wake us up
358
// Power down as many components as possible
359
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
364
// Flash 2 times before lowering
374
// Lower the mode by half, but don't go below lowest level
375
if ((PWM_LVL >> 1) < modes[0])
382
PWM_LVL = (PWM_LVL >> 1);
384
// See if we should change the current mode level if we've gone under the current mode.
385
if (PWM_LVL < modes[mode_idx])
387
// Lower our recorded mode
391
// Wait 3 seconds before lowering the level again
393
}//endiflowvoltagemon
398
return 0; // Standard Return Code