/* ----------------------------------------------------------------------- | |
* Title: advent.c | |
* Flicker 4 LEDs | |
* | |
* Author: Alexander Weber | |
* http://tinkerlog.com | |
* Date: 22.11.2009 | |
* Hardware: ATtiny13v | |
* Software: CrossPack-AVR-20090415 | |
* | |
* Credits: | |
* This code is based heavily on sritesmods version. | |
* Find the original at http://spritesmods.com/?art=minimalism&f=gpl | |
* | |
* Changes: | |
* - support 4 LEDs | |
* - added a bit of sampling for light detection | |
* - moved the "power down" out of the ISR, was always resetting | |
* - removed callibration, replaced by hardwired value. | |
*/ | |
#include <avr/io.h> | |
#include <util/delay.h> | |
#include <avr/interrupt.h> | |
#include <avr/eeprom.h> | |
#include <avr/pgmspace.h> | |
#include <avr/sleep.h> | |
#include <avr/wdt.h> | |
#define LED1 PB4 | |
#define LED2 PB3 | |
#define LED3 PB2 | |
#define LED4 PB1 | |
#define ADC2 2 | |
#define AMBIENT_LIGHT 300 | |
#define TRUE 1 | |
#define FALSE 0 | |
//Bunch o' random numbers: I'm too lazy to write or port a real random number | |
//generator. | |
//generated using bash: | |
//for x in `seq 0 255`; do echo -n $(($RANDOM%256)),; done | |
uint8_t const randomvals[] PROGMEM = { | |
234,191,103,250,144,74,39,34,215,128,9,122,144,74,137,105,123,218,158,175,205, | |
118,149,13,98,7,173,179,194,97,115,110,213,80,220,142,102,102,36,152,90,135, | |
105,176,173,49,6,197,48,140,176,122,4,53,83,216,212,202,170,180,214,53,161, | |
225,129,185,106,22,12,190,97,158,170,92,160,194,134,169,98,246,128,195,24, | |
198,165,156,77,126,113,136,58,156,196,136,41,246,164,84,138,171,184,42,214, | |
203,128,89,39,198,85,140,148,149,36,215,78,170,234,131,124,152,239,154,214, | |
130,194,49,3,69,248,120,179,101,163,131,124,184,148,213,118,213,81,177,149, | |
58,213,33,201,63,10,195,215,190,7,86,245,128,9,8,40,102,51,125,94,92,5,159, | |
75,253,158,40,4,6,178,241,92,124,73,248,1,157,61,50,86,136,113,22,16,171,209, | |
230,144,240,14,188,2,167,22,88,57,50,86,171,73,114,175,34,226,245,57,180,111, | |
220,186,170,242,141,229,49,158,30,82,161,49,124,65,139,24,95,14,133,65,238, | |
116,180,190,49,130,30,30,59,93,173,139,19,187,2,163,102,26,255,23,239,196,19, | |
6,162 | |
}; | |
uint8_t mode_ee EEMEM = 0; // stores the mode in eeprom | |
static volatile uint8_t sleep = 0; | |
// Gets a semi-random number between 0 and 255 | |
uint8_t getRandom(void) { | |
//This'll probably give a warning because we use it uninitialised. Little | |
//does the compiler know: that's actually what we _want_ :) | |
static uint8_t random1, random2; | |
random1++; | |
if (random1 == 0) { | |
random2 += 0x41; | |
} | |
return pgm_read_byte(randomvals + random1) ^ random2; | |
} | |
uint16_t getLight(void) { | |
uint16_t val = 0; | |
uint8_t i; | |
// measure pb4 using internal ref | |
ADMUX = (1 << REFS0) | ADC2; | |
// enable ADC, prescaler 8 | |
ADCSRA = (1 << ADEN) | 3; | |
// kill all leds | |
PORTB &= ~((1 << LED1) | (1 << LED2) | (1 << LED3) | (1 << LED4)); | |
_delay_ms(5); | |
// let led generate some voltage | |
DDRB &= ~(1 << LED1); | |
_delay_ms(5); | |
// warm up the ADC, discard the first conversion | |
ADCSRA |= (1 << ADSC); | |
while (ADCSRA & (1 << ADSC)); | |
for (i = 0; i < 4; i++) { | |
_delay_ms(5); | |
ADCSRA |= (1 << ADSC); | |
while (ADCSRA & (1 << ADSC)); | |
val += ADC; | |
} | |
val >>= 2; | |
ADCSRA = 0; // disable adc | |
DDRB |= (1 << LED1); // re-enable led | |
return val; | |
} | |
void powerDown(void) { | |
// Go to sleep until we're woken up by the wdt. | |
} | |
ISR(WDT_vect) { | |
//check if it's still dark | |
sleep = (getLight() > AMBIENT_LIGHT) ? TRUE : FALSE; | |
} | |
int main(void) { | |
uint8_t lval1, lval2, lval3, lval4; | |
uint8_t i, x, y; | |
uint8_t mode; | |
// set up wdt | |
wdt_enable(WDTO_2S); | |
WDTCR |= 0x40; // WDT generates interrupts instead of resets now. | |
// We want interrupts because a reset clears our nice random | |
// seeds, and an interrupt doesn't. | |
for (i = 0; i < 10; i++) { | |
_delay_ms(100); | |
} | |
// retrieve mode from eeprom and write back mode + 1 | |
mode = eeprom_read_byte(&mode_ee); | |
mode = mode % 4; | |
eeprom_write_byte(&mode_ee, mode + 1); | |
sei(); | |
// go directly into sleep mode and lets wake up by the wdt | |
sleep = TRUE; | |
// enable leds | |
DDRB = (1 << LED1) | (1 << LED2) | (1 << LED3) | (1 << LED4); | |
while (1) { | |
WDTCR |= 0x40; // make sure wdt keeps generating an int instead of a reset | |
if (sleep) { | |
// switch off all LEDs and power down | |
PORTB &= ~((1 << LED1) | (1 << LED2) | (1 << LED3) | (1 << LED4)); | |
set_sleep_mode(SLEEP_MODE_PWR_DOWN); | |
sleep_mode(); | |
} | |
else { | |
// get a random value for the leds intensity | |
lval1 = getRandom(); | |
lval2 = getRandom(); | |
lval3 = getRandom(); | |
lval4 = getRandom(); | |
// Manually do some pwm | |
for (x = 0; x < 20; x++) { | |
if (mode == 0) { | |
PORTB |= (1 << LED1); | |
} | |
else if (mode == 1) { | |
PORTB |= (1 << LED1) | (1 << LED2); | |
} | |
else if (mode == 2) { | |
PORTB |= (1 << LED1) | (1 << LED2) | (1 << LED3); | |
} | |
else if (mode == 3) { | |
PORTB |= (1 << LED1) | (1 << LED2) | (1 << LED3) | (1 << LED4); | |
} | |
for (y = 0; y != 255; y++) { | |
if (y == lval1) { | |
PORTB &= ~(1 << LED1); | |
} | |
if (y == lval2) { | |
PORTB &= ~(1 << LED2); | |
} | |
if (y == lval3) { | |
PORTB &= ~(1 << LED3); | |
} | |
if (y == lval4) { | |
PORTB &= ~(1 << LED4); | |
} | |
_delay_us(5); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment