3 #include <avr/interrupt.h>
6 // ------------- main settings ------------------
8 // #define UART 1 // for debugging, if defined, beep() deactivated
10 #define LED_BEEPER PB1
12 #define BUTTON_LEFT PB2
13 #define BUTTON_RIGHT PB4
15 #define BRIGHT_MAX 100
16 #define BRIGHT_DEF 1 // can't be > BRIGHT_MAX
18 #define BEFORE_SLEEP 300 // sec before sleep
20 // ---------------------------------------------
22 #define ADC_SAMPLE_LEN 20 // must be > ADC_SAMPLE_DROP * 3
23 #define ADC_SAMPLE_DROP 5
25 #define BAT_15MIN 302 // ADC value, ~15 min left
26 #define BAT_10MIN 301 // ..
27 #define BAT_5MIN 300 // ..
29 #define ON 0 // switchState
33 // ---------------------------------------------
38 // Some macros that make the code more readable
40 #define output_low(port,pin) port &= ~(1<<pin)
41 #define output_high(port,pin) port |= (1<<pin)
42 #define set_input(portdir,pin) portdir &= ~(1<<pin)
43 #define set_output(portdir,pin) portdir |= (1<<pin)
45 #define invert(port,pin) port ^= (1<<pin)
47 #define KEYBOARD_READ() ( 0b00010100 ^ (PINB & 0b00010100) )
49 #define LEFT 0b00010000
50 #define RIGHT 0b00000100
54 #define INT_DISABLE_BEEPER ({ TIMSK &= ~(1<<TOIE1); }) // interrupt off
55 #define INT_ENABLE_BEEPER ({ TIMSK |= (1<<TOIE1); }) // interrupt on
58 #define BEEP_LEN 240 // cycles (32kHz / TIMER1_DIV)
60 // -------------- simple UART TX ------------
64 #define PRINT_BUFF_LEN 16
66 uint8_t print_buff[ PRINT_BUFF_LEN ];
68 void put_char( uint8_t c ){
71 output_low( PORTB, LED_BEEPER );
72 for( uint8_t i = 10; i; i-- ){ // 10 bits
74 // _delay_us( 1e6 / BAUD ); // bit duration / (16MHz, 9600, 104 us)
86 if( c & 1 ) output_low( PORTB, LED_BEEPER ); else output_high( PORTB, LED_BEEPER ); // data bit 0 / data bit 1 or stop bit
94 while (*s) put_char(*s++);
97 void put_num( uint16_t num, uint8_t ret ){
98 itoa( num, (char *)print_buff, 10 );
99 put_str((char *)print_buff);
100 if ( ret ) put_str( "\n" ); else put_str( " " );
105 // -------------- EEPROM ---------------------
107 unsigned char EEPROM_read(unsigned char ucAddress)
109 while (EECR & (1<<EEPE)); //wait for completion of previous write
110 EEAR = ucAddress; //set up address register
111 EECR |= (1<<EERE); //start eeprom read by writing EERE
112 return EEDR; //return data from data register
115 void EEPROM_write(unsigned char ucAddress, unsigned char ucData)
117 while (EECR & (1<<EEPE)); //wait for completion of previous write
118 EECR = (0<<EEPM1)|(0<<EEPM0); //set programming mode
119 EEAR = ucAddress; //set up address register
120 EEDR = ucData; //set up data register
121 EECR |= (1<<EEMPE); //write lgical one to EMPE
122 EECR |= (1<<EEPE); //start eeprom write by setting EEPE
125 // uint8_t EEMEM memoBrightness = 0xff;
128 // -------------- beeper ---------------------
130 static volatile uint32_t beeper_mask;
131 static volatile uint8_t beeper_div;
133 ISR ( TIMER1_OVF_vect ) {
135 static uint16_t beeper_cnt;
137 // TCNT1 = 255; // 208kHz
138 // TCNT1 = 128; // 53kHz
139 // TCNT1 = 64; // 37kHz // 64
140 TCNT1 = 32; // 32kHz // 64
141 // TCNT1 = 1; // 29kHz // 64
143 if ( beeper_div++ % TIMER1_DIV == 0 ){
145 if( beeper_cnt++ < BEEP_LEN ){
146 if(beeper_mask & 1) invert(PORTB, LED_BEEPER);
151 if(beeper_mask == 0){
153 PRR |= (1<<PRTIM1); // power off Timer 1
159 void beep(uint32_t mask){
167 PRR &= ~(1<<PRTIM1); // power on Timer 1
168 // TCCR1 = 0; // Normal counter operation
169 TCCR1 = 0b0001; // PRESCALER(TIMER1_PRESCALER) // has no effect IMHO (PLL mode?)
170 TCNT1 = 0xFF; // Start terminal count at 0xFF
171 INT_ENABLE_BEEPER; // Enable Overflow interrupts for Timer 0
176 // -------------- delay ---------------------
178 void my_delay(){ // 50 ms
194 // --------------- ADC ----------------------
198 DIDR0 |= (1<<ADC3D); // disable digital inputs to reduce power consumption in the digital input buffer
199 PRR &= ~(1<<PRADC); // power on ADC
200 // ADMUX = (1<<REFS1) | (1<<REFS0); // AREF = 2.56v
201 ADMUX = (1<<REFS1); // AREF = 1.1v
203 ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // ADC Enable and prescaler of 128, // 16000000/128 = 125000
206 uint16_t adc_read() {
208 PRR &= ~(1<<PRADC); // power on ADC
209 ADMUX |= (1<<REFS1) | (1 << MUX1) | (1 << MUX0); // ADC3 activated / read ADCH
210 ADCSRA |= (1<<ADSC); // start single convertion
211 while(ADCSRA & (1<<ADSC)); // wait for conversion to complete
212 PRR |= (1<<PRADC); // power off ADC
216 // ------------ median value ----------------
218 uint16_t median( uint16_t * list, uint8_t n, uint8_t drop ){
223 for (c = 0 ; c < n - 1; c++) {
224 for (d = 0 ; d < n - c - 1; d++) {
225 if (list[d] > list[d+1]) {
235 for (c = drop ; c < n-drop ; c++) t += list[ c ];
237 return t/(n - drop*2);
240 // ------------------------------------------
241 // -------------- main ----------------------
242 // ------------------------------------------
246 uint8_t keyBlock = 0, keyMask = 0, prevKeyMask = 0, keyCnt = 0;
247 uint8_t brightness = 0, targBrightness = 0, targBrightnessOnSleep = 0;
248 uint8_t battStage = 0, switchState = ON;
249 uint16_t adc[ ADC_SAMPLE_LEN ];
250 uint16_t ADCVal = 0xffff, secCnt = 0, seconds = 0, sleepCnt = 0;
252 // if (MCUSR != 0) tMCUSRStored = MCUSR; else tMCUSRStored = GPIOR0; // MCU Reset Status Register
258 set_output(DDRB, LED_BEEPER);
259 set_input(DDRB, BUTTON_LEFT);
260 set_input(DDRB, BUTTON_RIGHT);
262 output_high(PORTB, BUTTON_LEFT); // pull-up
263 output_high(PORTB, BUTTON_RIGHT); // pull-up
265 set_output(DDRB, MAIN_LED);
272 MCU Reset Status Register
274 if ( tMCUSRStored == 0 ) beep( 0b10101 ); else {
275 for (uint8_t a = 0; a < 6; a++ ) {
278 while (keyBlock-- > 0) my_delay();
287 TCCR0A = 2<<COM0A0 | 1<<WGM00 | 1<<WGM01 ;
288 TCCR0B = 0<<WGM02 | 1<<CS00;
289 TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10; // page 89, TCCR1 – Timer/Counter1 Control Register
290 // GTCCR = 1<<PWM1B | 2<<COM1B0;
292 // set default brightness
294 targBrightness = EEPROM_read( 0x01 );
295 if ( targBrightness == 0xff || targBrightness > BRIGHT_MAX ) targBrightness = BRIGHT_DEF;
300 put_str("hello...\n");
309 if ( secCnt++ == 20 ){
313 adc[ seconds % ADC_SAMPLE_LEN ] = adc_read();
315 if ( seconds % ADC_SAMPLE_LEN == 0 && seconds > ADC_SAMPLE_LEN ){
317 ADCVal = median( adc, ADC_SAMPLE_LEN, ADC_SAMPLE_DROP );
319 if ( ADCVal <= BAT_15MIN && battStage == 0 ) battStage = 1;
320 if ( ADCVal <= BAT_10MIN && battStage == 1 ) battStage = 2;
321 if ( ADCVal <= BAT_10MIN && battStage == 2 ) battStage = 3;
323 if ( battStage == 1 ) beep(0b101);
324 if ( battStage == 2 ) beep(0b10101);
325 if ( battStage == 3 ) {
331 put_num( ADCVal, true );
341 if ( sleepCnt > BEFORE_SLEEP && switchState == ON ){
342 targBrightnessOnSleep = brightness;
348 // keyboard interface
350 if ( keyBlock > 0 ) {
354 keyMask = KEYBOARD_READ();
356 if ( switchState == ON ){
358 if ( prevKeyMask != keyMask ) keyCnt = 0; else keyCnt ++;
359 prevKeyMask = keyMask;
363 if ( keyMask == LEFT ) { if ( targBrightness < BRIGHT_MAX ) targBrightness ++; else { beep(0b1); keyBlock = 10; } }
364 if ( keyMask == RIGHT && targBrightness > 0 ) targBrightness --;
366 if ( keyMask == ( LEFT | RIGHT ) ) {
367 EEPROM_write( 0x01, brightness );
374 if ( keyMask != 0 ) {
376 if ( switchState == OFF ) {
381 if ( switchState == SLEEP ){
385 targBrightness = targBrightnessOnSleep;
391 if ( brightness < targBrightness ) brightness ++;
392 if ( brightness > targBrightness) brightness --;