Mouse control with arcade stick and Teensy LC

Status
Not open for further replies.

vanilor

Member
Hi, I'm trying to move the mouse cursor with an arcade stick wired to a Teensy LC. In my original code (borrowed from another project) I can't get the mouse cursor to stop moving. I'm just trying to get pin0 to work first and then I'll figure out the rest later. With code borrowed from the official Arduino page the cursor moves erratically and only pin 3 even works remotely correctly. (could be my wiring, I don't have resistors on the buttons currently.)

I just accidentally deleted my code, here's what I started with and I'm rewriting it. I will update the post in a few here.
Code:
/* USB Arcade Stick 
 *  All Buttons assigned as Keyboard keys for easy use with Emulation
 *  
 * Original code from the Teensy Examples. 
*/

#include 

// Create Bounce objects for each button.  The Bounce object
// automatically deals with contact chatter or "bounce", and
// it makes detecting changes very simple.
Bounce button0 = Bounce(0, 10);
Bounce button1 = Bounce(1, 10);  // 10 = 10 ms debounce time
Bounce button2 = Bounce(2, 10);  // which is appropriate for
Bounce button3 = Bounce(3, 10);  // most mechanical pushbuttons
Bounce button4 = Bounce(4, 10);
Bounce button5 = Bounce(5, 10);  // if a button is too "sensitive"
Bounce button6 = Bounce(6, 10);  // to rapid touch, you can
Bounce button7 = Bounce(7, 10);  // increase this time.
Bounce button8 = Bounce(8, 10);
Bounce button9 = Bounce(9, 10);
Bounce button10 = Bounce(10, 10);
Bounce button11 = Bounce(11, 10);
Bounce button12 = Bounce(12, 10);
Bounce button13 = Bounce(13, 10);

void setup() {
  // Configure the pins for input mode with pullup resistors.
  // The pushbuttons connect from each pin to ground.  When
  // the button is pressed, the pin reads LOW because the button
  // shorts it to ground.  When released, the pin reads HIGH
  // because the pullup resistor connects to +5 volts inside
  // the chip.  LOW for "on", and HIGH for "off" may seem
  // backwards, but using the on-chip pullup resistors is very
  // convenient.  The scheme is called "active low", and it's
  // very commonly used in electronics... so much that the chip
  // has built-in pullup resistors!
  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);  // Teensy++ LED, may need 1k resistor pullup
  pinMode(7, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);
  pinMode(13, INPUT_PULLUP);
}

void loop() {
  // Update all the buttons.  There should not be any long
  // delays in loop(), so this runs repetitively at a rate
  // faster than the buttons could be pressed and released.
  button0.update();
  button1.update();
  button2.update();
  button3.update();
  button4.update();
  button5.update();
  button6.update();
  button7.update();
  button8.update();
  button9.update();
  button10.update();
  button11.update();
  button12.update();
  button13.update();

  // Check each button for "falling" edge.
  // Type a message on the Keyboard when each button presses
  // Update the Joystick buttons only upon changes.
  // falling = high (not pressed - voltage from pullup resistor)
  //           to low (pressed - button connects pin to ground)
  if (button0.fallingEdge()) {
    Keyboard.press(KEY_LEFT);
  }
  if (button1.fallingEdge()) {
    Keyboard.press(KEY_UP);
  }
  if (button2.fallingEdge()) {
    Keyboard.press(KEY_DOWN);
  }
  if (button3.fallingEdge()) {
    Keyboard.press(KEY_RIGHT);
  }
  if (button4.fallingEdge()) {
    Keyboard.press(KEY_5);
  }
  if (button5.fallingEdge()) {
    Keyboard.press(KEY_1);
  }
  if (button6.fallingEdge()) {
    Keyboard.press(KEY_Z);
  }
  if (button7.fallingEdge()) {
    Keyboard.press(KEY_X);
  }
  if (button8.fallingEdge()) {
    Keyboard.press(KEY_C);
  }
  if (button9.fallingEdge()) {
    Keyboard.press(KEY_A);
  }
  if (button10.fallingEdge()) {
      Keyboard.press(KEY_S);
    }
  if (button11.fallingEdge()) {
      Keyboard.press(KEY_D);
    }
  if (button12.fallingEdge()) {
      Keyboard.press(KEY_ESC);
    }
  if (button13.fallingEdge()) {
      Keyboard.press(KEY_F);
    }

  // Check each button for "rising" edge
  // Type a message on the Keyboard when each button releases.
  // For many types of projects, you only care when the button
  // is pressed and the release isn't needed.
  // rising = low (pressed - button connects pin to ground)
  //          to high (not pressed - voltage from pullup resistor)
  if (button0.risingEdge()) {
    Keyboard.release(KEY_LEFT);
  }
  if (button1.risingEdge()) {
    Keyboard.release(KEY_UP);
  }
  if (button2.risingEdge()) {
    Keyboard.release(KEY_DOWN);
  }
  if (button3.risingEdge()) {
    Keyboard.release(KEY_RIGHT);
  }
  if (button4.risingEdge()) {
    Keyboard.release(KEY_5);
  }
  if (button5.risingEdge()) {
    Keyboard.release(KEY_1);
  }
  if (button6.risingEdge()) {
    Keyboard.release(KEY_Z);
  }
  if (button7.risingEdge()) {
    Keyboard.release(KEY_X);
  }
  if (button8.risingEdge()) {
    Keyboard.release(KEY_C);
  }
  if (button9.risingEdge()) {
    Keyboard.release(KEY_A);
  }
  if (button10.risingEdge()) {
    Keyboard.release(KEY_S);
  }
  if (button11.risingEdge()) {
    Keyboard.release(KEY_D);
  }
  if (button12.risingEdge()) {
    Keyboard.release(KEY_ESC);
  }
  if (button13.risingEdge()) {
    Keyboard.release(KEY_F);
  }
}

And the Ardunio code I just tried:

Code:
/*
   Button Mouse Control
   For Leonardo and Due boards only .Controls the mouse from 
   five pushbuttons on an Arduino Leonardo, Micro or Due.
   Hardware:
   * 5 pushbuttons attached to D2, D3, D4, D5, D6
   The mouse movement is always relative. This sketch reads
   four pushbuttons, and uses them to set the movement of the mouse.
   WARNING: When you use the Mouse.move() command, the Arduino takes
   over your mouse! Make sure you have control before you use the mouse commands.
*/

#include "Mouse.h"
// set pin numbers for the five buttons:
const int upButton = 0;
const int downButton = 1;
const int leftButton = 2;
const int rightButton = 3;
const int mouseButton = 4;
int range = 5; // output range of X or Y movement; affects movement speed
int responseDelay = 100; // response delay of the mouse, in ms

void setup() {
   // initialize the buttons' inputs:
   pinMode(upButton, INPUT);
   pinMode(downButton, INPUT);
   pinMode(leftButton, INPUT);
   pinMode(rightButton, INPUT);
   pinMode(mouseButton, INPUT);
   // initialize mouse control:
   Mouse.begin();
}

void loop() {
   // read the buttons:
   int upState = digitalRead(upButton);
   int downState = digitalRead(downButton);
   int rightState = digitalRead(rightButton);
   int leftState = digitalRead(leftButton);
   int clickState = digitalRead(mouseButton);
   // calculate the movement distance based on the button states:
   int xDistance = (leftState - rightState) * range;
   int yDistance = (upState - downState) * range;
   // if X or Y is non-zero, move:
   if ((xDistance != 0) || (yDistance != 0)) {
      Mouse.move(xDistance, yDistance, 0);
   }

   // if the mouse button is pressed:
   if (clickState == HIGH) {
      // if the mouse is not pressed, press it:
      if (!Mouse.isPressed(MOUSE_LEFT)) {
         Mouse.press(MOUSE_LEFT);
      }
   } else {                           // else the mouse button is not pressed:
      // if the mouse is pressed, release it:
      if (Mouse.isPressed(MOUSE_LEFT)) {
         Mouse.release(MOUSE_LEFT);
      }
   }
   // a delay so the mouse does not move too fast:
   delay(responseDelay);
}
 
could be my wiring, I don't have resistors on the buttons currently.

That's ok, as long as you use pinMode INPUT_PULLUP, and wire the buttons between digital pins and GND.

I see one of those programs is using INPUT_PULLUP, but the other has only INPUT.
 
Another thing to try is temporarily removing the Mouse and Keyboard stuff, and instead put Serial.print() lines into the code. This sort of thing is a lot easier to troubleshoot when you can watch the text printing in the serial monitor rather than trying to move and click your mouse or type characters into your code.
 
I'll give that a shot. I was trying to create a loop on fallingEdge with Mouse.Move in it and then break the loop with risingEdge. I realize that's not a great way to do it, but I'm completely new to the Teensy, so my code is very sloppy right now.
 
I tried this:
Code:
#include <Bounce.h>

/* USB Arcade Stick 
 *  All Buttons assigned as Keyboard keys for easy use with Emulation
 *  
 * Original code from the Teensy Examples. 
*/


int X;
int Y;
// Create Bounce objects for each button.  The Bounce object
// automatically deals with contact chatter or "bounce", and
// it makes detecting changes very simple.
Bounce button0 = Bounce(0, 10);
Bounce button1 = Bounce(1, 10);  // 10 = 10 ms debounce time
Bounce button2 = Bounce(2, 10);  // which is appropriate for
Bounce button3 = Bounce(3, 10);  // most mechanical pushbuttons
Bounce button4 = Bounce(4, 10);
Bounce button5 = Bounce(5, 10);  // if a button is too "sensitive"
Bounce button6 = Bounce(6, 10);  // to rapid touch, you can
Bounce button7 = Bounce(7, 10);  // increase this time.
Bounce button8 = Bounce(8, 10);
Bounce button9 = Bounce(9, 10);
Bounce button10 = Bounce(10, 10);
Bounce button11 = Bounce(11, 10);
Bounce button12 = Bounce(12, 10);
Bounce button13 = Bounce(13, 10);

void setup() {
  // Configure the pins for input mode with pullup resistors.
  // The pushbuttons connect from each pin to ground.  When
  // the button is pressed, the pin reads LOW because the button
  // shorts it to ground.  When released, the pin reads HIGH
  // because the pullup resistor connects to +5 volts inside
  // the chip.  LOW for "on", and HIGH for "off" may seem
  // backwards, but using the on-chip pullup resistors is very
  // convenient.  The scheme is called "active low", and it's
  // very commonly used in electronics... so much that the chip
  // has built-in pullup resistors!
  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);  // Teensy++ LED, may need 1k resistor pullup
  pinMode(7, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);
  pinMode(13, INPUT_PULLUP);
}

void loop() {
  // Update all the buttons.  There should not be any long
  // delays in loop(), so this runs repetitively at a rate
  // faster than the buttons could be pressed and released.
  button0.update();
  button1.update();
  button2.update();
  button3.update();
  button4.update();
  button5.update();
  button6.update();
  button7.update();
  button8.update();
  button9.update();
  button10.update();
  button11.update();
  button12.update();
  button13.update();

  // Check each button for "falling" edge.
  // Type a message on the Keyboard when each button presses
  // Update the Joystick buttons only upon changes.
  // falling = high (not pressed - voltage from pullup resistor)
  //           to low (pressed - button connects pin to ground)

  if (button0.fallingEdge()) {
   const int X = 1;     
  }
  if (button1.fallingEdge()) {
    Keyboard.press(KEY_UP);
  }
  if (button2.fallingEdge()) {
    Keyboard.press(KEY_DOWN);
  }
  if (button3.fallingEdge()) {
    Keyboard.press(KEY_RIGHT);
  }
  if (button4.fallingEdge()) {
    Keyboard.press(KEY_5);
  }
  if (button5.fallingEdge()) {
    Keyboard.press(KEY_1);
  }
  if (button6.fallingEdge()) {
    Keyboard.press(KEY_Z);
  }
  if (button7.fallingEdge()) {
    Keyboard.press(KEY_X);
  }
  if (button8.fallingEdge()) {
    Keyboard.press(KEY_C);
  }
  if (button9.fallingEdge()) {
    Keyboard.press(KEY_A);
  }
  if (button10.fallingEdge()) {
      Keyboard.press(KEY_S);
    }
  if (button11.fallingEdge()) {
      Keyboard.press(KEY_D);
    }
  if (button12.fallingEdge()) {
      Keyboard.press(KEY_ESC);
    }
  if (button13.fallingEdge()) {
      Keyboard.press(KEY_F);
    }
  Mouse.move (X, Y);
  // Check each button for "rising" edge
  // Type a message on the Keyboard when each button releases.
  // For many types of projects, you only care when the button
  // is pressed and the release isn't needed.
  // rising = low (pressed - button connects pin to ground)
  //          to high (not pressed - voltage from pullup resistor)
  if (button0.risingEdge()) {
    int X = 0;
  }
  if (button1.risingEdge()) {
    Keyboard.release(KEY_UP);
  }
  if (button2.risingEdge()) {
    Keyboard.release(KEY_DOWN);
  }
  if (button3.risingEdge()) {
    Keyboard.release(KEY_RIGHT);
  }
  if (button4.risingEdge()) {
    Keyboard.release(KEY_5);
  }
  if (button5.risingEdge()) {
    Keyboard.release(KEY_1);
  }
  if (button6.risingEdge()) {
    Keyboard.release(KEY_Z);
  }
  if (button7.risingEdge()) {
    Keyboard.release(KEY_X);
  }
  if (button8.risingEdge()) {
    Keyboard.release(KEY_C);
  }
  if (button9.risingEdge()) {
    Keyboard.release(KEY_A);
  }
  if (button10.risingEdge()) {
    Keyboard.release(KEY_S);
  }
  if (button11.risingEdge()) {
    Keyboard.release(KEY_D);
  }
  if (button12.risingEdge()) {
    Keyboard.release(KEY_ESC);
  }
  if (button13.risingEdge()) {
    Keyboard.release(KEY_F);
  }
}

And the mouse cursor doesn't do anything. My idea was to run Mouse.move once per loop, and set the Variables X and Y on fallingEdge and risingEdge respectively. The code compiles as X being unused when Y should be the unused one right now. Keyboard commands work fine, and I can start a loop like this:
Code:
  while (button0.fallingEdge())
    Mouse.move(0, 1);
then try to end it with
Code:
if (button0.risingEdge())
    break;
But that obviously doesn't work because I'm trying to break a loop without being in it. I've been trying to do this for 2 days now and I have no clue what I'm doing.
 
Okay, I tried adding INPUT_PULLUP to the second script and it works fine now, just need to add the other buttons. Thanks!
 
I just modified my script to this:
Code:
#include <Bounce.h>
#include "Mouse.h"
Bounce button0 = Bounce(0, 10);
Bounce button1 = Bounce(1, 10);  // 10 = 10 ms debounce time
Bounce button2 = Bounce(2, 10);  // which is appropriate for
Bounce button3 = Bounce(3, 10);  // most mechanical pushbuttons
Bounce button4 = Bounce(4, 10);
Bounce button5 = Bounce(5, 10);  // if a button is too "sensitive"
Bounce button6 = Bounce(6, 10);  // to rapid touch, you can
Bounce button7 = Bounce(7, 10);  // increase this time.
Bounce button8 = Bounce(8, 10);
Bounce button9 = Bounce(9, 10);
Bounce button10 = Bounce(10, 10);
Bounce button11 = Bounce(11, 10);
Bounce button12 = Bounce(12, 10);
Bounce button13 = Bounce(13, 10);
int range = 1; // output range of X or Y movement; affects movement speed
int responseDelay = 10; // response delay of the mouse, in ms

void setup() {
   // initialize the buttons' inputs:
  pinMode(1, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);  // Teensy++ LED, may need 1k resistor pullup
  pinMode(7, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);
  pinMode(13, INPUT_PULLUP);
   // initialize mouse control:
   Mouse.begin();
}

void loop() {
  button0.update();
  button1.update();
  button2.update();
  button3.update();
  button4.update();
  button5.update();
  button6.update();
  button7.update();
  button8.update();
  button9.update();
  button10.update();
  button11.update();
  button12.update();
  button13.update();
   // read the buttons:
   int upState = digitalRead(button0);
   int downState = digitalRead(button1);
   int rightState = digitalRead(button2);
   int leftState = digitalRead(button3);
   int clickState = digitalRead(button4);
   // calculate the movement distance based on the button states:
   int xDistance = (leftState - rightState) * range;
   int yDistance = (upState - downState) * range;
   // if X or Y is non-zero, move:
   if ((xDistance != 0) || (yDistance != 0)) {
      Mouse.move(xDistance, yDistance, 0);
   }

   // if the mouse button is pressed:
   if (clickState == HIGH) {
      // if the mouse is not pressed, press it:
      if (!Mouse.isPressed(MOUSE_MIDDLE)) {
         Mouse.press(MOUSE_MIDDLE);
      }
   } else {                           // else the mouse button is not pressed:
      // if the mouse is pressed, release it:
      if (Mouse.isPressed(MOUSE_MIDDLE)) {
         Mouse.release(MOUSE_MIDDLE);
      }
   }
   // a delay so the mouse does not move too fast:
   delay(responseDelay);
  if (button5.fallingEdge()) {
    Keyboard.press(KEY_F1);
  }
  if (button6.fallingEdge()) {
    Keyboard.press(KEY_F2);
  }
  if (button7.fallingEdge()) {
    Keyboard.press(KEY_F3);
  }
  if (button8.fallingEdge()) {
    Keyboard.press(KEY_F4);
  }
  if (button9.fallingEdge()) {
    Keyboard.press(KEY_ESC);
  }
  if (button10.fallingEdge()) {
    Keyboard.press(KEY_ENTER);
    }
  if (button11.fallingEdge()) {
      Mouse.press(MOUSE_LEFT);
    }
  if (button12.fallingEdge()) {
      Keyboard.press(KEY_RIGHT);
    }
  if (button13.fallingEdge()) {
      Keyboard.press(KEY_F);
    }
}
And I am getting this error:
Code:
Arduino: 1.8.11 (Windows 10), TD: 1.52, Board: "Teensy LC, Keyboard + Mouse + Joystick, 48 MHz, Smallest Code, US English"

acrade_stick: In function 'void loop()':
acrade_stick:56: error: cannot convert 'Bounce' to 'uint8_t {aka unsigned char}' for argument '1' to 'uint8_t digitalRead(uint8_t)'
    int upState = digitalRead(button0);

                                     ^

acrade_stick:57: error: cannot convert 'Bounce' to 'uint8_t {aka unsigned char}' for argument '1' to 'uint8_t digitalRead(uint8_t)'
    int downState = digitalRead(button1);

                                       ^

acrade_stick:58: error: cannot convert 'Bounce' to 'uint8_t {aka unsigned char}' for argument '1' to 'uint8_t digitalRead(uint8_t)'
    int rightState = digitalRead(button2);

                                        ^

acrade_stick:59: error: cannot convert 'Bounce' to 'uint8_t {aka unsigned char}' for argument '1' to 'uint8_t digitalRead(uint8_t)'
    int leftState = digitalRead(button3);

                                       ^

acrade_stick:60: error: cannot convert 'Bounce' to 'uint8_t {aka unsigned char}' for argument '1' to 'uint8_t digitalRead(uint8_t)'
    int clickState = digitalRead(button4);

                                        ^

cannot convert 'Bounce' to 'uint8_t {aka unsigned char}' for argument '1' to 'uint8_t digitalRead(uint8_t)'

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

What am I forgetting?
 
First to directly answer your question, use the read() function, like this:

Code:
  int clickState = digitalRead(button4.read());

However, this alone probably will not give you everything you need. You're probably going to need some sort of tracking of how long the button as been pressed, so you can transmit a repeating stream of Mouse.move() while the joystick is continuously pressed in 1 direction.

Maybe something like this?


in your global variables:
Code:
elapsedMillis button0millis;

in loop:
Code:
  if (button0.fallingEdge()) {
    // when button is first pressed, move the mouse and set elasped time to 0
    Mouse.move(0, -1);
    button0millis = 0;
  }
  if (button0.read() == LOW) {
    if (button0millis > 100) {
      // when button is still pressed and 100ms have elapsed, move the mouse more
      Mouse.move(0, -1);
      button0millis = 0;
    }
  }


Also, in your code above, looks like you have pinMode twice for pin 1, but none for pin 0. If pin 0 isn't working, that's probably why.
 
Status
Not open for further replies.
Back
Top