Last active
November 15, 2021 23:56
-
-
Save markadr/5857df614b0603b9d710 to your computer and use it in GitHub Desktop.
Example code to deal with a rotary encoder via the PI4J API on a RaspberryPi.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.pi4j.io.gpio.GpioController; | |
import com.pi4j.io.gpio.GpioFactory; | |
import com.pi4j.io.gpio.GpioPinDigitalInput; | |
import com.pi4j.io.gpio.Pin; | |
import com.pi4j.io.gpio.PinPullResistance; | |
import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent; | |
import com.pi4j.io.gpio.event.GpioPinListenerDigital; | |
import java.util.logging.Level; | |
import java.util.logging.Logger; | |
/** | |
* | |
* @author Mark de Reeper | |
*/ | |
public class RotaryEncoder { | |
private final GpioPinDigitalInput inputA; | |
private final GpioPinDigitalInput inputB; | |
private final GpioController gpio; | |
private long encoderValue = 0; | |
private int lastEncoded = 0; | |
private boolean firstPass = true; | |
private RotaryEncoderListener listener; | |
// based on [lastEncoded][encoded] lookup | |
private static final int stateTable[][]= { | |
{0, 1, 1, -1}, | |
{-1, 0, 1, -1}, | |
{-1, 1, 0, -1}, | |
{-1, 1, 1, 0} | |
}; | |
private static final Logger LOGGER = Logger.getLogger(RotaryEncoder.class.getName()); | |
public RotaryEncoder(Pin pinA, Pin pinB, long initalValue) { | |
encoderValue = initalValue; | |
gpio = GpioFactory.getInstance(); | |
inputA = gpio.provisionDigitalInputPin(pinA, "PinA", PinPullResistance.PULL_UP); | |
inputB = gpio.provisionDigitalInputPin(pinB, "PinB", PinPullResistance.PULL_UP); | |
GpioPinListenerDigital inputAListener = new GpioPinListenerDigital() { | |
@Override | |
public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent gpdsce) { | |
int stateA = gpdsce.getState().getValue(); | |
int stateB = inputB.getState().getValue(); | |
calcEncoderValue(stateA, stateB); | |
LOGGER.log(Level.FINE, "{0}{1} encodedValue: {2}", new Object[]{stateA, stateB, encoderValue}); | |
} | |
}; | |
inputA.addListener(inputAListener); | |
Runtime.getRuntime().addShutdownHook(new Thread() { | |
@Override | |
public void run() { | |
LOGGER.info("RotarySwitch: Shutting down...."); | |
if (gpio != null) { | |
gpio.removeAllListeners(); | |
gpio.shutdown(); | |
} | |
} | |
}); | |
LOGGER.log(Level.INFO, "RotarySwitch initialised on pinA {0} and pinB {1}", | |
new String[]{pinA.getName(), pinB.getName()}); | |
} | |
public long getValue() { | |
return encoderValue; | |
} | |
public void setListener(RotaryEncoderListener listener) { | |
this.listener = listener; | |
} | |
private void calcEncoderValue(int stateA, int stateB) { | |
// converting the 2 pin value to single number to end up with 00, 01, 10 or 11 | |
int encoded = (stateA << 1) | stateB; | |
if (firstPass) { | |
firstPass = false; | |
} else { | |
// going up states, 01, 11 | |
// going down states 00, 10 | |
int state = stateTable[lastEncoded][encoded]; | |
encoderValue += state; | |
if (listener != null) { | |
if (state == -1) { | |
listener.down(encoderValue); | |
} | |
if (state == 1) { | |
listener.up(encoderValue); | |
} | |
} | |
} | |
lastEncoded = encoded; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* | |
* @author Mark de Reeper | |
*/ | |
public interface RotaryEncoderListener { | |
void up(long encoderValue); | |
void down(long encoderValue); | |
} |
For me a much simpler solution worked - https://gist.github.com/kachurovskiy/c819c01b8b8bfd15e7e5b4e77eea91d0
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I made a version that works a bit better for my usage here https://gist.github.com/fredoche/69c5f59cead4b7828653 .
Because of the threading issue, I use a Lock to avoid concurrent and buggy reactions. I also noticed that the method described here worked better for me: http://theatticlight.net/posts/Reading-a-Rotary-Encoder-from-a-Raspberry-Pi/
Thanks for the original submission.