From 63966da14ab66bf711547f94e4d185f2027ad253 Mon Sep 17 00:00:00 2001 From: David Vazgenovich Shakaryan Date: Tue, 17 Dec 2019 23:59:05 -0800 Subject: add sound-reactive mode and pattern-cycling interrupt --- config.h | 20 +++++++++++-- eq.c | 51 ++++++++++++++++++++++++++++++++ eq.h | 4 +++ led.c | 20 ++++++------- led.h | 6 +--- main.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 6 files changed, 175 insertions(+), 28 deletions(-) create mode 100644 eq.c create mode 100644 eq.h diff --git a/config.h b/config.h index 1d25abc..00816db 100644 --- a/config.h +++ b/config.h @@ -1,2 +1,18 @@ -#define PIN_LED PB0 -#define NUM_LEDS 50 +#define F_CPU 8000000UL + +#define LED_COUNT 50 +#define LED_PIN PB3 + +#define EQ_PIN_INPUT PB2 +#define EQ_PIN_RESET PB0 +#define EQ_PIN_STROBE PB1 +#define EQ_THRESHOLDS \ + {16, 82}, \ + {24, 130}, \ + {24, 99}, \ + {24, 79}, \ + {24, 77}, \ + {24, 87}, \ + {26, 37} + +#define ISR_PIN PB4 diff --git a/eq.c b/eq.c new file mode 100644 index 0000000..eb7febd --- /dev/null +++ b/eq.c @@ -0,0 +1,51 @@ +#include "config.h" +#include "eq.h" + +#include +#include + +unsigned char eq_levels[7]; + +static const unsigned char thresholds[][2] = { EQ_THRESHOLDS }; + +static void reset() { + PORTB |= (1 << EQ_PIN_RESET); + PORTB &= ~(1 << EQ_PIN_RESET); + _delay_us(36); +} + +static void strobe() { + PORTB |= (1 << EQ_PIN_STROBE); + _delay_us(36); + PORTB &= ~(1 << EQ_PIN_STROBE); + _delay_us(36); +} + +static unsigned char map_level(unsigned char val, unsigned char min, unsigned char max) { + if (val <= min) + return 0; + else if (val >= max) + return 255; + else + return val * 255 / (max - min); +} + +void eq_read() { + reset(); + + for (int i = 0; i < 7; ++i) { + strobe(); + + ADCSRA |= (1 << ADSC); + while (ADCSRA & (1 << ADSC)); + eq_levels[i] = map_level(ADCH, thresholds[i][0], thresholds[i][1]); + } +} + +void eq_decay() { + reset(); + + for (int i = 0; i < 7; ++i) { + strobe(); + } +} diff --git a/eq.h b/eq.h new file mode 100644 index 0000000..2ad7beb --- /dev/null +++ b/eq.h @@ -0,0 +1,4 @@ +extern unsigned char eq_levels[]; + +void eq_decay(); +void eq_read(); diff --git a/led.c b/led.c index 5ea9923..8d53dea 100644 --- a/led.c +++ b/led.c @@ -3,7 +3,7 @@ #include -void signal_bit_0() { +static void signal_bit_0() { asm volatile ( "sbi %0, %1\n\t" "cbi %0, %1\n\t" @@ -11,11 +11,11 @@ void signal_bit_0() { "rjmp .+0\n\t" "rjmp .+0\n\t" : - : "I" (_SFR_IO_ADDR(PORTB)), "I" (PIN_LED) + : "I" (_SFR_IO_ADDR(PORTB)), "I" (LED_PIN) ); } -void signal_bit_1() { +static void signal_bit_1() { asm volatile ( "sbi %0, %1\n\t" "rjmp .+0\n\t" @@ -24,11 +24,11 @@ void signal_bit_1() { "rjmp .+0\n\t" "nop\n\t" : - : "I" (_SFR_IO_ADDR(PORTB)), "I" (PIN_LED) + : "I" (_SFR_IO_ADDR(PORTB)), "I" (LED_PIN) ); } -void signal_byte(unsigned char byte) { +static void signal_byte(unsigned char byte) { for (unsigned char mask = 0x80; mask != 0; mask >>= 1) { if (byte & mask) signal_bit_1(); @@ -37,20 +37,20 @@ void signal_byte(unsigned char byte) { } } -void signal_led(struct colour *c) { +static void signal_led(struct colour *c) { signal_byte(c->r); signal_byte(c->g); signal_byte(c->b); } -void signal_led_sequence(int num_leds, struct colour *seq, int num_seq, int width, int start) { +void led_signal_sequence(int num_leds, struct colour *seq, int num_seq, int col_width, int seq_start) { for(int i = 0; i < num_leds; ++i) { - int j, p = i - start; + int j, p = i - seq_start; if (p >= 0) - j = (p / width % num_seq); + j = (p / col_width % num_seq); else - j = (num_seq - ((p + 1) / -width % num_seq) - 1); + j = (num_seq - ((p + 1) / -col_width % num_seq) - 1); signal_led(&seq[j]); } diff --git a/led.h b/led.h index 585f297..fd11a87 100644 --- a/led.h +++ b/led.h @@ -2,8 +2,4 @@ struct colour { unsigned char r, g, b; }; -void signal_bit_0(); -void signal_bit_1(); -void signal_byte(unsigned char); -void signal_led(struct colour *); -void signal_led_sequence(int, struct colour *, int, int, int); +void led_signal_sequence(int, struct colour *, int, int, int); diff --git a/main.c b/main.c index d1a466d..06c585e 100644 --- a/main.c +++ b/main.c @@ -1,17 +1,37 @@ -#define F_CPU 8000000UL - -#include -#include -#include - #include "config.h" +#include "eq.h" #include "led.h" +#include +#include +#include +#include +#include + static struct colour seq[6]; +static bool interrupted = false; -int main() { - DDRB |= (1 << PIN_LED); - PORTB &= ~(1 << PIN_LED); +void red_green() { + memset(seq, 0, 2 * sizeof(seq[0])); + + seq[0].r = 255; + seq[1].g = 255; + + while (1) { + for (int i = 0; i < LED_COUNT; ++i) { + if (interrupted == true) { + interrupted = false; + return; + } + + led_signal_sequence(LED_COUNT, seq, 2, 1, i); + _delay_ms(200); + } + } +} + +void rainbow() { + memset(seq, 0, 6 * sizeof(seq[0])); seq[0].r = 255; seq[1].r = 255; @@ -24,11 +44,71 @@ int main() { seq[5].b = 255; while (1) { - for (int i = 0; i < NUM_LEDS; ++i) { - signal_led_sequence(NUM_LEDS, seq, 6, 4, i); + for (int i = 0; i < LED_COUNT; ++i) { + if (interrupted == true) { + interrupted = false; + return; + } + + led_signal_sequence(LED_COUNT, seq, 6, 4, i); _delay_ms(100); } } +} + +void sound_reactive() { + memset(seq, 0, 3 * sizeof(seq[0])); + + while (1) { + if (interrupted == true) { + interrupted = false; + return; + } + + eq_read(); + + seq[0].r = (eq_levels[0] > eq_levels[1]) ? eq_levels[0] : eq_levels[1]; + unsigned char t = (eq_levels[2] > eq_levels[3]) ? eq_levels[2] : eq_levels[3]; + seq[1].g = (t > eq_levels[4]) ? t : eq_levels[4]; + seq[2].b = (eq_levels[5] > eq_levels[6]) ? eq_levels[5] : eq_levels[6]; + + led_signal_sequence(LED_COUNT, seq, 3, 1, 0); + for (int i = 0; i < 20; ++i) { + eq_decay(); + } + _delay_ms(50); + } +} + + +int main() { + DDRB |= (1 << LED_PIN); + PORTB &= ~(1 << LED_PIN); + + DDRB |= (1 << EQ_PIN_RESET); + PORTB &= ~(1 << EQ_PIN_RESET); + DDRB |= (1 << EQ_PIN_STROBE); + PORTB |= (1 << EQ_PIN_STROBE); + DDRB &= ~(1 << EQ_PIN_INPUT); + + DDRB &= ~(1 << ISR_PIN); + GIMSK |= (1 << PCIE); + PCMSK |= (1 << PCINT4); + sei(); + + ADMUX |= (1 << MUX0) | (1 << ADLAR); + ADCSRA |= (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); + + while (1) { + sound_reactive(); + red_green(); + rainbow(); + } return 0; } + +ISR(PCINT0_vect) { + if (!(PINB & (1 << ISR_PIN))) + interrupted = true; +} -- cgit v1.2.3-70-g09d2