Skip to content

Instantly share code, notes, and snippets.

@cmoz
Created November 10, 2020 16:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cmoz/f501a53644ded1d3336a2974b287c19b to your computer and use it in GitHub Desktop.
Save cmoz/f501a53644ded1d3336a2974b287c19b to your computer and use it in GitHub Desktop.
/* -----------------------------------------------------------------------
* 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