/* Spin13x3 - manually spin running lights in a sideways figure eight Requires the Bounce, Turn, Trixel and LiquidCrystal libraries, a phase quadrature encoded control knob and a 13x3 or better LCD display with 5 or more characters of font RAM. http://arduino.cc/playground/Code/Bounce http://csail.mit.edu/~devon/Arduino/Turn http://csail.mit.edu/~devon/Arduino/Trixel Arduino <===> MotherboardShield <===> Mama's LCD Card Arduino <===> USB Serial <===> Programmer Arduino Hard- Silk- Sketch pin ware screen symbol ---- ------ ------ ------ D0 Serial RX D1 Serial TX D2 Knob EA D3 Knob EB D4 LCD D4 D5 LCD D5 D6 LCD D6 D7 LCD D7 D8 D9 Knob EKNOB KNOB_PRESS D10 D11 LCD RS D12 LCD Enable D13 Serial uses pins 0, 1 Knob uses pins 2*, 3**, 9 LCD uses pins 4, 5, 6, 7, 11, 12 * Arduino pin D2 triggers interrupt 0 ** Arduino pin D3 triggers interrupt 1 */ #include #include #include #include // RS Enable D4 D5 D6 D7 LiquidCrystal lcd(11, 12, 4, 5, 6, 7); // 1x3 character graphic display Trixel trix( &lcd); // interrupt EA interrupt EB EA EB Turn knob( 0, 1, 2, 3); const int KNOB_PRESS = 9; // 5ms debounce time Bounce press(KNOB_PRESS, 5); /* 13 x 9 trixel matrix (in 13 x 3 LCD) // (dotimes (y #x9) (princ "\n ") (dotimes (x #xD) (princ (format " %3X," (+ x (* y 16)))))) 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1A, 1B, 1C, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 2A, 2B, 2C, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 3A, 3B, 3C, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 4A, 4B, 4C, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 5A, 5B, 5C, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 6A, 6B, 6C, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 7A, 7B, 7C, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 8A, 8B, 8C 02, 03, 04, 08, 09, 0A, 11, 15, 17, 1B, 20, 26, 2C, 30, -- 36, ++ 3C, 40, 43, 46, 49, 4C, 50, -- 56, ++ 5C, 60, 66, 6C, 71, 75, 77, 7B, 82, 83, 84, 88, 89, 8A, */ const byte path[] = { 0x02, 0x03, 0x04, 0x15, 0x26, 0x36, 0x46, 0x56, 0x66, 0x77, 0x88, 0x89, 0x8A, // down-right 0x7B, 0x6C, 0x5C, 0x4C, 0x3C, 0x2C, 0x1B, // up 0x0A, 0x09, 0x08, 0x17, 0x26, 0x36, 0x46, 0x56, 0x66, 0x75, 0x84, 0x83, 0x82, // down-left 0x71, 0x60, 0x50, 0x40, 0x30, 0x20, 0x11 // up }; const byte pattern[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1}; #define SIZEOF_ARRAY(a) (sizeof(a)/sizeof(*(a))) int mod (int quotient, int divisor) { // A reasonable compiler would reduce mod to a single machine instruction int remainder = quotient % divisor; if (remainder < 0) remainder += divisor; return remainder; } void setup() { pinMode(KNOB_PRESS, INPUT); // knob click input digitalWrite(KNOB_PRESS, HIGH); // ... with pullup lcd.begin(13, 3); // LCD size in columns and rows trix.begin(13, 3); // Trixel area size lcd.print(" turn/click"); // show instructions on LCD ... lcd.setCursor(0, 1); lcd.print("control knob"); delay(1000); knob.sleep(); // ... until user turns knob } byte knob_mode = 0; // start in speed mode int old_count = 0; int phase = 0; void loop () { int count = knob.count() / 4; // four phases per click of this particular knob int delta = count - old_count; old_count = count; // Click knob to toggle position/speed modes byte knob_clicked = press.update() && press.risingEdge(); knob_mode ^= knob_clicked; if (knob_mode) { // position phase += delta; delay(10); } else { // speed phase += (count < 0 ? -1 : 1); int milliseconds = 200 / (count < 0 ? -count : count == 0 ? 1 : count); delay(milliseconds); #if 0 // speed limit if (milliseconds < 5) { knob.reset(); knob_mode = 1; } #endif } phase = mod(phase, SIZEOF_ARRAY(path)); // redisplay trix.clear(); for (int i = 0; i < SIZEOF_ARRAY(path); i++) { int offset = mod(i - phase, SIZEOF_ARRAY(pattern)); byte xy = path[i]; byte x = xy % 16; byte y = xy / 16; trixel_color color = (trixel_color)pattern[offset]; trix.setDot(x, y, color, boole_ior); } trix.setChar(3, 4, '-'); // mimic the Arduino[tm] logo trix.setChar(9, 4, '+'); trix.show(); }