playground:playground
Differences
This shows you the differences between two versions of the page.
Last revisionBoth sides next revision | |||
playground:playground [2013/06/16 13:03] – external edit 127.0.0.1 | playground:playground [2013/08/13 14:56] – bmbr | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== PlayGround ====== | ====== PlayGround ====== | ||
+ | |||
+ | The end product of the first [[Eagle Class]] | ||
+ | |||
+ | * [[http:// | ||
+ | * Code is also available on the [[http:// | ||
+ | * [[http:// | ||
+ | |||
+ | {{: | ||
+ | |||
+ | [[FILE: | ||
+ | |||
+ | http:// | ||
+ | br | ||
+ | < | ||
+ | |||
+ | <a href=" | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | <object type=" | ||
+ | </ | ||
+ | |||
+ | <code c> | ||
+ | |||
+ | - if 1 | ||
+ | |||
+ | /* | ||
+ | larson.c | ||
+ | The Larson Scanner | ||
+ | |||
+ | Written by Windell Oskay, http:// | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | An avr-gcc program for the Atmel ATTiny2313 | ||
+ | | ||
+ | | ||
+ | | ||
+ | * EEPROM is used to *correctly* remember last speed & brightness mode. | ||
+ | | ||
+ | * Skinny " | ||
+ | | ||
+ | * EEPROM is used to remember last speed & brightness mode. | ||
+ | |||
+ | |||
+ | More information about this project is at | ||
+ | | ||
+ | |||
+ | |||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | A makefile is provided to compile and install this program using AVR-GCC and avrdude. | ||
+ | To use it, follow these steps: | ||
+ | 1. Update the header of the makefile as needed to reflect the type of AVR programmer that you use. | ||
+ | 2. Open a terminal window and move into the directory with this file and the makefile. | ||
+ | 3. At the terminal enter | ||
+ | make clean < | ||
+ | make all < | ||
+ | make install < | ||
+ | 4. Make sure that avrdude does not report any errors. | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | |||
+ | If you a different programming environment, | ||
+ | |||
+ | |||
+ | |||
+ | | ||
+ | This code should be relatively straightforward, | ||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | * / | ||
+ | |||
+ | - include < | ||
+ | - include < | ||
+ | - include < | ||
+ | - include < | ||
+ | - include < | ||
+ | |||
+ | - define shortdelay(); | ||
+ | \ " \\ | ||
+ | "nop\ | ||
+ | \ "); | ||
+ | |||
+ | - define TIMER1_PRESCALE_1 | ||
+ | - define TIMER1_PRESCALE_8 | ||
+ | - define TIMER1_PRESCALE_64 | ||
+ | - define TIMER1_PRESCALE_256 | ||
+ | - define TIMER1_PRESCALE_1024 | ||
+ | |||
+ | uint16_t eepromWord __attribute__((section(" | ||
+ | |||
+ | int main (void) | ||
+ | { | ||
+ | uint8_t LEDs[[9]]; // Storage for current LED values | ||
+ | | ||
+ | int8_t eyeLoc[[5]]; | ||
+ | |||
+ | uint8_t LEDBright[[4]] = {1u, | ||
+ | | ||
+ | |||
+ | |||
+ | int8_t j, m; | ||
+ | | ||
+ | uint8_t position, loopcount, direction; | ||
+ | uint8_t ILED, RLED, MLED; | ||
+ | |||
+ | uint8_t delaytime; | ||
+ | | ||
+ | uint8_t skinnyEye = 0; | ||
+ | uint8_t | ||
+ | uint8_t | ||
+ | uint8_t BrightMode; | ||
+ | uint8_t debounce2, modeswitched; | ||
+ | | ||
+ | uint8_t CycleCountLow; | ||
+ | uint8_t LED0, LED1, LED2, LED3, LED4, LED5, LED6, LED7, LED8; | ||
+ | | ||
+ | // | ||
+ | MCUSR &= 0xF7; //Clear WDRF Flag | ||
+ | WDTCSR | ||
+ | WDTCSR | ||
+ | |||
+ | //Data direction register: DDR's | ||
+ | //Port A: 0, 1 are inputs. | ||
+ | //Port B: 0-3 are outputs, B4 is an input. | ||
+ | //Port D: 1-6 are outputs, D0 is an input. | ||
+ | | ||
+ | DDRA = 0U; | ||
+ | DDRB = 15U; | ||
+ | DDRD = 126U; | ||
+ | | ||
+ | PORTA = 3; // Pull-up resistors enabled, PA0, PA1 | ||
+ | PORTB = 16; // Pull-up resistor enabled, PA | ||
+ | PORTD = 0; | ||
+ | | ||
+ | |||
+ | TCCR1B = (1 << WGM12) | TIMER1_PRESCALE_1; | ||
+ | OCR1A = (uint16_t)800; | ||
+ | TIMSK |= 1 << OCIE1A; | ||
+ | |||
+ | /* Visualize outputs: | ||
+ | |||
+ | L to R: | ||
+ | |||
+ | D2 D3 D4 D5 D6 B0 B1 B2 B3 | ||
+ | | ||
+ | */ | ||
+ | | ||
+ | // | ||
+ | |||
+ | debounce = 0; | ||
+ | debounce2 = 0; | ||
+ | loopcount = 254; | ||
+ | delaytime = 0; | ||
+ | | ||
+ | direction = 0; | ||
+ | position = 0; | ||
+ | speedLevel = 0; // Range: 1, 2, 3 | ||
+ | BrightMode = 0; | ||
+ | CycleCountLow = 0; | ||
+ | UpdateConfig = 0; | ||
+ | modeswitched = 0; | ||
+ | | ||
+ | | ||
+ | if ((PINA & 2) == 0) // Check if Jumper 1, at location PA1 is shorted | ||
+ | { | ||
+ | // Optional place to do something. | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | if ((PINA & 1) == 0) // Check if Jumper 2, at location PA0 is shorted | ||
+ | { | ||
+ | skinnyEye = 1; | ||
+ | } | ||
+ | | ||
+ | | ||
+ | if ((PINB & 16) == 0) // Check if button pressed pressed down at turn-on | ||
+ | { | ||
+ | |||
+ | //Toggle Skinnymode | ||
+ | if (skinnyEye) | ||
+ | skinnyEye = 0; | ||
+ | else | ||
+ | skinnyEye = 1; | ||
+ | } | ||
+ | | ||
+ | | ||
+ | | ||
+ | if (skinnyEye){ | ||
+ | LEDBright[[0]] = 0; | ||
+ | LEDBright[[1]] = 4; | ||
+ | LEDBright[[2]] = 1; | ||
+ | LEDBright[[3]] = 0; | ||
+ | } | ||
+ | | ||
+ | | ||
+ | //Check EEPROM values: | ||
+ | | ||
+ | pt = (uint8_t) (eeprom_read_word(& | ||
+ | speedLevel = pt >> 4; | ||
+ | BrightMode = pt & 1; | ||
+ | |||
+ | if (pt == 0xFF) | ||
+ | { | ||
+ | BrightMode = 0; | ||
+ | } | ||
+ | | ||
+ | | ||
+ | if (speedLevel > 3) | ||
+ | speedLevel = 1; | ||
+ | | ||
+ | speedLevel = 0; | ||
+ | |||
+ | if ((speedLevel == 2) || (speedLevel == 3)) { | ||
+ | delaytime = 0; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | delaytime = 1; | ||
+ | } | ||
+ | | ||
+ | |||
+ | | ||
+ | for (;;) // main loop | ||
+ | { | ||
+ | |||
+ | |||
+ | loopcount++; | ||
+ | | ||
+ | if (loopcount > delaytime) | ||
+ | { | ||
+ | loopcount = 0; | ||
+ | | ||
+ | CycleCountLow++; | ||
+ | if (CycleCountLow > 250) | ||
+ | CycleCountLow = 0; | ||
+ | | ||
+ | | ||
+ | if (UpdateConfig){ | ||
+ | if (CycleCountLow > 100) // Avoid burning EEPROM in event of flaky power connection resets | ||
+ | { | ||
+ | | ||
+ | UpdateConfig = 0; | ||
+ | pt = (speedLevel << 4) | (BrightMode & 1); | ||
+ | eeprom_write_word(& | ||
+ | // Note: this function causes a momentary brightness glitch while it writes the EEPROM. | ||
+ | // We separate out this section to minimize the effect. | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | |||
+ | | ||
+ | | ||
+ | if ((PINB & 16) == 0) // Check for button press | ||
+ | { | ||
+ | debounce2++; | ||
+ | | ||
+ | if (debounce2 > 100) | ||
+ | { | ||
+ | if (modeswitched == 0) | ||
+ | { | ||
+ | debounce2 = 0; | ||
+ | UpdateConfig = 1; | ||
+ | |||
+ | switch( BrightMode ) { | ||
+ | | ||
+ | case 0: | ||
+ | BrightMode++; | ||
+ | case 1: | ||
+ | BrightMode++; | ||
+ | break; | ||
+ | case 2: | ||
+ | // off | ||
+ | // switch on POV | ||
+ | // wrap | ||
+ | BrightMode++; | ||
+ | break; | ||
+ | |||
+ | case 3: | ||
+ | // | ||
+ | // runs POV | ||
+ | BrightMode++; | ||
+ | break; | ||
+ | |||
+ | case 4: | ||
+ | sei(); | ||
+ | BrightMode++; | ||
+ | // runs POV | ||
+ | break; | ||
+ | case 5: | ||
+ | cli(); | ||
+ | // runs POV | ||
+ | BrightMode = 0 ; | ||
+ | break; | ||
+ | | ||
+ | default: | ||
+ | // interrupts off and wrap | ||
+ | BrightMode= 0; | ||
+ | break; | ||
+ | } | ||
+ | | ||
+ | modeswitched = 1; | ||
+ | } | ||
+ | } | ||
+ | else { | ||
+ | debounce = 1; // Flag that the button WAS pressed. | ||
+ | debounce2++; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | else{ | ||
+ | | ||
+ | debounce2 = 0; | ||
+ | modeswitched = 0; | ||
+ | | ||
+ | if (debounce) | ||
+ | { debounce = 0; | ||
+ | speedLevel++; | ||
+ | UpdateConfig = 1; | ||
+ | | ||
+ | if ((speedLevel == 2) || (speedLevel == 3)) { | ||
+ | delaytime = 0; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | delaytime = 1; | ||
+ | } | ||
+ | | ||
+ | debounce = 0; | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | | ||
+ | position++; | ||
+ | | ||
+ | if (speedLevel == 3) | ||
+ | position++; | ||
+ | | ||
+ | if (position >= 128) //was == 128 | ||
+ | { | ||
+ | | ||
+ | |||
+ | if (direction == 0) | ||
+ | direction = 1; | ||
+ | else | ||
+ | direction = 0; | ||
+ | } | ||
+ | | ||
+ | |||
+ | if (direction == 0) // Moving to right, as viewed from front. | ||
+ | { | ||
+ | ILED = (15+position) >> 4; | ||
+ | RLED = (15+position) - (ILED << 4); | ||
+ | MLED = 15 - RLED; | ||
+ | } | ||
+ | |||
+ | | ||
+ | { | ||
+ | ILED = (127 - position) >> 4; | ||
+ | MLED = (127 - position) | ||
+ | RLED = 15 - MLED; | ||
+ | } | ||
+ | |||
+ | j = 0; | ||
+ | while (j < 9) { | ||
+ | LEDs[[j]] = 0; | ||
+ | j++; | ||
+ | } | ||
+ | |||
+ | j = 0; | ||
+ | while (j < 5) { | ||
+ | | ||
+ | if (direction == 0) | ||
+ | m = ILED + (2 - j); // e.g., eyeLoc[[0]] = ILED + 2; | ||
+ | else | ||
+ | m = ILED + (j - 2); // e.g., eyeLoc[[0]] = ILED - 2; | ||
+ | | ||
+ | if (m > 8) | ||
+ | m -= (2 * (m - 8)); | ||
+ | | ||
+ | if (m < 0) | ||
+ | m *= -1; | ||
+ | | ||
+ | eyeLoc[[j]] = m; | ||
+ | | ||
+ | j++; | ||
+ | } | ||
+ | | ||
+ | j = 0; // For each of the eye parts... | ||
+ | while (j < 4) { | ||
+ | | ||
+ | LEDs[eyeLoc[j]] | ||
+ | LEDs[eyeLoc[j+1]] += LEDBright[[j]]*MLED; | ||
+ | |||
+ | j++; | ||
+ | } | ||
+ | | ||
+ | LED0 = LEDs[[0]]; | ||
+ | |||
+ | LED1 = LEDs[[1]]; | ||
+ | LED2 = LEDs[[2]]; | ||
+ | LED3 = LEDs[[3]]; | ||
+ | LED4 = LEDs[[4]]; | ||
+ | LED5 = LEDs[[5]]; | ||
+ | LED6 = LEDs[[6]]; | ||
+ | LED7 = LEDs[[7]]; | ||
+ | LED8 = LEDs[[8]]; | ||
+ | |||
+ | } | ||
+ | |||
+ | if ( BrightMode > 3 ) { | ||
+ | continue; | ||
+ | } | ||
+ | |||
+ | if (BrightMode == 0) | ||
+ | { // | ||
+ | // -> Use much less power. | ||
+ | j = 0; | ||
+ | while (j < 60) // Truncate brightness at a max value (60) in the interest of speed. | ||
+ | { | ||
+ | | ||
+ | if (LED0 > j) | ||
+ | PORTD = 4; | ||
+ | else | ||
+ | PORTD = 0; | ||
+ | | ||
+ | if (LED1 > j) | ||
+ | PORTD = 8; | ||
+ | else | ||
+ | PORTD = 0; | ||
+ | | ||
+ | if (LED2 > j) | ||
+ | PORTD = 16; | ||
+ | else | ||
+ | PORTD = 0; | ||
+ | | ||
+ | if (LED3 > j) | ||
+ | PORTD = 32; | ||
+ | else | ||
+ | PORTD = 0; | ||
+ | | ||
+ | if (LED4 > j) | ||
+ | PORTD = 64; | ||
+ | else | ||
+ | PORTD = 0; | ||
+ | | ||
+ | if (LED5 > j) { | ||
+ | PORTB = 17; | ||
+ | PORTD = 0;} | ||
+ | else { | ||
+ | PORTB = 16; | ||
+ | PORTD = 0; } | ||
+ | | ||
+ | if (LED6 > j) | ||
+ | PORTB = 18; | ||
+ | else | ||
+ | PORTB = 16; | ||
+ | | ||
+ | if (LED7 > j) | ||
+ | PORTB = 20; | ||
+ | else | ||
+ | PORTB = 16; | ||
+ | | ||
+ | if (LED8 > j) | ||
+ | PORTB = 24; | ||
+ | else | ||
+ | PORTB = 16; | ||
+ | |||
+ | j++; | ||
+ | // if (speedLevel == 3) | ||
+ | // j++; | ||
+ | PORTB = 16; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | | ||
+ | | ||
+ | |||
+ | j = 0; | ||
+ | while (j < 70) | ||
+ | { | ||
+ | | ||
+ | pt = 0; | ||
+ | if (LED0 > j) | ||
+ | pt = 4; | ||
+ | if (LED1 > j) | ||
+ | pt |= 8; | ||
+ | if (LED2 > j) | ||
+ | pt |= 16; | ||
+ | if (LED3 > j) | ||
+ | pt |= 32; | ||
+ | if (LED4 > j) | ||
+ | pt |= 64; | ||
+ | | ||
+ | PORTD = pt; | ||
+ | shortdelay(); | ||
+ | pt = 16; | ||
+ | if (LED5 > j) | ||
+ | pt |= 1; | ||
+ | if (LED6 > j) | ||
+ | pt |= 2; | ||
+ | if (LED7 > j) | ||
+ | pt |= 4; | ||
+ | if (LED8 > j) | ||
+ | pt |= 8; | ||
+ | | ||
+ | PORTB = pt; | ||
+ | shortdelay(); | ||
+ | | ||
+ | j++; | ||
+ | // if (speedLevel == 3) | ||
+ | // j++; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | | ||
+ | |||
+ | // | ||
+ | // -> Uses much less power. | ||
+ | |||
+ | } //End main loop | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | - define IS_BIT(a, | ||
+ | - define SET_BIT(a, | ||
+ | - define CLR_BIT(a, | ||
+ | |||
+ | |||
+ | - define LED0 ( 4 )//1 | ||
+ | - define LED1 ( 3 )//2 | ||
+ | - define LED2 ( 2 )//3 | ||
+ | - define LED3 ( 1 )//4 | ||
+ | - define LED4 ( 0 )//5 | ||
+ | |||
+ | // byte two | ||
+ | - define LED5 ( 3 ) | ||
+ | - define LED6 ( 2 ) | ||
+ | - define LED7 ( 1 ) | ||
+ | - define LED8 ( 0 ) | ||
+ | |||
+ | void delay_ms( uint16_t milliseconds) | ||
+ | { | ||
+ | |||
+ | for( ; milliseconds > 0; milliseconds--) | ||
+ | { | ||
+ | _delay_ms( 1); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | // NSL Cylon | ||
+ | - define B9__(x) ((x& | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | +((x& | ||
+ | |||
+ | - define _B9(d) ((uint16_t)B9__(HEX__(d))) | ||
+ | |||
+ | - define B9(d) 0b##d | ||
+ | |||
+ | |||
+ | const static uint16_t large_image[[]] PROGMEM | ||
+ | { | ||
+ | |||
+ | - if 1 | ||
+ | |||
+ | B9(000000000), | ||
+ | B9(111111111), | ||
+ | B9(100000001), | ||
+ | B9(100000001), | ||
+ | B9(000000000), | ||
+ | B9(100000000), | ||
+ | B9(100000000), | ||
+ | B9(100000000), | ||
+ | B9(111111111), | ||
+ | B9(000000000), | ||
+ | B9(111110001), | ||
+ | B9(100010001), | ||
+ | B9(100010001), | ||
+ | B9(100011111), | ||
+ | B9(000000000), | ||
+ | B9(111111111), | ||
+ | B9(001000000), | ||
+ | B9(000111000), | ||
+ | B9(000000100), | ||
+ | B9(000000010), | ||
+ | B9(111111111), | ||
+ | B9(000000000), | ||
+ | B9(100000001), | ||
+ | B9(100000001), | ||
+ | B9(111111111), | ||
+ | B9(000000000), | ||
+ | B9(000000000), | ||
+ | B9(000000000), | ||
+ | |||
+ | |||
+ | // nullspace (backwards) | ||
+ | |||
+ | B9(100010001), | ||
+ | B9(100010001), | ||
+ | B9(100010001), | ||
+ | B9(111111111), | ||
+ | B9(000000000), | ||
+ | B9(100000001), | ||
+ | B9(100000001), | ||
+ | B9(111111111), | ||
+ | B9(000000000), | ||
+ | B9(111111111), | ||
+ | B9(000010001), | ||
+ | |||
+ | |||
+ | B9(000010001), | ||
+ | B9(111111111), | ||
+ | B9(000000000), | ||
+ | B9(000011111), | ||
+ | B9(000010001), | ||
+ | B9(000010001), | ||
+ | B9(111111111), | ||
+ | B9(000000000), | ||
+ | B9(111110001), | ||
+ | B9(100010001), | ||
+ | B9(100010001), | ||
+ | B9(100011111), | ||
+ | B9(000000000), | ||
+ | B9(100000000), | ||
+ | B9(100000000), | ||
+ | B9(111111111), | ||
+ | B9(000000000), | ||
+ | B9(100000000), | ||
+ | B9(100000000), | ||
+ | B9(111111111), | ||
+ | B9(000000000), | ||
+ | B9(111111111), | ||
+ | B9(100000000), | ||
+ | B9(100000000), | ||
+ | B9(111111111), | ||
+ | B9(000000000), | ||
+ | B9(111111111), | ||
+ | B9(010000000), | ||
+ | B9(001110000), | ||
+ | B9(000001100), | ||
+ | B9(000000010), | ||
+ | B9(111111111), | ||
+ | |||
+ | // 0,0,0,0, | ||
+ | |||
+ | - else | ||
+ | |||
+ | // flickr | ||
+ | B9(010101010), | ||
+ | B9(010101010), | ||
+ | B9(101010101), | ||
+ | B9(101010101), | ||
+ | |||
+ | // | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | - endif | ||
+ | | ||
+ | 0,0,0,0, | ||
+ | 65535 | ||
+ | }; | ||
+ | |||
+ | |||
+ | // special pointer for reading from ROM memory | ||
+ | PGM_P largeimage_p PROGMEM = (PGM_P)large_image; | ||
+ | |||
+ | - define NUM_ELEM(x) (sizeof (x) / sizeof (*(x))) | ||
+ | |||
+ | // this function is called when timer1 compare matches OCR1A | ||
+ | |||
+ | SIGNAL( SIG_TIMER1_COMPA ) { | ||
+ | |||
+ | static uint8_t j = 0; | ||
+ | uint8_t tmpout; | ||
+ | |||
+ | uint16_t tmp=0; | ||
+ | |||
+ | //reset counter | ||
+ | if (pgm_read_word(largeimage_p + j ) == 65535 ) { | ||
+ | j = 0; | ||
+ | } | ||
+ | |||
+ | tmp = pgm_read_word(largeimage_p + j); | ||
+ | |||
+ | tmpout = 0; | ||
+ | |||
+ | if( IS_BIT(tmp, | ||
+ | if( IS_BIT(tmp, | ||
+ | if( IS_BIT(tmp, | ||
+ | if( IS_BIT(tmp, | ||
+ | |||
+ | PORTB = ( tmpout | ||
+ | |||
+ | tmpout = 0; | ||
+ | |||
+ | if( IS_BIT(tmp, | ||
+ | if( IS_BIT(tmp, | ||
+ | if( IS_BIT(tmp, | ||
+ | if( IS_BIT(tmp, | ||
+ | if( IS_BIT(tmp, | ||
+ | |||
+ | PORTD = tmpout<< | ||
+ | |||
+ | // word | ||
+ | j+=2; | ||
+ | } | ||
+ | |||
+ | - else | ||
+ | /* | ||
+ | larsonextend.c | ||
+ | The Larson Scanner -- Alternative version to allow scanner to run off the edge of the board. | ||
+ | |||
+ | |||
+ | It simulates one LED at brightness 4, followed by one LED of brightness 1, that moves across | ||
+ | the nine pixels, disappearing off either end of the board, before returning to scan in the other direction. | ||
+ | There is no longer any overlap of these " | ||
+ | the head fades in and the tail fades out. | ||
+ | Also, some of the input and output values and pull-up resistors have been changed from the original program | ||
+ | in anticipation of future extensibility. | ||
+ | With the buttons linked between the units, it seems to be flakey, at best, to get an accurate button press | ||
+ | on multiple units at the same time, so that section is commented out below. | ||
+ | | ||
+ | (a permanent installation in an enclosure), the unit was never really intended to change speeds. | ||
+ | get it to work like the original, but couldn' | ||
+ | |||
+ | Original written by Windell Oskay, http:// | ||
+ | New alternative version written by John Breen III | ||
+ | |||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | An avr-gcc program for the Atmel ATTiny2313 | ||
+ | Based on Version 1.1_alt1, written by Windell Oskay | ||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | |||
+ | More information about this project is at | ||
+ | | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | A makefile is provided to compile and install this program using AVR-GCC and avrdude. | ||
+ | To use it, follow these steps: | ||
+ | 1. Update the header of the makefile as needed to reflect the type of AVR programmer that you use. | ||
+ | 2. Open a terminal window and move into the directory with this file and the makefile. | ||
+ | 3. At the terminal enter | ||
+ | make clean < | ||
+ | make all < | ||
+ | make install < | ||
+ | 4. Make sure that avrdude does not report any errors. | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | |||
+ | If you a different programming environment, | ||
+ | |||
+ | |||
+ | |||
+ | | ||
+ | This code should be relatively straightforward, | ||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | * / | ||
+ | |||
+ | - include < | ||
+ | |||
+ | - define shortdelay(); | ||
+ | \ " \\ | ||
+ | "nop\ | ||
+ | \ "); | ||
+ | |||
+ | | ||
+ | int main (void) | ||
+ | { | ||
+ | uint8_t LEDs[[9]]; // Storage for current LED values | ||
+ | uint8_t rightLED[[6]], | ||
+ | | ||
+ | int8_t eyeLoc[[5]]; | ||
+ | |||
+ | uint8_t LEDBright[[4]] = {4u, | ||
+ | |||
+ | void delay_ms(uint8_t ms) { | ||
+ | |||
+ | return 0; | ||
+ | |||
+ | |||
+ | | ||
+ | | ||
+ | while (ms != 0) | ||
+ | { | ||
+ | for (i=0; i != delay_count; | ||
+ | ms--; | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | int8_t j, k, m; | ||
+ | | ||
+ | uint8_t position, loopcount, direction, initloopcount, | ||
+ | uint8_t runitout, d_base, a_base, d_mod, a_mod, far_left, far_right; | ||
+ | uint8_t ILED, RLED, MLED; // Eye position variables: Integer, Modulo, remainder | ||
+ | |||
+ | uint8_t delaytime; | ||
+ | |||
+ | uint8_t | ||
+ | unsigned int debounce2, BrightMode; | ||
+ | |||
+ | uint8_t LED0, LED1, LED2, LED3, LED4, LED5, LED6, LED7, LED8; | ||
+ | | ||
+ | // | ||
+ | MCUSR &= 0xF7; //Clear WDRF Flag | ||
+ | WDTCSR | ||
+ | WDTCSR | ||
+ | |||
+ | //Data direction register: DDR's | ||
+ | //Port A: 1 is an output, A0 is an input. | ||
+ | //Port B: 0-3 are outputs, B4 is an input. | ||
+ | //Port D: 1-6 are outputs, D0 is an input. | ||
+ | | ||
+ | DDRA = 2U; | ||
+ | DDRB = 15U; | ||
+ | DDRD = 126U; | ||
+ | | ||
+ | a_base = 3; // set a base value (resting value) for PA, to keep things easy to modify | ||
+ | d_base = 3; // set a base value (resting value) for PD, to keep things easy to modify | ||
+ | | ||
+ | PORTA = a_base; | ||
+ | PORTB = 16; // Pull-up resistor enabled, PB4 | ||
+ | PORTD = d_base; | ||
+ | | ||
+ | d_mod = 0; | ||
+ | a_mod = 0; | ||
+ | | ||
+ | /* Visualize outputs: | ||
+ | |||
+ | |||
+ | L to R: | ||
+ | D2 D3 D4 D5 D6 B0 B1 B2 B3 | ||
+ | < | ||
+ | |||
+ | (out to right) D1 --> | ||
+ | | ||
+ | * / | ||
+ | |||
+ | // Clear out all of the LED values to blank out the display | ||
+ | |||
+ | j = 0; | ||
+ | while (j < 9) { | ||
+ | LEDs[[j]] = 0; | ||
+ | j++; | ||
+ | } | ||
+ | |||
+ | LED0 = LEDs[[0]]; | ||
+ | |||
+ | LED1 = LEDs[[1]]; | ||
+ | LED2 = LEDs[[2]]; | ||
+ | LED3 = LEDs[[3]]; | ||
+ | LED4 = LEDs[[4]]; | ||
+ | LED5 = LEDs[[5]]; | ||
+ | LED6 = LEDs[[6]]; | ||
+ | LED7 = LEDs[[7]]; | ||
+ | LED8 = LEDs[[8]]; | ||
+ | | ||
+ | // | ||
+ | |||
+ | debounce = 1; | ||
+ | debounce2 = 1; | ||
+ | loopcount = 254; | ||
+ | initloopcount = 5; | ||
+ | delaytime = 0; | ||
+ | | ||
+ | direction = 0; | ||
+ | position = 0; | ||
+ | runitout = 0; | ||
+ | already_running = 0; | ||
+ | softbounce = 0; | ||
+ | far_left = 0; | ||
+ | far_right = 0; | ||
+ | speedLevel = 3; // Range: 1, 2, 3 | ||
+ | BrightMode = 0; | ||
+ | |||
+ | if ((PINB & 16) == 0) // Check if button held on startup; used to verify wiring configuration | ||
+ | { initloopcount = 0; // if so, set the startup loop counter to 0 so that we can watch the startup lights | ||
+ | softbounce = 1; // Also set the " | ||
+ | } | ||
+ | |||
+ | delay_ms(200); | ||
+ | |||
+ | PORTD = 1; //Pull D1 low, to trigger output on right side | ||
+ | |||
+ | delay_ms(10); | ||
+ | |||
+ | if ((PIND & 1) == 0) //Check to see if D1 output has latched D0 input | ||
+ | far_right = 1; //If D0 and D1 are connected, we're at the end of the chain; set far_right so we bounce back from this end | ||
+ | |||
+ | PORTD = d_base; //Set D1 high | ||
+ | |||
+ | PORTA = 1; //Pull A1 low, to trigger output on left side | ||
+ | |||
+ | delay_ms(10); | ||
+ | |||
+ | if ((PINA & 1) == 0) //Check to see if A1 output has latched A0 input | ||
+ | far_left = 1; //If A0 and A1 are connected, we're at the end of the chain; set far_left so we bounce back from this end | ||
+ | |||
+ | PORTA = a_base; //Set A1 high | ||
+ | |||
+ | |||
+ | //A little bit if visual verification to the user as to which way each end of the scanner is set | ||
+ | // (flash outwards if it's open-ended to go to the next scanner in the chain, flash inwards if it's the end and will bounce back | ||
+ | |||
+ | if (far_left) { | ||
+ | leftLED[[0]] = 7; | ||
+ | leftLED[[1]] = 11; | ||
+ | leftLED[[2]] = 19; | ||
+ | leftLED[[3]] = 19; | ||
+ | leftLED[[4]] = 19; | ||
+ | leftLED[[5]] = 19; | ||
+ | } | ||
+ | else { | ||
+ | leftLED[[0]] = 19; | ||
+ | leftLED[[1]] = 11; | ||
+ | leftLED[[2]] = 7; | ||
+ | leftLED[[3]] = 7; | ||
+ | leftLED[[4]] = 7; | ||
+ | leftLED[[5]] = 7; | ||
+ | } | ||
+ | |||
+ | if (far_right) { | ||
+ | rightLED[[0]] = 24; | ||
+ | rightLED[[1]] = 20; | ||
+ | rightLED[[2]] = 18; | ||
+ | rightLED[[3]] = 18; | ||
+ | rightLED[[4]] = 18; | ||
+ | rightLED[[5]] = 18; | ||
+ | } | ||
+ | else { | ||
+ | rightLED[[0]] = 18; | ||
+ | rightLED[[1]] = 20; | ||
+ | rightLED[[2]] = 24; | ||
+ | rightLED[[3]] = 24; | ||
+ | rightLED[[4]] = 24; | ||
+ | rightLED[[5]] = 24; | ||
+ | } | ||
+ | |||
+ | delay_ms(100); | ||
+ | * This is necessary because the clock speeds on each chip only have a 10% tolerance, and initial | ||
+ | * testing showed that the tests to configure far_left and far_right were causing | ||
+ | * " | ||
+ | */ | ||
+ | for (;;) // main loop | ||
+ | { | ||
+ | loopcount++; | ||
+ | |||
+ | if (loopcount > delaytime) | ||
+ | { | ||
+ | loopcount = 0; | ||
+ | | ||
+ | if ((PINB & 16) == 0) // Check for button press | ||
+ | { | ||
+ | if ((initloopcount >= 4) & (far_left == 1) & (already_running == 0)) | ||
+ | { | ||
+ | runitout = 1; | ||
+ | already_running = 1; | ||
+ | debounce = 0; // Start running the program, but only on the left-most unit. | ||
+ | } | ||
+ | | ||
+ | /* This is the section from the original program to let the button change the speeds and brightness. | ||
+ | debounce2++; | ||
+ | | ||
+ | if (debounce2 > 100) | ||
+ | { | ||
+ | debounce = 0; | ||
+ | | ||
+ | if (BrightMode == 0) | ||
+ | BrightMode = 1; | ||
+ | else | ||
+ | BrightMode = 0; | ||
+ | | ||
+ | } | ||
+ | | ||
+ | if (debounce) | ||
+ | { | ||
+ | speedLevel++; | ||
+ | | ||
+ | if ((speedLevel == 2) || (speedLevel == 3)) { | ||
+ | delaytime = 0; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | delaytime = 1; | ||
+ | } | ||
+ | |||
+ | debounce = 0; | ||
+ | } | ||
+ | } | ||
+ | else{ | ||
+ | debounce = 1; | ||
+ | debounce2 = 1; | ||
+ | } | ||
+ | * / | ||
+ | |||
+ | } | ||
+ | | ||
+ | if ((PINA & 1) == 0) // Check to see if display from the left has triggered to start | ||
+ | { | ||
+ | direction = 0; | ||
+ | runitout = 1; | ||
+ | } | ||
+ | | ||
+ | if ((PIND & 1) == 0) // Check to see if display from the right has triggered to start | ||
+ | { | ||
+ | direction = 1; | ||
+ | runitout = 1; | ||
+ | } | ||
+ | |||
+ | | ||
+ | if (runitout) | ||
+ | { | ||
+ | position++; | ||
+ | | ||
+ | if (speedLevel == 3) | ||
+ | position++; | ||
+ | | ||
+ | if ((softbounce == 1) & (((direction == 0) & (far_right == 1)) || ((direction == 1) & (far_left == 1))) & (position >= 224)) | ||
+ | { // this allows us to " | ||
+ | position = 15; | ||
+ | if (direction == 0) | ||
+ | direction = 1; | ||
+ | else | ||
+ | direction = 0; | ||
+ | } | ||
+ | | ||
+ | if (position >= 240) // To allow for runoff at the ends; was '== 128' | ||
+ | { | ||
+ | position = 0; | ||
+ | |||
+ | if (direction == 0) { | ||
+ | direction = 1; // we've reached the end, so go back in the other direction | ||
+ | if (far_right == 0) // If this isn't the end of the chain, we want to stop, and wait for a signal to go again | ||
+ | runitout = 0; | ||
+ | } | ||
+ | else { | ||
+ | direction = 0; | ||
+ | if (far_left == 0) // If this isn't the end of the chain, we want to stop, and wait for a signal to go again | ||
+ | runitout = 0; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if (direction == 0) // Moving to right, as viewed from front. | ||
+ | { | ||
+ | ILED = (15+position) >> 4; | ||
+ | RLED = (15+position) - (ILED << 4); | ||
+ | MLED = 15 - RLED; | ||
+ | } | ||
+ | |||
+ | else | ||
+ | { | ||
+ | ILED = (127 - position) >> 4; | ||
+ | MLED = (127 - position) | ||
+ | RLED = 15 - MLED; | ||
+ | } | ||
+ | | ||
+ | if ((ILED == 10) & (direction == 0) & (far_right == 0)) | ||
+ | d_mod = 2; // If we're heading to the right, and we're not at the end of the chain, we want to trigger D1 to start the next scanner | ||
+ | | ||
+ | j = 0; | ||
+ | while (j < 9) { | ||
+ | LEDs[[j]] = 0; | ||
+ | j++; | ||
+ | } | ||
+ | |||
+ | j = 0; | ||
+ | if ((softbounce == 1) & (((direction == 0) & (far_right == 1)) || ((direction == 1) & (far_left == 1)))) { | ||
+ | while (j < 5) { | ||
+ | | ||
+ | if (direction == 0) | ||
+ | m = ILED - (j + 1); | ||
+ | //m = ILED + (2 - j); // e.g., eyeLoc[[0]] = ILED + 2; | ||
+ | else | ||
+ | m = ILED + (j + 1); | ||
+ | //m = ILED + (j - 2); // e.g., eyeLoc[[0]] = ILED - 2; | ||
+ | | ||
+ | if ((direction == 0) & (m > 8)) | ||
+ | m = 8; | ||
+ | | ||
+ | if ((direction == 1) & (m < 0)) | ||
+ | m = 0; | ||
+ | | ||
+ | eyeLoc[[j]] = m; | ||
+ | | ||
+ | j++; | ||
+ | } | ||
+ | } | ||
+ | else { | ||
+ | while (j < 5) | ||
+ | { | ||
+ | if (direction == 0) | ||
+ | m = ILED - (j + 1); // e.g., eyeLoc[[0]] = ILED - 1; | ||
+ | else | ||
+ | m = ILED + (j + 1); // e.g., eyeLoc[[0]] = ILED + 1; | ||
+ | | ||
+ | if ((m == -1) & (direction == 1) & (far_left == 0)) | ||
+ | a_mod = 2; // If we're heading to the left, and we're not at the end of the chain, we want to trigger A1 to start the next scanner | ||
+ | | ||
+ | if (m > 8) | ||
+ | m = -1; // If eye position is past the end of the board, don't light it; set to -1 | ||
+ | | ||
+ | if (m < 0) | ||
+ | m = -1; // If eye position is past the end of the board, don't light it; set to -1 | ||
+ | | ||
+ | eyeLoc[[j]] = m; | ||
+ | | ||
+ | j++; | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | j = 0; // For each of the eye parts... | ||
+ | while (j < 4) | ||
+ | { | ||
+ | if (eyeLoc[[j]] >= 0) | ||
+ | LEDs[eyeLoc[j]] | ||
+ | if (eyeLoc[[j+1]] >= 0) | ||
+ | LEDs[eyeLoc[j+1]] += LEDBright[[j]]*MLED; | ||
+ | j++; | ||
+ | } | ||
+ | | ||
+ | LED0 = LEDs[[0]]; | ||
+ | |||
+ | LED1 = LEDs[[1]]; | ||
+ | LED2 = LEDs[[2]]; | ||
+ | LED3 = LEDs[[3]]; | ||
+ | LED4 = LEDs[[4]]; | ||
+ | LED5 = LEDs[[5]]; | ||
+ | LED6 = LEDs[[6]]; | ||
+ | LED7 = LEDs[[7]]; | ||
+ | LED8 = LEDs[[8]]; | ||
+ | } | ||
+ | else if (initloopcount < 4 ) | ||
+ | { | ||
+ | k = 0; | ||
+ | while (k < 6) { | ||
+ | PORTD = leftLED[[k]]; | ||
+ | PORTB = rightLED[[k]]; | ||
+ | delay_ms(1); | ||
+ | | ||
+ | PORTD = d_base; | ||
+ | PORTB = 16; | ||
+ | delay_ms(29); | ||
+ | |||
+ | k++; | ||
+ | } | ||
+ | delay_ms(100); | ||
+ | initloopcount++; | ||
+ | } | ||
+ | } | ||
+ | if (runitout) { | ||
+ | if (BrightMode == 0) | ||
+ | { // | ||
+ | // -> Use much less power. | ||
+ | j = 0; | ||
+ | PORTA = a_base - a_mod; // we set a_mod to correspond to A1's bit in PORTA; this makes it easier to change the pin configs later | ||
+ | while (j < 60) // Truncate brightness at a max value (60) in the interest of speed. | ||
+ | { | ||
+ | | ||
+ | if (LED0 > j) | ||
+ | PORTD = 7 - d_mod; | ||
+ | else | ||
+ | PORTD = d_base - d_mod; | ||
+ | | ||
+ | if (LED1 > j) | ||
+ | PORTD = 11 - d_mod; | ||
+ | else | ||
+ | PORTD = d_base - d_mod; | ||
+ | | ||
+ | if (LED2 > j) | ||
+ | PORTD = 19 - d_mod; | ||
+ | else | ||
+ | PORTD = d_base - d_mod; | ||
+ | | ||
+ | if (LED3 > j) | ||
+ | PORTD = 35 - d_mod; | ||
+ | else | ||
+ | PORTD = d_base - d_mod; | ||
+ | | ||
+ | if (LED4 > j) | ||
+ | PORTD = 67 - d_mod; | ||
+ | else | ||
+ | PORTD = d_base - d_mod; | ||
+ | | ||
+ | if (LED5 > j) { | ||
+ | PORTB = 17; | ||
+ | PORTD = d_base - d_mod;} | ||
+ | else { | ||
+ | PORTB = 16; | ||
+ | PORTD = d_base - d_mod;} | ||
+ | | ||
+ | if (LED6 > j) | ||
+ | PORTB = 18; | ||
+ | else | ||
+ | PORTB = 16; | ||
+ | | ||
+ | if (LED7 > j) | ||
+ | PORTB = 20; | ||
+ | else | ||
+ | PORTB = 16; | ||
+ | | ||
+ | if (LED8 > j) | ||
+ | PORTB = 24; | ||
+ | else | ||
+ | PORTB = 16; | ||
+ | |||
+ | j++; | ||
+ | // if (speedLevel == 3) | ||
+ | // j++; | ||
+ | PORTB = 16; | ||
+ | } | ||
+ | |||
+ | d_mod = 0; | ||
+ | a_mod = 0; | ||
+ | } | ||
+ | | ||
+ | | ||
+ | |||
+ | PORTA = a_base - a_mod; | ||
+ | |||
+ | j = 0; | ||
+ | while (j < 70) | ||
+ | { | ||
+ | | ||
+ | | ||
+ | pt = d_base - d_mod; | ||
+ | if (LED0 > j) | ||
+ | pt |= 4; | ||
+ | if (LED1 > j) | ||
+ | pt |= 8; | ||
+ | if (LED2 > j) | ||
+ | pt |= 16; | ||
+ | if (LED3 > j) | ||
+ | pt |= 32; | ||
+ | if (LED4 > j) | ||
+ | pt |= 64; | ||
+ | | ||
+ | PORTD = pt; | ||
+ | shortdelay(); | ||
+ | pt = 16; | ||
+ | if (LED5 > j) | ||
+ | pt |= 1; | ||
+ | if (LED6 > j) | ||
+ | pt |= 2; | ||
+ | if (LED7 > j) | ||
+ | pt |= 4; | ||
+ | if (LED8 > j) | ||
+ | pt |= 8; | ||
+ | | ||
+ | PORTB = pt; | ||
+ | shortdelay(); | ||
+ | | ||
+ | j++; | ||
+ | // if (speedLevel == 3) | ||
+ | // j++; | ||
+ | } | ||
+ | | ||
+ | d_mod = 0; // we want to stop triggering D1, so set the modifier of PORTD back to 0 | ||
+ | a_mod = 0; // we want to stop triggering A1, so set the modifier of PORTA back to 0 | ||
+ | |||
+ | } | ||
+ | } | ||
+ | |||
+ | // | ||
+ | // -> Uses much less power. | ||
+ | |||
+ | PORTA = a_base - a_mod; | ||
+ | } //End main loop | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | - endif | ||
+ | </ | ||
+ | |||
playground/playground.txt · Last modified: 2019/01/06 01:29 by 127.0.0.1