In this issue, we build the electronics to run the LED cube array that we soldered together in Part 1.
Build time: 3 HOURS
SKILL LEVEL: INTERMEDIATE
In our last issue, we showed you how to solder all 512 LEDs together to form the 8x8x8 LED structure.
In this issue, we will complete the LED cube with the necessary electronics. We will show you how we came up with the electronics design, how it works, and how to attach the cube array that you built in last month’s issue.
Similar to the 4x4x4 LED cube published in Issue 34, the individual parts are available from most electronics retailers, however, you should also be able to find kits for this project in Jaycar stores shortly after this issue hits the streets.
The Broad Overview
Part 2 of our 3 part project is the electronics section to drive the LED cube array that you should have already successfully soldered together in part 1.
The electronics for this project is a combination of D-type flip-flops, decoders, MOSFETs, and a handful of other components, all controlled by an ATmega328P.
To make assembly easy, and compact, we have designed a double-sided PCB, and we show you an easy way to program the ATmega328P using an Arduino Uno as the ISP.
We complete the project with a test pattern, and in part 3, we will show you how to program amazing animations.
How it works
LED cubes work on the phenomenon called the persistence of vision. This is essentially an optical illusion which tricks our mind into seeing rapidly changing patterns as a stationary image. We will use a technique called multiplexing to achieve this.
For this project, we will have eight 8x8 LED arrays stacked on top of each other with the cathodes of each layer connected to a transistor, which will connect the common cathodes on a layer to ground when active. We will then control the anodes of each LED on a layer.
This way, the only LEDs that can be illuminated at any one time are the LEDs that are pulled high and the layer which is pulled low.
To create the 3D image, we need to very rapidly switch all of the required LEDs on first to their desired state. We then activate the transistor to allow the LEDs to illuminate. We then change the LEDs to suit the next layer and activate the transistor for that layer.
Doing this at a rate faster than 30 times per second gives the illusion that the LEDs on each layer are illuminated at the same time, when in reality, only one layer can possibly be active at any given moment.
This technique significantly reduces the number of pins required to control all 512 LEDs in this array.
Microcontroller
This is an 8x8x8 LED cube, which means it consists of 8 individual arrays of 8 x 8 LEDs, all stacked on top of each other to create a cube of 512 LEDs with 64 LEDs to each layer.
If we were to control this cube in the same way we controlled the 4x4x4 LED cube, which used a single pin per LED and another pin for each layer, we would need 64 I/O pins for the LEDs and another 8 for the layers. This would be a total of 72 I/O pins! We simply can’t fathom a microcontroller that would have that many I/O pins and certainly not one that would be through-hole technology (THT). As such, we first did some research online for existing LED cubes and their methods of pin expansion. In this research, we encountered an awesome tutorial on the website Instructables by user CHR whose work was used as inspiration for our project.
In this research, we learned of a system using flip-flops as a memory latch and a de-multiplexer to switch between the flip-flops. This system allows us to use 8 I/O pins to control which pixels in a row are illuminated, 8 I/O pins to control which layer is illuminated, 3 pins to control which row on a layer are enabled, and a single pin to control the output enable of all of the flip-flops.
This means we need a microcontroller that has a minimum of 20 I/O pins all of which must be controllable as a digital output.
Lucky for us, the humble ATmega328P that we are used to in our Arduino Uno and Nano projects just scrapes by, having exactly 20 useable I/O pins. Thus, we decided that the ATmega328P will be suitable for our project.
Digital pins 0 - 7 (Port D pins 0 - 7) will be used to control the pixels per row.
Analog pins 0 - 5 (Port C pins 0 - 5) will be used to control layers 1 - 6.
Digital pins 12 - 13 (Port B pins 4 and 5) will be used to control layers 7 and 8.
Digital pin 8 - 10 (Port B pin 0 - 2) will be used to control the decoder.
AREF will have a 0.1µF bypass capacitor to ground as close to the pin as practical. This isn’t absolutely necessary since we will not be using the ADC of the microcontroller, however, it is still good practice.
The crystal pins Port B pin 6 and Port B pin 7 will be connected to a 16MHz crystal oscillator, and must have a 22pF load capacitor to ground on both pins. This ensures that the clock of the microcontroller is as stable as possible.
For transient protection and ripple reduction, VCC of the microcontroller will have a 0.1µF ceramic bypass capacitor and a 100µF electrolytic capacitor as close to the pin as practical. The 0.1µF will give any electrical noise or other such voltage spikes a path to ground, and the large electrolytic will help to reduce any ripple on the 5V line.
Reset will have a 10KΩ pull-up resistor and a tactile push button, which when pressed, will pull the reset pin low causing the Arduino to reboot.
D Type Flip-Flop
The role of the D type flip-flops in this project is as a simple memory latch. They hold the desired state on the output, irrespective of changes on the input.
To set their state, we pull the input pins 1D - 8D into a desired state of the output pins 1Q - 8Q. We then pull the clock pin (CLK) from low to high and have output enable (!OE) low.
Note: A high on the input will provide a high on output as there is no inversion.
However, the flip-flop’s will keep this same output no matter what happens on the input pins, until such time as the output enable pin is pulled low and the clock pin transitions from low to high. This can be seen in the truth table below.
The output(Q) of these flip-flops is connected to the anode of the LED in that position via a current limiting resistor. Thus, when an output pin is pulled high on the flip-flop, current can flow through the flip-flop into the LED and through the active layer MOSFET to ground.
More importantly, it will remain in this state until the clock pulses undergo a change from low to high, in which case, the output will change to match the input and once again stay in this state.
To cover all of the 64 LEDs required for a layer, we need to use 8 of these flip-flop ICs with each flip-flop IC containing 8 flip- flops, and thus controlling one row of 8 LEDs.
3-8 Decoder
We are using the decoder as a way to control the clock signals for the 8 flip-flops. Each of the 8 outputs of the decoder is connected to the clock (CLK) pin of a flip-flop. We can then use 3 pins from the microcontroller connected to A, B, and C of the decoder to control which of the outputs are high at any given time.
To do this, we first need to consult the truth table for the decoder.
As we can see, there are 3 address pins on this decoder G1, !G2A and !G2B. For our operation we need to tie !G2A and !G2B to ground potential and G1 to 5V.
In this configuration, we can create a program loop that will change the state of the address pins (A, B, and C), which will pull one output low as per the truth table.
That is to say, if A, B, and C are all pulled low output Y0 will be low and all other outputs will be high.
If we pulled input A high and B and C low. output Y1 will be low and all other pins high, etc. In this transition, Y0 which was low is now pulled high.
Since the 74HC574 flip-flops are edge triggered i.e. work on the leading edge of a transition of the clock pulse from low to high, this change from Y0 will be detected as a clock pulse by the flip-flop, and thus, the flip-flop will remember the state of its input pins until it is changed again by another clock pulse.
Layer MOSFETs
In order to control the layers, we opted to use the commonly available IRF540N MOSFET. This MOSFET, whilst overkill for the application, was selected as it is a very commonly available part from our local distributors.
We used a 10KΩ pulldown resistor on the base of each of the MOSFETs to ensure that the gates were not susceptible to noise, and also added a current limiting resistor to protect the microcontroller from damage. The IRF540N has quite a large gate capacitance, and whilst no DC current flows into the gate of a MOSFET, AC current can.
The 220Ω resistor on the gate will ensure that the fast switching speed does not allow too high a current to enter the gate, damaging the microcontroller by exceeding the maximum current output of 40mA.
The cube
It’s important that we explain how the cube is constructed so you will understand certain terminology while reading the construction and programming text. As such, we will briefly explain the construction, and show diagrams outlining the cube’s construction and the nomenclature used in this guide.
The cube itself is essentially 8 identical layers stacked on top of each other with every LED on a layer sharing a common cathode (negative). When we refer to a layer, it is as indicated here where layer 0 is the bottom layer and layer 7 the top.
We start at zero because the program uses an array and arrays in C++ start at zero.
Each layer is constructed using 64 LEDs, which we will later break down into 8 rows of 8 LEDs.
Each one of the rows of 8 LEDs are connected to one of the flip-flops, and as such, it’s important to note that when we refer to a row, we are referring to its position on a layer.
The anodes of the LED in one layer are then also connected to the anode of the LED directly above and below to form columns. We will refer to these columns as either columns or pixels. In the construction sense, they are columns as there make up an important part of the structure. Whereas, in the programming sense, we are more likely to refer to them as a pixel on a specific layer.
The Prototype:
As with most of our projects, we assemble a prototype of the circuit as you see here. This prototype, whilst only a partial prototype, allowed us to simulate a single layer of the project and was useful in testing the principle of operation. It helped us create and understand the program that we hope will be easy enough for our readers to understand and therefore modify.
Note: There is no need for you to recreate this prototype. It is way too complex, fragile in the breadboard, and takes several hours to make. We simply wanted to highlight that considerable effort has gone into the design of this project, and to share the sheer beauty of it.
The Electronics Build:
Parts Required: | Jaycar | ||
---|---|---|---|
1 x SN74HC138N Decoder | ZC4846 | ||
8 x SN74HC574N D-Type Flip-Flops | - | ||
1 x ATmega328P Microcontroller | ZZ8727 | ||
8 x IRF540N MOSFETs | ZT2466 | ||
1 x 16 pin DIP IC Socket | PI6502 | ||
8 x 20 pin DIP IC Sockets | PI6504 | ||
1 x 28 pin DIP IC Socket | PI6510 | ||
1 x 16MHz Crystal | Included with ZZ8727 | ||
1 x Tactile Pushbutton | SP0601 | ||
1 x 2.1mm DC Jack | PS0519 | ||
2 x 22pF Ceramic Capacitors | RC5316 | ||
11 x 0.1µF Ceramic Capacitors* | RC5496 | ||
10 x 100µF Electrolytic Capacitors | RE6130 | ||
64 x 120Ω 1/4W Resistors* | RR0550 | ||
9 x 10KΩ 1/4W Resistors* | RR0596 | ||
8 x 220Ω 1/4W Resistors* | RR0556 | ||
4 x M3 x 10mm Screws* | HP0406 | ||
4 x M3 Nuts* | HP0425 | ||
1 x Double Row 3-pin Header | HM3250 # | ||
1 x PCB | - |
OPTIONAL: | Jaycar | ||
---|---|---|---|
1 x USB to 2.1mm DC Cable (To Power from a 5V Phone Charger) | - | ||
4 x 20mm M3 Standoffs* | HP0907 | ||
4 x M3 Screws to suit Standoffs* | HP0400 |
* Quantity shown, may only be sold in packs.
^ The 100Ω resistor from Core Electronics should work fine in lieu of the 120Ω.
# The 3-pin header from Jaycar needs to be cut down.
PCB KEY
This key is very useful for troubleshooting. Once you have installed the components it can be near impossible to see the values printed underneath. Thus, it's incredibly difficult to discover a component installed incorrectly. Having a key like this allows you to systematically check the component in a location without needing to remove it.
Note: The PCB shown here is revision D. There may be some slight modifications to the final design which will be available as a kit from Jaycar and the parts list in this article. The parts list is correct however, the values printed on the PCB shown in this article may not be.
Assembling the project isn’t a complex task, however, there are some steps that need to be followed in a specific order. As such, we have opted to show the step-by-step build process, which we took to construct and test the project.
Naturally, the first step was populating the PCB with the necessary components. For this, we generally start with the low-profile components such as the resistors and work our way up to the biggest, which are the electrolytic capacitors.
Given the size of the board, and the fact that all of the resistors were in the same direction, we made a conscious effort to place all of the resistors in the PCB so that the colour bands can be read from left to right. This is a small step but can go a long way in assisting with troubleshooting if something were to go wrong.
Our resistors came in a pack of 8 so we did one pack at a time. Bend all 8 resistors from a pack over your finger.
With all 8 bent, insert them into the PCB one at a time, slightly bending the leads out so that the resistor will not fall out as you’re inserting the other 7 resistors.
With all 8 resistors from a pack inserted into their correct location, solder one lead of each resistor to the PCB. Check the front of the PCB to make sure the resistor is sitting flush against the PCB.
Note: Only soldering one lead means that you can easily reposition the resistor. If you find some of your resistors are not seated correctly, you can simply flip the board back over and use a finger to put slight pressure on the offending resistor while you reflow the solder joint with your soldering iron. This should cause the resistor to sit flush against the PCB, but be careful not to burn yourself as the resistors will get very hot quickly.
Once you’re happy that all of the 8 resistors you just placed are positioned correctly, and in the correct spot, you can solder the remaining lead. After this, you can trim the leads.
Note: When trimming the leads, we recommend the use of good quality side cutters. We like to use a flat side cutter often called flush cuts, which are a pair that allow you to get close to the PCB, however, you don’t want to cut flush to the PCB. Rather, you want to cut the lead at the apex of the solder joint as shown here. After cutting the leads, you still want the nice volcano looking shape like the left-hand lead of this LED. Whilst clearly exaggerated in this image, it’s common to see makers cutting the solder joint like the right side thinking that’s the use for flush cuts. Cutting your leads like this may increase the chances of damaging your PCB.
You can now repeat the same process with the remaining 73 resistors.
Note: Be very careful and ensure that you’re using the correct resistors in the correct locations as changing components when the LED array is attached will be a nightmare.
When you’re done, go back over the PCB to make sure no resistors were missed and that the resistors are in the correct positions and soldered correctly. You can use the component key provided to ensure that the components have been soldered into the correct spots. Having the resistors all in the same direction will be very handy here.
Once satisfied, you can move onto the next size of components. In our case, this is the component Q1, which is a 16MHz crystal. It can be found just above the ATmega328P footprint.
The crystal is not polarity sensitive but can be sensitive to heat. It’s good practice to solder crystals as quickly as practical and letting the package cool completely between solder joints. This will significantly reduce the chances of damage. Many datasheets suggest around a 3-second or less solder time at 350°C to guarantee no damage will occur.
The next component on the top side of the PCB is the reset switch. The good news is these switches have the leads bent in a way that they lock into the PCB and don’t easily fall out. Simply insert the switch into the board and solder it in.
Note: The switch will only go in one way and is not polarity sensitive.
With the switch soldered in, you can now move onto the IC sockets. Whilst these are not exactly mandatory given the fact that you’re not likely to replace them, as doing so after construction would necessitate a complete reconstruction of the cube after all. However, we highly recommend them as it’s possible to solder the IC in the wrong way and this becomes very difficult to rectify. With an IC socket, if you put the IC in incorrectly, you can always take it out and replace it. Whereas, trying to desolder an IC soldered directly to a circuit board can be difficult and damage the PCB’s traces and pads.
To solder the IC sockets, we insert the socket into the PCB so that the notch on the socket matches the notch on the PCB overlay. We then solder 2 leads in place on opposite corners of the socket. This allows us to double-check that the socket has been installed correctly and is flat against the PCB. If it’s not flat, you can follow the same procedure we used on the resistors i.e. reflowing the solder while pressing against the component.
When you’re satisfied that the socket is installed flush and in the correct position / orientation, you can solder the remainder of the pins.
Note: If you solder the IC socket to the PCB in the incorrect orientation its best at this point to leave it as is. Trying to desolder all 20+ pins will greatly increase the chances of damage to the PCB. You just need to make sure the notch on the IC being inserted into the socket matches the silkscreen markings and not the IC socket.
With all of the IC sockets installed, you can move on to the ceramic capacitors. These are not polarity sensitive, and thus, can be inserted into the PCB in either direction. Like the crystal, these monolithic ceramic capacitors can be sensitive to heat, and the manufacturers recommend that the component be subjected to the soldering temperatures for a maximum of 3-seconds. So, like with the crystal, do your best to ensure that you don’t let the soldering iron dwell on the joint for too long, and let the part cool before attempting a touch up or soldering the second leg.
The next step is to solder the electrolytic capacitors. This component is polarity sensitive and both the capacitor and PCB have markings to help identify this polarity. The capacitors themselves have two methods of identifying the devices polarity. The wrapping on the casing has a negative symbol label on it to show the leg on that side is the negative leg.
Another way to identify the polarity of the electrolytic capacitor is by the positive lead, which is always longer than the negative lead. This longer leg goes into our PCB marked with the + symbol.
You’re now on the home stretch for the top side of the PCB construction. It’s just a case of inserting all of the IC’s into the IC sockets and being sure to check the notch on the IC matches the notch on the PCB.
Next, flip the PCB over to the back side and add the DC jack and the 2-row 3 pin header.
Take a through look over your PCB to make sure there are no components missing and everything is installed correctly before we start to program.
Note: We will install the MOSFETs and LED structure after programming.
PROGRAMMING THE ATMEGA328P
Even though the MOSFETs are not yet installed, we can still verify that the circuit is working and that the microcontroller is able to be programmed (Imagine finishing the cube and finding out that the microcontroller was faulty?!).
To program the microcontroller on this board, we need an in-circuit serial programmer (ICSP) or sometimes shortened to just (ISP).
There are many programmers that can be used for this purpose but we will show the process using an Arduino Uno as an ICSP.
The very first step is to upload the ICSP software to the Arduino Uno that we will be using as the programmer. This is a sketch included in the example section of the Arduino Integrated development environment (IDE).
You can find the Sketch by clicking File > Examples > ArduinoISP > ArduinoISP
Scroll down to line 81 and uncomment that line.
// #define USE_OLD_STYLE_WIRING
It should now read:
#define USE_OLD_STYLE_WIRING
This will tell the Arduino that we intend to wire the Arduino using the digital pins and not the ICSP header.
You can then upload the sketch to the Arduino Uno.
Note: If you’re new to Arduino, we thoroughly recommend that you check out our awesome getting started with Arduino guide from Issue 17 called ‘Setting up the Arduino IDE’. This will show you the process of using the Arduino IDE on various different operating systems.
With the Arduino as ISP programming sketch uploaded to the Arduino Uno, we can start connecting the Uno to the ICSP header on the PCB of the 8x8x8 LED cube.
Note: Disconnect the Arduino Uno from the USB port while making these connections.
With the Arduino Uno as our ISP connected to the 8x8x8 LED cube, we can now upload programs. However, we need to power the LED cube first. To aid in this, we have made it possible to power the LED cube’s electronics directly via the programmer. Simply solder the solder bridge across a jumper (JP1) on the bottom of the PCB.
Note: This should not be done with the LED array attached. You will not be able to power the entire cube from this pin using the Arduino Uno as the programmer, as this will exceed the current capabilities of the Arduino and possibly your computer’s USB port.
IMPORTANT NOTE: It is very important that after confirming the 8x8x8 LED cube is functioning correctly that you remove this solder bridge and confirm that it is removed. If you power the cube via the DC jack with the Arduino connected to the cube and powered via USB you will be connecting your computer power supply to the cube power supply. If the voltage potential on the supplies is different, a large current could flow from the higher potential supply into the lower potential supply. This could result in damage to any number of components including your computer power supply. Therefore, It is imperative that you remove this solder bridge after this procedure.
If you understandably don’t want to take that risk, you can leave the jumper untouched and power the device via a separate power supply while you run the test program. This way, the 5V supply to the Arduino Uno and the 5V supply to the LED cube are isolated, and current can not flow between them. Since both supplies share a common ground potential, all data signals will still be received fine.
In either case, with the cube powered, you can now upload the provided code to the 8x8x8 LED cube controller.
Open the sketch in your Arduino IDE.
Connect the Arduino Uno to your computer’s USB port and make sure the correct COM port has been selected in the Arduino IDE.
Make sure the programmer is set to Arduino as ISP in the Arduino IDE.
Upload the sketch using the Arduino Uno as an in-circuit serial programmer. Once done, remove the ICSP wires leaving VCC and ground on, if powering via the programmer.
You should now verify that the program was uploaded correctly. We used an oscilloscope but you can also use a multimeter with a little patience.
Testing with an oscilloscope
If like us you’re lucky enough to have your own scope you have a nice easy way to test that the cube is working. We have added some test points on the PCB which will allow you to easily verify that the program is functioning correctly. These test points are attached to the gate of the MOSFETs for layer 6 and 7, and were originally added to help test and compare the performance of two different MOSFETs.
To use them to test if the microcontroller is functioning as expected, you can attach your oscilloscope probes to the test points Gate_Q8, Gate_Q9, and the ground alligator clips to the ground pin.
To aid in this, you may want to solder in some male headers to the bottom of the PCB. This will make it much easier to attach your scope probes.
Set both of your scope’s channels to DC coupling, 2V per division, with a time-base of 4ms per division.
Ensure your scope and probes are both set to x1 as the frequency is well under the 1MHz range.
From here, you should be able to see the voltage at the gate of each MOSFET is a pulsating DC square wave. Both waveforms should have an amplitude close to 5V and the frequency should be around 60Hz.
What you are seeing here is the ‘on’ time for layers 7 and 8. It shows that each layer is only illuminated for around 2ms but is repeated 62 times per second.
In the program, we are triggering an interrupt 500 times a second that writes the values to the flip-flops and then triggers each layer. Thus, we can see that the program is running and can be confident to move on with the rest of the construction.
Testing with a multimeter
If you don’t have an oscilloscope, don’t despair. You can still test that the program has been uploaded correctly with a multimeter, albeit possibly not quite as easy.
If your multimeter has a frequency range, you can use the test points to confirm that you get a frequency of around 60Hz when you place the ground probe on the ground test point and the anode probe on the test point Gate_Q8 or Gate_Q9. This will confirm that the program has been uploaded and is running as expected.
If your multimeter does not have a frequency range, you can still test the program is working by using the voltage range.
The pattern we are drawing in the program is the outline of a cube (You need to imagine it obviously as we don’t have the LEDs connected yet).
If you split the cube into layers, knowing that only one layer is ever on at any one time, we can see that the four corners are the only outputs that will be on for every layer. The inner pixels don’t ever come on and the outer pixels will be illuminated twice out of the 8 layers.
If you were to place the negative probe (black) of your multimeter to ground and the positive (red) to any one of the four corners, you should see a voltage of around 3V. Whereas, if you place it to the outer pins you should see 2/8th of that voltage or 0.75V. This will confirm that the program was uploaded and operating correctly. You can now confidently move on with the rest of the construction.
Finishing Construction
With the program uploaded and verified, work can begin on the final steps of construction starting with the LED cube array being attached.
ATTACHING THE LED CUBE ARRAY
Before you start, just a reminder to handle the LED cube with care because it can very easily be bent out of shape, which will give it a less than ideal presentation. Dropping the cube, even from a small height, will surely bend it, as would carelessly handling it. On top of that, it requires us to place all 64 LED anodes making up the columns to the PCB. This is a time consuming and stressful process. You need to gingerly manipulate each of the anode columns into their respective hole on the PCB using pliers or tweezers, etc.
To get started, place the LED cube into the 3D printed jig (from Issue 35), which will hold the cube steady and reduce the risk of damaging the cube. Next, ensure that the busbar markings across the PCB align with the busbars on the LED cube. This way, the LED legs forming the columns will be in the correct position. Start at row one, aligning the columns into their respective hole on the PCB so that 1mm or so protruded past the bottom of the PCB.
Solder them to the PCB.
Next, place slight pressure on the PCB so that it is pressed against the remaining 56 LED leads / columns. Using tweezers or long nose pliers, push the leads which are flush against the PCB into their respective hole. This took us about an hour and a half to complete, requiring constant pressure on the top of the PCB the entire time (You may want to consider a toilet break or have a bite to eat before undertaking this step).
SOLDER THE MOSFETS
Once you have all 64 anodes installed and soldered, the next step is to install the MOSFETs. With the LED cube array soldered on top, it’s impossible to solder the MOSFETs in the usual way (i.e. from the opposite side of the board). To overcome this issue, we made the solder pads for the MOSFET larger than usual on the component side, which will allow you to solder them to the PCB from the same side they are placed.
The tab of the MOSFET aligns with the bar printed on the silkscreen and the first pin aligns with the dot on the silkscreen.
Note: It’s important to cut the legs of the MOSFET before you solder it to the PCB. With the LED cube soldered on top you won’t be able to trim these leads. We just trimmed the leads so that about 3.5mm of lead were remaining from the ridge.
POWER
Power from a 5VDC 1.5A - 2A power supply. We used a USB phone charger with a USB to 2.1mm DC plug cable.
3D PRINTED BASE
The final step is to attach the 3D printed base to the PCB. This base is designed to attach to the PCB via 4 x M3 15mm bolts and nuts. We printed the base on our Cocoon Create i3 at 100-microns layer height, using 3D fillies branded white PLA.
The print is designed to sit flat on the build platform and must be printed with supports due to the overhangs for the PCB brackets.
We printed ours with a raft. In this orientation and settings, it took around 10.5 hours to print. You can speed this up dramatically by reducing the resolution to 200 or 300-microns, which would allow it to print in 5.5hours or 3.5 hours respectively.
If you don’t have a 3D printer you can use brass standoffs in place of the 3D printed case. The standoffs will just need to be 20mm or longer to provide the necessary clearance for the MOSFETs.
TEST PATTERN
Due to time constraints and delays in getting the PCB manufactured, we were unable to provide an example program to display animations on the cube. We were, however, able to create a program that will allow you to display a stationary image on the cube, which we intended to be used as a test program.
However, this test program can quite easily be modified to display any image you choose to program into it.
The program relies on a 2-dimensional array that you can see below:
volatile unsigned cube[8][8] = {
{B11111111, B10000001, B10000001, B10000001, B10000001, B10000001, B10000001, B11111111}, //layer 0
{B10000001, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B10000001}, //layer 1
{B10000001, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B10000001}, //layer 2
{B10000001, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B10000001}, //layer 3
{B10000001, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B10000001}, //layer 4
{B10000001, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B10000001}, //layer 5
{B10000001, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B10000001}, //layer 6
{B11111111, B10000001, B10000001, B10000001, B10000001, B10000001, B10000001, B11111111}, //layer 7
}
As you can see, each layer consists of 8 elements, each 8 bits long. Each one of these elements represents one row of that layer, thus it may be easier to follow if we displayed a layer like this.
{
B11111111,
B10000001,
B10000001,
B10000001,
B10000001,
B10000001,
B10000001,
B11111111
}, //layer 0
This shows the entire first layer (layer 0) in a binary format. It may be even easier to visualise if we were to add it to a table like this.
Every ‘1’ indicates that the LED should be illuminated and every ‘0’ means the LED should be off. Hopefully, you’re looking at this code and table, and can easily see how simple it will be to modify the code to display other patterns.
The tricky part will, of course, be manipulating the code to produce fluid looking animations.
For now, you can manually modify the code in this two-dimensional array and see what interesting patterns you can make. Be sure to show them off to us on social media though.
Another part of the code you may want to tinker with is the interrupt timer. We created a timer that triggers an interrupt at 500Hz.
cli();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 31999; // = 16000000 / (1 * 500) - 1
TCCR1B |= (1 << WGM12);
TCCR1B |= (0 << CS12) | (0 << CS11) |
(1 << CS10);
TIMSK1 |= (1 << OCIE1A);
sei();
You may want to have a play with this to help see how the code functions by slowing the interrupt frequency. You can do this by changing the value stored in OCR1A in the line:
OCR1A = 31999; // = 16000000 / (1 * 500) - 1
Using the equation:
OCR1A = (clock frequency / (prescaler x desired frequency )) -1
The clock frequency is the 16MHz crystal and the prescaler can be 1, 8, 64, 256 or 1024.
Note: the value stored in OCR1A must be lower than 65536 when using timer 1.
So, if you wanted an interrupt frequency of 5 Hertz the OCR1A value should be:
OCR1A = (16000000 / (1 x 5 )) -1 = 3,199,999
This exceeds the maximum of 65536, so we need to change the prescaler. Let’s try again with a prescaler of 64.
OCR1A = (16000000 / (64 x 5 )) -1 = 49,999
This will work and produce an interrupt frequency of around 5Hz.
WHERE TO FROM HERE?
Congratulations on building such a gargantuan project, the soldering alone would be a feat for most people. In the next issue, we will finish off this project by delving into the code and getting some animations displaying.