Skip to content

Instantly share code, notes, and snippets.

@c00kiemon5ter
Last active December 24, 2015 01:59
Show Gist options
  • Save c00kiemon5ter/6727747 to your computer and use it in GitHub Desktop.
Save c00kiemon5ter/6727747 to your computer and use it in GitHub Desktop.
controlling a 3x3 led cube through mcp23017 with arduino. Included effects: blink, cube slices, up down, cube sides, zig zag, spin and rain.
/* 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_state(const byte gpio) {
Serial.print("gpio state: ");
Serial.println(gpio, BIN);
}
/* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */
/* 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);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment