/****************************************************************************** * tilt_menu_demo * Keith Neufeld * December 15-16, 2007 * * Demonstrate a MEMS accelerometer-based system of using a tilting device * to select a menu item. * * Demo system uses Arduino, Analog Devices ADXL202 with XFILT and YFILT * analog outputs fed to Arduino analog inputs 0-1, and a 4x4 matrix of LEDs * with row select on digital outputs 7-4 and column select on outputs 3-0. ******************************************************************************/ #define PINX 0 #define PINY 1 // #define TILT_MIN 460 // #define TILT_CTR 528 // #define TILT_MAX 600 #define TILT_MIN 480 #define TILT_MAX 580 #define TILT_WIDTH (TILT_MAX - TILT_MIN) #define HYSTERESIS 5 // 4x4 display #define DISPLAYSIZE 4 #undef DEBUG_ACCEL #undef DEMO_LEDS void setup() { led_matrix_setup(); #ifdef DEBUG_ACCEL // Serial.begin(9600); #endif // DEBUG_ACCEL #ifdef DEMO_LEDS while (1) { led_matrix_demo(); } #endif // DEMO_LEDS } // Maintain previous position for calculating hysteresis, and initialize // to approximate center of display. int prow = DISPLAYSIZE / 2, pcol = DISPLAYSIZE / 2; void loop() { int x, y, row, col; #ifdef DEBUG_ACCEL Serial.print("x "); Serial.print(anx()); Serial.print("\ty "); Serial.println(any()); delay(100); #else // DEBUG_ACCEL // translate full range to usable range, // reverse orientation from direction of tilt to which surface is on top, // and translate origin from lower left to upper left x = TILT_MAX - analogRead(PINX); y = analogRead(PINY) - TILT_MIN; // If we're within HYSTERESIS of borders of last reading, keep using the // previous setting. if (x > pcol * TILT_WIDTH / DISPLAYSIZE - HYSTERESIS && x < (pcol + 1) * TILT_WIDTH / DISPLAYSIZE + HYSTERESIS && y > prow * TILT_WIDTH / DISPLAYSIZE - HYSTERESIS && y < (prow + 1) * TILT_WIDTH / DISPLAYSIZE + HYSTERESIS) { row = prow; col = pcol; } else { // scale from usable tilt range to size of display row = DISPLAYSIZE * y / TILT_WIDTH; col = DISPLAYSIZE * x / TILT_WIDTH; } // trim overs/unders to size of display row = (row < 0) ? 0 : (row < DISPLAYSIZE) ? row : DISPLAYSIZE - 1; col = (col < 0) ? 0 : (col < DISPLAYSIZE) ? col : DISPLAYSIZE - 1; led_matrix_set(row, col); prow = row; pcol = col; delay(100); #endif // DEBUG_ACCEL } /****************************************************************************** * Control an LED matrix. * Tristate pins not in use; make desired row/column pins outputs to use. ******************************************************************************/ // wired with low pins at bottom/right or top/left? #define WIRINGREVERSED //#undef WIRINGREVERSED // wiring positions within output register #define ROWSHIFT DISPLAYSIZE #define COLSHIFT 0 void led_matrix_setup() { int i; led_matrix_clear(); for (i = 0; i < 4; ++ i) { digitalWrite(i + ROWSHIFT, HIGH); // rows are wired to anodes digitalWrite(i + COLSHIFT, LOW); // columns wired to cathodes } } void led_matrix_clear (void) { int i; for (i = 0; i < 8; ++ i) { pinMode(i, INPUT); } } void led_matrix_set (int row, int col) { // Because we're matrixing, we MUST clear previous rows/columns // before setting new ones. led_matrix_clear(); #ifdef WIRINGREVERSED pinMode(ROWSHIFT + DISPLAYSIZE - 1 - row, OUTPUT); pinMode(COLSHIFT + DISPLAYSIZE - 1 - col, OUTPUT); #else // WIRINGREVERSED pinMode(row + ROWSHIFT, OUTPUT); pinMode(col + COLSHIFT, OUTPUT); #endif // WIRINGREVERSED } #ifdef DEMO_LEDS void led_matrix_demo (void) { int row, col; for (row = 0; row < 4; ++ row) { for (col = 0; col < 4; ++ col) { led_matrix_set(row, col); delay(100); } } } #endif // DEMO_LEDS