diff options
author | David Vazgenovich Shakaryan <dvshakaryan@gmail.com> | 2019-12-17 23:59:05 -0800 |
---|---|---|
committer | David Vazgenovich Shakaryan <dvshakaryan@gmail.com> | 2019-12-17 23:59:05 -0800 |
commit | 63966da14ab66bf711547f94e4d185f2027ad253 (patch) | |
tree | fddaf4558fb2ed23952768ad549f9dff36422e53 | |
parent | c5047bb9952655dc8d0fabf6a54b9e278b243d8b (diff) | |
download | christmas_lights-63966da14ab66bf711547f94e4d185f2027ad253.tar.gz christmas_lights-63966da14ab66bf711547f94e4d185f2027ad253.tar.xz |
add sound-reactive mode and pattern-cycling interrupt
-rw-r--r-- | config.h | 20 | ||||
-rw-r--r-- | eq.c | 51 | ||||
-rw-r--r-- | eq.h | 4 | ||||
-rw-r--r-- | led.c | 20 | ||||
-rw-r--r-- | led.h | 6 | ||||
-rw-r--r-- | main.c | 102 |
6 files changed, 175 insertions, 28 deletions
@@ -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 @@ -0,0 +1,51 @@ +#include "config.h" +#include "eq.h" + +#include <avr/io.h> +#include <util/delay.h> + +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(); + } +} @@ -0,0 +1,4 @@ +extern unsigned char eq_levels[]; + +void eq_decay(); +void eq_read(); @@ -3,7 +3,7 @@ #include <avr/io.h> -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]); } @@ -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); @@ -1,17 +1,37 @@ -#define F_CPU 8000000UL - -#include <avr/io.h> -#include <stdlib.h> -#include <util/delay.h> - #include "config.h" +#include "eq.h" #include "led.h" +#include <avr/eeprom.h> +#include <avr/interrupt.h> +#include <stdbool.h> +#include <string.h> +#include <util/delay.h> + 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; +} |