Hello,
I’m trying to adapt using a couple of accelerometers instead of potentiometers to control the paddles in a pong game. The first step was to try and figure out how to control a circular object on an OLED screen, with boundary detection.
I’ve had a go at it, and it works. However, is there a better, or more efficient way of doing this? I’m a complete novice, and want to learn the best ways to approach things.
Code is below, however first some notes:
- The accelerometer is a 3 axis ADXL 345.
- This is some strange Chinese SPI display that claims to be 128x64, but I don’t think it is. The ball goes out of bounds if the vertical pixel count is more than 32.
- I used software SPI because hardware SPI is simply too fast, and the ball is uncontrollable.
Thank you,
N.
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <SparkFun_ADXL345.h> // SparkFun ADXL345 Library
ADXL345 adxl = ADXL345(); // USE FOR I2C COMMUNICATION
/* Uncomment this block to use hardware SPI
#define OLED_DC 9
#define OLED_CS 0
#define OLED_RESET 10
Adafruit_SSD1306 display(OLED_DC, OLED_RESET, OLED_CS);
*/
// Using software SPI because hardware SPI is too fast for this demo
// If using software SPI (the default case):
#define OLED_MOSI 11
#define OLED_CLK 13
#define OLED_DC 9
#define OLED_CS 0
#define OLED_RESET 10
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
// variables for boundary detection of OLED
int a = 64; // initial position of ball on x axis
int b = 16; // initial position of ball on y axis
void setup() {
// ADXL345 configurator
Serial.begin(9600); // Start the serial terminal
adxl.powerOn(); // Power on the ADXL345
adxl.setRangeSetting(4); // Give the range settings. Used 4 after trying the rest
// Accepted values are 2g, 4g, 8g or 16g
// Higher Values = Wider Measurement Range
// Lower Values = Greater Sensitivity
adxl.setSpiBit(0); // Configure the device to be in 4 wire SPI mode when set to '0' or 3 wire SPI mode when set to 1
// Default: Set to 1
// SPI pins on the ATMega328: 11, 12 and 13 as reference in SPI Library
adxl.setActivityXYZ(0, 0, 0); // Set to activate movement detection in the axes "adxl.setActivityXYZ(X, Y, Z);" (1 == ON, 0 == OFF)
adxl.setActivityThreshold(75); // 62.5mg per increment // Set activity // Inactivity thresholds (0-255)
adxl.setInactivityXYZ(0, 0, 0); // Set to detect inactivity in all the axes "adxl.setInactivityXYZ(X, Y, Z);" (1 == ON, 0 == OFF)
adxl.setInactivityThreshold(75); // 62.5mg per increment // Set inactivity // Inactivity thresholds (0-255)
adxl.setTimeInactivity(10); // How many seconds of no activity is inactive?
adxl.setTapDetectionOnXYZ(0, 0, 0); // Detect taps in the directions turned ON "adxl.setTapDetectionOnX(X, Y, Z);" (1 == ON, 0 == OFF)
// Set values for what is considered a TAP and what is a DOUBLE TAP (0-255)
adxl.setTapThreshold(50); // 62.5 mg per increment
adxl.setTapDuration(15); // 625 μs per increment
adxl.setDoubleTapLatency(80); // 1.25 ms per increment
adxl.setDoubleTapWindow(200); // 1.25 ms per increment
// Set values for what is considered FREE FALL (0-255)
adxl.setFreeFallThreshold(7); // (5 - 9) recommended - 62.5mg per increment
adxl.setFreeFallDuration(30); // (20 - 70) recommended - 5ms per increment
// Setting all interupts to take place on INT1 pin
//adxl.setImportantInterruptMapping(1, 1, 1, 1, 1); // Sets "adxl.setEveryInterruptMapping(single tap, double tap, free fall, activity, inactivity);"
// Accepts only 1 or 2 values for pins INT1 and INT2. This chooses the pin on the ADXL345 to use for Interrupts.
// This library may have a problem using INT2 pin. Default to INT1 pin.
// Turn on Interrupts for each mode (1 == ON, 0 == OFF)
adxl.InactivityINT(0);
adxl.ActivityINT(0);
adxl.FreeFallINT(0);
adxl.doubleTapINT(0);
adxl.singleTapINT(0);
//attachInterrupt(digitalPinToInterrupt(interruptPin), ADXL_ISR, RISING); // Attach Interrupt
// ADXL345 configurator end
// begin display
display.begin(SSD1306_SWITCHCAPVCC);
display.clearDisplay();
// begin complete
}
void loop() {
int x, y, z; // variables for accelerometer
adxl.readAccel(&x, &y, &z); // read values. Tried omitting z, but it didn't work.
// There are 9 cases of x and y positioning
// Case 1. x tilt left, y steady
if (x <= -3 && y > -3 && y < 3 && a > 2) {
display.fillCircle(a, b, 1, WHITE);
display.display();
display.clearDisplay();
a--;
}
// Case 2. x tilt right, y steady
if (x >= 3 && y > -3 && y < 3 && a < 126) {
display.fillCircle(a, b, 1, WHITE);
display.display();
display.clearDisplay();
a++;
}
// Case 3. x steady, y tilt up
if (y >= 3 && x > -3 && x < 3 && b > 2) {
display.fillCircle(a, b, 1, WHITE);
display.display();
display.clearDisplay();
b--;
}
// Case 4. x steady, y tilt down
if (y <= -3 && x > -3 && x < 3 && b < 30) {
display.fillCircle(a, b, 1, WHITE);
display.display();
display.clearDisplay();
b++;
}
// Case 5. x tilt left, y tilt up
if (x <= -3 && y >= 3 && a > 2 && b > 2) {
display.fillCircle(a, b, 1, WHITE);
display.display();
display.clearDisplay();
a--;
b--;
}
// Case 6. x tilt left, y tilt down
if (x <= -3 && y <= -3 && a > 2 && b < 30) {
display.fillCircle(a, b, 1, WHITE);
display.display();
display.clearDisplay();
a--;
b++;
}
// Case 7. x tilt right, y tilt up
if (x >= 3 && y >= 3 && a < 126 && b > 2) {
display.fillCircle(a, b, 1, WHITE);
display.display();
display.clearDisplay();
a++;
b--;
}
// Case 8. x tilt right, y tilt down
if (x >= 3 && y <= -3 && a < 126 && b < 30) {
display.fillCircle(a, b, 1, WHITE);
display.display();
display.clearDisplay();
a++;
b++;
}
// 9. x steady, y steady
if (x > -3 && x < 3 && y > -3 && y < 3) {
display.fillCircle(a, b, 1, WHITE);
display.display();
}
}