Table of contents
Abstract
This is an incredible LED Christmas Tree I made by Charlieplexing 206 LEDs. For driving the LEDs I used just an Arduino Nano. No driver IC, transistors, or resistors are used in the project. So, the circuit is very straightforward. For arranging the LEDs I laser cut an acrylic sheet and the tree is organized into 12 layers. All the layers are stacked with M3x15mm Male-to-Female Nylon hex spacers. I was inspired by the project 72LED Christmas tree made with Arduino from radio pliers.
Project
For making the Christmas tree I used 206 LEDs and a Arduino Nano. However, controlling that huge number of LEDs using a microcontroller is not an easy task. If you want to control each LED independently you will be required 206 pins microcontroller for direct connection. But there are other options and using those you can save microcontroller pins and control each LED individually. Connecting LEDs in matrix form or using shift registers are two of them. Using shift registers will increase the complexity and cost of your project. Charlieplexing is another easy and inexpensive method. I used this method for making the project. I only used 15 pins of the Arduino Nano for driving 206 LEDs. The connections are very easy and do not involve lots of wiring. The schematic diagram is as follows.
The brightness of the LEDs can be adjusted programmatically or using a potentiometer connected to the A5 pin of the Nano and this option can be altered by the switch connected to the A4 pin of the Arduino. You don't need any resistor with the LEDs as I used timer interrupt for ON/OFF the LEDs and no LED is on for a long time (40us only).
For organizing the LEDs I used a 2 mm acrylic sheet. The spacing between two pins of a 5 mm LED is 2.54 mm. So 2 mm acrylic sheet is the right selection and it fits well with the LED. I distributed the LEDs into 12 layers. For arranging LEDs in layers I laser cut the acrylic sheet in gear form. The cut sheets are shown below. The design files are attached in a zip file at the last.
At the center of the design, there is a hole that will be used for passing wires from one layer to another. Three M3 size drill holes are made in every layer for attaching one layer with the other using M3x15mm hex spacers. In layer 11 (the bottommost layer) there are 28 teeth and it gradually reduced by two towards the top.
Topmost layer has 6 LEDs. At the top, a star is placed with 5 teeth. The LED distribution is as follows:
28 -> 26 -> 24 -> 22 -> 20 -> 18 -> 16 -> 14 -> 12 -> 10 -> 8 -> 6 (Total: 204 + 2 for start)
The diameter of the bottom layer is 140mm and is gradually reduced by 10mm on every layer.
LED placement of a layer is shown in the following image. Every adjacent LED has the opposite polarity. On one side all the LED pins are soldered together with a copper wire and it looks like a ring. On the other side, two adjacent LEDs are connected with opposite polarity. Every layer has an even number of teeth.
All the layers are prepared before making the tree stacking layers one after another.
I was curious about how it is going to look after attaching all the layers. So, I arranged one after another and it looks like below without any space.
Now, it is time to attach the layers. I added two layers together using three 15mm male-to-female Nylon hex spacers. For connecting LEDs to the Arduino pins I used 24 AWG single strand insulating wire.
For the bottom layer, three additional hex spacers with a bigger gap are attached that will work as a base of the tree.
A closer look with the hex spacers attached.
The final outlook of the completed Christmas tree looks like the image below. It looks great.
I made the Arduino circuit with a switch and resistor in a perfboard.
I used male pin headers for attaching the circuit board with the LED tree.
For the programming, I used the Arduino platform and this program does not need any additional libraries. However, an understanding of timer and timer interrupt is required. Timer 2 was utilized in the sketch. For controlling every layer an uint32 value is used. The value for turning all the LEDs is as follows.
Connections of the layer LEDs with the corresponding pins are illustrated in the following screenshot. It will help you to better understand the Arduino sketch. Let me explain a little more about the connection and control bit. If we consider layer 11, there are 28 LEDs for layer 11 and the common side of the layer is connected to the D2 pin of the Nano. On the common side, the anode of 14 LEDs and the cathode of the other 14 LEDs are connected all together with the copper ring. The minus sign (-) of the above screenshot represents the cathode and the plus sign (+) represents the anode of the LED. That means the anode of the rightmost LED is connected to the D3 pin and the cathode is connected to the D2 pin. Then for the next LED, the anode is connected to the D2 pin, and the cathode is connected to the D3 pin. So, if we want to connect right most LED then D2 should be low and D3 should be high.
The Arduino sketch is given below with useful comments. The original program was written by radio pliers. I modified it as my connection and requirement. You are free to modify it and use the program.
#define OFF_TIMER 28800 // Off timer setting value (Set the time until stop in seconds. 28800=8Hr) #define BRIGHT 80 // Specify the brightness of the LED with a value of 0-100. Effective when not manually adjusting light (A4=HIGH)) #define BRIGHT_MODE_PIN 18 // Brightness setting mode switching pin (A4) If LOW, use variable resistance setting; if HIGH, use program setting value #define BRIGHTNESS_PIN 19 // Brightness setting variable resistor (A5) float bMag = 1.0; // Brightness correction magnification α during program dimming (final brightness = αx + β) float bOffset = 0.0; // Brightness correction offset β during program dimming volatile byte bSet = 0; // Brightness setting value (value set to interrupt timer, 0-240, if 0, lights off) volatile long timeElapsed; // elapsed time volatile uint32_t Ly[12]; // Display pattern memory 12 stages uint32_t Ly_a[12], Ly_b[12], Ly_c[12]; // Display pattern operation memory void setup() { Serial.begin(115200); pinMode(BRIGHT_MODE_PIN, INPUT_PULLUP); // Presence or absence of brightness setting using variable resistor (HIGH: None, LOW: Yes) pinMode(BRIGHTNESS_PIN, INPUT_PULLUP); pinMode(13, OUTPUT); timeElapsed = 0; // Elapsed time timer tc2Setup(); // Setting timer 2 (interrupt at 1ms cycle) show(10); // Dummy execution once for initialization (brightness settings) //ledTest(); // If uncommented, LED connection test (lights up one by one from the bottom) } void loop() { starSpiralUp(1); // Lights up in a spiral from bottom to top topExplosion(1); dimming(1); // dimming randomStar(2); // Random lighting for 3 seconds with argument 1 fallingRing(3); // falling ring rotateAndClimb(2); // Climb while rotating propeller(1); // propeller stackUpDown(2); // UP/DOWN swing(1); // swing verticalSlice(2); verticalCut(1); // vertical cut parallelCut(1); dimming(2); // dimming show(1000); Serial.println(timeElapsed); if (timeElapsed > OFF_TIMER) { // If the display time exceeds the set value while (1) { // Stop in an infinite loop (break out by resetting) } } } void tc2Setup() { // TC2 settings for dynamic lighting cli(); // Disable interrupts TCCR2B = 0x00; // Stop timer 2 TCCR2A = 0b00000010; // Set the mode again // |||| ++--- WGM: CTC mode, Clear TCNT2 with OCR2A // ||++------- COM2B D3 PD3 Standard port operation (OC2A disconnection) // ++--------- COM2A D11 PB3 Standard port operation (OC2B disconnection) TCCR2B = 0b00000100; // Clock setting 1/64 (speeding up to prevent flickering as the number of stages increases) // |+++--- CS:1/64 : 250kHz (4μs step) // +------ WGM02 /* // (Below is before change) TCCR2B = 0b00000101; // Clock setting 1/128 // |+++--- CS:1/128 : 125kHz (8μs step) // +------ WGM02 */ OCR2A = 250 - 1; // 250 count cycle (interrupt at 1ms cycle) OCR2B = 10 - 1; // Interrupt at 10 counts (40us) (value is provisional) TIMSK2 = 0b00000110; // ||+---- No TOIE2 overflow interrupt // |+---- OCIE2A compare match A interrupt enabled // +------ OCIE2B compare match B interrupt enabled sei(); // enable interrupts } ISR(TIMER2_COMPA_vect) { // Timer 2 A interrupt (lights up the specified LED), interrupt at 1ms cycle static int scanN = 0; // refresh position counter static int ttt = 0; // Elapsed time counter ttt++; if (ttt >= 1000) { // After 1 second ttt = 0; timeElapsed++; // Increment the display timer by 1 second (value used in auto-off timer) } if (bSet > 0) { // If the brightness setting value is 0 or more (bSet is 8 bits, so there is no need to disable interrupts) ledOff(); // Turn off all LEDs (turn off to hide behind the scenes) switch (scanN) { // Lights up the LED corresponding to the scan number (lights up in time division) case 0: d2High(); break; case 1: d3High(); break; case 2: d4High(); break; case 3: d5High(); break; case 4: d6High(); break; case 5: d7High(); break; case 6: d8High(); break; case 7: d9High(); break; case 8: d10High(); break; case 9: d11High(); break; case 10: d12High(); break; case 11: a0High(); break; case 12: a1High(); break; case 13: a2High(); break; case 14: a3High(); break; default: break; } } scanN ++; // Update scan number if (scanN >= 15) { // Return to zero if the upper limit is exceeded scanN = 0; } // scanN = 11; // force set value for debugging } ISR(TIMER2_COMPB_vect) { // Timer 2 B interrupt (turn off and brightness setting) int bSetBuff; ledOff(); // Turn off all LEDs bSetBuff = bSet; // It would be a problem if the value changed during processing, so copy it (bSet is 8 bits, so you don't need to disable interrupts) if (bSetBuff <= 0) { // If 0 or negative OCR2B = 0; // Set OCR2B to 0 (Even if you set it to 0, it will remain lit for the minimum time, so forcefully turn it off on the COMPA side) } else { // Otherwise (if greater than or equal to 1) OCR2B = bSetBuff - 1; // Set the value minus 1 } } void show(unsigned long t) { // Wait the specified time to show. Perform dimming calculation at the same time int x; delay(t); if (digitalRead(BRIGHT_MODE_PIN) == LOW) { // If brightness adjustment using variable resistor is enabled x = analogRead(BRIGHTNESS_PIN); // Read the brightness sensor value x = map(x, 0, 1023, 10, 240); // Scale ADC value to range 10-240 } else { // If you do not use a variable resistor x = map(BRIGHT, 0, 100, 10, 240); // Use the BRIGHT value of the program settings } x = x * bMag + bOffset; // Brightness correction calculation bSet = constrain(x, 0, 240); // Final brightness (used as PWM settings in interrupt routine) } void ledTest() { // LED connection test (lights up the LEDs one by one from the bottom) for (;;) { // Infinite loop (the contents are the same as starSpiralUp) Ly[11] = 0x00000004; // Plant the seeds show(300); // lights up for (int j = 0; j <= 204; j++) { // to the top spiralUp(); // spiral up show(200); // lights up } clearArray(); delay(200); } } void ledOff() { // Turn off all LEDs by port operation (set all LED pins to Low by inputting) PORTD &= B00000011; // D2-7 LOW PORTB &= B11100000; // D8-12 LOW PORTC &= B11110000; // A0-A3 Low DDRD &= B00000010; // Assign D2-7 to input (D0, D1 are serial) DDRB &= B11100000; // Assign D8-12 to input DDRC &= B11110000; // Assign A0-A3 to input } void allOn() { // Turn on all LEDs in pattern memory) Ly[0] = 0x0007E000; Ly[1] = 0x000FF000; Ly[2] = 0x001FF800; Ly[3] = 0x003FFC00; Ly[4] = 0x007FFE00; Ly[5] = 0x00FFFF00; Ly[6] = 0x01FFFF80; Ly[7] = 0x03FFFFC0; Ly[8] = 0x07FFFFE0; Ly[9] = 0x0FFFFFF0; Ly[10] = 0x1FFFFFF8; Ly[11] = 0x3FFFFFFC; } void clearArray() { // Clear pattern memory for (int i = 0; i < 12; i++) { Ly[i] = 0; Ly_a[i] = 0; Ly_b[i] = 0; Ly_c[i] = 0; } } void spiralUp() { // Spiral up Ly[0] &= 0x0007E000; // Clear outside the display area Ly[1] &= 0x000FF000; Ly[2] &= 0x001FF800; Ly[3] &= 0x003FFC00; Ly[4] &= 0x007FFE00; Ly[5] &= 0x00FFFF00; Ly[6] &= 0x01FFFF80; Ly[7] &= 0x03FFFFC0; Ly[8] &= 0x07FFFFE0; Ly[9] &= 0x0FFFFFF0; Ly[10] &= 0x1FFFFFF8; Ly[11] &= 0x3FFFFFFC; Ly[0] = Ly[0] << 1; if (Ly[1] & 0x00020000) Ly[0] |= 0x00008000; // If the left end of Ly[1] is 1, set the right end of Ly[0] to 1 Ly[1] = Ly[1] << 1; if (Ly[2] & 0x00040000) Ly[1] |= 0x00004000; // If the left end of Ly[2] is 1, set the right end of Ly[1] to 1 Ly[2] = Ly[2] << 1; if (Ly[3] & 0x00080000) Ly[2] |= 0x00002000; // If the left end of Ly[3] is 1, set the right end of Ly[2] to 1 Ly[3] = Ly[3] << 1; if (Ly[4] & 0x00100000) Ly[3] |= 0x00001000; // If the left end of Ly[4] is 1, set the right end of Ly[3] to 1 Ly[4] = Ly[4] << 1; if (Ly[5] & 0x00200000) Ly[4] |= 0x00000800; // If the left end of Ly[5] is 1, set the right end of Ly[4] to 1 Ly[5] = Ly[5] << 1; if (Ly[6] & 0x00400000) Ly[5] |= 0x00000400; // If the left end of Ly[6] is 1, set the right end of Ly[5] to 1 Ly[6] = Ly[6] << 1; if (Ly[7] & 0x00800000) Ly[6] |= 0x00000200; // If the left end of Ly[7] is 1, set the right end of Ly[6] to 1 Ly[7] = Ly[7] << 1; if (Ly[8] & 0x01000000) Ly[7] |= 0x00000100; // If the left end of Ly[8] is 1, set the right end of Ly[7] to 1 Ly[8] = Ly[8] << 1; if (Ly[9] & 0x02000000) Ly[8] |= 0x00000080; // If the left end of Ly[9] is 1, set the right end of Ly[8] to 1 Ly[9] = Ly[9] << 1; if (Ly[10] & 0x04000000) Ly[9] |= 0x00000040; // If the left end of Ly[10] is 1, set the right end of Ly[9] to 1 Ly[10] = Ly[10] << 1; if (Ly[11] & 0x08000000) Ly[10] |= 0x00000020; // If the left end of Ly[11] is 1, set the right end of Ly[10] to 1 Ly[11] = Ly[11] << 1; } void starSpiralUp(int n) { // Light up the LEDs one by one from bottom to top while rotating for (int i = 0; i < n; i++) { // specified number of times Ly[11] = 0x00000020; // Put the seeds at the bottom show(20); // for (int j = 0; j <= 204; j++) { // to the top spiralUp(); // spiral up show(20); // lights up } clearArray(); delay(200); } } void topExplosion(int c) { // Explosion at the tip for (int n = 0; n < c; n++) { // specified number of times clearArray(); for (int i = 0; i < 12; i++) { Ly[i] = 0xFFFFFFFF; // Lights from top to bottom show(30); // Wait } } delay(500); // Wait for a while with all lights on } void randomStar(int n) { // Light up randomly for (int i = 0; i < n; i++) { // number of times specified by argument for (int j = 0; j < 40; j++) { // 6 seconds (0.15 seconds x 40 times) Ly[0] |= 0x00018000; // The two tips are always lit Ly[1] = random(0, 0xFFFFFFF) & random(0, 0xFFFFFFF); // Lights up with probability 1/4 Ly[2] = random(0, 0xFFFFFFF) & random(0, 0xFFFFFFF); // It didn't work when I set the upper limit of random numbers to the full 32 bits, so I kept it at 28 bits. Ly[3] = random(0, 0xFFFFFFF) & random(0, 0xFFFFFFF); Ly[4] = random(0, 0xFFFFFFF) & random(0, 0xFFFFFFF); Ly[5] = random(0, 0xFFFFFFF) & random(0, 0xFFFFFFF); Ly[6] = random(0, 0xFFFFFFF) & random(0, 0xFFFFFFF); Ly[7] = random(0, 0xFFFFFFF) & random(0, 0xFFFFFFF); Ly[8] = random(0, 0xFFFFFFF) & random(0, 0xFFFFFFF); Ly[9] = random(0, 0xFFFFFFF) & random(0, 0xFFFFFFF); Ly[10] = random(0, 0xFFFFFFF) & random(0, 0xFFFFFFF); Ly[11] = random(0, 0xFFFFFFF) & random(0, 0xFFFFFFF); show(150); } } // n clearArray(); show(1000); } void dimming(int c) { // Slowly brightening and dimming float x, ratio; bMag = 0.0; // Set light intensity to zero show(10); // Reflect the brightness setting value allOn(); // All lights on x = OCR2B; // Record the starting brightness ratio = pow(2.0 * x, 1.0 / 40.0); // Calculate the brightness increase ratio to double the brightness for (int j = 0; j < c; j++) { // specified number of times bMag = 1.0/x; for (int i = 0; i <= 40; i++) { // Brightening in a geometric series bMag *= ratio; // Correct the value show(30); } for (int i = 40; i >= 0; i--) { // dimming bMag /= ratio; show(30); } show(100); } clearArray(); // Clear pattern memory bMag = 1.0; // Return brightness correction coefficient to default // show(500); // Turns off finally } void fallingRing(int c) { // Drop the ring from above for (int n = 0; n < c; n++) { // specified number of times clearArray(); Ly[0] = 0xFFFFFFFF; // Put the story at the beginning show(100); // Wait a moment to show for (int i = 0; i < 11; i++) { Ly[i + 1] = Ly[i]; // Shift backward (down) Ly[i] = 0; show(70); // Wait } } clearArray(); // Turns off at the end delay(200); } void rotateAndClimb(int n) { // Climb while rotating clearArray(); for (int i = 0; i < n; i++) { // specified number of times for (int j = 0; j < 200; j++) { if ( (j % 18) > 8) { // every 8th time, Ly[11] |= 0x00000004; // Embed a star at the bottom } else { Ly[11] &= ~0x00000004; // Erase the star } show(40); spiralUp(); } for (int j = 0; j < 204; j++) { Ly[11] &= ~0x00000004; show(40); spiralUp(); } } clearArray(); delay(500); } void propeller(int n) { // Propeller display int a; for (int i = 0; i < n; i++) { // Repeat the number of times specified by the argument for (a = 0; a < 1680 * 2; a += 7) { // Forward rotation (1680 is the least common multiple of 16,14,12,10) invertV(a); // Display an inverted V shape at the specified angle show(5); } for (a = 1680 * 2; a > 0; a -= 7) { // Reverse rotation invertV(a); show(5); } } delay(300); } void invertV(int k) { // Lights up in an inverted V shape at the specified angle (half turn with argument 840) Ly[0] = 0b00000000000000011000000000000000; // The top two are always lit Ly[1] = 0b00000000000000101000000000000000 >> ((k / 420) % 2); // Move the V-shaped pattern to the specified angle Ly[2] = 0b00000000000001001000000000000000 >> ((k / 280) % 3); // Note that 840 is the least common multiple of 8,7,6,5,4,3,2 Ly[3] = 0b00000000000010001000000000000000 >> ((k / 210) % 4); Ly[4] = 0b00000000000100001000000000000000 >> ((k / 168) % 5); Ly[5] = 0b00000000001000001000000000000000 >> ((k / 140) % 6); Ly[6] = 0b00000000010000001000000000000000 >> ((k / 120) % 7); Ly[7] = 0b00000000100000001000000000000000 >> ((k / 105) % 8); Ly[8] = 0b00000001000000001000000000000000 >> ((k / 93) % 9); // Ly[9] = 0b00000010000000001000000000000000 >> ((k / 84) % 10); Ly[10] = 0b00000100000000001000000000000000 >> ((k / 76) % 11); Ly[11] = 0b00001000000000001000000000000000 >> ((k / 70) % 12); } void stackUpDown(int n) { // Turns on when stacking, turns off when stacking down for (int i = 0; i < n; i++) { for (int z = 11; z >= 0; z--) { // Stack lights from bottom to top Ly[z] = 0xFFFFFFFF; show(30); } show(200); // Wait for a while with all lights on for (int z = 11; z >= 0; z--) { // turn off from bottom to top Ly[z] = 0x0000; show(30); } show(200); // Wait for a while with all lights off for (int z = 0; z <= 11; z++) { // Light stacked upside down from top to bottom Ly[z] = 0xFFFFFFFF; show(30); } show(200); // Wait for a while with all lights on for (int z = 0; z <= 11; z++) { // Turn off from top to bottom Ly[z] = 0x0000; show(30); } show(300); // Wait for a while with all lights off } // repeat n times } void swing(int n) { // Move diagonal line to the right for (int i = 0; i < n; i++) { // specified number of times for (int j = 0; j < 1; j++) { // 1 time for left rotation Ly[0] = 0x00010000; // Draw a diagonal line on the left side Ly[1] = 0x00020000; Ly[2] = 0x00040000; Ly[3] = 0x00080000; Ly[4] = 0x00100000; Ly[5] = 0x00200000; Ly[6] = 0x00400000; Ly[7] = 0x00800000; Ly[8] = 0x01000000; Ly[9] = 0x02000000; Ly[10] = 0x04000000; Ly[11] = 0x08000000; for (int k = 0; k < 22; k++) { // 22 times for (int m = 0; m < 12; m++) { // for each layer Ly[m] = Ly[m] >> 1; // Shift the image to the right } show(50); // Wait for display } } show(200); for (int j = 0; j < 1; j++) { // 1 time for right rotation Ly[0] = 0x00008000; // Draw a diagonal line on the right side Ly[1] = 0x00004000; Ly[2] = 0x00002000; Ly[3] = 0x00001000; Ly[4] = 0x00000800; Ly[5] = 0x00000400; Ly[6] = 0x00000200; Ly[7] = 0x00000100; Ly[8] = 0x00000080; Ly[9] = 0x00000040; Ly[10] = 0x00000020; Ly[11] = 0x00000010; for (int k = 0; k < 22; k++) { // 22 times for (int m = 0; m < 12; m++) { Ly[m] = Ly[m] << 1; // Shift the image to the right } show(50); // Wait for display } } show(200); for (int j = 0; j < 1; j++) { // once with cross swing Ly_a[0] = 0x00010000; Ly_b[0] = 0x00008000; // Add diagonal lines on both sides Ly_a[1] = 0x00020000; Ly_b[1] = 0x00004000; Ly_a[2] = 0x00040000; Ly_b[2] = 0x00002000; Ly_a[3] = 0x00080000; Ly_b[3] = 0x00001000; Ly_a[4] = 0x00100000; Ly_b[4] = 0x00000800; Ly_a[5] = 0x00200000; Ly_b[5] = 0x00000400; Ly_a[6] = 0x00400000; Ly_b[6] = 0x00000200; Ly_a[7] = 0x00800000; Ly_b[7] = 0x00000100; Ly_a[8] = 0x01000000; Ly_b[8] = 0x00000080; Ly_a[9] = 0x02000000; Ly_b[9] = 0x00000040; Ly_a[10] = 0x04000000; Ly_b[10] = 0x00000020; Ly_a[11] = 0x08000000; Ly_b[11] = 0x00000010; for (int k = 0; k < 22; k++) { // 22 times for (int m = 0; m < 12; m++) { Ly_a[m] = Ly_a[m] >> 1; // Shift the image of a buffer to the right } for (int m = 0; m < 12; m++) { Ly_b[m] = Ly_b[m] << 1; // Shift the image of b buffer to the left } for (int m = 0; m < 12; m++) { Ly[m] = Ly_a[m] | Ly_b[m]; // Synthesize into display memory } show(50); // Wait for display } } show(300); } } void verticalCut(int n) { // Vertical cut to turn on and off horizontally clearArray(); for (int i = 0; i < n; i++) { // specified number of times vSliceTogle(1); cutShow(); // Lights from right to left vSliceTogle(2); cutShow(); vSliceTogle(3); cutShow(); vSliceTogle(4); cutShow(); vSliceTogle(5); cutShow(); vSliceTogle(6); cutShow(); vSliceTogle(7); cutShow(); vSliceTogle(8); cutShow(); vSliceTogle(9); cutShow(); vSliceTogle(10); cutShow(); vSliceTogle(11); cutShow(); vSliceTogle(12); // All lights on show(500); vSliceTogle(1); cutShow(); // Turn off from right to left (reverse with XOR) vSliceTogle(2); cutShow(); vSliceTogle(3); cutShow(); vSliceTogle(4); cutShow(); vSliceTogle(5); cutShow(); vSliceTogle(6); cutShow(); vSliceTogle(7); cutShow(); vSliceTogle(8); cutShow(); vSliceTogle(9); cutShow(); vSliceTogle(10); cutShow(); vSliceTogle(11); cutShow(); vSliceTogle(12); cutShow(); show(500); // Turn off all lights vSliceTogle(12); cutShow(); // Lights from left to right vSliceTogle(11); cutShow(); vSliceTogle(10); cutShow(); vSliceTogle(9); cutShow(); vSliceTogle(8); cutShow(); vSliceTogle(7); cutShow(); vSliceTogle(6); cutShow(); vSliceTogle(5); cutShow(); vSliceTogle(4); cutShow(); vSliceTogle(3); cutShow(); vSliceTogle(2); cutShow(); vSliceTogle(1); cutShow(); show(500); // All lights on vSliceTogle(12); cutShow(); // Turns off from left to right vSliceTogle(11); cutShow(); vSliceTogle(10); cutShow(); vSliceTogle(9); cutShow(); vSliceTogle(8); cutShow(); vSliceTogle(7); cutShow(); vSliceTogle(6); cutShow(); vSliceTogle(5); cutShow(); vSliceTogle(4); cutShow(); vSliceTogle(3); cutShow(); vSliceTogle(2); cutShow(); vSliceTogle(1); cutShow(); show(500); // Turn off all lights clearArray(); } } void parallelCut(int n) { // Vertical cut to turn on and off horizontally clearArray(); for (int i = 0; i < n; i++) { // specified number of times vSliceTogle(1); vSliceTogle(12); cutShow(); vSliceTogle(2); vSliceTogle(11); cutShow(); vSliceTogle(3); vSliceTogle(10); cutShow(); vSliceTogle(4); vSliceTogle(9); cutShow(); vSliceTogle(5); vSliceTogle(8); cutShow(); vSliceTogle(6); vSliceTogle(7); show(1000); vSliceTogle(1); vSliceTogle(12); cutShow(); vSliceTogle(2); vSliceTogle(11); cutShow(); vSliceTogle(3); vSliceTogle(10); cutShow(); vSliceTogle(4); vSliceTogle(9); cutShow(); vSliceTogle(5); vSliceTogle(8); cutShow(); vSliceTogle(6); vSliceTogle(7); show(1000); clearArray(); } } void verticalSlice(int n) { clearArray(); for (int i = 0; i < n; i++) { // specified number of times vSliceTogle(1); cutShow(); vSliceTogle(1); vSliceTogle(2); cutShow(); // Move slice from right to left vSliceTogle(2); vSliceTogle(3); cutShow(); vSliceTogle(3); vSliceTogle(4); cutShow(); vSliceTogle(4); vSliceTogle(5); cutShow(); vSliceTogle(5); vSliceTogle(6); cutShow(); vSliceTogle(6); vSliceTogle(7); cutShow(); vSliceTogle(7); vSliceTogle(8); cutShow(); vSliceTogle(8); vSliceTogle(9); cutShow(); vSliceTogle(9); vSliceTogle(10); cutShow(); vSliceTogle(10); vSliceTogle(11); cutShow(); vSliceTogle(11); vSliceTogle(12); cutShow(); vSliceTogle(12); delay(200); vSliceTogle(12); cutShow(); vSliceTogle(12); vSliceTogle(11); cutShow(); // left to right vSliceTogle(11); vSliceTogle(10); cutShow(); vSliceTogle(10); vSliceTogle(9); cutShow(); vSliceTogle(9); vSliceTogle(8); cutShow(); vSliceTogle(8); vSliceTogle(7); cutShow(); vSliceTogle(7); vSliceTogle(6); cutShow(); vSliceTogle(6); vSliceTogle(5); cutShow(); vSliceTogle(5); vSliceTogle(4); cutShow(); vSliceTogle(4); vSliceTogle(3); cutShow(); vSliceTogle(3); vSliceTogle(2); cutShow(); vSliceTogle(2); vSliceTogle(1); cutShow(); vSliceTogle(1); delay(400); } } void cutShow() { // Wait for the specified time (source shortening measure) show(50); } void vSliceTogle(int n) { // Invert the specified column (invert the bits vertically using XOR) switch (n) { case 1: Ly[11] ^= 0b00000000000000000000010000000000; break; case 2: Ly[8] ^= 0b00000000000000000000100000000000; Ly[9] ^= 0b00000000000000000000110000000000; Ly[10] ^= 0b00000000000000000000101000000000; Ly[11] ^= 0b00000000000000000000100100000000; break; case 3: Ly[6] ^= 0b00000000000000000001000000000000; Ly[7] ^= 0b00000000000000000001100000000000; Ly[8] ^= 0b00000000000000000001010000000000; Ly[9] ^= 0b00000000000000000001001000000000; Ly[10] ^= 0b00000000000000000001000100000000; Ly[11] ^= 0b00000000000000000001000010000000; break; case 4: Ly[4] ^= 0b00000000000000000010000000000000; Ly[5] ^= 0b00000000000000000011000000000000; Ly[6] ^= 0b00000000000000000010100000000000; Ly[7] ^= 0b00000000000000000010010000000000; Ly[8] ^= 0b00000000000000000010001000000000; Ly[9] ^= 0b00000000000000000010000100000000; Ly[10] ^= 0b00000000000000000010000010000000; Ly[11] ^= 0b00000000000000000010000001000000; break; case 5: Ly[2] ^= 0b00000000000000000100000000000000; Ly[3] ^= 0b00000000000000000110000000000000; Ly[4] ^= 0b00000000000000000101000000000000; Ly[5] ^= 0b00000000000000000100100000000000; Ly[6] ^= 0b00000000000000000100010000000000; Ly[7] ^= 0b00000000000000000100001000000000; Ly[8] ^= 0b00000000000000000100000100000000; Ly[9] ^= 0b00000000000000000100000010000000; Ly[10] ^= 0b00000000000000000100000001000000; Ly[11] ^= 0b00000000000000000100000000100000; break; case 6: Ly[0] ^= 0b00000000000000001000000000000000; Ly[1] ^= 0b00000000000000001100000000000000; Ly[2] ^= 0b00000000000000001010000000000000; Ly[3] ^= 0b00000000000000001001000000000000; Ly[4] ^= 0b00000000000000001000100000000000; Ly[5] ^= 0b00000000000000001000010000000000; Ly[6] ^= 0b00000000000000001000001000000000; Ly[7] ^= 0b00000000000000001000000100000000; Ly[8] ^= 0b00000000000000001000000010000000; Ly[9] ^= 0b00000000000000001000000001000000; Ly[10] ^= 0b00000000000000001000000000100000; Ly[11] ^= 0b00000000000000001000000000010000; break; case 7: Ly[0] ^= 0b00000000000000010000000000000000; Ly[1] ^= 0b00000000000000110000000000000000; Ly[2] ^= 0b00000000000001010000000000000000; Ly[3] ^= 0b00000000000010010000000000000000; Ly[4] ^= 0b00000000000100010000000000000000; Ly[5] ^= 0b00000000001000010000000000000000; Ly[6] ^= 0b00000000010000010000000000000000; Ly[7] ^= 0b00000000100000010000000000000000; Ly[8] ^= 0b00000001000000010000000000000000; Ly[9] ^= 0b00000010000000010000000000000000; Ly[10] ^= 0b00000100000000010000000000000000; Ly[11] ^= 0b00001000000000010000000000000000; break; case 8: Ly[2] ^= 0b00000000000000100000000000000000; Ly[3] ^= 0b00000000000001100000000000000000; Ly[4] ^= 0b00000000000010100000000000000000; Ly[5] ^= 0b00000000000100100000000000000000; Ly[6] ^= 0b00000000001000100000000000000000; Ly[7] ^= 0b00000000010000100000000000000000; Ly[8] ^= 0b00000000100000100000000000000000; Ly[9] ^= 0b00000001000000100000000000000000; Ly[10] ^= 0b00000010000000100000000000000000; Ly[11] ^= 0b00000100000000100000000000000000; break; case 9: Ly[4] ^= 0b00000000000001000000000000000000; Ly[5] ^= 0b00000000000011000000000000000000; Ly[6] ^= 0b00000000000101000000000000000000; Ly[7] ^= 0b00000000001001000000000000000000; Ly[8] ^= 0b00000000010001000000000000000000; Ly[9] ^= 0b00000000100001000000000000000000; Ly[10] ^= 0b00000001000001000000000000000000; Ly[11] ^= 0b00000010000001000000000000000000; break; case 10: Ly[6] ^= 0b00000000000010000000000000000000; Ly[7] ^= 0b00000000000110000000000000000000; Ly[8] ^= 0b00000000001010000000000000000000; Ly[9] ^= 0b00000000010010000000000000000000; Ly[10] ^= 0b00000000100010000000000000000000; Ly[11] ^= 0b00000001000010000000000000000000; break; case 11: Ly[8] ^= 0b00000000000100000000000000000000; Ly[9] ^= 0b00000000001100000000000000000000; Ly[10] ^= 0b00000000010100000000000000000000; Ly[11] ^= 0b00000000100100000000000000000000; break; case 12: Ly[11] ^= 0b00000000001000000000000000000000; break; default: break; } } // Light up the corresponding LED with Charlie Plexing // corresponding DDR bit is 1 for OUTPUT void d2High() { // Output High from D2 and light the specified LED (turn the other port Low) if ( Ly[11] & 0x10000000 ) DDRD |= B00001000; // D3 if ( Ly[11] & 0x04000000 ) DDRD |= B00010000; // D4 if ( Ly[11] & 0x01000000 ) DDRD |= B00100000; // D5 if ( Ly[11] & 0x00400000 ) DDRD |= B01000000; // D6 if ( Ly[11] & 0x00100000 ) DDRD |= B10000000; // D7 if ( Ly[11] & 0x00040000 ) DDRB |= B00000001; // D8 if ( Ly[11] & 0x00010000 ) DDRB |= B00000010; // D9 if ( Ly[11] & 0x00004000 ) DDRB |= B00000100; // D10 if ( Ly[11] & 0x00001000 ) DDRB |= B00001000; // D11 if ( Ly[11] & 0x00000400 ) DDRB |= B00010000; // D12 if ( Ly[11] & 0x00000100 ) DDRC |= B00000001; // A0 if ( Ly[11] & 0x00000040 ) DDRC |= B00000010; // A1 if ( Ly[11] & 0x00000010 ) DDRC |= B00000100; // A2 if ( Ly[11] & 0x00000004 ) DDRC |= B00001000; // A3 DDRD |= B00000100; // Assign D2 to output PORTD |= B00000100; // D2 High. Now turn on the LED (do this last to minimize the amount of light) } void d3High() { // Output High from D3 and light the specified LED if ( Ly[11] & 0x20000000 ) DDRD |= B00000100; // D2 if ( Ly[10] & 0x08000000 ) DDRD |= B00010000; // D4 if ( Ly[10] & 0x02000000 ) DDRD |= B00100000; // D5 if ( Ly[10] & 0x00800000 ) DDRD |= B01000000; // D6 if ( Ly[10] & 0x00200000 ) DDRD |= B10000000; // D7 if ( Ly[10] & 0x00080000 ) DDRB |= B00000001; // D8 if ( Ly[10] & 0x00020000 ) DDRB |= B00000010; // D9 if ( Ly[10] & 0x00008000 ) DDRB |= B00000100; // D10 if ( Ly[10] & 0x00002000 ) DDRB |= B00001000; // D11 if ( Ly[10] & 0x00000800 ) DDRB |= B00010000; // D12 if ( Ly[10] & 0x00000200 ) DDRC |= B00000001; // A0 if ( Ly[10] & 0x00000080 ) DDRC |= B00000010; // A1 if ( Ly[10] & 0x00000020 ) DDRC |= B00000100; // A2 if ( Ly[10] & 0x00000008 ) DDRC |= B00001000; // A3 DDRD |= B00001000; // Assign D3 to output PORTD |= B00001000; // Set D3 to High (LED will light up) } void d4High() { // Output High from D4 and light the specified LED if ( Ly[11] & 0x08000000 ) DDRD |= B00000100; // D2 if ( Ly[10] & 0x10000000 ) DDRD |= B00001000; // D3 if ( Ly[9] & 0x04000000 ) DDRD |= B00100000; // D5 if ( Ly[9] & 0x01000000 ) DDRD |= B01000000; // D6 if ( Ly[9] & 0x00400000 ) DDRD |= B10000000; // D7 if ( Ly[9] & 0x00100000 ) DDRB |= B00000001; // D8 if ( Ly[9] & 0x00040000 ) DDRB |= B00000010; // D9 if ( Ly[9] & 0x00010000 ) DDRB |= B00000100; // D10 if ( Ly[9] & 0x00004000 ) DDRB |= B00001000; // D11 if ( Ly[9] & 0x00001000 ) DDRB |= B00010000; // D12 if ( Ly[9] & 0x00000400 ) DDRC |= B00000001; // A0 if ( Ly[9] & 0x00000100 ) DDRC |= B00000010; // A1 if ( Ly[9] & 0x00000040 ) DDRC |= B00000100; // A2 if ( Ly[9] & 0x00000010 ) DDRC |= B00001000; // A3 DDRD |= B00010000; // Assign D4 to output PORTD |= B00010000; // Set D4 to High (LED will light up) } void d5High() { // Output High from D5 and light the specified LED if ( Ly[11] & 0x02000000 ) DDRD |= B00000100; // D2 if ( Ly[10] & 0x04000000 ) DDRD |= B00001000; // D3 if ( Ly[9] & 0x08000000 ) DDRD |= B00010000; // D4 if ( Ly[8] & 0x02000000 ) DDRD |= B01000000; // D6 if ( Ly[8] & 0x00800000 ) DDRD |= B10000000; // D7 if ( Ly[8] & 0x00200000 ) DDRB |= B00000001; // D8 if ( Ly[8] & 0x00080000 ) DDRB |= B00000010; // D9 if ( Ly[8] & 0x00020000 ) DDRB |= B00000100; // D10 if ( Ly[8] & 0x00008000 ) DDRB |= B00001000; // D11 if ( Ly[8] & 0x00002000 ) DDRB |= B00010000; // D12 if ( Ly[8] & 0x00000800 ) DDRC |= B00000001; // A0 if ( Ly[8] & 0x00000200 ) DDRC |= B00000010; // A1 if ( Ly[8] & 0x00000080 ) DDRC |= B00000100; // A2 if ( Ly[8] & 0x00000020 ) DDRC |= B00001000; // A3 DDRD |= B00100000; // Assign D5 to output PORTD |= B00100000; // Set D5 to High (LED will light up) } void d6High() { // Output High from D6 and light the specified LED if ( Ly[11] & 0x00800000 ) DDRD |= B00000100; // D2 if ( Ly[10] & 0x01000000 ) DDRD |= B00001000; // D3 if ( Ly[9] & 0x02000000 ) DDRD |= B00010000; // D4 if ( Ly[8] & 0x04000000 ) DDRD |= B00100000; // D5 if ( Ly[7] & 0x01000000 ) DDRD |= B10000000; // D7 if ( Ly[7] & 0x00400000 ) DDRB |= B00000001; // D8 if ( Ly[7] & 0x00100000 ) DDRB |= B00000010; // D9 if ( Ly[7] & 0x00040000 ) DDRB |= B00000100; // D10 if ( Ly[7] & 0x00010000 ) DDRB |= B00001000; // D11 if ( Ly[7] & 0x00004000 ) DDRB |= B00010000; // D12 if ( Ly[7] & 0x00001000 ) DDRC |= B00000001; // A0 if ( Ly[7] & 0x00000400 ) DDRC |= B00000010; // A1 if ( Ly[7] & 0x00000100 ) DDRC |= B00000100; // A2 if ( Ly[7] & 0x00000040 ) DDRC |= B00001000; // A3 DDRD |= B01000000; // Assign D6 to output PORTD |= B01000000; // Set D6 to High (LED will light up) } void d7High() { // Output High from D7 and light the specified LED if ( Ly[11] & 0x00200000 ) DDRD |= B00000100; // D2 if ( Ly[10] & 0x00400000 ) DDRD |= B00001000; // D3 if ( Ly[9] & 0x00800000 ) DDRD |= B00010000; // D4 if ( Ly[8] & 0x01000000 ) DDRD |= B00100000; // D5 if ( Ly[7] & 0x02000000 ) DDRD |= B01000000; // D6 if ( Ly[6] & 0x00800000 ) DDRB |= B00000001; // D8 if ( Ly[6] & 0x00200000 ) DDRB |= B00000010; // D9 if ( Ly[6] & 0x00080000 ) DDRB |= B00000100; // D10 if ( Ly[6] & 0x00020000 ) DDRB |= B00001000; // D11 if ( Ly[6] & 0x00008000 ) DDRB |= B00010000; // D12 if ( Ly[6] & 0x00002000 ) DDRC |= B00000001; // A0 if ( Ly[6] & 0x00000800 ) DDRC |= B00000010; // A1 if ( Ly[6] & 0x00000200 ) DDRC |= B00000100; // A2 if ( Ly[6] & 0x00000080 ) DDRC |= B00001000; // A3 DDRD |= B10000000; // Assign D7 to output PORTD |= B10000000; // Set D7 to High (LED will light up) } void d8High() { // Output High from D8 and light the specified LED if ( Ly[11] & 0x00080000 ) DDRD |= B00000100; // D2 if ( Ly[10] & 0x00100000 ) DDRD |= B00001000; // D3 if ( Ly[9] & 0x00200000 ) DDRD |= B00010000; // D4 if ( Ly[8] & 0x00400000 ) DDRD |= B00100000; // D5 if ( Ly[7] & 0x00800000 ) DDRD |= B01000000; // D6 if ( Ly[6] & 0x01000000 ) DDRD |= B10000000; // D7 if ( Ly[5] & 0x00800000 ) DDRB |= B00000010; // D9 if ( Ly[5] & 0x00200000 ) DDRB |= B00000100; // D10 if ( Ly[5] & 0x00080000 ) DDRB |= B00001000; // D11 if ( Ly[5] & 0x00020000 ) DDRB |= B00010000; // D12 if ( Ly[5] & 0x00008000 ) DDRC |= B00000001; // A0 if ( Ly[5] & 0x00002000 ) DDRC |= B00000010; // A1 if ( Ly[5] & 0x00000800 ) DDRC |= B00000100; // A2 if ( Ly[5] & 0x00000200 ) DDRC |= B00001000; // A3 DDRB |= B00000001; // Assign D8 to output PORTB |= B00000001; // Set D8 to High (LED will light up) } void d9High() { // Output High from D9 and light the specified LED if ( Ly[11] & 0x00020000 ) DDRD |= B00000100; // D2 if ( Ly[10] & 0x00040000 ) DDRD |= B00001000; // D3 if ( Ly[9] & 0x00080000 ) DDRD |= B00010000; // D4 if ( Ly[8] & 0x00100000 ) DDRD |= B00100000; // D5 if ( Ly[7] & 0x00200000 ) DDRD |= B01000000; // D6 if ( Ly[6] & 0x00400000 ) DDRD |= B10000000; // D7 if ( Ly[5] & 0x00400000 ) DDRB |= B00000001; // D8 if ( Ly[4] & 0x00400000 ) DDRB |= B00000100; // D10 if ( Ly[4] & 0x00100000 ) DDRB |= B00001000; // D11 if ( Ly[4] & 0x00040000 ) DDRB |= B00010000; // D12 if ( Ly[4] & 0x00010000 ) DDRC |= B00000001; // A0 if ( Ly[4] & 0x00004000 ) DDRC |= B00000010; // A1 if ( Ly[4] & 0x00001000 ) DDRC |= B00000100; // A2 if ( Ly[4] & 0x00000400 ) DDRC |= B00001000; // A3 DDRB |= B00000010; // Assign D9 to output PORTB |= B00000010; // Set D9 to High (LED will light up) } void d10High() { // Output High from D10 and light the specified LED if ( Ly[11] & 0x00008000 ) DDRD |= B00000100; // D2 if ( Ly[10] & 0x00010000 ) DDRD |= B00001000; // D3 if ( Ly[9] & 0x00020000 ) DDRD |= B00010000; // D4 if ( Ly[8] & 0x00040000 ) DDRD |= B00100000; // D5 if ( Ly[7] & 0x00080000 ) DDRD |= B01000000; // D6 if ( Ly[6] & 0x00100000 ) DDRD |= B10000000; // D7 if ( Ly[5] & 0x00100000 ) DDRB |= B00000001; // D8 if ( Ly[4] & 0x00200000 ) DDRB |= B00000010; // D9 if ( Ly[3] & 0x00200000 ) DDRB |= B00001000; // D11 if ( Ly[3] & 0x00080000 ) DDRB |= B00010000; // D12 if ( Ly[3] & 0x00020000 ) DDRC |= B00000001; // A0 if ( Ly[3] & 0x00008000 ) DDRC |= B00000010; // A1 if ( Ly[3] & 0x00002000 ) DDRC |= B00000100; // A2 if ( Ly[3] & 0x00000800 ) DDRC |= B00001000; // A3 DDRB |= B00000100; // Assign D10 to output PORTB |= B00000100; // Set D10 to High (LED will light up) } void d11High() { // Output High from D11 and light the specified LED if ( Ly[11] & 0x00002000 ) DDRD |= B00000100; // D2 if ( Ly[10] & 0x00004000 ) DDRD |= B00001000; // D3 if ( Ly[9] & 0x00008000 ) DDRD |= B00010000; // D4 if ( Ly[8] & 0x00010000 ) DDRD |= B00100000; // D5 if ( Ly[7] & 0x00020000 ) DDRD |= B01000000; // D6 if ( Ly[6] & 0x00040000 ) DDRD |= B10000000; // D7 if ( Ly[5] & 0x00040000 ) DDRB |= B00000001; // D8 if ( Ly[4] & 0x00080000 ) DDRB |= B00000010; // D9 if ( Ly[3] & 0x00100000 ) DDRB |= B00000100; // D10 if ( Ly[2] & 0x00080000 ) DDRB |= B00010000; // D12 if ( Ly[2] & 0x00020000 ) DDRC |= B00000001; // A0 if ( Ly[2] & 0x00008000 ) DDRC |= B00000010; // A1 if ( Ly[2] & 0x00002000 ) DDRC |= B00000100; // A2 if ( Ly[2] & 0x00000800 ) DDRC |= B00001000; // A3 DDRB |= B00001000; // Assign D11 to output PORTB |= B00001000; // Set D11 to High (LED will light up) } void d12High() { // Output High from D12 and light the specified LED if ( Ly[11] & 0x00000800 ) DDRD |= B00000100; // D2 if ( Ly[10] & 0x00001000 ) DDRD |= B00001000; // D3 if ( Ly[9] & 0x00002000 ) DDRD |= B00010000; // D4 if ( Ly[8] & 0x00004000 ) DDRD |= B00100000; // D5 if ( Ly[7] & 0x00008000 ) DDRD |= B01000000; // D6 if ( Ly[6] & 0x00010000 ) DDRD |= B10000000; // D7 if ( Ly[5] & 0x00010000 ) DDRB |= B00000001; // D8 if ( Ly[4] & 0x00020000 ) DDRB |= B00000010; // D9 if ( Ly[3] & 0x00040000 ) DDRB |= B00000100; // D10 if ( Ly[2] & 0x00100000 ) DDRB |= B00001000; // D11 if ( Ly[1] & 0x00080000 ) DDRC |= B00000001; // A0 if ( Ly[1] & 0x00020000 ) DDRC |= B00000010; // A1 if ( Ly[1] & 0x00008000 ) DDRC |= B00000100; // A2 if ( Ly[1] & 0x00002000 ) DDRC |= B00001000; // A3 DDRB |= B00010000; // Assign D12 to output PORTB |= B00010000; // Set D12 to High (LED will light up) } void a0High() { // Outputs High from A0 and lights up the specified LED (turns the other port Low) if ( Ly[11] & 0x00000200 ) DDRD |= B00000100; // D2 if ( Ly[10] & 0x00000400 ) DDRD |= B00001000; // D3 if ( Ly[9] & 0x00000800 ) DDRD |= B00010000; // D4 if ( Ly[8] & 0x00001000 ) DDRD |= B00100000; // D5 if ( Ly[7] & 0x00002000 ) DDRD |= B01000000; // D6 if ( Ly[6] & 0x00004000 ) DDRD |= B10000000; // D7 if ( Ly[5] & 0x00004000 ) DDRB |= B00000001; // D8 if ( Ly[4] & 0x00008000 ) DDRB |= B00000010; // D9 if ( Ly[3] & 0x00010000 ) DDRB |= B00000100; // D10 if ( Ly[2] & 0x00040000 ) DDRB |= B00001000; // D11 if ( Ly[1] & 0x00040000 ) DDRB |= B00010000; // D12 if ( Ly[0] & 0x00020000 ) DDRC |= B00000010; // A1 if ( Ly[0] & 0x00008000 ) DDRC |= B00000100; // A2 if ( Ly[0] & 0x00002000 ) DDRC |= B00001000; // A3 DDRC |= B00000001; // Assign A0 to output PORTC |= B00000001; // A0 High. Now turn on the LED (do this last to minimize the amount of light) } void a1High() { // Outputs High from A0 and lights up the specified LED (turns the other port Low) if ( Ly[11] & 0x00000080 ) DDRD |= B00000100; // D2 if ( Ly[10] & 0x00000100 ) DDRD |= B00001000; // D3 if ( Ly[9] & 0x00000200 ) DDRD |= B00010000; // D4 if ( Ly[8] & 0x00000400 ) DDRD |= B00100000; // D5 if ( Ly[7] & 0x00000800 ) DDRD |= B01000000; // D6 if ( Ly[6] & 0x00001000 ) DDRD |= B10000000; // D7 if ( Ly[5] & 0x00001000 ) DDRB |= B00000001; // D8 if ( Ly[4] & 0x00002000 ) DDRB |= B00000010; // D9 if ( Ly[3] & 0x00004000 ) DDRB |= B00000100; // D10 if ( Ly[2] & 0x00010000 ) DDRB |= B00001000; // D11 if ( Ly[1] & 0x00010000 ) DDRB |= B00010000; // D12 if ( Ly[0] & 0x00040000 ) DDRC |= B00000010; // A1 DDRC |= B00000010; // Assign A1 to output PORTC |= B00000010; // A1 High. Now turn on the LED (do this last to minimize the amount of light) } void a2High() { // Outputs High from A0 and lights up the specified LED (turns the other port Low) if ( Ly[11] & 0x00000020 ) DDRD |= B00000100; // D2 if ( Ly[10] & 0x00000040 ) DDRD |= B00001000; // D3 if ( Ly[9] & 0x00000080 ) DDRD |= B00010000; // D4 if ( Ly[8] & 0x00000100 ) DDRD |= B00100000; // D5 if ( Ly[7] & 0x00000200 ) DDRD |= B01000000; // D6 if ( Ly[6] & 0x00000400 ) DDRD |= B10000000; // D7 if ( Ly[5] & 0x00000400 ) DDRB |= B00000001; // D8 if ( Ly[4] & 0x00000800 ) DDRB |= B00000010; // D9 if ( Ly[3] & 0x00001000 ) DDRB |= B00000100; // D10 if ( Ly[2] & 0x00004000 ) DDRB |= B00001000; // D11 if ( Ly[1] & 0x00004000 ) DDRB |= B00010000; // D12 if ( Ly[0] & 0x00010000 ) DDRC |= B00000010; // A1 DDRC |= B00000100; // Assign A2 to output PORTC |= B00000100; // A2 High. Now turn on the LED (do this last to minimize the amount of light) } void a3High() { // Outputs High from A0 and lights up the specified LED (turns the other port Low) if ( Ly[11] & 0x00000008 ) DDRD |= B00000100; // D2 if ( Ly[10] & 0x00000010 ) DDRD |= B00001000; // D3 if ( Ly[9] & 0x00000020 ) DDRD |= B00010000; // D4 if ( Ly[8] & 0x00000040 ) DDRD |= B00100000; // D5 if ( Ly[7] & 0x00000080 ) DDRD |= B01000000; // D6 if ( Ly[6] & 0x00000100 ) DDRD |= B10000000; // D7 if ( Ly[5] & 0x00000100 ) DDRB |= B00000001; // D8 if ( Ly[4] & 0x00000200 ) DDRB |= B00000010; // D9 if ( Ly[3] & 0x00000400 ) DDRB |= B00000100; // D10 if ( Ly[2] & 0x00001000 ) DDRB |= B00001000; // D11 if ( Ly[1] & 0x00001000 ) DDRB |= B00010000; // D12 if ( Ly[0] & 0x00004000 ) DDRC |= B00000010; // A1 DDRC |= B00001000; // Assign A3 to output PORTC |= B00001000; // A3 High. Now turn on the LED (do this last to minimize the amount of light) }
The demo video in action is added below.
Attachments
Arduino sketch and schematic.zipReferences
The original project was published here and written in Japanese.
Top Comments