Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Typical driver layout.
- ---
- -| |- VCC
- OTC -| |- Voltage ADC
- Star 3 -| |- PWM (FET)
- GND -| |- PWM (1x7135)
- ---
- ---
- PB5 -|1 8|- VCC
- PB3 -|2 7|- PB2
- PB4 -|3 6|- PB1
- GND -|4 5|- PB0
- ---
- */
- #if defined(__AVR_ATtiny13A__)
- # define F_CPU 4800000UL
- #else
- # define F_CPU 8000000UL
- #endif
- #define ADC_PRESCALER_MASK (~(uint8_t)((1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0)))
- /* 1/128 for 62.5 kHz operation */
- #define ADC_PRESCALER_128 ((1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0))
- /* 1/64 */
- #define ADC_PRESCALER_64 ((1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0))
- /* 1/8 */
- #define ADC_PRESCALER_8 ((0 << ADPS2) | (1 << ADPS1) | (1 << ADPS0))
- #include <avr/io.h>
- #include <avr/eeprom.h>
- #include <avr/interrupt.h>
- #include <avr/pgmspace.h>
- #include <avr/sleep.h>
- #include <util/delay.h>
- /* Fuses */
- #if defined(__AVR_ATtiny13A__)
- /*
- low fuse:
- - Enable programming & download.
- - 4 ms startup delay.
- - 4.8 MHz clock.
- high fuse:
- - Enable Brown-Out Detection at 1.8V.
- */
- FUSES =
- {
- .low = FUSE_SPIEN & FUSE_SUT1 & FUSE_CKSEL1,
- .high = FUSE_BODLEVEL0
- };
- #elif defined(__AVR_ATtiny25__)
- /*
- low fuse:
- - 4 ms startup delay.
- - 8 MHz clock
- high fuse:
- - Enable programming & download.
- - Enable Brown-Out Detection at 1.8V.
- */
- FUSES =
- {
- .low = FUSE_SUT1 & FUSE_CKSEL3 & FUSE_CKSEL2 & FUSE_CKSEL0,
- .high = FUSE_SPIEN & FUSE_BODLEVEL0,
- .extended = EFUSE_DEFAULT
- };
- #else
- #error no fuse definitions
- #endif
- /* #include "../include/cell_levels.h" */
- #ifndef __cell_levels_h
- #define __cell_levels_h
- /*
- Macros for the cell voltage readout with the ADC from a two resistor
- voltage divider. Resistor values should be specified with no more than 4
- digits to avoid overflow. So a 4.7k/19k pair can be specified as 47/190
- or as 470/1900.
- The diode drop before voltage divider should be specified in units of 10 mV.
- */
- #include <stdint.h>
- #if defined(DRIVER_BLFA6)
- /* Driver in the BLF-A6 / astrolux S1. 65B / 223 resistors -> 4.64k / 22k */
- #define VCC_DIV_R1 464ul
- #define VCC_DIV_R2 2200ul
- #define VCC_DIV_DIODE_DROP 0ul
- #elif defined(DRIVER_MTN17DDm)
- /*
- MTN-17DDm driver. Uses 4.7k / 19.1k. Has voltage divider after reverse
- polarity diode which drops about 140 mV (measured).
- */
- #define VCC_DIV_R1 470ul
- #define VCC_DIV_R2 1910ul
- #define VCC_DIV_DIODE_DROP 14ul
- #else
- /* Generic values (4.7k/19k). */
- #define VCC_DIV_R1 470ul
- #define VCC_DIV_R2 1900ul
- #define VCC_DIV_DIODE_DROP 0ul
- #endif
- /*
- 8-bit ADC value from voltage, as a 3 digit value (ie. 385 for 3.85V).
- */
- #define ADC8_FROM_CELL_V( vcc ) ((uint8_t)((uint32_t)(vcc) * VCC_DIV_R1 * 255ul / (110ul * (VCC_DIV_R1 + VCC_DIV_R2))))
- #define ADC8_CELL_DIODE_DROP ADC8_FROM_CELL_V( VCC_DIV_DIODE_DROP )
- #endif
- /* #include "../include/portability.h" */
- #ifndef __portability_h
- #define __portability_h
- /*
- I'm using macros here because even inline static functions somehow add to
- code size.
- */
- #if defined(__AVR_ATtiny13A__)
- # define watchdog_interrupt_enable() \
- do { WDTCR |= (1 << WDTIE); } while(0)
- # define watchdog_interrupt_disable() \
- do { WDTCR &= ~(1 << WDTIE); } while(0)
- #else
- # define watchdog_interrupt_enable() \
- do { WDTCR |= (1 << WDIE); } while(0)
- # define watchdog_interrupt_disable() \
- do { WDTCR &= ~(1 << WDIE); } while(0)
- #endif
- #endif
- volatile uint8_t g_have_power;
- volatile uint8_t g_wdt_count;
- volatile uint8_t g_flash_count;
- /* flash the 7135 channel to say we're running */
- static
- void flash()
- {
- PORTB |= (1 << PORTB0);
- _delay_ms( 10 );
- PORTB &= ~(1 << PORTB0);
- }
- /* Watchdog interrupt. */
- ISR( WDT_vect )
- {
- /* Count time. */
- ++g_wdt_count;
- /* If power is out, start ADC. */
- if( !g_have_power )
- {
- ADCSRA |= (1 << ADSC);
- sei();
- set_sleep_mode( SLEEP_MODE_IDLE );
- sleep_mode();
- }
- }
- /* ADC interrupt. */
- ISR( ADC_vect )
- {
- uint8_t cell_level = ADCH;
- if( cell_level < ADC8_FROM_CELL_V( 200 ) )
- {
- /* power's out */
- if( g_have_power )
- {
- /* This is new. Start counting. */
- g_wdt_count = 0;
- g_have_power = 0;
- /* Enable recursive interrupt. */
- sei();
- /* Make ADC run faster. */
- ADCSRA &= ADC_PRESCALER_MASK;
- ADCSRA = ADC_PRESCALER_8;
- /* Go to sleep. */
- while( g_have_power == 0 )
- {
- set_sleep_mode( SLEEP_MODE_PWR_DOWN );
- sleep_mode();
- }
- }
- else
- {
- /*
- Power was already out. Nothing to do here. We're 3 interrupts
- deep at this point so we'll return to the WDT interrupt which
- will return to this interrupt (in the loop above) which will
- put us back to sleep.
- */
- }
- }
- else
- {
- /* we have power */
- if( g_have_power )
- {
- /* We already had power. Just start the next conversion. */
- ADCSRA |= (1 << ADSC);
- }
- else
- {
- /* Power was restored. */
- g_have_power = 1;
- /* Tell main loop to flash the delay. */
- g_flash_count = g_wdt_count;
- /* Restore regular ADC speed. */
- ADCSRA &= ADC_PRESCALER_MASK;
- ADCSRA = ADC_PRESCALER_64;
- }
- }
- }
- int main(void)
- {
- g_have_power = 1;
- /* initialize ADC to read cell level on ADC1 (PB2) */
- /* disable digital input */
- DIDR0 |= (1 << ADC1D);
- /* internal 1.1V ref, left adjusted, ADC1 (PB2) */
- #if defined(__AVR_ATtiny13A__)
- ADMUX = (1 << REFS0) | (1 << ADLAR) | (1 << MUX0);
- #else
- ADMUX = (1 << REFS1) | (1 << ADLAR) | (1 << MUX0);
- #endif
- /* ADC prescaler for normal operation */
- ADCSRA = ADC_PRESCALER_64;
- /* Also disable digital input on OTC pin. */
- DIDR0 |= (1 << ADC3D);
- /* enable 7135 output */
- DDRB |= (1 << DDB0);
- /* big flash to show we rebooted */
- PORTB |= (1 << PORTB0);
- _delay_ms( 200 );
- PORTB &= ~(1 << PORTB0);
- /* enable watchdog interrupt every 0.125s */
- watchdog_interrupt_enable();
- WDTCR |= (1 << WDP1) | (1 << WDP0) ;
- /* enable ADC interrupt */
- ADCSRA |= (1 << ADIE);
- sei();
- /* enable ADC, start conversion */
- ADCSRA |= (1 << ADEN) | (1 << ADSC);
- while( 1 == 1 )
- {
- /* main loop */
- if( g_flash_count > 0 )
- {
- --g_flash_count;
- flash();
- _delay_ms( 500 );
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement