Skip to content

Instantly share code, notes, and snippets.

@rlogiacco
Created March 31, 2017 00:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rlogiacco/96ef37772b64a393fc17156f7b84bad3 to your computer and use it in GitHub Desktop.
Save rlogiacco/96ef37772b64a393fc17156f7b84bad3 to your computer and use it in GitHub Desktop.
Innov@ction
#include <Elapsed.h>
#include <Effects.h>
#include <Qube.h>
#include <FormattingSerialDebug.h>
#define BUTTON_PIN 2
#define SIZE 3
const int pins[SIZE][SIZE] = { //
{ 3, 4, 5 }, // row 1
{ 6, 7, 8 }, // row 2
{ 9, 10, 11 } // row 3
};
const int layers[] = { A0, A1, A2 };
Qube qube(SIZE);
#define EFFECTS_SIZE 7
Effect** effects = new Effect*[EFFECTS_SIZE];
uint8_t currentEffect = EFFECTS_SIZE - 1;
Effect* effect;
void setup() {
SERIAL_DEBUG_SETUP(9600);
for (int i = 0; i < SIZE; i++) {
pinMode(layers[i], OUTPUT);
for (int j = 0; j < SIZE; j++)
pinMode(pins[i][j], OUTPUT);
}
pinMode(BUTTON_PIN, INPUT_PULLUP);
noInterrupts();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
// Compare value 16M / prescaler / frequency
OCR1A = 10; // 6.25kHz
// Turn on CTC mode:
TCCR1B |= (1 << WGM12);
// Set CS12 bit for 256 prescaler:
TCCR1B |= (1 << CS12);
// Enable timer compare interrupt:
TIMSK1 |= (1 << OCIE1A);
interrupts();
if (digitalRead(BUTTON_PIN) == LOW) {
qube.test(200);
}
effects[0] = new Rain(qube, 5, 100);
effects[1] = new RandomFill(qube, 5);
effects[2] = new RandomBlinker(qube, 2, 20);
effects[3] = new PlaneBounce(qube, 5, Z);
effects[4] = new Windmill(qube, 5, Z);
effects[5] = new Blink(qube, 3);
// last effect
effects[6] = new Carousel(qube, 3, effects, EFFECTS_SIZE);
effect = effects[currentEffect];
effect->init();
}
volatile uint8_t layer = 0;
ISR(TIMER1_COMPA_vect) {
digitalWrite(layers[layer++], LOW);
if (layer == qube.size)
layer = 0;
if (qube) {
uint8_t position = 0;
for (uint8_t y = 0; y < qube.size; y++) {
for (uint8_t x = 0; x < qube.size; x++) {
uint8_t byte = qube[layer][position / 8];
uint8_t shift = 7 - position % 8;
uint8_t bit = ((byte >> shift) & 0x1);
position++;
digitalWrite(pins[y][x], bit);
}
}
digitalWrite(layers[layer], HIGH);
}
}
#define DEBOUNCE 15
#define DMASK ((1<<DEBOUNCE)-1)
#define DF (1<<(DEBOUNCE-1))
#define DR (DMASK-DF)
// macro for detection of raising edge and debouncing
#define DRE(signal, state) ((state=((state<<1)|(signal&1))&DMASK)==DR)
// macro for detection of falling edge and debouncing
#define DFE(signal, state) ((state=((state<<1)|(signal&1))&DMASK)==DF)
uint16_t pinState;
void loop() {
if(DFE(digitalRead(BUTTON_PIN), pinState)) {
currentEffect = ++currentEffect % EFFECTS_SIZE;
DEBUG("current effect is %u", currentEffect);
DEBUG("state is %u", (bool)qube);
effect = effects[currentEffect];
effect->init();
}
effect->update();
}
#include <Effects.h>
#include <Qube.h>
#include <FormattingSerialDebug.h>
#define BUTTON_PIN 7
#define SIZE 3
const int pins[SIZE][SIZE] = { //
{ A3, A1, A2 }, // row 1
{ 13, 12, A0 }, // row 2
{ 10, 9, 11 } // row 3
};
const int layers[] = { 3, 2, 4 };
Qube qube(SIZE);
void setup() {
SERIAL_DEBUG_SETUP(9600);
for (int i = 0; i < SIZE; i++) {
pinMode(layers[i], OUTPUT);
for (int j = 0; j < SIZE; j++)
pinMode(pins[i][j], OUTPUT);
}
pinMode(BUTTON_PIN, INPUT_PULLUP);
// interrupt setup
// frequency should be no less than 100Hz * cube size for flicker free results
noInterrupts();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
// Compare value 16M / prescaler / frequency
OCR1A = 10; // 6.25kHz or 160us
// OCR1A = 208 // this is minimum flicker free update frequency of 300Hz
// OCR1A = 625 // try this to visualize flickering (frequency of 100Hz)
// OCR1A = 3125 // try this to visualize multiplexing (frequency of 20Hz)
// Turn on CTC mode:
TCCR1B |= (1 << WGM12);
// Set CS12 bit for 256 prescaler:
TCCR1B |= (1 << CS12);
// Enable timer compare interrupt:
TIMSK1 |= (1 << OCIE1A);
interrupts();
}
volatile uint8_t layer = 0;
// This needs to be re-implemented based on your specific
// cube implementation: the following example uses a simple
// implementation directly driven by the MCU and 3 npn transistors
ISR(TIMER1_COMPA_vect) {
digitalWrite(layers[layer++], LOW);
if (layer == qube.size)
layer = 0;
// if qube is disabled then we have nothing to do
if (qube) {
uint8_t position = 0;
for (uint8_t y = 0; y < qube.size; y++) {
for (uint8_t x = 0; x < qube.size; x++) {
uint8_t byte = qube[layer][position / 8];
uint8_t shift = 7 - position % 8;
uint8_t bit = ((byte >> shift) & 0x1);
position++;
digitalWrite(pins[y][x], bit);
}
}
digitalWrite(layers[layer], HIGH);
}
}
// This simple loop will test your wiring and bit to LED mapping
void loop() {
int speed = 250;
// Blink 3 times the first voxel
for (uint8_t i = 0; i < 3; i++) {
qube.voxel(Coord(0, 0, 0), ON);
delay(speed);
qube.voxel(Coord(0, 0, 0), OFF);
delay(speed);
}
// Turn on each voxel in a specific order:
// rows, columns, layers
for (uint8_t z = 0; z < qube.size; z++) {
for (uint8_t y = 0; y < qube.size; y++) {
for (uint8_t x = 0; x < qube.size; x++) {
qube.voxel(Coord(x, y, z), ON);
delay(speed);
}
}
}
// Turn off each voxel in reverse order
for (uint8_t z = qube.size; z > 0; z--) {
for (uint8_t y = qube.size; y > 0; y--) {
for (uint8_t x = qube.size; x > 0; x--) {
qube.voxel(Coord(x - 1, y - 1, z - 1), OFF);
delay(speed);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment