Skip to content

Instantly share code, notes, and snippets.

@c00kiemon5ter
Last active December 24, 2015 01:59
Show Gist options
  • Select an option

  • Save c00kiemon5ter/6727747 to your computer and use it in GitHub Desktop.

Select an option

Save c00kiemon5ter/6727747 to your computer and use it in GitHub Desktop.

Revisions

  1. c00kiemon5ter revised this gist Sep 27, 2013. 1 changed file with 3 additions and 11 deletions.
    14 changes: 3 additions & 11 deletions cube_mcp23017.ino
    Original file line number Diff line number Diff line change
    @@ -76,17 +76,9 @@ static void check_mcp(void) {
    else Serial.println("done\n");
    }

    static void print_gpio_a_state(void) {
    Serial.print("gpioa state: ");
    Serial.println(gpio_a, BIN);
    }
    static void print_gpio_b_state(void) {
    Serial.print("gpiob state: ");
    Serial.println(gpio_b, BIN);
    }
    static void print_gpio_state(void) {
    print_gpio_a_state();
    print_gpio_b_state();
    static void print_gpio_state(const byte gpio) {
    Serial.print("gpio state: ");
    Serial.println(gpio, BIN);
    }

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */
  2. c00kiemon5ter revised this gist Sep 27, 2013. No changes.
  3. c00kiemon5ter created this gist Sep 27, 2013.
    340 changes: 340 additions & 0 deletions cube_mcp23017.ino
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,340 @@
    /* Cube project throug mcp23017 */
    #include <Wire.h>

    static const byte MCP_ADDR = 0x20; // I2C Address of MCP23017 Chip
    static const byte GPIO_A = 0x12; // Register Address of Port A
    static const byte GPIO_B = 0x13; // Register Address of Port B

    /* global state of gpio ports */
    static byte gpio_a;
    static byte gpio_b;

    /* Working with a 3x3 Cube */
    static const unsigned CUBE_SIDE = 3;

    /* each pin belongs in a bank and has a mask */
    struct pin {
    const byte gpio;
    const byte mask;
    };

    /* 3 Levels of 3x3=9 leds each */
    static const struct pin LVL_0 = { GPIO_B, 0b00000001 };
    static const struct pin LVL_1 = { GPIO_B, 0b00000100 };
    static const struct pin LVL_2 = { GPIO_B, 0b00000010 };

    static const struct pin levels[CUBE_SIDE] = { LVL_0, LVL_1, LVL_2 };

    /* 3x3=9 columns in a grid - COL_<y><x> */
    static const struct pin COL_00 = { GPIO_B, 0b00100000 };
    static const struct pin COL_01 = { GPIO_B, 0b00001000 };
    static const struct pin COL_02 = { GPIO_B, 0b00010000 };
    static const struct pin COL_10 = { GPIO_A, 0b00000100 };
    static const struct pin COL_11 = { GPIO_A, 0b00010000 };
    static const struct pin COL_12 = { GPIO_A, 0b00001000 };
    static const struct pin COL_20 = { GPIO_A, 0b00100000 };
    static const struct pin COL_21 = { GPIO_A, 0b01000000 };
    static const struct pin COL_22 = { GPIO_A, 0b10000000 };

    static const pin columns[CUBE_SIDE][CUBE_SIDE] = {
    { COL_00, COL_01, COL_02 },
    { COL_10, COL_11, COL_12 },
    { COL_20, COL_21, COL_22 },
    };

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */
    /* DEBUG HELPERS */
    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    static void check_mcp(void) {
    byte error, address;
    int nDevices;

    Serial.println("Scanning for I2C...");

    nDevices = 0;
    for(address = 1; address < 127; address++ ) {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0) {
    Serial.print("I2C device found at address 0x");
    if (address < 16) Serial.print("0");
    Serial.println(address, HEX);
    nDevices++;
    } else if (error == 4) {
    Serial.print("Unknow error at address 0x");
    if (address < 16) Serial.print("0");
    Serial.println(address, HEX);
    }
    }

    if (nDevices == 0) Serial.println("No I2C devices found\n");
    else Serial.println("done\n");
    }

    static void print_gpio_a_state(void) {
    Serial.print("gpioa state: ");
    Serial.println(gpio_a, BIN);
    }
    static void print_gpio_b_state(void) {
    Serial.print("gpiob state: ");
    Serial.println(gpio_b, BIN);
    }
    static void print_gpio_state(void) {
    print_gpio_a_state();
    print_gpio_b_state();
    }

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */
    /* INIT STATE */
    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    void setup(void)
    {
    Wire.begin();
    Serial.begin(9600);

    Wire.beginTransmission(MCP_ADDR);
    Wire.write(0b00000000);
    Wire.write(0b00000000); // set all of GPIO A to outputs
    Wire.write(0b00000000); // set all of GPIO B to outputs
    Wire.endTransmission();

    /* clear all GPIO A pins */
    Wire.beginTransmission(MCP_ADDR);
    Wire.write(GPIO_A);
    Wire.write(0b00000000);
    Wire.endTransmission();

    /* clear all GPIO B pins */
    Wire.beginTransmission(MCP_ADDR);
    Wire.write(GPIO_B);
    Wire.write(0b00000000);
    Wire.endTransmission();

    /* initialize randomizer */
    randomSeed(analogRead(0));
    }

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */
    /* MAIN EXECUTION */
    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    static inline const byte bit_clear(byte * const gpio, const struct pin pin) { return (*gpio &= ~pin.mask); }
    static inline const byte bit_set (byte * const gpio, const struct pin pin) { return (*gpio |= pin.mask); }
    static const byte (* const operation[2])(byte * const gpio, const struct pin pin) = { bit_clear, bit_set };

    static void set_pin(const struct pin pin, const bool state) {
    Wire.beginTransmission(MCP_ADDR);
    Wire.write(pin.gpio);
    switch (pin.gpio) {
    case GPIO_A: Wire.write((operation[state](&gpio_a, pin))); break;
    case GPIO_B: Wire.write((operation[state](&gpio_b, pin))); break;
    }
    Wire.endTransmission();
    }

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    static void set_led(const unsigned z, const unsigned y, const unsigned x, const bool state) {
    set_pin(levels[z], state);
    set_pin(columns[y][x], state);
    }

    static void set_all_lvls(const bool state) {
    for (unsigned lvl=0; lvl<CUBE_SIDE; ++lvl)
    set_pin(levels[lvl], state);
    }
    static void set_all_cols(const bool state) {
    for (unsigned y=0; y<CUBE_SIDE; ++y)
    for (unsigned x=0; x<CUBE_SIDE; ++x)
    set_pin(columns[y][x], state);
    }

    static void set_all(const bool state) {
    set_all_lvls(state);
    set_all_cols(state);
    }

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    static void blink_all(const unsigned d = 500) {
    set_all(HIGH);
    delay(d);
    set_all(LOW);
    delay(d);
    }

    static void zig_zag(const unsigned d = 500) {
    const struct pin order[CUBE_SIDE * CUBE_SIDE] = {
    COL_00, COL_01, COL_02,
    COL_12, COL_11, COL_10,
    COL_20, COL_21, COL_22,
    };

    set_all_cols(LOW);
    set_all_lvls(HIGH);

    for (unsigned col=0; col<CUBE_SIDE*CUBE_SIDE; ++col) {
    set_pin(order[col], HIGH);
    delay(d);
    }
    }

    static void spin(const unsigned d = 500) {
    const struct {
    struct pin led[CUBE_SIDE];
    } order[CUBE_SIDE+1] = {
    { { COL_10, COL_11, COL_12 } },
    { { COL_00, COL_11, COL_22 } },
    { { COL_01, COL_11, COL_21 } },
    { { COL_02, COL_11, COL_20 } },
    };

    set_all_lvls(HIGH);
    for (unsigned i = 0; i<CUBE_SIDE+1; ++i) {
    for (unsigned l = 0; l<CUBE_SIDE; ++l)
    set_pin(order[i].led[l], HIGH);
    delay(d);
    for (unsigned l = 0; l<CUBE_SIDE; ++l)
    set_pin(order[i].led[l], LOW);
    }
    }

    static void spin_outer(const unsigned d = 500) {
    const struct {
    struct pin led[2];
    } order[CUBE_SIDE+1] = {
    { { COL_10, COL_12 } },
    { { COL_00, COL_22 } },
    { { COL_01, COL_21 } },
    { { COL_02, COL_20 } },
    };

    set_all_lvls(HIGH);
    for (unsigned i = 0; i<CUBE_SIDE+1; ++i) {
    for (unsigned l=0; l<2; ++l)
    set_pin(order[i].led[l], HIGH);
    delay(d);
    for (unsigned l=0; l<2; ++l)
    set_pin(order[i].led[l], LOW);
    }
    }

    static void rain(const unsigned d = 500) {
    for (unsigned i=0; i<CUBE_SIDE*CUBE_SIDE; ++i) {
    long x1 = random(CUBE_SIDE);
    long y1 = random(CUBE_SIDE);
    long x2 = random(CUBE_SIDE);
    long y2 = random(CUBE_SIDE);
    for (int lvl=CUBE_SIDE-1; lvl>=0; --lvl) {
    set_pin(levels[lvl], HIGH);
    set_pin(columns[y1][x1], HIGH);
    set_pin(columns[y2][x2], HIGH);
    delay(d);
    set_pin(levels[lvl], LOW);
    set_pin(columns[y1][x1], LOW);
    set_pin(columns[y2][x2], LOW);
    }
    }
    }

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    static void set_slice(const unsigned slice, const char axis, const uint8_t state) {
    switch (axis) {
    case 'x':
    set_all_lvls(state);
    for (unsigned x=0; x<CUBE_SIDE; ++x)
    set_pin(columns[slice][x], state);
    break;
    case 'y':
    set_all_lvls(state);
    for (unsigned y=0; y<CUBE_SIDE; ++y)
    set_pin(columns[y][slice], state);
    break;
    case 'z':
    set_all_cols(state);
    set_pin(levels[slice], state);
    break;
    }
    }

    static void cube_slices(const unsigned d = 500) {
    for (char *p = "xyz"; *p; ++p) {
    for (unsigned slice=0; slice<CUBE_SIDE; ++slice) {
    set_slice(slice, *p, HIGH);
    delay(d);
    set_slice(slice, *p, LOW);
    }
    }
    }

    static void up_down(const unsigned d = 500) {
    const unsigned lvl_order[CUBE_SIDE+1] = { 0, 1, 2, 1, };

    /* light all columns */
    set_all_cols(HIGH);
    set_all_lvls(LOW);

    /* light each level in order */
    for (unsigned lvl=0; lvl<CUBE_SIDE+1; ++lvl) {
    set_slice(lvl_order[(CUBE_SIDE+lvl)%(CUBE_SIDE+1)], 'z', LOW);
    set_slice(lvl_order[lvl], 'z', HIGH);
    delay(d);
    }
    }

    static void cube_sides(const unsigned d = 500) {
    const struct {
    unsigned slice;
    char axis;
    } order[CUBE_SIDE*2] = {
    {0, 'x'}, {0, 'y'}, {2, 'z'},
    {2, 'x'}, {2, 'y'}, {0, 'z'},
    };

    set_all(LOW);

    for (unsigned i=0; i<CUBE_SIDE*2; ++i) {
    set_slice(order[i].slice, order[i].axis, HIGH);
    delay(d);
    set_slice(order[i].slice, order[i].axis, LOW);
    }
    }

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    void loop(void)
    {
    static const unsigned fast = 150;
    static const unsigned norm = 400;
    static const unsigned slow = 600;

    static struct effect {
    const unsigned repeat;
    void (* const effect)(const unsigned interval);
    const unsigned interval;
    } effects[] = {
    { 2, blink_all, slow },
    { 3, blink_all, norm },
    { 5, blink_all, fast },
    { 2, cube_slices, norm },
    { 3, up_down, norm },
    { 2, cube_sides, norm },
    { 3, zig_zag, fast },
    { 6, spin, fast },
    { 5, spin_outer, fast },
    { 4, rain, fast },
    /* -- end of effects -- */
    { 0, NULL, 0 },
    };

    for (struct effect *e = effects; e; ++e)
    for (unsigned i=0; i<e->repeat; ++i)
    e->effect(e->interval);
    }
  4. @grobotronics grobotronics renamed this gist Sep 16, 2013. 1 changed file with 40 additions and 57 deletions.
    97 changes: 40 additions & 57 deletions 3x3_cube_mcp.ino → cube_mcp23017.ino
    Original file line number Diff line number Diff line change
    @@ -99,23 +99,21 @@ void setup(void)
    Serial.begin(9600);

    Wire.beginTransmission(MCP_ADDR);
    Wire.write((byte)0x00);
    Wire.write((byte)0x00); // set all of GPIO A to outputs
    Wire.write((byte)0x00); // set all of GPIO B to outputs
    Wire.write(0b00000000);
    Wire.write(0b00000000); // set all of GPIO A to outputs
    Wire.write(0b00000000); // set all of GPIO B to outputs
    Wire.endTransmission();

    /* clear all GPIOA pins */
    gpio_a = 0b00000000;
    /* clear all GPIO A pins */
    Wire.beginTransmission(MCP_ADDR);
    Wire.write(GPIO_A);
    Wire.write(gpio_a);
    Wire.write(0b00000000);
    Wire.endTransmission();

    /* clear all GPIOB pins */
    gpio_b = 0b00000000;
    /* clear all GPIO B pins */
    Wire.beginTransmission(MCP_ADDR);
    Wire.write(GPIO_B);
    Wire.write(gpio_b);
    Wire.write(0b00000000);
    Wire.endTransmission();

    /* initialize randomizer */
    @@ -189,73 +187,58 @@ static void zig_zag(const unsigned d = 500) {

    static void spin(const unsigned d = 500) {
    const struct {
    struct {
    unsigned y;
    unsigned x;
    } led_cords[3];
    struct pin led[CUBE_SIDE];
    } order[CUBE_SIDE+1] = {
    { { {1,0}, {1,1}, {1,2} } },
    { { {0,0}, {1,1}, {2,2} } },
    { { {2,1}, {1,1}, {0,1} } },
    { { {2,0}, {1,1}, {0,2} } }
    { { COL_10, COL_11, COL_12 } },
    { { COL_00, COL_11, COL_22 } },
    { { COL_01, COL_11, COL_21 } },
    { { COL_02, COL_11, COL_20 } },
    };

    set_all_lvls(HIGH);
    for (unsigned i = 0; i<CUBE_SIDE+1; ++i) {
    for (unsigned lvl=0; lvl<CUBE_SIDE; ++lvl) {
    set_led(lvl, order[i].led_cords[0].y, order[i].led_cords[0].x, HIGH);
    set_led(lvl, order[i].led_cords[1].y, order[i].led_cords[1].x, HIGH);
    set_led(lvl, order[i].led_cords[2].y, order[i].led_cords[2].x, HIGH);
    }
    for (unsigned l = 0; l<CUBE_SIDE; ++l)
    set_pin(order[i].led[l], HIGH);
    delay(d);
    for (unsigned lvl=0; lvl<CUBE_SIDE; ++lvl) {
    set_led(lvl, order[i].led_cords[0].y, order[i].led_cords[0].x, LOW);
    set_led(lvl, order[i].led_cords[1].y, order[i].led_cords[1].x, LOW);
    set_led(lvl, order[i].led_cords[2].y, order[i].led_cords[2].x, LOW);
    }
    for (unsigned l = 0; l<CUBE_SIDE; ++l)
    set_pin(order[i].led[l], LOW);
    }
    }

    static void spin_outer(const unsigned d = 500) {
    const struct {
    struct {
    unsigned y;
    unsigned x;
    } led_cords[2];
    struct pin led[2];
    } order[CUBE_SIDE+1] = {
    { { {1,0}, {1,2} } },
    { { {0,0}, {2,2} } },
    { { {2,1}, {0,1} } },
    { { {2,0}, {0,2} } }
    { { COL_10, COL_12 } },
    { { COL_00, COL_22 } },
    { { COL_01, COL_21 } },
    { { COL_02, COL_20 } },
    };

    set_all_lvls(HIGH);
    for (unsigned i = 0; i<CUBE_SIDE+1; ++i) {
    for (unsigned lvl=0; lvl<CUBE_SIDE; ++lvl) {
    set_led(lvl, order[i].led_cords[0].y, order[i].led_cords[0].x, HIGH);
    set_led(lvl, order[i].led_cords[1].y, order[i].led_cords[1].x, HIGH);
    }
    for (unsigned l=0; l<2; ++l)
    set_pin(order[i].led[l], HIGH);
    delay(d);
    for (unsigned lvl=0; lvl<CUBE_SIDE; ++lvl) {
    set_led(lvl, order[i].led_cords[0].y, order[i].led_cords[0].x, LOW);
    set_led(lvl, order[i].led_cords[1].y, order[i].led_cords[1].x, LOW);
    }
    for (unsigned l=0; l<2; ++l)
    set_pin(order[i].led[l], LOW);
    }
    }

    static void rain(const unsigned d = 500) {
    for (unsigned i=0; i<CUBE_SIDE*CUBE_SIDE; ++i) {
    long x1 = random(CUBE_SIDE);
    long y1 = random(CUBE_SIDE);
    long x2 = random(CUBE_SIDE);
    long y2 = random(CUBE_SIDE);
    long x1 = random(CUBE_SIDE);
    long y1 = random(CUBE_SIDE);
    long x2 = random(CUBE_SIDE);
    long y2 = random(CUBE_SIDE);
    for (int lvl=CUBE_SIDE-1; lvl>=0; --lvl) {
    set_pin(levels[lvl], HIGH);
    set_pin(columns[y1][x1], HIGH);
    set_pin(columns[y2][x2], HIGH);
    set_pin(levels[lvl], HIGH);
    set_pin(columns[y1][x1], HIGH);
    set_pin(columns[y2][x2], HIGH);
    delay(d);
    set_pin(levels[lvl], LOW);
    set_pin(columns[y1][x1], LOW);
    set_pin(columns[y2][x2], LOW);

    set_pin(levels[lvl], LOW);
    set_pin(columns[y1][x1], LOW);
    set_pin(columns[y2][x2], LOW);
    }
    }
    }
    @@ -341,7 +324,7 @@ void loop(void)
    { 3, blink_all, norm },
    { 5, blink_all, fast },
    { 2, cube_slices, norm },
    { 5, up_down, norm },
    { 3, up_down, norm },
    { 2, cube_sides, norm },
    { 3, zig_zag, fast },
    { 6, spin, fast },
    @@ -351,7 +334,7 @@ void loop(void)
    { 0, NULL, 0 },
    };

    for (struct effect *e = effects; e; ++e)
    for (unsigned i=0; i<e->repeat; ++i)
    for (struct effect *e = effects; e; ++e)
    for (unsigned i=0; i<e->repeat; ++i)
    e->effect(e->interval);
    }
  5. @grobotronics grobotronics revised this gist Sep 16, 2013. 1 changed file with 45 additions and 34 deletions.
    79 changes: 45 additions & 34 deletions 3x3_cube_mcp.ino
    Original file line number Diff line number Diff line change
    @@ -14,7 +14,7 @@ static const unsigned CUBE_SIDE = 3;

    /* each pin belongs in a bank and has a mask */
    struct pin {
    const byte gpio;
    const byte gpio;
    const byte mask;
    };

    @@ -46,7 +46,7 @@ static const pin columns[CUBE_SIDE][CUBE_SIDE] = {
    /* DEBUG HELPERS */
    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    void check_mcp(void) {
    static void check_mcp(void) {
    byte error, address;
    int nDevices;

    @@ -76,15 +76,15 @@ void check_mcp(void) {
    else Serial.println("done\n");
    }

    void print_gpio_a_state(void) {
    static void print_gpio_a_state(void) {
    Serial.print("gpioa state: ");
    Serial.println(gpio_a, BIN);
    }
    void print_gpio_b_state(void) {
    static void print_gpio_b_state(void) {
    Serial.print("gpiob state: ");
    Serial.println(gpio_b, BIN);
    }
    void print_gpio_state(void) {
    static void print_gpio_state(void) {
    print_gpio_a_state();
    print_gpio_b_state();
    }
    @@ -142,36 +142,36 @@ static void set_pin(const struct pin pin, const bool state) {

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    void set_led(const unsigned z, const unsigned y, const unsigned x, const bool state) {
    static void set_led(const unsigned z, const unsigned y, const unsigned x, const bool state) {
    set_pin(levels[z], state);
    set_pin(columns[y][x], state);
    }

    void set_all_lvls(const bool state) {
    static void set_all_lvls(const bool state) {
    for (unsigned lvl=0; lvl<CUBE_SIDE; ++lvl)
    set_pin(levels[lvl], state);
    }
    void set_all_cols(const bool state) {
    static void set_all_cols(const bool state) {
    for (unsigned y=0; y<CUBE_SIDE; ++y)
    for (unsigned x=0; x<CUBE_SIDE; ++x)
    set_pin(columns[y][x], state);
    }

    void set_all(const bool state) {
    static void set_all(const bool state) {
    set_all_lvls(state);
    set_all_cols(state);
    }

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    void blink_all(const unsigned d = 500) {
    static void blink_all(const unsigned d = 500) {
    set_all(HIGH);
    delay(d);
    set_all(LOW);
    delay(d);
    }

    void zig_zag(const unsigned d = 500) {
    static void zig_zag(const unsigned d = 500) {
    const struct pin order[CUBE_SIDE * CUBE_SIDE] = {
    COL_00, COL_01, COL_02,
    COL_12, COL_11, COL_10,
    @@ -187,7 +187,7 @@ void zig_zag(const unsigned d = 500) {
    }
    }

    void spin(const unsigned d = 500) {
    static void spin(const unsigned d = 500) {
    const struct {
    struct {
    unsigned y;
    @@ -215,7 +215,7 @@ void spin(const unsigned d = 500) {
    }
    }

    void spin_outer(const unsigned d = 500) {
    static void spin_outer(const unsigned d = 500) {
    const struct {
    struct {
    unsigned y;
    @@ -241,7 +241,7 @@ void spin_outer(const unsigned d = 500) {
    }
    }

    void rain(const unsigned d = 500) {
    static void rain(const unsigned d = 500) {
    for (unsigned i=0; i<CUBE_SIDE*CUBE_SIDE; ++i) {
    long x1 = random(CUBE_SIDE);
    long y1 = random(CUBE_SIDE);
    @@ -262,7 +262,7 @@ void rain(const unsigned d = 500) {

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    void set_slice(const unsigned slice, const char axis, const uint8_t state) {
    static void set_slice(const unsigned slice, const char axis, const uint8_t state) {
    switch (axis) {
    case 'x':
    set_all_lvls(state);
    @@ -281,7 +281,7 @@ void set_slice(const unsigned slice, const char axis, const uint8_t state) {
    }
    }

    void light_each_slice(const unsigned d = 500) {
    static void cube_slices(const unsigned d = 500) {
    for (char *p = "xyz"; *p; ++p) {
    for (unsigned slice=0; slice<CUBE_SIDE; ++slice) {
    set_slice(slice, *p, HIGH);
    @@ -291,23 +291,22 @@ void light_each_slice(const unsigned d = 500) {
    }
    }

    void up_down(const unsigned d = 500, unsigned loops = 12) {
    static void up_down(const unsigned d = 500) {
    const unsigned lvl_order[CUBE_SIDE+1] = { 0, 1, 2, 1, };

    /* light all columns */
    set_all_cols(HIGH);
    set_all_lvls(LOW);

    /* light each level in order */
    for (unsigned lvl = 0; loops>0; --loops) {
    for (unsigned lvl=0; lvl<CUBE_SIDE+1; ++lvl) {
    set_slice(lvl_order[(CUBE_SIDE+lvl)%(CUBE_SIDE+1)], 'z', LOW);
    set_slice(lvl_order[lvl], 'z', HIGH);
    lvl = (lvl + 1) % (CUBE_SIDE+1);
    delay(d);
    }
    }

    void cube_sides(const unsigned d = 500) {
    static void cube_sides(const unsigned d = 500) {
    const struct {
    unsigned slice;
    char axis;
    @@ -329,18 +328,30 @@ void cube_sides(const unsigned d = 500) {

    void loop(void)
    {
    const unsigned fast = 150;
    const unsigned norm = 400;
    const unsigned slow = 600;

    for (unsigned i=0; i<2; ++i) blink_all(slow);
    for (unsigned i=0; i<3; ++i) blink_all(norm);
    for (unsigned i=0; i<5; ++i) blink_all(fast);
    for (unsigned i=0; i<2; ++i) light_each_slice(norm);
    for (unsigned i=0; i<1; ++i) up_down(norm);
    for (unsigned i=0; i<2; ++i) cube_sides(norm);
    for (unsigned i=0; i<3; ++i) zig_zag(fast);
    for (unsigned i=0; i<6; ++i) spin(fast);
    for (unsigned i=0; i<5; ++i) spin_outer(fast);
    for (unsigned i=0; i<4; ++i) rain(fast);
    static const unsigned fast = 150;
    static const unsigned norm = 400;
    static const unsigned slow = 600;

    static struct effect {
    const unsigned repeat;
    void (* const effect)(const unsigned interval);
    const unsigned interval;
    } effects[] = {
    { 2, blink_all, slow },
    { 3, blink_all, norm },
    { 5, blink_all, fast },
    { 2, cube_slices, norm },
    { 5, up_down, norm },
    { 2, cube_sides, norm },
    { 3, zig_zag, fast },
    { 6, spin, fast },
    { 5, spin_outer, fast },
    { 4, rain, fast },
    /* -- end of effects -- */
    { 0, NULL, 0 },
    };

    for (struct effect *e = effects; e; ++e)
    for (unsigned i=0; i<e->repeat; ++i)
    e->effect(e->interval);
    }
  6. @grobotronics grobotronics created this gist Sep 16, 2013.
    346 changes: 346 additions & 0 deletions 3x3_cube_mcp.ino
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,346 @@
    /* Cube project throug mcp23017 */
    #include <Wire.h>

    static const byte MCP_ADDR = 0x20; // I2C Address of MCP23017 Chip
    static const byte GPIO_A = 0x12; // Register Address of Port A
    static const byte GPIO_B = 0x13; // Register Address of Port B

    /* global state of gpio ports */
    static byte gpio_a;
    static byte gpio_b;

    /* Working with a 3x3 Cube */
    static const unsigned CUBE_SIDE = 3;

    /* each pin belongs in a bank and has a mask */
    struct pin {
    const byte gpio;
    const byte mask;
    };

    /* 3 Levels of 3x3=9 leds each */
    static const struct pin LVL_0 = { GPIO_B, 0b00000001 };
    static const struct pin LVL_1 = { GPIO_B, 0b00000100 };
    static const struct pin LVL_2 = { GPIO_B, 0b00000010 };

    static const struct pin levels[CUBE_SIDE] = { LVL_0, LVL_1, LVL_2 };

    /* 3x3=9 columns in a grid - COL_<y><x> */
    static const struct pin COL_00 = { GPIO_B, 0b00100000 };
    static const struct pin COL_01 = { GPIO_B, 0b00001000 };
    static const struct pin COL_02 = { GPIO_B, 0b00010000 };
    static const struct pin COL_10 = { GPIO_A, 0b00000100 };
    static const struct pin COL_11 = { GPIO_A, 0b00010000 };
    static const struct pin COL_12 = { GPIO_A, 0b00001000 };
    static const struct pin COL_20 = { GPIO_A, 0b00100000 };
    static const struct pin COL_21 = { GPIO_A, 0b01000000 };
    static const struct pin COL_22 = { GPIO_A, 0b10000000 };

    static const pin columns[CUBE_SIDE][CUBE_SIDE] = {
    { COL_00, COL_01, COL_02 },
    { COL_10, COL_11, COL_12 },
    { COL_20, COL_21, COL_22 },
    };

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */
    /* DEBUG HELPERS */
    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    void check_mcp(void) {
    byte error, address;
    int nDevices;

    Serial.println("Scanning for I2C...");

    nDevices = 0;
    for(address = 1; address < 127; address++ ) {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0) {
    Serial.print("I2C device found at address 0x");
    if (address < 16) Serial.print("0");
    Serial.println(address, HEX);
    nDevices++;
    } else if (error == 4) {
    Serial.print("Unknow error at address 0x");
    if (address < 16) Serial.print("0");
    Serial.println(address, HEX);
    }
    }

    if (nDevices == 0) Serial.println("No I2C devices found\n");
    else Serial.println("done\n");
    }

    void print_gpio_a_state(void) {
    Serial.print("gpioa state: ");
    Serial.println(gpio_a, BIN);
    }
    void print_gpio_b_state(void) {
    Serial.print("gpiob state: ");
    Serial.println(gpio_b, BIN);
    }
    void print_gpio_state(void) {
    print_gpio_a_state();
    print_gpio_b_state();
    }

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */
    /* INIT STATE */
    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    void setup(void)
    {
    Wire.begin();
    Serial.begin(9600);

    Wire.beginTransmission(MCP_ADDR);
    Wire.write((byte)0x00);
    Wire.write((byte)0x00); // set all of GPIO A to outputs
    Wire.write((byte)0x00); // set all of GPIO B to outputs
    Wire.endTransmission();

    /* clear all GPIOA pins */
    gpio_a = 0b00000000;
    Wire.beginTransmission(MCP_ADDR);
    Wire.write(GPIO_A);
    Wire.write(gpio_a);
    Wire.endTransmission();

    /* clear all GPIOB pins */
    gpio_b = 0b00000000;
    Wire.beginTransmission(MCP_ADDR);
    Wire.write(GPIO_B);
    Wire.write(gpio_b);
    Wire.endTransmission();

    /* initialize randomizer */
    randomSeed(analogRead(0));
    }

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */
    /* MAIN EXECUTION */
    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    static inline const byte bit_clear(byte * const gpio, const struct pin pin) { return (*gpio &= ~pin.mask); }
    static inline const byte bit_set (byte * const gpio, const struct pin pin) { return (*gpio |= pin.mask); }
    static const byte (* const operation[2])(byte * const gpio, const struct pin pin) = { bit_clear, bit_set };

    static void set_pin(const struct pin pin, const bool state) {
    Wire.beginTransmission(MCP_ADDR);
    Wire.write(pin.gpio);
    switch (pin.gpio) {
    case GPIO_A: Wire.write((operation[state](&gpio_a, pin))); break;
    case GPIO_B: Wire.write((operation[state](&gpio_b, pin))); break;
    }
    Wire.endTransmission();
    }

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    void set_led(const unsigned z, const unsigned y, const unsigned x, const bool state) {
    set_pin(levels[z], state);
    set_pin(columns[y][x], state);
    }

    void set_all_lvls(const bool state) {
    for (unsigned lvl=0; lvl<CUBE_SIDE; ++lvl)
    set_pin(levels[lvl], state);
    }
    void set_all_cols(const bool state) {
    for (unsigned y=0; y<CUBE_SIDE; ++y)
    for (unsigned x=0; x<CUBE_SIDE; ++x)
    set_pin(columns[y][x], state);
    }

    void set_all(const bool state) {
    set_all_lvls(state);
    set_all_cols(state);
    }

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    void blink_all(const unsigned d = 500) {
    set_all(HIGH);
    delay(d);
    set_all(LOW);
    delay(d);
    }

    void zig_zag(const unsigned d = 500) {
    const struct pin order[CUBE_SIDE * CUBE_SIDE] = {
    COL_00, COL_01, COL_02,
    COL_12, COL_11, COL_10,
    COL_20, COL_21, COL_22,
    };

    set_all_cols(LOW);
    set_all_lvls(HIGH);

    for (unsigned col=0; col<CUBE_SIDE*CUBE_SIDE; ++col) {
    set_pin(order[col], HIGH);
    delay(d);
    }
    }

    void spin(const unsigned d = 500) {
    const struct {
    struct {
    unsigned y;
    unsigned x;
    } led_cords[3];
    } order[CUBE_SIDE+1] = {
    { { {1,0}, {1,1}, {1,2} } },
    { { {0,0}, {1,1}, {2,2} } },
    { { {2,1}, {1,1}, {0,1} } },
    { { {2,0}, {1,1}, {0,2} } }
    };

    for (unsigned i = 0; i<CUBE_SIDE+1; ++i) {
    for (unsigned lvl=0; lvl<CUBE_SIDE; ++lvl) {
    set_led(lvl, order[i].led_cords[0].y, order[i].led_cords[0].x, HIGH);
    set_led(lvl, order[i].led_cords[1].y, order[i].led_cords[1].x, HIGH);
    set_led(lvl, order[i].led_cords[2].y, order[i].led_cords[2].x, HIGH);
    }
    delay(d);
    for (unsigned lvl=0; lvl<CUBE_SIDE; ++lvl) {
    set_led(lvl, order[i].led_cords[0].y, order[i].led_cords[0].x, LOW);
    set_led(lvl, order[i].led_cords[1].y, order[i].led_cords[1].x, LOW);
    set_led(lvl, order[i].led_cords[2].y, order[i].led_cords[2].x, LOW);
    }
    }
    }

    void spin_outer(const unsigned d = 500) {
    const struct {
    struct {
    unsigned y;
    unsigned x;
    } led_cords[2];
    } order[CUBE_SIDE+1] = {
    { { {1,0}, {1,2} } },
    { { {0,0}, {2,2} } },
    { { {2,1}, {0,1} } },
    { { {2,0}, {0,2} } }
    };

    for (unsigned i = 0; i<CUBE_SIDE+1; ++i) {
    for (unsigned lvl=0; lvl<CUBE_SIDE; ++lvl) {
    set_led(lvl, order[i].led_cords[0].y, order[i].led_cords[0].x, HIGH);
    set_led(lvl, order[i].led_cords[1].y, order[i].led_cords[1].x, HIGH);
    }
    delay(d);
    for (unsigned lvl=0; lvl<CUBE_SIDE; ++lvl) {
    set_led(lvl, order[i].led_cords[0].y, order[i].led_cords[0].x, LOW);
    set_led(lvl, order[i].led_cords[1].y, order[i].led_cords[1].x, LOW);
    }
    }
    }

    void rain(const unsigned d = 500) {
    for (unsigned i=0; i<CUBE_SIDE*CUBE_SIDE; ++i) {
    long x1 = random(CUBE_SIDE);
    long y1 = random(CUBE_SIDE);
    long x2 = random(CUBE_SIDE);
    long y2 = random(CUBE_SIDE);
    for (int lvl=CUBE_SIDE-1; lvl>=0; --lvl) {
    set_pin(levels[lvl], HIGH);
    set_pin(columns[y1][x1], HIGH);
    set_pin(columns[y2][x2], HIGH);
    delay(d);
    set_pin(levels[lvl], LOW);
    set_pin(columns[y1][x1], LOW);
    set_pin(columns[y2][x2], LOW);

    }
    }
    }

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    void set_slice(const unsigned slice, const char axis, const uint8_t state) {
    switch (axis) {
    case 'x':
    set_all_lvls(state);
    for (unsigned x=0; x<CUBE_SIDE; ++x)
    set_pin(columns[slice][x], state);
    break;
    case 'y':
    set_all_lvls(state);
    for (unsigned y=0; y<CUBE_SIDE; ++y)
    set_pin(columns[y][slice], state);
    break;
    case 'z':
    set_all_cols(state);
    set_pin(levels[slice], state);
    break;
    }
    }

    void light_each_slice(const unsigned d = 500) {
    for (char *p = "xyz"; *p; ++p) {
    for (unsigned slice=0; slice<CUBE_SIDE; ++slice) {
    set_slice(slice, *p, HIGH);
    delay(d);
    set_slice(slice, *p, LOW);
    }
    }
    }

    void up_down(const unsigned d = 500, unsigned loops = 12) {
    const unsigned lvl_order[CUBE_SIDE+1] = { 0, 1, 2, 1, };

    /* light all columns */
    set_all_cols(HIGH);
    set_all_lvls(LOW);

    /* light each level in order */
    for (unsigned lvl = 0; loops>0; --loops) {
    set_slice(lvl_order[(CUBE_SIDE+lvl)%(CUBE_SIDE+1)], 'z', LOW);
    set_slice(lvl_order[lvl], 'z', HIGH);
    lvl = (lvl + 1) % (CUBE_SIDE+1);
    delay(d);
    }
    }

    void cube_sides(const unsigned d = 500) {
    const struct {
    unsigned slice;
    char axis;
    } order[CUBE_SIDE*2] = {
    {0, 'x'}, {0, 'y'}, {2, 'z'},
    {2, 'x'}, {2, 'y'}, {0, 'z'},
    };

    set_all(LOW);

    for (unsigned i=0; i<CUBE_SIDE*2; ++i) {
    set_slice(order[i].slice, order[i].axis, HIGH);
    delay(d);
    set_slice(order[i].slice, order[i].axis, LOW);
    }
    }

    /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

    void loop(void)
    {
    const unsigned fast = 150;
    const unsigned norm = 400;
    const unsigned slow = 600;

    for (unsigned i=0; i<2; ++i) blink_all(slow);
    for (unsigned i=0; i<3; ++i) blink_all(norm);
    for (unsigned i=0; i<5; ++i) blink_all(fast);
    for (unsigned i=0; i<2; ++i) light_each_slice(norm);
    for (unsigned i=0; i<1; ++i) up_down(norm);
    for (unsigned i=0; i<2; ++i) cube_sides(norm);
    for (unsigned i=0; i<3; ++i) zig_zag(fast);
    for (unsigned i=0; i<6; ++i) spin(fast);
    for (unsigned i=0; i<5; ++i) spin_outer(fast);
    for (unsigned i=0; i<4; ++i) rain(fast);
    }