2
// LuxDrv 0.1 DrJones 2011
4
// 630 bytes (with timer)
6
// License: Free for private and noncommercial use for members of BudgetLightForum
10
// Batt-ADC (ADC1) with mode down-shifting
11
// BATT indicator using blinks in beacon-mode
13
// ? off-time checking; requires adding diode,R,C
14
// ? blink your name in morse code :)
20
#define PWM OCR0B //PWM-value
22
#define portinit() do{ DDRB=(1<<outpin); PORTB=0xff-(1<<outpin); }while(0)
26
#include <avr/pgmspace.h>
31
//########################################################################################### MODE/PWM SETUP
33
//251, 252, 253 are special mode codes handled differently, all other are PWM values
35
#define F_CPU 4800000 //CPU: 4.8MHz PWM: 9.4kHz // low fuse: 0x75 //+16bytes compared to 1.2MHz
36
PROGMEM byte modes[]={ 255, 6,51,255, 5,6,14,37,98,255, 251, 252, 253 }; // 9kHz modes, 5 is lowest
37
// dummy main modes more levels strobe,beacon,timer
40
//#define F_CPU 1200000 //CPU: 1.2MHz PWM: 2.35kHz //low fuse: 0x66
41
//PROGMEM byte modes[]={ 255, 2,51,255, 2,5,14,37,98,255, 251, 252, 253 }; //2.35kHz modes, 2 is lowest
42
//// dummy main modes more levels strobe,beacon,timer
45
//#define F_CPU 600000 //CPU: 0.6MHz PWM: 1.18kHz //low fuse: 0x65
46
//PROGMEM byte modes[]={ 255, 2,51,255, 1,5,14,37,98,255, 251, 252, 253 }; //1.18kHz modes, 1 is lowest
47
//// dummy main modes more levels strobe,beacon,timer
50
//###########################################################################################
53
#include <util/delay.h>
54
#include <avr/interrupt.h>
55
#include <avr/sleep.h>
56
#include <avr/eeprom.h>
59
#define WDTIME 0b01000011 //125ms
61
#define sleepinit() do{ WDTCR=WDTIME; sei(); MCUCR=(MCUCR &~0b00111000)|0b00100000; }while(0) //WDT-int and Idle-Sleep
63
#define pwminit() do{ TCCR0A=0b00100001; TCCR0B=0b00000001; }while(0) //chan A, phasePWM, clk/1 ->2.35kHz@1.2MHz
66
#define SLEEP asm volatile ("SLEEP")
67
#define ADCoff ADCSRA&=~(1<<7) //ADC off (enable=0);
68
#define ADCon ADCSRA|=(1<<7) //ADC on
69
#define ACoff ACSR|=(1<<7) //AC off (disable=1)
70
#define ACon ACSR&=~(1<<7) //AC on (disable=0)
73
//_____________________________________________________________________________________________________________________
76
//saving a few byte by doing that inline
77
inline void eepwrite(byte addr, byte data) { while(EECR & 2); EEARL=addr; EEDR=data; EECR =4; EECR =6; }
78
inline byte eepread(byte addr) { while(EECR & 2); EEARL=addr; EECR=1; return EEDR; }
81
volatile byte mypwm=0;
82
volatile byte ticks=0;
86
byte eep[32]; //EEPROM buffer
90
inline void getmode(void) { //read current mode from EEPROM and write next mode
92
eeprom_read_block(&eep, 0, sizeof(eep)); //+44 //read block
93
while((eep[eepos]==0) && (eepos<sizeof(eep))) eepos++; //+16 //find mode byte
94
if (eepos<sizeof(eep)) mode=eep[eepos];
95
else eepos=0; //+6 //not found
98
if (mode & 0x80) { //last on-time was short
99
mode&=0x7f; if (mode>=sizeof(modes)) mode=1;
100
next=mode+1; if (next>=sizeof(modes)) next=1;
101
} //else next=1; //previous mode was locked, this one is yet a short on, so restart from 1st mode.
102
eepwrite(eepos,next|0x80); //write next mode, with short-on marker
105
inline void savemode(void) { //lock mode: keep this mode for next time
107
eepos=(eepos+1)&31; //+12 //wear leveling, use next cell
108
eepwrite(eepos,mode);
114
ISR(WDT_vect) { //WatchDogTimer Interrupt
115
if (ticks<255) ticks++;
116
if (ticks==16) savemode(); //lock mode after 2s
130
getmode(); //get mode# to use
132
pmode=pgm_read_byte(&modes[mode]); //read actual PWM value/special code
137
case 251: mypwm=255; while(1){ PWM=mypwm; _delay_ms(20); PWM=0; _delay_ms(60); } break; //strobe 12.5Hz //+48
139
case 252: mypwm=255; while(1){ PWM=mypwm; _delay_ms(20); PWM=0; i=70;do{SLEEP;}while(--i); } break; //beacon 10s //+48
141
case 253: i=5; do{ byte j=i; do{PWM=255; _delay_ms(20); PWM=8; _delay_ms(300); }while(--j); //blink remaining minutes
142
byte k=59;do{_delay_ms(1000);PWM^=8;}while(--k); //wait 1 minute
143
}while(--i); //for 5 min
144
i=100; do{ PWM=255; _delay_ms(30); PWM=0; _delay_ms(70); }while(--i); //strobe 10s
145
while(1){PWM^=8;SLEEP;} //"off" //+136
148
default: mypwm=pmode; while(1){PWM=mypwm;SLEEP;} //all other: PWM value
150
//mypwm: prepared for being ramped down in WDT on low-batt condition.