p857211 发表于 2013-6-18 00:05:02

Arduino 8x8x8的光立方制作过程(附电路图和程式码)

本帖最后由 p857211 于 2013-6-18 00:19 编辑




视频:Arduino 8x8x8 Cube    http://www.youtube.com/watch?v=1YnRPepOV4E
先前实验制作的4x4x4         http://www.youtube.com/watch?v=daCo3CaDQsA


#include <avr/interrupt.h>
#include <string.h>
#define AXIS_X 1
#define AXIS_Y 2
#define AXIS_Z 3

volatile unsigned char cube;
volatile int current_layer = 0;

void setup()
{
int i;

for(i=0; i<14; i++)
    pinMode(i, OUTPUT);


DDRC = 0xff;
PORTC = 0x00;


TCCR2A = 0x00;
TCCR2B = 0x00;

TCCR2A |= (0x01 << WGM21);
OCR2A = 10;
TCNT2 = 0x00;
TCCR2B |= (0x01 << CS22) | (0x01 << CS21);

TIMSK2 |= (0x01 << OCIE2A);
}

ISR (TIMER2_COMPA_vect)
{
int i;


PORTC = 0x00;
PORTB &= 0x0f;

PORTB |= 0x08;

for (i=0; i<8; i++)
{
    PORTD = cube;
    PORTB = (PORTB & 0xF8) | (0x07 & (i+1));
}

PORTB &= 0b00110111;

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, 1000);
    effect_planboing(AXIS_Y, 1000);
    effect_planboing(AXIS_X, 1000);
    effect_boxside_randsend_parallel (AXIS_X, 0, 100, 1);
    effect_boxside_randsend_parallel (AXIS_X, 1, 100, 1);
    effect_boxside_randsend_parallel (AXIS_Y, 0, 100, 1);
    effect_boxside_randsend_parallel (AXIS_Y, 1, 100, 1);
    effect_boxside_randsend_parallel (AXIS_Z, 0, 100, 1);
    effect_boxside_randsend_parallel (AXIS_Z, 1, 100, 1);
    effect_random_filler(20,1);
    effect_random_filler(20,0);
    effect_random_filler(20,1);
    effect_random_filler(20,0);
space(100);
space(100);

firework(-2,1,600);
   
    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);
    space(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);
    firework(0,0,0);
firework(-2,-2,50);
firework(1,1,-250);
firework(0,1,200);
firework(1,-3,400);
firework(2,-3,600);
firework(2,1,500);
firework(2,-2,200);
firework(2,1,0);
firework(0,0,0);



firework(2,-2,500);
   
}
}


// ==========================================================================================
//   Effect functions


void space(int iterations){

        int i, ii;
        int rnd_y;
        int rnd_z;
        int rnd_num;
      int time;
       
      time = 700;

        for (ii=0;ii<iterations;ii++)
        {
                time = time - (iterations/15);
                rnd_num = rand()%4;
               
                for (i=0; i < rnd_num;i++)
                {
                        rnd_y = rand()%8;
                        rnd_z = rand()%8;
                        setvoxel(7,rnd_y,rnd_z);
                }
               
                delay_ms(time);
                shift(AXIS_X,-1);
        }

        for (ii=0;ii<iterations;ii++)
        {
                time = time + (iterations/15);
                rnd_num = rand()%4;
               
                for (i=0; i < rnd_num;i++)
                {
                        rnd_y = rand()%8;
                        rnd_z = rand()%8;
                        setvoxel(7,rnd_y,rnd_z);
                }
               
                delay_ms(time);
                shift(AXIS_X,-1);
        }

}



void firework(int i,int j, int time){

fill(0x00);

setvoxel(3-i,4-j,0);
delay_ms(900-time);

clrvoxel(3-i,4-j,0);
setvoxel(4-i,4-j,1);
delay_ms(1200-time);

clrvoxel(4-i,4-j,1);
setvoxel(4-i,5-j,2);
delay_ms(1400-time);

clrvoxel(4-i,5-j,2);
setvoxel(3-i,5-j,3);
delay_ms(1700-time);

clrvoxel(3-i,5-j,3);
setvoxel(3-i,4-j,4);
delay_ms(2000-time);

clrvoxel(3-i,4-j,4);
setvoxel(4-i,4-j,5);
delay_ms(2000-time);

clrvoxel(4-i,4-j,5);
setvoxel(4-i,3-j,6);
delay_ms(2000-time);

//Explode
clrvoxel(4-i,3-j,6);
setvoxel(4-i,3-j,7);
setvoxel(4-i,4-j,6);
setvoxel(4-i,2-j,6);
setvoxel(3-i,3-j,6);
setvoxel(5-i,3-j,6);
delay_ms(2000-time);

shift(AXIS_Z,-1);
setvoxel(4-i,5-j,5);
setvoxel(4-i,1-j,5);
setvoxel(2-i,3-j,5);
setvoxel(6-i,3-j,5);
delay_ms(900-time);

shift(AXIS_Z,-1);
setvoxel(4-i,6-j,3);
setvoxel(4-i,0-j,3);
setvoxel(1-i,3-j,3);
setvoxel(7-i,3-j,3);
delay_ms(900-time);

shift(AXIS_Z,-1);
setvoxel(4-i,7-j,1);
setvoxel(3-i,0-j,1);
setvoxel(0-i,3-j,1);
setvoxel(7-i,2-j,1);
delay_ms(1400-time);

shift(AXIS_Z,-1);
delay_ms(1400-time);

shift(AXIS_Z,-1);
delay_ms(1400-time);

shift(AXIS_Z,-1);
delay_ms(1400-time);

shift(AXIS_Z,-1);
delay_ms(700-time);

fill(0x00);

}


// ==========================================================================================

void draw_positions_axis (char axis, unsigned char positions, 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;
        unsigned char pos;
        int notdone = 1;
        int notdone2 = 1;
        int sent = 0;
       
        for (i=0;i<64;i++)
        {
                pos = 0;
        }
       
        while (notdone)
        {
                if (mode == 1)
                {
                        notdone2 = 1;
                        while (notdone2 && sent<64)
                        {
                                i = rand()%64;
                                if (pos == 0)
                                {
                                        sent++;
                                        pos += 1;
                                        notdone2 = 0;
                                }
                        }
                } else if (mode == 2)
                {
                        if (sent<64)
                        {
                                pos += 1;
                                sent++;
                        }
                }
               
                done = 0;
                for (i=0;i<64;i++)
                {
                        if (pos > 0 && pos <7)
                        {
                                pos += 1;
                        }
                               
                        if (pos == 7)
                                done++;
                }
               
                if (done == 64)
                        notdone = 0;
               
                for (i=0;i<64;i++)
                {
                        if (origin == 0)
                        {
                                cubepos = pos;
                        } else
                        {
                                cubepos = (7-pos);
                        }
                }
               
               
                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 |= (1 << x);
}


// Set a single voxel to ON
void clrvoxel(int x, int y, int z)
{
        if (inrange(x,y,z))
                cube &= ~(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 & (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 ^= (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 = 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 = 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 |= (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 &= ~(1 << x);
                        }
                }
        }
}

void setplane_y (int y)
{
        int z;
        if (y>=0 && y<8)
        {
                for (z=0;z<8;z++)
                        cube = 0xff;
        }
}

void clrplane_y (int y)
{
        int z;
        if (y>=0 && y<8)
        {
                for (z=0;z<8;z++)
                        cube = 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 = 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 |= 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 = byteline(x1,x2);
                        } else
                        {
                                cube |= ((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 = byteline(x1,x2);
        cube = byteline(x1,x2);
        cube = byteline(x1,x2);
        cube = 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迴圈
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");
      }
    }
}
}



//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);
                }
        }
}

bacon6581 发表于 2013-6-18 07:09:22

这小线飞的,真赞!

heiketiguo 发表于 2013-6-18 07:53:33

视频怎么是Youtube?

幻生幻灭 发表于 2013-6-18 08:47:14

有密集恐惧症和缺乏耐心毅力者请勿模仿哈

咯小3虽 发表于 2013-6-18 09:13:33

厉害!膜拜

学慧放弃 发表于 2013-6-18 09:51:28

我焊的时候是一个一个用尺量的,焊得不错

五哥U五哥 发表于 2013-6-18 20:03:19

视频只有9’’。

五哥U五哥 发表于 2013-6-18 20:11:04

第一个视频只有9’’。

Pizzro 发表于 2013-6-19 02:04:28

蛋疼的男人

谷东昌 发表于 2014-1-8 18:15:43

谢谢楼主!!!

nust_奔跑 发表于 2014-1-8 20:05:45

楼主真心强大啊!

谷东昌 发表于 2014-1-9 03:18:56

楼主问一下你这个代码看的懂吗??
还有arduino的i/o口是怎么接的,分别是哪几个i/o口接到板子上,哪几个接138??哪几个接74hc574??还有哪几个接地线??

谷东昌 发表于 2014-1-9 03:19:37


楼主问一下你这个代码看的懂吗??
firework();啥意思??百度不到。。

p857211 发表于 2014-1-14 10:32:57

谷东昌 发表于 2014-1-9 03:19 static/image/common/back.gif
楼主问一下你这个代码看的懂吗??
firework();啥意思??百度不到。。

firrework(); 那是煙火的動畫程式
運算都寫在副程式裡
在loop裡用函數把它呼叫出來
這樣方便 隨意編排動畫順序
而不會導致 重復復製相同的程式 亂七八糟 讓自己看不懂

谷东昌 发表于 2014-1-20 21:33:24

p857211 发表于 2014-1-14 10:32 static/image/common/back.gif
firrework(); 那是煙火的動畫程式
運算都寫在副程式裡
在loop裡用函數把它呼叫出來


谢过。。。。。。。
页: [1] 2
查看完整版本: Arduino 8x8x8的光立方制作过程(附电路图和程式码)