8x8x8 Led Cube driven by 4x PCF8575 for the columns and 1x PCF8574 for the layers
led_cube.cpp
- Committer:
- Bas
- Date:
- 2012-11-01
- Revision:
- 1:e08a4d27f534
- Parent:
- 0:920c5ed65a45
File content as of revision 1:e08a4d27f534:
#include "led_cube.h" LED_CUBE::LED_CUBE(I2C* _interface) : row(_interface, 0x07,PCF8574_TYPE), colums_0_1(_interface, 0x00), colums_2_3(_interface, 0x01), colums_4_5(_interface, 0x02), colums_6_7(_interface, 0x03) { _interface->frequency(400000); //400KHz duty.attach_us(this, &LED_CUBE::UpdateRow,1250);// each row = 1/8 duty } LED_CUBE::~LED_CUBE() {} void LED_CUBE::UpdateRow() { static int rownr = 0; if (rownr < 0 || rownr > 7) { rownr = 0; } row.WriteByte(0xFF); // switch off all rows before updating next colums to avoid ghost data from previous colums colums_0_1.WriteBytes(~cubeData[8 * rownr + 0],~cubeData[8 * rownr + 2]); //update the columns colums_2_3.WriteBytes(~cubeData[8 * rownr + 1],~cubeData[8 * rownr + 3]); colums_4_5.WriteBytes(~cubeData[8 * rownr + 6],~cubeData[8 * rownr + 4]); colums_6_7.WriteBytes(~cubeData[8 * rownr + 7],~cubeData[8 * rownr + 5]); row.WriteByte(~(1<<rownr)); // now display the row rownr++; } //clear everything void LED_CUBE::clear_cube(void) { row.WriteByte(0xFF); colums_0_1.WriteBytes(0xFF,0xFF); colums_2_3.WriteBytes(0xFF,0xFF); colums_4_5.WriteBytes(0xFF,0xFF); colums_6_7.WriteBytes(0xFF,0xFF); clearVoxels(); } //set a voxel in the cube array void LED_CUBE::setVoxel(unsigned char x, unsigned char y, unsigned char z) { if (inrange(x, y, z)) cubeData[z*8 + x] |= 0x01<<y; } //clear a single voxel in the cube array void LED_CUBE::clearVoxel(unsigned char x, unsigned char y, unsigned char z) { if (inrange(x, y, z)) cubeData[z*8 + x] &= ~(0x01<<y); } //return the value of a single voxel in the cube array unsigned char LED_CUBE::getVoxel(unsigned char x, unsigned char y, unsigned char z) { if (inrange(x, y, z)) { if(cubeData[z*8 + x] & 0x01<<y) { return 1; } else { return 0; } } else { return 0; } } void LED_CUBE::copyColumn(unsigned char x, unsigned char y, unsigned char col) { for(unsigned char z = 0; z < 8; z++) { if(col&(0x01<<z)) { setVoxel(x, y, z); } else { clearVoxel(x, y, z); } } } // In some effect we want to just take bool and write it to a voxel // this function calls the apropriate voxel manipulation function. void LED_CUBE::alterVoxel(unsigned char x, unsigned char y, unsigned char z, unsigned char state) { if (state == 1) { setVoxel(x,y,z); } else { clearVoxel(x,y,z); } } // Flip the state of a voxel. // If the voxel is 1, its turned into a 0, and vice versa. void LED_CUBE::flipVoxel(unsigned char x, unsigned char y, unsigned char z) { if (inrange(x, y, z)) cubeData[z*8 + x] ^= (1 << y); } void LED_CUBE::setPlane_x (int x) { int z; if (x>=0 && x<8) { for (z=0; z<8; z++) cubeData[z*8 + x] = 0xFF; } } void LED_CUBE::clearPlane_x (int x) { int z; if (x>=0 && x<8) { for (z=0; z<8; z++) cubeData[z*8 + x] = 0x00; } } void LED_CUBE::setPlane_y (int y) { int z; int x; if (y>=0 && y<8) { for (z=0; z<8; z++) { for (x=0; x<8; x++) { cubeData[z*8 + x] |= (1 << y); } } } } void LED_CUBE::clearPlane_y (int y) { int z; int x; if (y>=0 && y<8) { for (z=0; z<8; z++) { for (x=0; x<8; x++) { cubeData[z*8 + x] &= ~(1 << y); } } } } // Sets all voxels along a X/Y plane at a given point // on axis Z void LED_CUBE::setPlane_z (int z) { int i; if (z>=0 && z<8) { for (i=0; i<8; i++) cubeData[z*8 + i] = 0xFF; } } // Clears voxels in the same manner as above void LED_CUBE::clearPlane_z (int z) { int i; if (z>=0 && z<8) { for (i=0; i<8; i++) cubeData[z*8 + i] = 0x00; } } void LED_CUBE::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 LED_CUBE::clearPlane (char axis, unsigned char i) { switch (axis) { case AXIS_X: clearPlane_x(i); break; case AXIS_Y: clearPlane_y(i); break; case AXIS_Z: clearPlane_z(i); break; } } void LED_CUBE::setSlope_XY(int x1, int y1, int x2, int y2) { float slope, offset; int x,y,z; if (x1>x2) { int tmp; tmp = x2; x2 = x1; x1 = tmp; tmp = y2; y2 = y1; y1 = tmp; } slope=float(y2-y1)/float(x2-x1); offset=-x1*slope +y1; if ((x2-x1)>=7) { for(x=0; x<8; x++) { y = floor((x*slope + offset)+0.5); for(z=0; z<8; z++) { setVoxel(x,y,z); } } } else if(x1==x2) { for(y=0; y<8; y++) { for(z=0; z<8; z++) { setVoxel(x1,y,z); } } } else { for(y=0; y<8; y++) { x = floor(((y-offset)/slope)+0.5); for(z=0; z<8; z++) { setVoxel(x,y,z); } } } } void LED_CUBE::setSlope_XZ(int x1, int z1, int x2, int z2) { float slope, offset; int x,z; if (x1>x2) { int tmp; tmp = x2; x2 = x1; x1 = tmp; tmp = z2; z2 = z1; z1 = tmp; } slope=float(z2-z1)/float(x2-x1); offset=-x1*slope +z1; if ((x2-x1)>=7) { for(x=0; x<8; x++) { z = floor((x*slope + offset)+0.5); cubeData[z*8 + x] = 0xFF; } } else if(x1==x2) { for(z=0; z<8; z++) { cubeData[z*8 + x1] = 0xFF; } } else { for(z=0; z<8; z++) { x = floor(((z-offset)/slope)+0.5); cubeData[z*8 + x] = 0xFF; } } } void LED_CUBE::setSlope_YZ(int y1, int z1, int y2, int z2) { float slope, offset; int x,y,z; if (y1>y2) { int tmp; tmp = y2; y2 = y1; y1 = tmp; tmp = z2; z2 = z1; z1 = tmp; } slope=float(z2-z1)/float(y2-y1); offset=-y1*slope +z1; if ((y2-y1)>=7) { for(y=0; y<8; y++) { z = floor((y*slope + offset)+0.5); for(x=0; x<8; x++) { setVoxel(x,y,z); } } } else if(y1==y2) { for(z=0; z<8; z++) { for(x=0; x<8; x++) { setVoxel(x,y1,z); } } } else { for(z=0; z<8; z++) { y = floor(((z-offset)/slope)+0.5); for(x=0; x<8; x++) { setVoxel(x,y,z); } } } } //clear all the voxels in the array void LED_CUBE::clearVoxels(void) { memset(cubeData, 0, 64*sizeof(unsigned char)); } // Fill a value into all 64 byts of the cube buffer // Mostly used for clearing. fill(0xr0) // or setting all on. fill(0xff) void LED_CUBE::fill (unsigned char pattern) { memset(cubeData, pattern, 64*sizeof(unsigned char)); } // Draw a box with all walls drawn and all voxels inside set void LED_CUBE::box_filled(int x1, int y1, int z1, int x2, int y2, int z2) { int ix; int iz; argorder(x1, x2, &x1, &x2); argorder(y1, y2, &y1, &y2); argorder(z1, z2, &z1, &z2); for (iz=z1; iz<=z2; iz++) { for (ix=x1; ix<=x2; ix++) { cubeData[iz*8 + ix] |= byteline(y1,y2); } } } // Draw a hollow box with side walls. void LED_CUBE::box_walls(int x1, int y1, int z1, int x2, int y2, int z2) { int ix; int iz; argorder(x1, x2, &x1, &x2); argorder(y1, y2, &y1, &y2); argorder(z1, z2, &z1, &z2); for (iz=z1; iz<=z2; iz++) { for (ix=x1; ix<=x2; ix++) { if (ix == x1 || ix == x2 || iz == z1 || iz == z2) { cubeData[iz*8 + ix] = byteline(y1,y2); } else { cubeData[iz*8 + ix] |= ((0x01 << y1) | (0x01 << y2)); } } } } // Draw a wireframe box. This only draws the corners and edges, // no walls. void LED_CUBE::box_wireframe(int x1, int y1, int z1, int x2, int y2, int z2) { int ix; int iz; argorder(x1, x2, &x1, &x2); argorder(y1, y2, &y1, &y2); argorder(z1, z2, &z1, &z2); // Lines along Y axis cubeData[z1*8 + x1] |= byteline(y1,y2); cubeData[z1*8 + x2] |= byteline(y1,y2); cubeData[z2*8 + x1] |= byteline(y1,y2); cubeData[z2*8 + x2] |= byteline(y1,y2); // Lines along X axis for (ix=x1; ix<=x2; ix++) { setVoxel(ix,y1,z1); setVoxel(ix,y1,z2); setVoxel(ix,y2,z1); setVoxel(ix,y2,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); } } // Draw a line between any coordinates in 3d space. // Uses integer values for input, so dont expect smooth animations. void LED_CUBE::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; // 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); } else { xy = (float)(y2-y1)/(float)(x2-x1); } if (z1>z2) { xz = (float)(z1-z2)/(float)(x2-x1); } else { xz = (float)(z2-z1)/(float)(x2-x1); } // 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); } } void LED_CUBE::circle(int xr, int yr, int zr, int d ,char axis) { if (d%2) { // odd diameter, place center on half pixels // later } else { // use midpoint circle algorithm int r = d/2; int f = 1 - r; int ddF_x = 1; int ddF_y = -2 * r; int x = 0; int y = r; setVoxel(xr, yr+r, zr); setVoxel(xr, yr-r, zr); setVoxel(xr+r, yr, zr); setVoxel(xr-r, yr, zr); while (x<y) { if (f >= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; setVoxel(xr + x, yr + y, zr); setVoxel(xr - x, yr + y, zr); setVoxel(xr + x, yr - y, zr); setVoxel(xr - x, yr - y, zr); setVoxel(xr + y, yr + x, zr); setVoxel(xr - y, yr + x, zr); setVoxel(xr + y, yr - x, zr); setVoxel(xr - y, yr - x, zr); } } } void LED_CUBE::CopyBlock(int x1, int y1, int z1, int x2, int y2, int z2, int xc, int yc, int zc) { int ix; int iz; int nx; int nz=0; unsigned char tmp_data[64]; argorder(x1, x2, &x1, &x2); argorder(y1, y2, &y1, &y2); argorder(z1, z2, &z1, &z2); for (iz=z1; iz<=z2; iz++) { nx=0; for (ix=x1; ix<=x2; ix++) { //copy block data into tmp array and mask. tmp_data[iz*8 + ix] = cubeData[iz*8 + ix] & byteline(y1,y2); //shift the tmp data to the new y location if (yc >= y1) { tmp_data[iz*8 + ix] = tmp_data[iz*8 + ix] << (yc-y1); } else { tmp_data[iz*8 + ix] = tmp_data[iz*8 + ix] >> (y1-yc); } //alter the cubedata on the new x and z location with the tmp data. use old y location and copy to the new location cubeData[(zc+nz)*8 + xc+nx] = (cubeData[(zc+nz)*8 + xc+nx] & (~byteline(yc,yc+y2-y1))) | tmp_data[iz*8 + ix]; nx++; } nz++; } } void LED_CUBE::MoveBlock(int x1, int y1, int z1, int x2, int y2, int z2, int xm, int ym, int zm) { int ix; int iz; int nx; int nz=0; unsigned char tmp_data[64]; argorder(x1, x2, &x1, &x2); argorder(y1, y2, &y1, &y2); argorder(z1, z2, &z1, &z2); for (iz=z1; iz<=z2; iz++) { for (ix=x1; ix<=x2; ix++) { //copy block data into tmp array and mask. tmp_data[iz*8 + ix] = cubeData[iz*8 + ix] & byteline(y1,y2); //clear the original voxels cubeData[iz*8 + ix] &= ~byteline(y1,y2); //shift the tmp data to the new y location if (ym >= y1) { tmp_data[iz*8 + ix] = tmp_data[iz*8 + ix] << (ym-y1); } else { tmp_data[iz*8 + ix] = tmp_data[iz*8 + ix] >> (y1-ym); } } } for (iz=z1; iz<=z2; iz++) { nx=0; for (ix=x1; ix<=x2; ix++) { //alter the cubedata on the new x and z location with the tmp data. use old y location and copy to the new location cubeData[(zm+nz)*8 + xm+nx] = (cubeData[(zm+nz)*8 + xm+nx] & (~byteline(ym,ym+y2-y1))) | tmp_data[iz*8 + ix]; nx++; } nz++; } } char LED_CUBE::byteline (int start, int end) { char line=0; int bitnr; for (bitnr=0; bitnr<8; bitnr++) { if (bitnr>=start && bitnr<=end) { line |= (1<<bitnr); } } return line; } // This function validates that we are drawing inside the cube. unsigned char LED_CUBE::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; } } void LED_CUBE::argorder(int ix1, int ix2, int *ox1, int *ox2) { if (ix1>ix2) { int tmp; tmp = ix1; ix1= ix2; ix2 = tmp; } *ox1 = ix1; *ox2 = ix2; } double LED_CUBE::map(double in, double inMin, double inMax, double outMin, double outMax) { double out; out = (in-inMin)/(inMax-inMin)*(outMax-outMin) + outMin; return out; }