8x8x8 Led Cube driven by 4x PCF8575 for the columns and 1x PCF8574 for the layers
Revision 1:e08a4d27f534, committed 2012-11-01
- Comitter:
- Bas
- Date:
- Thu Nov 01 22:31:54 2012 +0000
- Parent:
- 0:920c5ed65a45
- Commit message:
- Added several simple graphic functions helping to create animations
Changed in this revision
led_cube.cpp | Show annotated file Show diff for this revision Revisions of this file |
led_cube.h | Show annotated file Show diff for this revision Revisions of this file |
--- a/led_cube.cpp Sat Sep 08 22:14:10 2012 +0000 +++ b/led_cube.cpp Thu Nov 01 22:31:54 2012 +0000 @@ -30,7 +30,8 @@ } //clear everything -void LED_CUBE::clear_cube(void){ +void LED_CUBE::clear_cube(void) +{ row.WriteByte(0xFF); colums_0_1.WriteBytes(0xFF,0xFF); colums_2_3.WriteBytes(0xFF,0xFF); @@ -39,35 +40,555 @@ clearVoxels(); } -//set a voxel in my space saver cube array -void LED_CUBE::setVoxel(unsigned char x, unsigned char y, unsigned char z){ - cubeData[z*8 + y] |= 0x01<<x; +//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 my space saver cube array -void LED_CUBE::clearVoxel(unsigned char x, unsigned char y, unsigned char z){ - cubeData[z*8 + y] &= ~(0x01<<x); +//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 the voxel in my cube array -unsigned char LED_CUBE::getVoxel(unsigned char x, unsigned char y, unsigned char z){ - if(cubeData[z*8 + y] & 0x01<<x){ - return 1; - }else{ +//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 < Zd; z++){ - if(col&(0x01<<z)){ +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{ + } 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){ +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; } \ No newline at end of file
--- a/led_cube.h Sat Sep 08 22:14:10 2012 +0000 +++ b/led_cube.h Thu Nov 01 22:31:54 2012 +0000 @@ -1,46 +1,66 @@ -#ifndef __LED_CUBE_H -#define __LED_CUBE_H - -#define VERSION 1.0 - -#include <mbed.h> -#include "pcf8574.h" -#include "pcf8575.h" - -#define PI 3.14159 -#define Xd 8 -#define Yd 8 -#define Zd 8 -#define centre 3.5 -#define Vd Xd*Yd*Zd - -#define SB(x,n) (x|=(1<<n)) -#define CB(x,n) (x&=~(1<<n)) -#define TB(x,n) (x^=(1<<n)) -#define PB(x,n) do{SB(x,n);CB(x,n);}while(0) - -class LED_CUBE -{ -public: - LED_CUBE(I2C* _interface); - ~LED_CUBE(void); - - void clear_cube(void); - void setVoxel(unsigned char x, unsigned char y, unsigned char z); - void clearVoxel(unsigned char x, unsigned char y, unsigned char z); - unsigned char getVoxel(unsigned char x, unsigned char y, unsigned char z); - void copyColumn(unsigned char x, unsigned char y, unsigned char col); - void clearVoxels(void); - -private: - PCF8574 row; - PCF8575 colums_0_1; - PCF8575 colums_2_3; - PCF8575 colums_4_5; - PCF8575 colums_6_7; - unsigned char cubeData[64]; - Ticker duty; - void UpdateRow(void); - -}; +#ifndef __LED_CUBE_H +#define __LED_CUBE_H + +#define VERSION 1.0 + +#include <mbed.h> +#include "pcf8574.h" +#include "pcf8575.h" + +#define AXIS_X 1 +#define AXIS_Y 2 +#define AXIS_Z 3 +#define PI 3.14159265 +#define center 3.5 +#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) + +class LED_CUBE +{ +public: + LED_CUBE(I2C* _interface); + ~LED_CUBE(void); + + void clear_cube(void); + void setVoxel(unsigned char x, unsigned char y, unsigned char z); + void clearVoxel(unsigned char x, unsigned char y, unsigned char z); + unsigned char getVoxel(unsigned char x, unsigned char y, unsigned char z); + void copyColumn(unsigned char x, unsigned char y, unsigned char col); + void alterVoxel(unsigned char x, unsigned char y, unsigned char z, unsigned char state); + void flipVoxel(unsigned char x, unsigned char y, unsigned char z); + void setPlane_x (int x); + void clearPlane_x (int x); + void setPlane_y (int y); + void clearPlane_y (int y); + void setPlane_z (int z); + void clearPlane_z (int z); + void setPlane (char axis, unsigned char i); + void clearPlane (char axis, unsigned char i); + void setSlope_XY(int x1, int y1, int x2, int y2); + void setSlope_XZ(int x1, int z1, int x2, int z2); + void setSlope_YZ(int y1, int z1, int y2, int z2); + void clearVoxels(void); + void fill (unsigned char pattern); + void box_filled(int x1, int y1, int z1, int x2, int y2, int z2); + void box_walls(int x1, int y1, int z1, int x2, int y2, int z2); + void box_wireframe(int x1, int y1, int z1, int x2, int y2, int z2); + void line(int x1, int y1, int z1, int x2, int y2, int z2); + void circle(int xr, int yr, int zr, int d ,char axis); + void CopyBlock(int x1, int y1, int z1, int x2, int y2, int z2, int xc, int yc, int zc); + void MoveBlock(int x1, int y1, int z1, int x2, int y2, int z2, int xm, int ym, int zm); + void RotateBlock(int x1, int y1, int height, char axis, char dir); + +private: + PCF8574 row; + PCF8575 colums_0_1; + PCF8575 colums_2_3; + PCF8575 colums_4_5; + PCF8575 colums_6_7; + unsigned char cubeData[64]; + Ticker duty; + void UpdateRow(void); + char byteline (int start, int end); + unsigned char inrange(int x, int y, int z); + void argorder(int ix1, int ix2, int *ox1, int *ox2); + double map(double in, double inMin, double inMax, double outMin, double outMax); + }; #endif \ No newline at end of file