1 /* Arduino Projects for Dummies
4 * Chapter 15: Building an LED Cube
5 * Drives animation on a 9x9x9 LED cube
10 #include <avr/pgmspace.h> // Allows use of program memory space to store patterns
12 // LED Pattern Table in program memory (PROGMEM)
13 // The last column is the display time in units of 100ms.
15 prog_uchar PROGMEM patternData[] = {
16 // Blink all LEDs on and off
17 B111, B111, B111, B111, B111, B111, B111, B111, B111, 10,
18 B000, B000, B000, B000, B000, B000, B000, B000, B000, 10,
19 B111, B111, B111, B111, B111, B111, B111, B111, B111, 10,
20 B000, B000, B000, B000, B000, B000, B000, B000, B000, 10,
22 // Test pattern showing each LED in order:
23 // Left to Right columns, then
24 // Front to Back rows, then
25 // Top to Bottom plane
26 B100, B000, B000, B000, B000, B000, B000, B000, B000, 1,
27 B010, B000, B000, B000, B000, B000, B000, B000, B000, 1,
28 B001, B000, B000, B000, B000, B000, B000, B000, B000, 1,
29 B000, B100, B000, B000, B000, B000, B000, B000, B000, 1,
30 B000, B010, B000, B000, B000, B000, B000, B000, B000, 1,
31 B000, B001, B000, B000, B000, B000, B000, B000, B000, 1,
32 B000, B000, B100, B000, B000, B000, B000, B000, B000, 1,
33 B000, B000, B010, B000, B000, B000, B000, B000, B000, 1,
34 B000, B000, B001, B000, B000, B000, B000, B000, B000, 1,
35 B000, B000, B000, B100, B000, B000, B000, B000, B000, 1,
36 B000, B000, B000, B010, B000, B000, B000, B000, B000, 1,
37 B000, B000, B000, B001, B000, B000, B000, B000, B000, 1,
38 B000, B000, B000, B000, B100, B000, B000, B000, B000, 1,
39 B000, B000, B000, B000, B010, B000, B000, B000, B000, 1,
40 B000, B000, B000, B000, B001, B000, B000, B000, B000, 1,
41 B000, B000, B000, B000, B000, B100, B000, B000, B000, 1,
42 B000, B000, B000, B000, B000, B010, B000, B000, B000, 1,
43 B000, B000, B000, B000, B000, B001, B000, B000, B000, 1,
44 B000, B000, B000, B000, B000, B000, B100, B000, B000, 1,
45 B000, B000, B000, B000, B000, B000, B010, B000, B000, 1,
46 B000, B000, B000, B000, B000, B000, B001, B000, B000, 1,
47 B000, B000, B000, B000, B000, B000, B000, B100, B000, 1,
48 B000, B000, B000, B000, B000, B000, B000, B010, B000, 1,
49 B000, B000, B000, B000, B000, B000, B000, B001, B000, 1,
50 B000, B000, B000, B000, B000, B000, B000, B000, B100, 1,
51 B000, B000, B000, B000, B000, B000, B000, B000, B010, 1,
52 B000, B000, B000, B000, B000, B000, B000, B000, B001, 10,
54 // criscrossing planes
55 B111, B111, B111, B000, B000, B000, B000, B000, B000, 1,
56 B000, B000, B000, B111, B111, B111, B000, B000, B000, 1,
57 B000, B000, B000, B000, B000, B000, B111, B111, B111, 1,
58 B000, B000, B000, B111, B111, B111, B000, B000, B000, 1,
59 B111, B111, B111, B000, B000, B000, B000, B000, B000, 1,
60 B100, B100, B100, B100, B100, B100, B100, B100, B100, 1,
61 B010, B010, B010, B010, B010, B010, B010, B010, B010, 1,
62 B001, B001, B001, B001, B001, B001, B001, B001, B001, 1,
63 B010, B010, B010, B010, B010, B010, B010, B010, B010, 1,
64 B100, B100, B100, B100, B100, B100, B100, B100, B100, 1,
67 B000, B000, B000, B000, B000, B000, B000, B000, B000, 10,
70 B100, B000, B000, B100, B000, B000, B100, B000, B000, 1,
71 B000, B100, B000, B000, B100, B000, B000, B100, B000, 1,
72 B000, B000, B100, B000, B000, B100, B000, B000, B100, 1,
73 B000, B000, B010, B000, B000, B010, B000, B000, B010, 1,
74 B000, B000, B001, B000, B000, B001, B000, B000, B001, 1,
75 B000, B001, B000, B000, B001, B000, B000, B001, B000, 1,
76 B001, B000, B000, B001, B000, B000, B001, B000, B000, 1,
77 B010, B000, B000, B010, B000, B000, B010, B000, B000, 1,
78 B100, B000, B000, B100, B000, B000, B100, B000, B000, 1,
79 B000, B100, B000, B000, B100, B000, B000, B100, B000, 1,
80 B000, B000, B100, B000, B000, B100, B000, B000, B100, 1,
81 B000, B000, B010, B000, B000, B010, B000, B000, B010, 1,
82 B000, B000, B001, B000, B000, B001, B000, B000, B001, 1,
83 B000, B001, B000, B000, B001, B000, B000, B001, B000, 1,
84 B001, B000, B000, B001, B000, B000, B001, B000, B000, 1,
85 B010, B000, B000, B010, B000, B000, B010, B000, B000, 1,
86 B100, B000, B000, B100, B000, B000, B100, B000, B000, 1,
87 B100, B000, B000, B100, B000, B000, B100, B000, B000, 1,
88 B000, B100, B000, B000, B100, B000, B000, B100, B000, 1,
89 B000, B000, B100, B000, B000, B100, B000, B000, B100, 1,
90 B000, B000, B010, B000, B000, B010, B000, B000, B010, 1,
91 B000, B000, B001, B000, B000, B001, B000, B000, B001, 1,
92 B000, B001, B000, B000, B001, B000, B000, B001, B000, 1,
93 B001, B000, B000, B001, B000, B000, B001, B000, B000, 1,
94 B010, B000, B000, B010, B000, B000, B010, B000, B000, 1,
95 B100, B000, B000, B100, B000, B000, B100, B000, B000, 1,
96 B000, B100, B000, B000, B100, B000, B000, B100, B000, 1,
97 B000, B000, B100, B000, B000, B100, B000, B000, B100, 1,
98 B000, B000, B010, B000, B000, B010, B000, B000, B010, 1,
99 B000, B000, B001, B000, B000, B001, B000, B000, B001, 1,
100 B000, B001, B000, B000, B001, B000, B000, B001, B000, 1,
101 B001, B000, B000, B001, B000, B000, B001, B000, B000, 1,
102 B010, B000, B000, B010, B000, B000, B010, B000, B000, 1,
103 B100, B000, B000, B100, B000, B000, B100, B000, B000, 1,
105 // Two orbiting columns
106 B100, B000, B001, B100, B000, B001, B100, B000, B001, 1,
107 B000, B101, B000, B000, B101, B000, B000, B101, B000, 1,
108 B001, B000, B100, B001, B000, B100, B001, B000, B100, 1,
109 B010, B000, B010, B010, B000, B010, B010, B000, B010, 1,
110 B100, B000, B001, B100, B000, B001, B100, B000, B001, 1,
111 B000, B101, B000, B000, B101, B000, B000, B101, B000, 1,
112 B001, B000, B100, B001, B000, B100, B001, B000, B100, 1,
113 B010, B000, B010, B010, B000, B010, B010, B000, B010, 1,
114 B100, B000, B001, B100, B000, B001, B100, B000, B001, 1,
115 B000, B101, B000, B000, B101, B000, B000, B101, B000, 1,
116 B001, B000, B100, B001, B000, B100, B001, B000, B100, 1,
117 B010, B000, B010, B010, B000, B010, B010, B000, B010, 1,
118 B100, B000, B001, B100, B000, B001, B100, B000, B001, 1,
119 B000, B101, B000, B000, B101, B000, B000, B101, B000, 1,
120 B001, B000, B100, B001, B000, B100, B001, B000, B100, 1,
121 B010, B000, B010, B010, B000, B010, B010, B000, B010, 1,
122 B100, B000, B001, B100, B000, B001, B100, B000, B001, 1,
123 B000, B101, B000, B000, B101, B000, B000, B101, B000, 1,
124 B001, B000, B100, B001, B000, B100, B001, B000, B100, 1,
125 B010, B000, B010, B010, B000, B010, B010, B000, B010, 1,
128 // Little cube to big cube
129 B000, B000, B000, B000, B011, B011, B000, B011, B011, 10,
130 B111, B111, B111, B111, B111, B111, B111, B111, B111, 10,
131 B000, B000, B000, B000, B011, B011, B000, B011, B011, 5,
132 B000, B000, B000, B000, B000, B000, B000, B000, B001, 2,
133 B000, B000, B000, B000, B011, B011, B000, B011, B011, 2,
134 B111, B111, B111, B111, B111, B111, B111, B111, B111, 2,
135 B000, B000, B000, B000, B011, B011, B000, B011, B011, 2,
136 B000, B000, B000, B000, B000, B000, B000, B000, B001, 2,
137 B000, B000, B000, B000, B011, B011, B000, B011, B011, 2,
138 B111, B111, B111, B111, B111, B111, B111, B111, B111, 1,
139 B000, B000, B000, B000, B011, B011, B000, B011, B011, 1,
140 B000, B000, B000, B000, B000, B000, B000, B000, B001, 1,
141 B000, B000, B000, B000, B011, B011, B000, B011, B011, 1,
142 B111, B111, B111, B111, B111, B111, B111, B111, B111, 1,
143 B110, B110, B000, B110, B110, B000, B000, B000, B000, 1,
144 B100, B000, B000, B000, B000, B000, B000, B000, B000, 1,
145 B110, B110, B000, B110, B110, B000, B000, B000, B000, 1,
146 B111, B111, B111, B111, B111, B111, B111, B111, B111, 1,
147 B000, B000, B000, B000, B011, B011, B000, B011, B011, 1,
148 B000, B000, B000, B000, B000, B000, B000, B000, B001, 1,
149 B000, B000, B000, B000, B011, B011, B000, B011, B011, 1,
150 B111, B111, B111, B111, B111, B111, B111, B111, B111, 1,
151 B110, B110, B000, B110, B110, B000, B000, B000, B000, 1,
152 B100, B000, B000, B000, B000, B000, B000, B000, B000, 1,
153 B110, B110, B000, B110, B110, B000, B000, B000, B000, 1,
154 B111, B111, B111, B111, B111, B111, B111, B111, B111, 1,
155 B000, B011, B011, B000, B011, B011, B000, B000, B000, 1,
156 B000, B000, B001, B000, B000, B000, B000, B000, B000, 1,
157 B000, B011, B011, B000, B011, B011, B000, B000, B000, 1,
158 B111, B111, B111, B111, B111, B111, B111, B111, B111, 1,
159 B000, B000, B000, B110, B110, B000, B110, B110, B000, 1,
160 B000, B000, B000, B000, B000, B000, B100, B000, B000, 1,
161 B000, B000, B000, B110, B110, B000, B110, B110, B000, 1,
162 B111, B111, B111, B111, B111, B111, B111, B111, B111, 1,
163 B000, B011, B011, B000, B011, B011, B000, B000, B000, 1,
164 B000, B000, B001, B000, B000, B000, B000, B000, B000, 1,
165 B000, B011, B011, B000, B011, B011, B000, B000, B000, 1,
166 B111, B111, B111, B111, B111, B111, B111, B111, B111, 1,
167 B000, B000, B000, B110, B110, B000, B110, B110, B000, 1,
168 B000, B000, B000, B000, B000, B000, B100, B000, B000, 1,
169 B000, B000, B000, B110, B110, B000, B110, B110, B000, 1,
171 // Diagonal wipe, starting in the center
172 B111, B111, B111, B111, B111, B111, B111, B111, B111, 5,
173 B111, B111, B111, B111, B111, B111, B111, B101, B111, 1,
174 B111, B111, B111, B111, B101, B111, B111, B101, B111, 1,
175 B111, B111, B111, B111, B101, B111, B111, B100, B111, 1,
176 B111, B101, B111, B111, B100, B111, B111, B100, B110, 1,
177 B111, B101, B111, B111, B100, B111, B111, B100, B110, 1,
178 B111, B011, B111, B111, B100, B110, B111, B100, B100, 1,
179 B111, B100, B110, B111, B100, B100, B111, B100, B000, 1,
180 B111, B100, B100, B111, B100, B000, B111, B000, B000, 1,
181 B111, B100, B000, B111, B000, B000, B011, B000, B000, 1,
182 B111, B000, B000, B011, B000, B000, B001, B001, B000, 1,
184 // A 2-LED wide diaginal stripe that orbits the cube
185 B011, B000, B000, B001, B001, B000, B000, B001, B001, 1,
186 B001, B001, B000, B000, B001, B001, B000, B000, B011, 1,
187 B000, B001, B001, B000, B000, B011, B000, B000, B110, 1,
188 B000, B000, B011, B000, B000, B110, B000, B100, B100, 1,
189 B000, B000, B110, B000, B100, B100, B100, B100, B000, 1,
190 B000, B100, B100, B100, B100, B000, B110, B000, B000, 1,
191 B100, B100, B000, B110, B000, B000, B011, B000, B000, 1,
192 B110, B000, B000, B011, B000, B000, B001, B001, B000, 1,
193 B011, B000, B000, B001, B001, B000, B000, B001, B001, 1,
194 B001, B001, B000, B000, B001, B001, B000, B000, B011, 1,
195 B000, B001, B001, B000, B000, B011, B000, B000, B110, 1,
196 B000, B000, B011, B000, B000, B110, B000, B100, B100, 1,
197 B000, B000, B110, B000, B100, B100, B100, B100, B000, 1,
198 B000, B100, B100, B100, B100, B000, B110, B000, B000, 1,
199 B100, B100, B000, B110, B000, B000, B011, B000, B000, 1,
200 B110, B000, B000, B011, B000, B000, B001, B001, B000, 1,
203 B000, B000, B000, B000, B000, B000, B000, B000, B000, 10,
207 const int cubeSize=3; // The dimensions of the cube, in LEDs
208 const int planeSize=9; // The number of LEDs on each plane of the cube
209 const int planeDisplayTime=1000; // The time each plane is displayed in microseconds
210 const int updateSpeed=100; // Multiplier for displayTime to get milliseconds
212 byte patternBuffer[planeSize]; // Stores the current pattern from patternData
213 int patternIndex; // Keeps track of the line of the pattern being displayed
214 int patternBufferIndex; // Counts where we are while painting the display
215 byte displayTime; // Multiplied by 100ms to set the frame duration
216 unsigned long endTime; // Tracks when we are finished with the frame
218 int ledrow; // Counts LED rows in the refresh loop
219 int ledcol; // Counts LEDs columns in the refresh loop
220 int ledpin; // Counts LEDs in the refresh loop
222 // Defining pins in array makes it easier to access them in the program
223 // and change how they are wired up, if necessary.
225 int LEDPin[] = {2,3,4,5,6,7,8,9,10};
226 int PlanePin[] = {14,15,16};
230 // set up LED pins as output (active HIGH)
231 for (int i=0; i<planeSize; i++) {
232 pinMode(LEDPin[i], OUTPUT);
234 // set up plane pins as outputs (active LOW)
235 for (int i=0; i<cubeSize; i++) {
236 pinMode(PlanePin[i], OUTPUT);
240 // display pattern in table until displayTime is zero (then repeat)
243 // Initialize patternIndex to the beginning of the pattern data table
245 // Loop over entries in pattern data table while the displayTime>0
247 // memcpy is copies the data from the Program Memory (PROMGMEM) into a temporary array buffer
248 // called pattern buffer. This will be used to determine what to light up
249 memcpy_P( patternBuffer, patternData+patternIndex, planeSize );
250 // The size of the pattern index is incremented by 9, which keeps track of
251 // where we are getting our data from in the pattern Buffer.
252 // It will be reset back to 0 after all three planes are displayed.
253 patternIndex += planeSize;
254 // Read the displayTime from PROGMEM and increment the pattern index to get the right values.
255 // The displayTime is every 10th data element.
256 displayTime = pgm_read_byte_near( patternData + patternIndex++ );
257 // Calculate the endTime from the current time (ms) and the displayTime
258 endTime = millis() + displayTime * updateSpeed;
260 // loop while displayTime>0 and current time < endTime
261 while ( millis() < endTime ) {
262 patternBufferIndex = 0; // reset index counter to beginning of buffer
264 // Loop over the planes of the cube
265 for (int plane=0; plane<cubeSize; plane++) {
266 // Turn the previous plane off
268 digitalWrite(PlanePin[cubeSize-1], HIGH);
271 digitalWrite(PlanePin[plane-1], HIGH);
274 // Prepare the digital pins to light up LEDs
276 for (ledrow=0; ledrow<cubeSize; ledrow++) {
277 for (ledcol=0; ledcol<cubeSize; ledcol++) {
278 // the binary values in the ledcol variable are shifted left by 1 bit, indicated by: "1 <<"
279 // The & is a bitwise AND. If both patternBuffer and the new value coming in from ledcol
280 // are 1, the resulting output is HIGH, otherwise the output is LOW.
281 // ledpin++ simply goes to the next LEDPin in the list.
282 digitalWrite( LEDPin[ledpin++], patternBuffer[patternBufferIndex] & (1 << ledcol) );
285 patternBufferIndex++;
289 // turn current plane on
290 digitalWrite(PlanePin[plane], LOW);
291 // delay planeDisplayTime us
292 delayMicroseconds(planeDisplayTime);
294 } // End of the while loop
296 while (displayTime > 0); // read patterns until time=0 which signals end