aboutsummaryrefslogtreecommitdiffstats
path: root/instructables/arduinocube/arduinocube.pde
diff options
context:
space:
mode:
authorvg <vgm+dev@devys.org>2020-07-07 16:24:01 +0200
committervg <vgm+dev@devys.org>2020-07-07 16:24:01 +0200
commit66dcf910bd4744d8ced56cb9586aa937a1a2d4c5 (patch)
treedf4dca1ae4af1e5df0be0d1f4f2cd0d54751f8e8 /instructables/arduinocube/arduinocube.pde
downloadhic-master.tar.gz
hic-master.tar.bz2
hic-master.zip
first commitHEADmaster
Diffstat (limited to 'instructables/arduinocube/arduinocube.pde')
-rw-r--r--instructables/arduinocube/arduinocube.pde790
1 files changed, 790 insertions, 0 deletions
diff --git a/instructables/arduinocube/arduinocube.pde b/instructables/arduinocube/arduinocube.pde
new file mode 100644
index 0000000..87ce566
--- /dev/null
+++ b/instructables/arduinocube/arduinocube.pde
@@ -0,0 +1,790 @@
+#include <avr/interrupt.h>
+#include <string.h>
+#define AXIS_X 1
+#define AXIS_Y 2
+#define AXIS_Z 3
+
+volatile unsigned char cube[8][8];
+volatile int current_layer = 0;
+
+void setup()
+{
+ int i;
+
+ for(i=0; i<14; i++)
+ pinMode(i, OUTPUT);
+
+ // pinMode(A0, OUTPUT) as specified in the arduino reference didn't work. So I accessed the registers directly.
+ DDRC = 0xff;
+ PORTC = 0x00;
+
+ // Reset any PWM configuration that the arduino may have set up automagically!
+ TCCR2A = 0x00;
+ TCCR2B = 0x00;
+
+ TCCR2A |= (0x01 << WGM21); // CTC mode. clear counter on TCNT2 == OCR2A
+ OCR2A = 10; // Interrupt every 25600th cpu cycle (256*100)
+ TCNT2 = 0x00; // start counting at 0
+ TCCR2B |= (0x01 << CS22) | (0x01 << CS21); // Start the clock with a 256 prescaler
+
+ TIMSK2 |= (0x01 << OCIE2A);
+}
+
+ISR (TIMER2_COMPA_vect)
+{
+ int i;
+
+ // all layer selects off
+ PORTC = 0x00;
+ PORTB &= 0x0f;
+
+ PORTB |= 0x08; // output enable off.
+
+ for (i=0; i<8; i++)
+ {
+ PORTD = cube[current_layer][i];
+ PORTB = (PORTB & 0xF8) | (0x07 & (i+1));
+ }
+
+ PORTB &= 0b00110111; // Output enable on.
+
+ if (current_layer < 6)
+ {
+ PORTC = (0x01 << current_layer);
+ } else if (current_layer == 6)
+ {
+ digitalWrite(12, HIGH);
+ } else
+ {
+ digitalWrite(13, HIGH);
+ }
+
+ current_layer++;
+
+ if (current_layer == 8)
+ current_layer = 0;
+}
+
+void loop()
+{
+ int i,x,y,z;
+
+ while (true)
+ {
+
+ effect_planboing(AXIS_Z, 400);
+ effect_planboing(AXIS_Y, 400);
+ effect_planboing(AXIS_X, 400);
+
+ effect_blinky2();
+
+ effect_random_filler(75,1);
+ effect_random_filler(75,0);
+
+ effect_rain(100);
+
+ effect_boxside_randsend_parallel (AXIS_X, 0, 150, 1);
+ effect_boxside_randsend_parallel (AXIS_X, 1, 150, 1);
+ effect_boxside_randsend_parallel (AXIS_Y, 0, 150, 1);
+ effect_boxside_randsend_parallel (AXIS_Y, 1, 150, 1);
+ effect_boxside_randsend_parallel (AXIS_Z, 0, 150, 1);
+ effect_boxside_randsend_parallel (AXIS_Z, 1, 150, 1);
+
+ }
+}
+
+
+// ==========================================================================================
+// Effect functions
+// ==========================================================================================
+
+void draw_positions_axis (char axis, unsigned char positions[64], int invert)
+{
+ int x, y, p;
+
+ fill(0x00);
+
+ for (x=0; x<8; x++)
+ {
+ for (y=0; y<8; y++)
+ {
+ if (invert)
+ {
+ p = (7-positions[(x*8)+y]);
+ } else
+ {
+ p = positions[(x*8)+y];
+ }
+
+ if (axis == AXIS_Z)
+ setvoxel(x,y,p);
+
+ if (axis == AXIS_Y)
+ setvoxel(x,p,y);
+
+ if (axis == AXIS_X)
+ setvoxel(p,y,x);
+ }
+ }
+
+}
+
+
+void effect_boxside_randsend_parallel (char axis, int origin, int delay, int mode)
+{
+ int i;
+ int done;
+ unsigned char cubepos[64];
+ unsigned char pos[64];
+ int notdone = 1;
+ int notdone2 = 1;
+ int sent = 0;
+
+ for (i=0;i<64;i++)
+ {
+ pos[i] = 0;
+ }
+
+ while (notdone)
+ {
+ if (mode == 1)
+ {
+ notdone2 = 1;
+ while (notdone2 && sent<64)
+ {
+ i = rand()%64;
+ if (pos[i] == 0)
+ {
+ sent++;
+ pos[i] += 1;
+ notdone2 = 0;
+ }
+ }
+ } else if (mode == 2)
+ {
+ if (sent<64)
+ {
+ pos[sent] += 1;
+ sent++;
+ }
+ }
+
+ done = 0;
+ for (i=0;i<64;i++)
+ {
+ if (pos[i] > 0 && pos[i] <7)
+ {
+ pos[i] += 1;
+ }
+
+ if (pos[i] == 7)
+ done++;
+ }
+
+ if (done == 64)
+ notdone = 0;
+
+ for (i=0;i<64;i++)
+ {
+ if (origin == 0)
+ {
+ cubepos[i] = pos[i];
+ } else
+ {
+ cubepos[i] = (7-pos[i]);
+ }
+ }
+
+
+ delay_ms(delay);
+ draw_positions_axis(axis,cubepos,0);
+
+ }
+
+}
+
+
+void effect_rain (int iterations)
+{
+ int i, ii;
+ int rnd_x;
+ int rnd_y;
+ int rnd_num;
+
+ for (ii=0;ii<iterations;ii++)
+ {
+ rnd_num = rand()%4;
+
+ for (i=0; i < rnd_num;i++)
+ {
+ rnd_x = rand()%8;
+ rnd_y = rand()%8;
+ setvoxel(rnd_x,rnd_y,7);
+ }
+
+ delay_ms(1000);
+ shift(AXIS_Z,-1);
+ }
+}
+
+// Set or clear exactly 512 voxels in a random order.
+void effect_random_filler (int delay, int state)
+{
+ int x,y,z;
+ int loop = 0;
+
+
+ if (state == 1)
+ {
+ fill(0x00);
+ } else
+ {
+ fill(0xff);
+ }
+
+ while (loop<511)
+ {
+ x = rand()%8;
+ y = rand()%8;
+ z = rand()%8;
+
+ if ((state == 0 && getvoxel(x,y,z) == 0x01) || (state == 1 && getvoxel(x,y,z) == 0x00))
+ {
+ altervoxel(x,y,z,state);
+ delay_ms(delay);
+ loop++;
+ }
+ }
+}
+
+
+void effect_blinky2()
+{
+ int i,r;
+ fill(0x00);
+
+ for (r=0;r<2;r++)
+ {
+ i = 750;
+ while (i>0)
+ {
+ fill(0x00);
+ delay_ms(i);
+
+ fill(0xff);
+ delay_ms(100);
+
+ i = i - (15+(1000/(i/10)));
+ }
+
+ delay_ms(1000);
+
+ i = 750;
+ while (i>0)
+ {
+ fill(0x00);
+ delay_ms(751-i);
+
+ fill(0xff);
+ delay_ms(100);
+
+ i = i - (15+(1000/(i/10)));
+ }
+ }
+
+}
+
+// Draw a plane on one axis and send it back and forth once.
+void effect_planboing (int plane, int speed)
+{
+ int i;
+ for (i=0;i<8;i++)
+ {
+ fill(0x00);
+ setplane(plane, i);
+ delay_ms(speed);
+ }
+
+ for (i=7;i>=0;i--)
+ {
+ fill(0x00);
+ setplane(plane,i);
+ delay_ms(speed);
+ }
+}
+
+// ==========================================================================================
+// Draw functions
+// ==========================================================================================
+
+
+// Set a single voxel to ON
+void setvoxel(int x, int y, int z)
+{
+ if (inrange(x,y,z))
+ cube[z][y] |= (1 << x);
+}
+
+
+// Set a single voxel to ON
+void clrvoxel(int x, int y, int z)
+{
+ if (inrange(x,y,z))
+ cube[z][y] &= ~(1 << x);
+}
+
+
+
+// This function validates that we are drawing inside the cube.
+unsigned char inrange(int x, int y, int z)
+{
+ if (x >= 0 && x < 8 && y >= 0 && y < 8 && z >= 0 && z < 8)
+ {
+ return 0x01;
+ } else
+ {
+ // One of the coordinates was outside the cube.
+ return 0x00;
+ }
+}
+
+// Get the current status of a voxel
+unsigned char getvoxel(int x, int y, int z)
+{
+ if (inrange(x,y,z))
+ {
+ if (cube[z][y] & (1 << x))
+ {
+ return 0x01;
+ } else
+ {
+ return 0x00;
+ }
+ } else
+ {
+ return 0x00;
+ }
+}
+
+// In some effect we want to just take bool and write it to a voxel
+// this function calls the apropriate voxel manipulation function.
+void altervoxel(int x, int y, int z, int state)
+{
+ if (state == 1)
+ {
+ setvoxel(x,y,z);
+ } else
+ {
+ clrvoxel(x,y,z);
+ }
+}
+
+// Flip the state of a voxel.
+// If the voxel is 1, its turned into a 0, and vice versa.
+void flpvoxel(int x, int y, int z)
+{
+ if (inrange(x, y, z))
+ cube[z][y] ^= (1 << x);
+}
+
+// Makes sure x1 is alwas smaller than x2
+// This is usefull for functions that uses for loops,
+// to avoid infinite loops
+void argorder(int ix1, int ix2, int *ox1, int *ox2)
+{
+ if (ix1>ix2)
+ {
+ int tmp;
+ tmp = ix1;
+ ix1= ix2;
+ ix2 = tmp;
+ }
+ *ox1 = ix1;
+ *ox2 = ix2;
+}
+
+// Sets all voxels along a X/Y plane at a given point
+// on axis Z
+void setplane_z (int z)
+{
+ int i;
+ if (z>=0 && z<8)
+ {
+ for (i=0;i<8;i++)
+ cube[z][i] = 0xff;
+ }
+}
+
+// Clears voxels in the same manner as above
+void clrplane_z (int z)
+{
+ int i;
+ if (z>=0 && z<8)
+ {
+ for (i=0;i<8;i++)
+ cube[z][i] = 0x00;
+ }
+}
+
+void setplane_x (int x)
+{
+ int z;
+ int y;
+ if (x>=0 && x<8)
+ {
+ for (z=0;z<8;z++)
+ {
+ for (y=0;y<8;y++)
+ {
+ cube[z][y] |= (1 << x);
+ }
+ }
+ }
+}
+
+void clrplane_x (int x)
+{
+ int z;
+ int y;
+ if (x>=0 && x<8)
+ {
+ for (z=0;z<8;z++)
+ {
+ for (y=0;y<8;y++)
+ {
+ cube[z][y] &= ~(1 << x);
+ }
+ }
+ }
+}
+
+void setplane_y (int y)
+{
+ int z;
+ if (y>=0 && y<8)
+ {
+ for (z=0;z<8;z++)
+ cube[z][y] = 0xff;
+ }
+}
+
+void clrplane_y (int y)
+{
+ int z;
+ if (y>=0 && y<8)
+ {
+ for (z=0;z<8;z++)
+ cube[z][y] = 0x00;
+ }
+}
+
+void setplane (char axis, unsigned char i)
+{
+ switch (axis)
+ {
+ case AXIS_X:
+ setplane_x(i);
+ break;
+
+ case AXIS_Y:
+ setplane_y(i);
+ break;
+
+ case AXIS_Z:
+ setplane_z(i);
+ break;
+ }
+}
+
+void clrplane (char axis, unsigned char i)
+{
+ switch (axis)
+ {
+ case AXIS_X:
+ clrplane_x(i);
+ break;
+
+ case AXIS_Y:
+ clrplane_y(i);
+ break;
+
+ case AXIS_Z:
+ clrplane_z(i);
+ break;
+ }
+}
+
+// Fill a value into all 64 byts of the cube buffer
+// Mostly used for clearing. fill(0x00)
+// or setting all on. fill(0xff)
+void fill (unsigned char pattern)
+{
+ int z;
+ int y;
+ for (z=0;z<8;z++)
+ {
+ for (y=0;y<8;y++)
+ {
+ cube[z][y] = pattern;
+ }
+ }
+}
+
+
+
+// Draw a box with all walls drawn and all voxels inside set
+void box_filled(int x1, int y1, int z1, int x2, int y2, int z2)
+{
+ int iy;
+ int iz;
+
+ argorder(x1, x2, &x1, &x2);
+ argorder(y1, y2, &y1, &y2);
+ argorder(z1, z2, &z1, &z2);
+
+ for (iz=z1;iz<=z2;iz++)
+ {
+ for (iy=y1;iy<=y2;iy++)
+ {
+ cube[iz][iy] |= byteline(x1,x2);
+ }
+ }
+
+}
+
+// Darw a hollow box with side walls.
+void box_walls(int x1, int y1, int z1, int x2, int y2, int z2)
+{
+ int iy;
+ int iz;
+
+ argorder(x1, x2, &x1, &x2);
+ argorder(y1, y2, &y1, &y2);
+ argorder(z1, z2, &z1, &z2);
+
+ for (iz=z1;iz<=z2;iz++)
+ {
+ for (iy=y1;iy<=y2;iy++)
+ {
+ if (iy == y1 || iy == y2 || iz == z1 || iz == z2)
+ {
+ cube[iz][iy] = byteline(x1,x2);
+ } else
+ {
+ cube[iz][iy] |= ((0x01 << x1) | (0x01 << x2));
+ }
+ }
+ }
+
+}
+
+// Draw a wireframe box. This only draws the corners and edges,
+// no walls.
+void box_wireframe(int x1, int y1, int z1, int x2, int y2, int z2)
+{
+ int iy;
+ int iz;
+
+ argorder(x1, x2, &x1, &x2);
+ argorder(y1, y2, &y1, &y2);
+ argorder(z1, z2, &z1, &z2);
+
+ // Lines along X axis
+ cube[z1][y1] = byteline(x1,x2);
+ cube[z1][y2] = byteline(x1,x2);
+ cube[z2][y1] = byteline(x1,x2);
+ cube[z2][y2] = byteline(x1,x2);
+
+ // Lines along Y axis
+ for (iy=y1;iy<=y2;iy++)
+ {
+ setvoxel(x1,iy,z1);
+ setvoxel(x1,iy,z2);
+ setvoxel(x2,iy,z1);
+ setvoxel(x2,iy,z2);
+ }
+
+ // Lines along Z axis
+ for (iz=z1;iz<=z2;iz++)
+ {
+ setvoxel(x1,y1,iz);
+ setvoxel(x1,y2,iz);
+ setvoxel(x2,y1,iz);
+ setvoxel(x2,y2,iz);
+ }
+
+}
+
+// Returns a byte with a row of 1's drawn in it.
+// byteline(2,5) gives 0b00111100
+char byteline (int start, int end)
+{
+ return ((0xff<<start) & ~(0xff<<(end+1)));
+}
+
+// Flips a byte 180 degrees.
+// MSB becomes LSB, LSB becomes MSB.
+char flipbyte (char byte)
+{
+ char flop = 0x00;
+
+ flop = (flop & 0b11111110) | (0b00000001 & (byte >> 7));
+ flop = (flop & 0b11111101) | (0b00000010 & (byte >> 5));
+ flop = (flop & 0b11111011) | (0b00000100 & (byte >> 3));
+ flop = (flop & 0b11110111) | (0b00001000 & (byte >> 1));
+ flop = (flop & 0b11101111) | (0b00010000 & (byte << 1));
+ flop = (flop & 0b11011111) | (0b00100000 & (byte << 3));
+ flop = (flop & 0b10111111) | (0b01000000 & (byte << 5));
+ flop = (flop & 0b01111111) | (0b10000000 & (byte << 7));
+ return flop;
+}
+
+// Draw a line between any coordinates in 3d space.
+// Uses integer values for input, so dont expect smooth animations.
+void line(int x1, int y1, int z1, int x2, int y2, int z2)
+{
+ float xy; // how many voxels do we move on the y axis for each step on the x axis
+ float xz; // how many voxels do we move on the y axis for each step on the x axis
+ unsigned char x,y,z;
+ unsigned char lasty,lastz;
+
+ // We always want to draw the line from x=0 to x=7.
+ // If x1 is bigget than x2, we need to flip all the values.
+ if (x1>x2)
+ {
+ int tmp;
+ tmp = x2; x2 = x1; x1 = tmp;
+ tmp = y2; y2 = y1; y1 = tmp;
+ tmp = z2; z2 = z1; z1 = tmp;
+ }
+
+
+ if (y1>y2)
+ {
+ xy = (float)(y1-y2)/(float)(x2-x1);
+ lasty = y2;
+ } else
+ {
+ xy = (float)(y2-y1)/(float)(x2-x1);
+ lasty = y1;
+ }
+
+ if (z1>z2)
+ {
+ xz = (float)(z1-z2)/(float)(x2-x1);
+ lastz = z2;
+ } else
+ {
+ xz = (float)(z2-z1)/(float)(x2-x1);
+ lastz = z1;
+ }
+
+
+
+ // For each step of x, y increments by:
+ for (x = x1; x<=x2;x++)
+ {
+ y = (xy*(x-x1))+y1;
+ z = (xz*(x-x1))+z1;
+ setvoxel(x,y,z);
+ }
+
+}
+
+// Delay loop.
+// This is not calibrated to milliseconds,
+// but we had allready made to many effects using this
+// calibration when we figured it might be a good idea
+// to calibrate it.
+void delay_ms(uint16_t x)
+{
+ uint8_t y, z;
+ for ( ; x > 0 ; x--){
+ for ( y = 0 ; y < 90 ; y++){
+ for ( z = 0 ; z < 6 ; z++){
+ asm volatile ("nop");
+ }
+ }
+ }
+}
+
+
+
+// Shift the entire contents of the cube along an axis
+// This is great for effects where you want to draw something
+// on one side of the cube and have it flow towards the other
+// side. Like rain flowing down the Z axiz.
+void shift (char axis, int direction)
+{
+ int i, x ,y;
+ int ii, iii;
+ int state;
+
+ for (i = 0; i < 8; i++)
+ {
+ if (direction == -1)
+ {
+ ii = i;
+ } else
+ {
+ ii = (7-i);
+ }
+
+
+ for (x = 0; x < 8; x++)
+ {
+ for (y = 0; y < 8; y++)
+ {
+ if (direction == -1)
+ {
+ iii = ii+1;
+ } else
+ {
+ iii = ii-1;
+ }
+
+ if (axis == AXIS_Z)
+ {
+ state = getvoxel(x,y,iii);
+ altervoxel(x,y,ii,state);
+ }
+
+ if (axis == AXIS_Y)
+ {
+ state = getvoxel(x,iii,y);
+ altervoxel(x,ii,y,state);
+ }
+
+ if (axis == AXIS_X)
+ {
+ state = getvoxel(iii,y,x);
+ altervoxel(ii,y,x,state);
+ }
+ }
+ }
+ }
+
+ if (direction == -1)
+ {
+ i = 7;
+ } else
+ {
+ i = 0;
+ }
+
+ for (x = 0; x < 8; x++)
+ {
+ for (y = 0; y < 8; y++)
+ {
+ if (axis == AXIS_Z)
+ clrvoxel(x,y,i);
+
+ if (axis == AXIS_Y)
+ clrvoxel(x,i,y);
+
+ if (axis == AXIS_X)
+ clrvoxel(i,y,x);
+ }
+ }
+}
+