Adding encoders to an existing code

vsfamurri

New member
Hello,

I am very hopeless with coding, I used to understand a bit more, years passed and now I am a complete rookie.

In essence I am trying to make this project from instructable, where this guy makes this perfect button board for video games, in my case I need rotary encoders instead of pots, and after spending hours trying to Frankenstein his script with others I find online, I decided to ask for help to you guys (Been reading the forum a lot the last 2/3 days)

Here is the script;



This code is for a teensy 3.1 used in my green russian control board
You must select the teensy board in Tools and change USB Type to Joystick
*/

//How many buttons I'm using, must equal amount of values in following array
#define NUM_BUTTONS 14
//Which pins I have attached to my buttons
int buttonList[NUM_BUTTONS] = {2,3,4,5,6,7,8,9,10,11,12,14,15,16};
//Led intensity, so super bright LEDS aren't shining in our eyes
#define INTENSITY 200

void setup() {
//This makes it so the states are send by us manually
Joystick.useManualSend(true);

//Declare button pins as input with the internal pullup resistor on
for (int i = 0; i < NUM_BUTTONS; i++) {
pinMode(buttonList, INPUT_PULLUP);
}

//Declare our LED pins as outputs
pinMode(17, OUTPUT);
pinMode(18, OUTPUT);
pinMode(19, OUTPUT);
pinMode(20, OUTPUT);
}

void loop() {
//Read our analogue pots
//Remember that the analogue pin numbers are different than the digital ones!
Joystick.sliderLeft(analogRead(7));
Joystick.sliderRight(analogRead(8));

//Read our button states
for (int i = 0; i < NUM_BUTTONS; i++) {
if (digitalRead(buttonList) == HIGH) { //Check to see if pin is HIGH
Joystick.button(i + 1, 0); //If pin is HIGH, button isn't pressed, so send 0
} else {
Joystick.button(i + 1, 1); //If pin is LOW, button is pressed, so send 1
}
}


//Special case for LED status lights
//Check status of button and change LED accordingly

if (digitalRead(12) == LOW) //Check if button is pressed/switch flipped
analogWrite(17, INTENSITY); //Set corresponding LED pin to intensity level
else
analogWrite(17, 0); //Otherwise turn off

if (digitalRead(7) == LOW) //Same for other pins
analogWrite(18, INTENSITY);
else
analogWrite(18, 0);

if (digitalRead(9) == LOW)
analogWrite(19, INTENSITY);
else
analogWrite(19, 0);

if (digitalRead(11) == LOW)
analogWrite(20, INTENSITY);
else
analogWrite(20, 0);

Joystick.send_now(); //Send control states
delay(5); //Slow things down a bit
}

I don't want to sound like I am demanding for someone to do my homework, but I am really stuck. I managed to have the encoders rotation to print a text on the serial monitor, but I don't know how to have a joypad press rather than a text print, again, I am at almost 0 with this.

If anyone can help I would much appreciate it!

Grazie
 
To make the code readable it is helpful to use the code formatting in the forum like
C++:
// this code is easiet to read
void myFunction{
    Serial.print("Hello")
}

What exactly is your goal? Have a Teensy as a Joystick? You turn one encoder by one step and what should be happening then? One button press for each step...? Different buttons for different directions? In the code I see
Code:
Joystick.sliderLeft(analogRead(7));
which maps the analog pot to the Joystick slider. Is that your goal? In that case you can map the value from the encoder to the slider. But as there is "no limit" compared to a pot you have to decide how to deal with it. You could limit the encoder value to the maximum of 1023 (set it back when it is over that limit).
 
To make the code readable it is helpful to use the code formatting in the forum like
C++:
// this code is easiet to read
void myFunction{
    Serial.print("Hello")
}

What exactly is your goal? Have a Teensy as a Joystick? You turn one encoder by one step and what should be happening then? One button press for each step...? Different buttons for different directions? In the code I see
Code:
Joystick.sliderLeft(analogRead(7));
which maps the analog pot to the Joystick slider. Is that your goal? In that case you can map the value from the encoder to the slider. But as there is "no limit" compared to a pot you have to decide how to deal with it. You could limit the encoder value to the maximum of 1023 (set it back when it is over that limit).
Oh yes so much more readable. Sorry was my first post, I'll make sure I use that function.

In essence I want a clockwise turn to be a button press, and a counterclockwise to be another different button press, so when I make a full rotation I have essentially made a number of button pushes. Is to adjust a parameter (brake bias) in a racing sim.


I think the line that you suggested might work, will put it to action tomorrow and let you know if I managed. Many thanks
 
You haven't indicated exactly what type of encoder you are using and how you are connecting it up. If you tell us that it would help people give you better solutions.
At a guess you will want something roughly along these lines in your code:
Code:
uint8_t lastEncoderValue;
const int upButton = 1; // button to press if turned up
const int downButton = 2; // button to press if turned down
startup() {
...
lastEncoderValue = readEncoder();
...
}

loop() {
...
uint8_t newEncoder = readEncoder();
if (newEncoder != lastEncoderValue) { // moved
  int delta = (int)(newEncoder-lastEncoderValue);
  if (delta > 0) {
    joystick.button(upButton,1); // press the up button
    joystick.button(downButton,0);
  } else {
    joystick.button(upButton,0);
    joystick.button(downButton,1); // press the down button
  }
  lastEncoderValue = newEncoder;
} else { // no change, don't press any buttons.
    joystick.button(upButton,0);
    joystick.button(downButton,0);
}
...
}

The basic logic is compare the current encoder location with the previous one, if it's increased then press one button, if it's decreased press the other. If it's remained the same then press none. The change calculation is done with 8 bit unsigned int values that way as long as your encoder is at least 8 bits long situations like the output wrapping around from maximum to minimum are handled correctly.

This code does make some assumptions on timing:
1) if the encoder moves two steps between updates then only one button press will be sent.
2) if the encoder moves at a rate fast enough to constantly move at least one step each time around the loop then a single long button press will be sent rather than lots of presses.
3) Button presses will be very very short since they are only held down for one cycle through the main loop. I don't know if there will be issues with these getting registered by the game.
4) The encoder is at least 8 bits resolution, it will never turn more than 127 steps between runs through the main loop.
5) Only relative position matters, you don't care about absolute encoder position only that turning it produces the correct button press.

Issues 1 and 2 are both highly unlikely, the loop will be running at a very high rate so it's unlikely your encoder will be changing anywhere close enough to fast enough for this to be true.

You could easily fix 3) if it proves to be an issue by adding pauses but the more you do this the bigger the risk of issues 1 or 2 showing up. Id this does prove to be a problem whether a simple and easy fix like a pause is an option would depend on the expected encoder rates and how long the button press needs to be.

There are lots of ways to avoid these issues completely by adding a little bit of complexity to the code. You could track how far the encoder has moved and how many button presses have been sent and so calculate the number of presses of which button need to be sent. The code could then send the correct number with suitable minimum press lengths and gaps between them. But if the simple approach works then why worry about adding the extra complexity.
 
Last edited:
Back
Top