LED Christmas Tree Charlieplexing 206 LEDs

Table of contents

LED Christmas Tree Charlieplexing 206 LEDs

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.

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.

image 

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. 

image

image

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.

image

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.

image

All the layers are prepared before making the tree stacking layers one after another.

image

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.

image

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.

image

For the bottom layer, three additional hex spacers with a bigger gap are attached that will work as a base of the tree.

image

A closer look with the hex spacers attached.

image

The final outlook of the completed Christmas tree looks like the image below. It looks great.

image

I made the Arduino circuit with a switch and resistor in a perfboard.

image

I used male pin headers for attaching the circuit board with the LED tree.

image

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.

image

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.

image

image

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.zip

References

The original project was published here and written in Japanese

Category : Holiday Projects