ATtiny414 Ugly Runway Sweater
ATtiny414 Ugly Sweater Runway lights
6 Modes
modes:
Normal
Normal with dual run and flash.
up down
random
all on
SOS
Lipo Battery
USB C charge control and can be powered by USB.
79 LED lights
Current draw average is 130ma
Run time is about 8 hours.
Ugly Runway Sweater Guarded by the Black Panther
Diagram of how running lights are Charlie Plexed on sweater. To make easier for code.
20221113_154747.mp4
USB C Charge port.
Control Box, 3d printed on Ender3
ATtiny-runway-ugly-sweater-high.flv
Over 400 lines of code:
//Code in C with Microchip Studio
/* * ATtiny414-Runway-lights.c * v1.3 2022-11-13 * Created: 10/26/2022 16:27:03 * Author : Sherman Stebbins * Used Micro Chip Studio 7 * Updated 2022-11-13 - worked on modes * Updated 2022-11-17 - Fixed SOS mode. */
#define F_CPU 10000000UL#include <avr/io.h>#include <util/delay.h>#include <avr/interrupt.h>#include <stdlib.h> //for rand(); works
#define PA PIN4_bm#define PB PIN5_bm#define PC PIN6_bm#define PD PIN7_bm
#define ModeMax 6//#define DEBG
const uint8_t led_dir[12] = { ( PA | PB), //LED 0 1 ( PA | PB), //LED 0 1 ( PC | PB), //LED 2 3 ( PC | PB), //LED 2 3 ( PC | PA), //LED 4 5 ( PC | PA), //LED 4 5 ( PA | PD), //LED 6 7 ( PA | PD), //LED 6 7 ( PB | PD), //LED 8 9 ( PB | PD), //LED 8 9 ( PD | PC), //LED 10 11 ( PD | PC) }; //LED 10 11
const uint8_t led[12] = { ( PA ), //LED 0 ( PB ), //LED 1 ( PC ), //LED 2 ( PB ), //LED 3 ( PC ), //LED 4 ( PA ), //LED 5 ( PA ), //LED 6 ( PD ), //LED 7 ( PB ), //LED 8 ( PD ), //LED 9 ( PC ), //LED 10 ( PD) }; //LED 11
static volatile uint8_t sleepstate = 0;static volatile uint8_t mode = 5;static volatile uint8_t modeChange=0;uint8_t randLoops;
void sos(void);void newDot(void);void newDash(void);void whiteOn(void);void redOn(void);void greenOn(void);void whiteOff(void);void redOff(void);void greenOff(void);void allColorLedOn(void);void allColorLedOff(void);void gotosleep(void);void ledOn(uint8_t);void ledOff(void);void allLedOn(uint8_t);void rainDrop(uint8_t, uint8_t);void randRainDrops(uint8_t);void upDown(uint8_t, uint8_t);void randLeds(uint8_t);
void flashTest(void){ //for(uint8_t i = mode;i>=0;i--){ PORTB_OUT &= ~(PIN2_bm); _delay_ms(100); PORTB_OUT = PIN2_bm; //}}void changeMode(void){ flashTest(); mode++; if(mode>=ModeMax){ mode=0; } modeChange=0;}ISR(PORTB_PORT_vect){ if(~PORTB_IN & PIN3_bm){ } if(~PORTB.INTFLAGS & PIN3_bm){ while(PORTB.IN & PIN3_bm){ } } PORTB.INTFLAGS = 0b11111111;// PORTB.INTFLAGS = PORT_INT3_bm; modeChange=1; _delay_ms(50); // mode++; // if(mode > ModeMax-1){ // mode=0; // }}
int main(void){ CCP = 0xD8; CLKCTRL_MCLKCTRLB = 0b00000001; //set at max speed div by 2 so 10mhz while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm){;} //wait for clock sync.// long tt = random(10,20); //PORTA.OUTSET = (1<<) PORTA.DIRSET = 0; PORTB.DIRSET = PIN0_bm|PIN1_bm|PIN2_bm; PORTA.DIRSET = PIN1_bm|PIN2_bm; PORTB.DIRSET &= ~(PIN3_bm); PORTB.PIN3CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc|PORT_INVEN_bm; PORTA_OUT = PIN2_bm; PORTB_OUT = PIN2_bm; _delay_ms(100); //pull up pin 2 and set it to trigger int on falling edge: PORTB.PIN2CTRL = PORT_ISC_RISING_gc; //this was my fix for changing current draw sei(); //Set enable interrupt //set sleep to power down //SLPCTRL.CTRLA = 0b00000101; //sherms way SLPCTRL.CTRLA = SLPCTRL_SMODE_PDOWN_gc | SLPCTRL_SEN_bm; //Microchip studio showed this // gotosleep(); //sleep// allColorLedOn(); while (1){ // allColorLedOn(); if(modeChange){ changeMode();} // mode=5; switch(mode){ case 0: allColorLedOn(); for(uint8_t i=0;i<12;i++){ ledOn(i); _delay_ms(70); ledOff(); } ledOff(); _delay_ms(70); break; case 1: allColorLedOn(); rainDrop(250,1); break; case 2: allColorLedOn(); upDown(150,1); break; case 3: allColorLedOn(); randLeds(1); break; case 4: allColorLedOn(); allLedOn(1); //about 1min per 100 (250 max). break; case 5: sos(); break; default: break; } #ifdef DEBG ledOn(mode); _delay_ms(50); ledOff(); #endif // gotosleep(); }}void ledOn(uint8_t light){ PORTA.DIR = led_dir[light]; PORTA.OUT = led[light]; greenOn();}void ledOff(void){ //PORTA.DIRCLR = (PA|PB|PC|PD); PORTA.DIR &= ~(PA|PB|PC|PD); //same}
void whiteOn(void){// PORTB.DIRSET = PIN0_bm; PORTB.OUTSET = PIN1_bm;}
void redOn(void){// PORTB.DIRSET = PIN1_bm; PORTA.OUTSET = PIN1_bm;}void greenOn(void){ PORTA.DIRSET = PIN2_bm; PORTA.OUTSET = PIN2_bm;// PORTA.DIR = PIN2_bm;// PORTA.OUT = PIN2_bm;}void whiteOff(void){ PORTB_OUT &= ~PIN1_bm;}void redOff(void){ PORTA.OUTCLR= PIN1_bm;}void greenOff(void){ PORTA.OUTCLR = PIN2_bm;}void allColorLedOn(void){ PORTB_DIRSET = PIN0_bm; PORTB_OUTSET = PIN0_bm; whiteOn(); redOn(); greenOn();}
void allColorLedOff(){ PORTB_OUTCLR = PIN0_bm; whiteOff(); redOff(); greenOff();}void newDot(){ PORTB.OUTSET = PIN1_bm; PORTA.OUTSET = PIN2_bm; _delay_ms(400); PORTB.OUTCLR = PIN1_bm; PORTA_OUT &= ~PIN2_bm; _delay_ms(300);}void newDash(){ PORTB_OUTSET = PIN1_bm; PORTA.OUTSET = PIN2_bm; _delay_ms(800); PORTB_OUTCLR = PIN1_bm; PORTA_OUTCLR = PIN2_bm; _delay_ms(300);}void sos(){ //..-. ..- -.-. -.- / ..- //fuck u //..-. / ..- //f u newDot(); newDot(); newDash(); newDot(); _delay_ms(500); newDot(); newDot(); newDash(); _delay_ms(1000);}
void rainDrop(uint8_t speed, uint8_t loops){ ledOff(); for(uint8_t l=0;l<loops;l++){ for(uint8_t i=0;i<12;i++){ for (uint8_t k=0;k<speed;k++){ // if(modeChange){ // changeMode(); // return;} ledOn(i); _delay_us(50); ledOff(); _delay_us(20); if(i>0){ ledOn(i-1); _delay_us(50); ledOff(); _delay_us(20); }/* // unremark if you want 3 lines of lights running instead of 2 if(i>1){ ledOn(i-2); _delay_us(50); ledOff(); _delay_us(20); }*/ } } for(int i=0;i<3;i++){ ledOn(11); _delay_ms(40); ledOff(); _delay_ms(40); } }}
void randRainDrops(uint8_t loops){ ledOff(); int randNum; for(uint8_t l=0;l<loops;l++){ randNum = (rand() % 205)+10; for(uint8_t i=0;i<12;i++){ for (int k=0;k<randNum;k++){ // if(modeChange){ // changeMode(); // return;}
ledOn(i); _delay_us(50); ledOff(); _delay_us(50); if(i>0){ ledOn(i-1); _delay_us(50); ledOff(); _delay_us(50); } } } for(int i=0;i<5;i++){ ledOn(11); _delay_ms(10); ledOff(); _delay_ms(10); } }}
void upDown(uint8_t speed, uint8_t loops){ ledOff(); uint8_t j; for(uint8_t h=0;h<loops;h++){ for(uint8_t i=0;i<12;i++){ for (uint8_t k=0;k<speed;k++){ // if(modeChange){ // changeMode(); // return;}
ledOn(i); _delay_us(50); ledOff(); _delay_us(20); } } for(uint8_t i=12;i>0;i--){ j=i-1; for (uint8_t k=0;k<speed;k++){ ledOn(j); _delay_us(50); ledOff(); _delay_us(20); } } }}
void randLeds(uint8_t loops){ uint8_t randLight; uint8_t randTime; for(uint8_t i=0;i<loops;i++){ for (uint8_t k=0;k<48;k++){ // if(modeChange){ // changeMode(); // return;}
randLight = rand() % 12; ledOn(randLight); randTime = (rand() % 80) + 10; for(uint8_t l=0;l<randTime;l++){ _delay_us(200); } ledOff(); } }}
void allLedOn(uint8_t loops){ for (uint16_t j=0;j<loops*250;j++){ for(uint8_t k=0;k<15;k++){ for (uint8_t i = 0; i<12 ; i++) { // if(modeChange){ // changeMode(); // return;}
ledOn(i); ledOff(); } } }}
void gotosleep(void){ PORTA.DIRSET = 0b00000000; PORTB.PIN0CTRL = PORT_PULLUPEN_bm; PORTB.PIN1CTRL = PORT_PULLUPEN_bm; PORTA.PIN1CTRL = PORT_PULLUPEN_bm; PORTA.PIN4CTRL = PORT_PULLUPEN_bm; PORTA.PIN5CTRL = PORT_PULLUPEN_bm; PORTA.PIN6CTRL = PORT_PULLUPEN_bm; PORTA.PIN7CTRL = PORT_PULLUPEN_bm;
sei(); SLPCTRL.CTRLA = 0b00000101; //set power down and sleep enable asm("sleep"); //sleep //turn off pull ups after sleep PORTB.PIN0CTRL &= ~(PORT_PULLUPEN_bm); PORTB.PIN1CTRL &= ~(PORT_PULLUPEN_bm); PORTA.PIN1CTRL &= ~(PORT_PULLUPEN_bm); PORTA.PIN4CTRL &= ~(PORT_PULLUPEN_bm); PORTA.PIN5CTRL &= ~(PORT_PULLUPEN_bm); PORTA.PIN6CTRL &= ~(PORT_PULLUPEN_bm); PORTA.PIN7CTRL &= ~(PORT_PULLUPEN_bm);
}ISR(PORTA_PORT_vect){ if(sleepstate){ sleepstate=0; } //PORTA.INTFLAGS = 0x04; //clear int flag, from Ben Heck.. PORTA.INTFLAGS = PORT_INT2_bm; //not tested, got from iotn402.h}
/* * ATtiny414-Runway-lights.c * v1.3 2022-11-13 * Created: 10/26/2022 16:27:03 * Author : Sherman Stebbins * Used Micro Chip Studio 7 * Updated 2022-11-13 - worked on modes * Updated 2022-11-17 - Fixed SOS mode. */
#define F_CPU 10000000UL#include <avr/io.h>#include <util/delay.h>#include <avr/interrupt.h>#include <stdlib.h> //for rand(); works
#define PA PIN4_bm#define PB PIN5_bm#define PC PIN6_bm#define PD PIN7_bm
#define ModeMax 6//#define DEBG
const uint8_t led_dir[12] = { ( PA | PB), //LED 0 1 ( PA | PB), //LED 0 1 ( PC | PB), //LED 2 3 ( PC | PB), //LED 2 3 ( PC | PA), //LED 4 5 ( PC | PA), //LED 4 5 ( PA | PD), //LED 6 7 ( PA | PD), //LED 6 7 ( PB | PD), //LED 8 9 ( PB | PD), //LED 8 9 ( PD | PC), //LED 10 11 ( PD | PC) }; //LED 10 11
const uint8_t led[12] = { ( PA ), //LED 0 ( PB ), //LED 1 ( PC ), //LED 2 ( PB ), //LED 3 ( PC ), //LED 4 ( PA ), //LED 5 ( PA ), //LED 6 ( PD ), //LED 7 ( PB ), //LED 8 ( PD ), //LED 9 ( PC ), //LED 10 ( PD) }; //LED 11
static volatile uint8_t sleepstate = 0;static volatile uint8_t mode = 5;static volatile uint8_t modeChange=0;uint8_t randLoops;
void sos(void);void newDot(void);void newDash(void);void whiteOn(void);void redOn(void);void greenOn(void);void whiteOff(void);void redOff(void);void greenOff(void);void allColorLedOn(void);void allColorLedOff(void);void gotosleep(void);void ledOn(uint8_t);void ledOff(void);void allLedOn(uint8_t);void rainDrop(uint8_t, uint8_t);void randRainDrops(uint8_t);void upDown(uint8_t, uint8_t);void randLeds(uint8_t);
void flashTest(void){ //for(uint8_t i = mode;i>=0;i--){ PORTB_OUT &= ~(PIN2_bm); _delay_ms(100); PORTB_OUT = PIN2_bm; //}}void changeMode(void){ flashTest(); mode++; if(mode>=ModeMax){ mode=0; } modeChange=0;}ISR(PORTB_PORT_vect){ if(~PORTB_IN & PIN3_bm){ } if(~PORTB.INTFLAGS & PIN3_bm){ while(PORTB.IN & PIN3_bm){ } } PORTB.INTFLAGS = 0b11111111;// PORTB.INTFLAGS = PORT_INT3_bm; modeChange=1; _delay_ms(50); // mode++; // if(mode > ModeMax-1){ // mode=0; // }}
int main(void){ CCP = 0xD8; CLKCTRL_MCLKCTRLB = 0b00000001; //set at max speed div by 2 so 10mhz while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm){;} //wait for clock sync.// long tt = random(10,20); //PORTA.OUTSET = (1<<) PORTA.DIRSET = 0; PORTB.DIRSET = PIN0_bm|PIN1_bm|PIN2_bm; PORTA.DIRSET = PIN1_bm|PIN2_bm; PORTB.DIRSET &= ~(PIN3_bm); PORTB.PIN3CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc|PORT_INVEN_bm; PORTA_OUT = PIN2_bm; PORTB_OUT = PIN2_bm; _delay_ms(100); //pull up pin 2 and set it to trigger int on falling edge: PORTB.PIN2CTRL = PORT_ISC_RISING_gc; //this was my fix for changing current draw sei(); //Set enable interrupt //set sleep to power down //SLPCTRL.CTRLA = 0b00000101; //sherms way SLPCTRL.CTRLA = SLPCTRL_SMODE_PDOWN_gc | SLPCTRL_SEN_bm; //Microchip studio showed this // gotosleep(); //sleep// allColorLedOn(); while (1){ // allColorLedOn(); if(modeChange){ changeMode();} // mode=5; switch(mode){ case 0: allColorLedOn(); for(uint8_t i=0;i<12;i++){ ledOn(i); _delay_ms(70); ledOff(); } ledOff(); _delay_ms(70); break; case 1: allColorLedOn(); rainDrop(250,1); break; case 2: allColorLedOn(); upDown(150,1); break; case 3: allColorLedOn(); randLeds(1); break; case 4: allColorLedOn(); allLedOn(1); //about 1min per 100 (250 max). break; case 5: sos(); break; default: break; } #ifdef DEBG ledOn(mode); _delay_ms(50); ledOff(); #endif // gotosleep(); }}void ledOn(uint8_t light){ PORTA.DIR = led_dir[light]; PORTA.OUT = led[light]; greenOn();}void ledOff(void){ //PORTA.DIRCLR = (PA|PB|PC|PD); PORTA.DIR &= ~(PA|PB|PC|PD); //same}
void whiteOn(void){// PORTB.DIRSET = PIN0_bm; PORTB.OUTSET = PIN1_bm;}
void redOn(void){// PORTB.DIRSET = PIN1_bm; PORTA.OUTSET = PIN1_bm;}void greenOn(void){ PORTA.DIRSET = PIN2_bm; PORTA.OUTSET = PIN2_bm;// PORTA.DIR = PIN2_bm;// PORTA.OUT = PIN2_bm;}void whiteOff(void){ PORTB_OUT &= ~PIN1_bm;}void redOff(void){ PORTA.OUTCLR= PIN1_bm;}void greenOff(void){ PORTA.OUTCLR = PIN2_bm;}void allColorLedOn(void){ PORTB_DIRSET = PIN0_bm; PORTB_OUTSET = PIN0_bm; whiteOn(); redOn(); greenOn();}
void allColorLedOff(){ PORTB_OUTCLR = PIN0_bm; whiteOff(); redOff(); greenOff();}void newDot(){ PORTB.OUTSET = PIN1_bm; PORTA.OUTSET = PIN2_bm; _delay_ms(400); PORTB.OUTCLR = PIN1_bm; PORTA_OUT &= ~PIN2_bm; _delay_ms(300);}void newDash(){ PORTB_OUTSET = PIN1_bm; PORTA.OUTSET = PIN2_bm; _delay_ms(800); PORTB_OUTCLR = PIN1_bm; PORTA_OUTCLR = PIN2_bm; _delay_ms(300);}void sos(){ //..-. ..- -.-. -.- / ..- //fuck u //..-. / ..- //f u newDot(); newDot(); newDash(); newDot(); _delay_ms(500); newDot(); newDot(); newDash(); _delay_ms(1000);}
void rainDrop(uint8_t speed, uint8_t loops){ ledOff(); for(uint8_t l=0;l<loops;l++){ for(uint8_t i=0;i<12;i++){ for (uint8_t k=0;k<speed;k++){ // if(modeChange){ // changeMode(); // return;} ledOn(i); _delay_us(50); ledOff(); _delay_us(20); if(i>0){ ledOn(i-1); _delay_us(50); ledOff(); _delay_us(20); }/* // unremark if you want 3 lines of lights running instead of 2 if(i>1){ ledOn(i-2); _delay_us(50); ledOff(); _delay_us(20); }*/ } } for(int i=0;i<3;i++){ ledOn(11); _delay_ms(40); ledOff(); _delay_ms(40); } }}
void randRainDrops(uint8_t loops){ ledOff(); int randNum; for(uint8_t l=0;l<loops;l++){ randNum = (rand() % 205)+10; for(uint8_t i=0;i<12;i++){ for (int k=0;k<randNum;k++){ // if(modeChange){ // changeMode(); // return;}
ledOn(i); _delay_us(50); ledOff(); _delay_us(50); if(i>0){ ledOn(i-1); _delay_us(50); ledOff(); _delay_us(50); } } } for(int i=0;i<5;i++){ ledOn(11); _delay_ms(10); ledOff(); _delay_ms(10); } }}
void upDown(uint8_t speed, uint8_t loops){ ledOff(); uint8_t j; for(uint8_t h=0;h<loops;h++){ for(uint8_t i=0;i<12;i++){ for (uint8_t k=0;k<speed;k++){ // if(modeChange){ // changeMode(); // return;}
ledOn(i); _delay_us(50); ledOff(); _delay_us(20); } } for(uint8_t i=12;i>0;i--){ j=i-1; for (uint8_t k=0;k<speed;k++){ ledOn(j); _delay_us(50); ledOff(); _delay_us(20); } } }}
void randLeds(uint8_t loops){ uint8_t randLight; uint8_t randTime; for(uint8_t i=0;i<loops;i++){ for (uint8_t k=0;k<48;k++){ // if(modeChange){ // changeMode(); // return;}
randLight = rand() % 12; ledOn(randLight); randTime = (rand() % 80) + 10; for(uint8_t l=0;l<randTime;l++){ _delay_us(200); } ledOff(); } }}
void allLedOn(uint8_t loops){ for (uint16_t j=0;j<loops*250;j++){ for(uint8_t k=0;k<15;k++){ for (uint8_t i = 0; i<12 ; i++) { // if(modeChange){ // changeMode(); // return;}
ledOn(i); ledOff(); } } }}
void gotosleep(void){ PORTA.DIRSET = 0b00000000; PORTB.PIN0CTRL = PORT_PULLUPEN_bm; PORTB.PIN1CTRL = PORT_PULLUPEN_bm; PORTA.PIN1CTRL = PORT_PULLUPEN_bm; PORTA.PIN4CTRL = PORT_PULLUPEN_bm; PORTA.PIN5CTRL = PORT_PULLUPEN_bm; PORTA.PIN6CTRL = PORT_PULLUPEN_bm; PORTA.PIN7CTRL = PORT_PULLUPEN_bm;
sei(); SLPCTRL.CTRLA = 0b00000101; //set power down and sleep enable asm("sleep"); //sleep //turn off pull ups after sleep PORTB.PIN0CTRL &= ~(PORT_PULLUPEN_bm); PORTB.PIN1CTRL &= ~(PORT_PULLUPEN_bm); PORTA.PIN1CTRL &= ~(PORT_PULLUPEN_bm); PORTA.PIN4CTRL &= ~(PORT_PULLUPEN_bm); PORTA.PIN5CTRL &= ~(PORT_PULLUPEN_bm); PORTA.PIN6CTRL &= ~(PORT_PULLUPEN_bm); PORTA.PIN7CTRL &= ~(PORT_PULLUPEN_bm);
}ISR(PORTA_PORT_vect){ if(sleepstate){ sleepstate=0; } //PORTA.INTFLAGS = 0x04; //clear int flag, from Ben Heck.. PORTA.INTFLAGS = PORT_INT2_bm; //not tested, got from iotn402.h}