/*
* LED ring
*
* A charlieplexed 20 LED blinker with ATTiny45. Space efficient
* daisychained LED placing with shared anode/cathode soldering pads.
*
* Video of the real device: https://www.youtube.com/embed/Tuk5kyZv42A
*
*/
//
// With (PB5 PB4 PB3 PB2 PB1 PB0) (ATTiny)
// build a lo, hi, tri-state matrix.
//
// Powerdown after UPTIME_MAX xxx (~xx sec). Press reset to wake up.
//
// ATMEL ATTINY13a
//
// +-\/-+
// PB5 1|. |8 Vcc
// PB3 2| |7 PB2
// PB4 3| |6 PB1
// GND 4| |5 PB0
// +----+
extern "C" {
#include "led_map.h"
#include "power_down.h"
#include "delay.h"
}
#include <avr/io.h>
#include <avr/pgmspace.h>
// #include "bootloader.h"
#define STEP_LENGTH 4000
#define UPTIME_SECONDS(s) (s /* s */ * 1000000 / STEP_LENGTH)
#define UPTIME_MAX UPTIME_SECONDS(60)
#define BUTTON_RELEASED(_) (PINB & (1 << 5))
static
uint32_t uptime = 0;
static inline
void setup(void) {
// MCUSR = 0; // reset watchdog
PORTB = _BV(5); // All input with pull up on PB5
DDRB = 0x00; // Input
delay_ms(10); // wait for stable PB5
}
static const unsigned char period_length[] PROGMEM = {
21, 22 //, 23, 24
};
#define N_ID (sizeof(period_length)/sizeof(period_length[0]))
typedef struct {
unsigned char period;
unsigned char led;
} animation_state_t;
animation_state_t animation_state[N_ID];
void animation_step(uint8_t id) {
animation_state_t *s = animation_state + id;
s->period++;
if (s->period < pgm_read_byte(period_length + id)) {
return;
}
s->period = 0;
led_map_set(s->led, !led_map_get(s->led));
s->led = (s->led + 1) % LED_COUNT;
}
static inline
void uptime_step(void) {
if (++uptime > UPTIME_MAX) {
do {
power_down();
// Wait for high
} while (!BUTTON_RELEASED());
// Debounce
delay_ms(50);
uptime = 0;
}
}
static inline
void comm_step(void) {
if (!BUTTON_RELEASED()) { // && (uptime > UPTIME_SECONDS(2))) {
// power down in 0.2 sec or earlier
uint32_t newuptime = UPTIME_MAX - UPTIME_SECONDS(0.2);
if (newuptime > uptime) {
uptime = newuptime;
}
}
}
static inline
void loop() {
unsigned id;
led_map_step();
for (id = 0; id < N_ID; id++) {
animation_step(id);
}
uptime_step();
comm_step();
delay_us(STEP_LENGTH);
}
/*
int main(void)
{
setup();
while (1) loop();
return 0;
}
/*
* compile-command: "make sflash@led_circle"
* Local Variables:
* compile-command: "make flash@led_circle"
* End:
*/
tiny:PB5
tiny:PB3
tiny:PB4
tiny:GND
tiny:PB0
tiny:PB1
tiny:PB2
tiny:VCC
led1:A
led1:C
led2:A
led2:C
led3:A
led3:C
led4:A
led4:C
led5:A
led5:C
led6:A
led6:C
led7:A
led7:C
led8:A
led8:C
led9:A
led9:C
led10:A
led10:C
led11:A
led11:C
led12:A
led12:C
led13:A
led13:C
led14:A
led14:C
led15:A
led15:C
led16:A
led16:C
led17:A
led17:C
led18:A
led18:C
led19:A
led19:C
led20:A
led20:C
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r