Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #define F_CPU 14745600
- #include <avr/io.h>
- #include <inttypes.h>
- #include <avr/interrupt.h>
- #include "../../libnerdkits/delay.h"
- #include "../../libnerdkits/lcd.h"
- #include <avr/pgmspace.h>
- #define SER PC0
- #define CLOCK PC1
- #define LATCH PC2
- #define PORT595 PORTC
- #define DDR595 DDRC
- volatile uint8_t mode = 0;
- volatile uint16_t delay = 10; // initial delay
- volatile uint8_t number_of_strips = 3;
- // for some reason i cant dynamically set the size of an array based on the amount of shift registers. So i have hard set this to 30
- volatile uint8_t SHIFT_REGISTER[30]; // each 595 has its own 8bit var
- volatile uint16_t fdelay[10]; // each strip has its own var in this array used for timing
- volatile uint16_t snowflakes = 0; // used to tally up the number of snowflakes to display on lcd
- //********************************************************************************************************
- void high_shift() { // push out a 1
- PORT595 |= (1<<SER);
- PORT595 |= (1<<CLOCK);
- PORT595 &= ~(1<<CLOCK);
- PORT595 &= ~(1<<SER);
- }
- //********************************************************************************************************
- void low_shift() { // push out a 0
- PORT595 |= (1<<CLOCK);
- PORT595 &= ~(1<<CLOCK);
- }
- //********************************************************************************************************
- void latch() { // trigger latch
- PORT595 |= (1<<LATCH);
- PORT595 &= ~(1<<LATCH);
- }
- //********************************************************************************************************
- void shift_out(uint8_t data) { // push out 8 bits
- uint8_t loop;
- for (loop = 0; loop < 8; loop++) {
- if (data & 0x01) high_shift();
- else low_shift();
- data >>= 1;
- }
- }
- //********************************************************************************************************
- ISR(TIMER1_COMPA_vect) { //50hz timer which constantly shifts out led status
- int8_t loop;
- for (loop=(number_of_strips*3);loop>=0;loop--) {
- shift_out(SHIFT_REGISTER[loop]);
- }
- for (loop=0;loop<number_of_strips;loop++) {
- if (fdelay[loop] > 1) fdelay[loop]--;
- }
- latch();
- }
- //********************************************************************************************************
- void sync_strips() { // will sync all strips with the first one.
- uint8_t i;
- for (i=0; i<(number_of_strips*3-3);i++) {
- SHIFT_REGISTER[i+3] = SHIFT_REGISTER[i];
- }
- }
- //********************************************************************************************************
- void clear_strips() { // as it says clears all the strips
- SHIFT_REGISTER[0] = 0;
- SHIFT_REGISTER[1] = 0;
- SHIFT_REGISTER[2] = 0;
- sync_strips();
- }
- //********************************************************************************************************
- ISR(PCINT1_vect) { // external pin change interupt
- //uint8_t debounce;
- uint8_t debounce = (debounce << 1) | ((PINC >> PC5) & 1);
- if (debounce != 0xFF) {
- while ((debounce != 0x00) && (debounce != 0xFF)) { // debounce and filter interference
- debounce = (debounce << 1) | ((PINC >> PC5) & 1);
- delay_ms(1);
- }
- if (!debounce) { // code to run if button was actually pressed and not interference
- mode++;
- update_lcd_top();
- }
- while (debounce != 0xFF) { // debounce
- debounce = (debounce << 1) | ((PINC >> PC5) & 1);
- delay_ms(1);
- }
- }
- debounce = (debounce << 1) | ((PINC >> PC4) & 1);
- if (debounce != 0xFF) {
- while ((debounce != 0x00) && (debounce != 0xFF)) { // debounce and filter interference
- debounce = (debounce << 1) | ((PINC >> PC4) & 1);
- delay_ms(1);
- }
- if (!debounce) { // code to run if button was actually pressed and not interference
- if (delay > 1) delay -= 1;
- }
- while (debounce != 0xFF) { // debounce
- debounce = (debounce << 1) | ((PINC >> PC4) & 1);
- delay_ms(1);
- }
- }
- debounce = (debounce << 1) | ((PINC >> PC3) & 1);
- if (debounce != 0xFF) {
- while ((debounce != 0x00) && (debounce != 0xFF)) { // debounce and filter interference
- debounce = (debounce << 1) | ((PINC >> PC3) & 1);
- delay_ms(1);
- }
- if (!debounce) { // code to run if button was actually pressed and not interference
- delay += 1;
- }
- while (debounce != 0xFF) { // debounce
- debounce = (debounce << 1) | ((PINC >> PC3) & 1);
- delay_ms(1);
- }
- }
- }
- //********************************************************************************************************
- void update_lcd_top() { // updates top row of the lcd
- FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
- lcd_home();
- lcd_write_string(PSTR(" ")); // clear it first
- lcd_line_one();
- fprintf_P(&lcd_stream, PSTR("Mode: %u Del: %u"), mode,delay);
- }
- //********************************************************************************************************
- //********************************************************************************************************
- int main() {
- // start up the LCD
- lcd_init();
- FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
- lcd_home();
- //enable pin change interrupt
- PCICR |= (1<<PCIE1);
- PCMSK1 |= (1<<PCINT13)|(1<<PCINT12)|(1<<PCINT11);
- //Configure pin as input and enable pullup resistor for interupt
- DDRC &= ~((1<<PC5)|(1<<PC4)|(1<<PC3));
- PORTC |= (1<<PC5)|(1<<PC4)|(1<<PC3);
- // setup pins used for 595
- DDR595 |= (1<<SER) | (1<<LATCH) | (1<<CLOCK);
- PORT595 &= ~((1<<SER) | (1<<LATCH) | (1<<CLOCK));
- //Timer1 CK/1024 (14.4khz) clear timer on compare
- TCCR1B |= (1<<WGM13)|(1<<WGM12)|(1<<CS12)|(1<<CS10);
- ICR1 = 287; // generates a 50hz interupt
- TIMSK1 |= (1<<OCIE1A);
- sei();
- volatile uint8_t i;
- volatile uint8_t status[10] = {0,0,0,0,0,0,0,0,0,0,0}; // because all the strips are not synced each strip needs a status
- volatile flake_size[10] = {0,0,0,0,0,0,0,0,0,0,0}; // used to randomly generate size of each flake
- update_lcd_top();
- while(1) {
- switch (mode)
- {
- case 0:
- /*
- STATUS[i] STATES:
- 0 - start of loop, pick a random number before starting.
- 1 - waiting for initial delay before starting
- 2 - starting initial drop down of leds
- 3 - snow flake falling
- */
- for (i=0; i<number_of_strips;i++) {
- if ((status[i] == 0) && (fdelay[i] == 0)) { // generate delay before starting snowflake
- status[i] = 1;
- fdelay[i] = rand() % (delay*20) + 1;
- flake_size[i] = rand() % 6 + 1;
- }
- if (status[i] == 1) { // wait for delay before starting snowflake
- if (fdelay[i] == 1) {
- status[i] = 2;
- }
- }
- if (status[i] == 2) { // start snowflak falling onto strip
- if (fdelay[i] == 1) { // internal delay
- SHIFT_REGISTER[i*3] = (SHIFT_REGISTER[i*3] >>1) | 0x80;
- fdelay[i] = delay;
- if (flake_size[i] == 1) if (SHIFT_REGISTER[i*3] == 0x80) status[i] = 3;
- if (flake_size[i] == 2) if (SHIFT_REGISTER[i*3] == 0xC0) status[i] = 3;
- if (flake_size[i] == 3) if (SHIFT_REGISTER[i*3] == 0xE0) status[i] = 3;
- if (flake_size[i] == 4) if (SHIFT_REGISTER[i*3] == 0xF0) status[i] = 3;
- if (flake_size[i] == 5) if (SHIFT_REGISTER[i*3] == 0xF8) status[i] = 3;
- if (flake_size[i] == 6) if (SHIFT_REGISTER[i*3] == 0xFC) status[i] = 3;
- }
- }
- if (status[i] == 3) { // make snowflake fall to bottom
- if (fdelay[i] == 1) {
- SHIFT_REGISTER[i*3+2] >>= 1; // shift 3rd register along
- if (SHIFT_REGISTER[i*3+1] & 0x01) SHIFT_REGISTER[i*3+2] |= 0x80; //if dot is at bottom of 2nd register light up the first one of 3rd register
- SHIFT_REGISTER[i*3+1] >>= 1; // shift 2nd register along
- if (SHIFT_REGISTER[i*3] & 0x01) SHIFT_REGISTER[i*3+1] |= 0x80; // if dot is at the bottom of 1st register light up the first one on 2nd register
- SHIFT_REGISTER[i*3] >>= 1; // shift first register long by 1
- fdelay[i] = delay;
- if ((SHIFT_REGISTER[i*3+2] == 0x00) && (SHIFT_REGISTER[i*3+1] == 0x00) && (SHIFT_REGISTER[i*3] == 0x00)) { // if all 3 are cleared start from the start again
- status[i] = 0;
- fdelay[i] = 0;
- lcd_line_two();
- lcd_write_string(PSTR(" "));
- lcd_line_two();
- fprintf_P(&lcd_stream, PSTR("Snowflakes: %u"), ++snowflakes);
- }
- }
- }
- }
- break;
- case 1: // all these cases will run the code below.
- case 2: // all snowflakes are the same size depending on mode.
- case 3: // below code is almost the same as above. only change is when status goes from 2 to 3.
- case 4:
- case 5:
- /*
- STATUS[i] STATES:
- 0 - start of loop, pick a random number before starting.
- 1 - waiting for initial delay before starting
- 2 - starting initial drop down of leds
- 3 - snow flake falling
- */
- for (i=0; i<number_of_strips;i++) {
- if ((status[i] == 0) && (fdelay[i] == 0)) { // generate delay before starting snowflake
- status[i] = 1;
- fdelay[i] = rand() % (delay*20) + 1;
- flake_size[i] = rand() % 4 + 1;
- }
- if (status[i] == 1) { // wait for delay before starting snowflake
- if (fdelay[i] == 1) {
- status[i] = 2;
- }
- }
- if (status[i] == 2) { // start snowflak falling onto strip
- if (fdelay[i] == 1) { // internal delay
- SHIFT_REGISTER[i*3] = (SHIFT_REGISTER[i*3] >>1) | 0x80;
- fdelay[i] = delay;
- if (mode == 1) if (SHIFT_REGISTER[i*3] == 0x80) status[i] = 3;
- if (mode == 2) if (SHIFT_REGISTER[i*3] == 0xC0) status[i] = 3;
- if (mode == 3) if (SHIFT_REGISTER[i*3] == 0xE0) status[i] = 3;
- if (mode == 4) if (SHIFT_REGISTER[i*3] == 0xF0) status[i] = 3;
- if (mode == 5) if (SHIFT_REGISTER[i*3] == 0xF8) status[i] = 3;
- }
- }
- if (status[i] == 3) {
- if (fdelay[i] == 1) {
- SHIFT_REGISTER[i*3+2] >>= 1; // shift 3rd register along
- if (SHIFT_REGISTER[i*3+1] & 0x01) SHIFT_REGISTER[i*3+2] |= 0x80; //if dot is at bottom of 2nd register light up the first one of 3rd register
- SHIFT_REGISTER[i*3+1] >>= 1; // shift 2nd register along
- if (SHIFT_REGISTER[i*3] & 0x01) SHIFT_REGISTER[i*3+1] |= 0x80; // if dot is at the bottom of 1st register light up the first one on 2nd register
- SHIFT_REGISTER[i*3] >>= 1; // shift first register long by 1
- fdelay[i] = delay;
- if ((SHIFT_REGISTER[i*3+2] == 0x00) && (SHIFT_REGISTER[i*3+1] == 0x00) && (SHIFT_REGISTER[i*3] == 0x00)) {// if all 3 are cleared start from the start again
- status[i] = 0;
- fdelay[i] = 0;
- lcd_line_two();
- lcd_write_string(PSTR(" "));
- lcd_line_two();
- fprintf_P(&lcd_stream, PSTR("Snowflakes: %u"), ++snowflakes);
- }
- }
- }
- }
- break;
- default:
- clear_strips();
- mode = 0;
- update_lcd_top();
- break;
- }
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement