1
/* Simple sample firmware for otc less design (single cell).
3
Half press less than about 300 ms: next mode
4
between 300 and 900 ms: previous mode
5
longer: blink out voltage reading
6
(0 to 255) in 3 decimals
8
Suggested capacity of buffer cap (C2): >= 47 uF.
9
Vbatt is connected to PB3 (Pin2).
10
Voltage divider still connected to Pin7.
11
Timing specified for Attiny25 at 10 Mhz.
13
Created and built with Atmel Studio.
14
Fuses for Attiny25: lfuse: 0xD2, hfuse: 0xDF.
17
#include <avr/interrupt.h>
18
#include <avr/sleep.h>
23
#define PIN_POWER_DETECT PB3
24
#define INT_POWER_DETECT PCINT3
26
#define VLT_CHANNEL 0x01
27
#define VLT_DIDR ADC1D
28
#define ADC_VREF ((1 << REFS1) | (1 << REFS2)) // 2.56V
29
#define ADC_PRESCL 0x06
31
#define PWM_PHASE 0xA1
32
#define PWM_7135 OCR0A
36
#define PWM_LEVELS_7135 30, 80, 255, 255, 255, 0
37
#define PWM_LEVELS_FET 0, 0, 0, 30, 80, 255
39
// forward declarations
40
uint8_t adc_init_and_read();
42
void blink_once_long();
43
void blink_value(uint8_t value);
44
void delay_250_micro_sec(uint8_t n);
45
void delay_50_milli_sec(uint8_t n);
50
volatile uint8_t s_clicked = 0;
51
const uint8_t pwm_levels_7135[] = { PWM_LEVELS_7135 };
52
const uint8_t pwm_levels_fet[] = { PWM_LEVELS_FET };
53
uint8_t mode_index = 0;
55
////////////////////////////////////////////////////////////////////////////////
59
uint8_t blink_voltage = 0;
62
// set LED ports as output
63
DDRB = (1 << PIN_7135) | (1 << PIN_FET);
69
// enable pin change interrupts
70
PCMSK = (1 << INT_POWER_DETECT);
74
// start with first mode
75
PWM_7135 = pwm_levels_7135[mode_index];
76
PWM_FET = pwm_levels_fet[mode_index];
82
if ( s_clicked <= 10 ) // < about 300 ms
86
if ( mode_index >= MODE_COUNT )
89
else if ( s_clicked <= 30 ) // < about 900 ms
93
if ( mode_index == 255 )
94
mode_index = MODE_COUNT - 1;
96
else // > about 900 ms
103
PWM_7135 = pwm_levels_7135[mode_index];
104
PWM_FET = pwm_levels_fet[mode_index];
107
voltage = adc_init_and_read();
110
blink_value(voltage);
116
////////////////////////////////////////////////////////////////////////////////
123
// turn off PWM generation (might not be necessary)
128
ADCSRA &= ~(1 << ADEN);
130
// disable pin change interrupt
131
GIMSK &= ~(1 << PCIE);
135
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
142
WDTCR = (1<<WDIE) | WDTO_30MS;
148
} while ( (PINB & (1 << PIN_POWER_DETECT)) == 0 );
153
delay_250_micro_sec(10);
155
// activate pwm generation
159
// enable pin change interrupts
160
PCMSK = (1 << INT_POWER_DETECT);
161
GIMSK |= (1 << PCIE);
164
////////////////////////////////////////////////////////////////////////////////
166
void delay_250_micro_sec(uint8_t n)
179
////////////////////////////////////////////////////////////////////////////////
181
void delay_50_milli_sec(uint8_t n)
185
delay_250_micro_sec(200);
191
////////////////////////////////////////////////////////////////////////////////
195
delay_50_milli_sec(20);
198
////////////////////////////////////////////////////////////////////////////////
202
PWM_7135 = pwm_levels_7135[mode_index];
203
PWM_FET = pwm_levels_fet[mode_index];
206
////////////////////////////////////////////////////////////////////////////////
214
////////////////////////////////////////////////////////////////////////////////
219
delay_50_milli_sec(5);
221
delay_50_milli_sec(5);
224
////////////////////////////////////////////////////////////////////////////////
226
void blink_once_long()
234
////////////////////////////////////////////////////////////////////////////////
236
void blink_once_short()
239
delay_50_milli_sec(1);
241
delay_50_milli_sec(5);
244
////////////////////////////////////////////////////////////////////////////////
246
void blink_value(uint8_t value)
252
while ( value >= 100 )
263
while ( value >= 10 )
282
////////////////////////////////////////////////////////////////////////////////
288
while (ADCSRA & (1 << ADSC))
294
ADCSRA |= (1 << ADSC);
298
////////////////////////////////////////////////////////////////////////////////
300
uint8_t adc_init_and_read()
302
DIDR0 |= (1 << VLT_DIDR);
303
ADMUX = ADC_VREF | (1 << ADLAR) | VLT_CHANNEL;
304
ADCSRA = (1 << ADEN) | (1 << ADSC) | ADC_PRESCL;
305
adc_read(); // first run not reliable (see spec)
309
////////////////////////////////////////////////////////////////////////////////
310
// empty interrupt function required otherwise mcu will reset
316
////////////////////////////////////////////////////////////////////////////////