In my application I am using the script from the LCD "Hello World" page to display serial messages from my external device. I am using a optical rotary encoder fro Amazon. The application script works fine with the cheap mechanical encoders that are 15PPR. Is there a way to slow down the optical encoder so that it counts every other pulse or some other fraction?
Thanks
/* Read Quadrature Encoder
Connect Encoder to Pins encoder0PinA, encoder0PinB, and +5V.
Sketch by max wolf / www.meso.net
v. 0.1 - very basic functions - mw 20061220
*/
int val;
int encoder0PinA = 3;
int encoder0PinB = 4;
int encoder0Pos = 0;
int encoder0PinALast = LOW;
int n = LOW;
void setup() {
pinMode (encoder0PinA, INPUT);
pinMode (encoder0PinB, INPUT);
Serial.begin (9600);
}
void loop() {
n = digitalRead(encoder0PinA);
if ((encoder0PinALast == LOW) && (n == HIGH)) {
if (digitalRead(encoder0PinB) == LOW) {
encoder0Pos--;
} else {
encoder0Pos++;
}
Serial.print (encoder0Pos);
Serial.print ("/");
}
encoder0PinALast = n;
}
You might have a better time if you used a library to deal with your RotEnc rather than roll your own, for example:
If your loop() has any logic that will take a while, like transmitting data over a 9600-baud UART interface, your program might just completely miss some pulses from a fast-moving rotary encoder. Using interrupts will help with that.
another encoder-library that works very reliably and has comfort-functions like
limiting values, set a start value is the NewEncoder-library
here is a demo-code with explaining.
(can't resist to ask a rhetoric question: which code will be used from a newcomer?
That code that is easiest to understand and based on understanding it to modify it)
#include "NewEncoder.h" //https://github.com/gfvalvo/NewEncoder
const byte EncChA_Pin = 2;
const byte EncChB_Pin = 3;
const int minVal = -10;
const int maxVal = 10;
const int startVal = 2;
// Pins 2 and 3 should work for many processors, including Uno.
// See README https://github.com/gfvalvo/NewEncoder#readme
// for meaning of constructor arguments.
// Use FULL_PULSE for encoders that produce one complete quadrature pulse per detnet, such as: https://www.adafruit.com/product/377
// Use HALF_PULSE for endoders that produce one complete quadrature pulse for every two detents, such as: https://www.mouser.com/ProductDetail/alps/ec11e15244g1/?qs=YMSFtX0bdJDiV4LBO61anw==&countrycode=US¤cycode=USD
NewEncoder myEncoderObject(EncChA_Pin, EncChB_Pin, minVal, maxVal, startVal, FULL_PULSE);
int16_t currentValue;
int16_t prevEncoderValue;
void setup() {
// myEncState is a variable of type EncoderState
// EncoderState is a structured variable that has two "simple" variables
// .currentValue which is type int16_t
// (16 bit signed integer valuerange -36767 to 36767)
// currentValue counts up / down with each pulse created through rotating the encoder
// and
// .currentClick which is of type "EncoderClick"
// the variable type "EncoderClick" can have just 3 values
// NoClick, DownClick, UpClick where "click" means a "pulse" created through rotating the encoder
NewEncoder::EncoderState myEncState;
Serial.begin(115200);
delay(2000);
Serial.println("Starting");
if (!myEncoderObject.begin()) {
Serial.println("Encoder Failed to Start. Check pin assignments and available interrupts. Aborting.");
while (1) {
yield();
}
} else {
// store values of currentValue and EncoderClick into variable myEncState
myEncoderObject.getState(myEncState);
Serial.print("Encoder Successfully Started at value = ");
prevEncoderValue = myEncState.currentValue;
Serial.println(prevEncoderValue);
}
}
void loop() {
NewEncoder::EncoderState myCurrentEncoderState;
// store actual values into variable myCurrentEncoderState
if (myEncoderObject.getState(myCurrentEncoderState)) {
Serial.print("Encoder: ");
currentValue = myCurrentEncoderState.currentValue;
// if currentValue has REALLY changed print new currentValue
if (currentValue != prevEncoderValue) {
Serial.println(currentValue);
prevEncoderValue = currentValue;
// if currentValue stayed the same because the number is at upper/lower limit
// check if encoder was rotated by using the UpClick / DownClick-values
} else
switch (myCurrentEncoderState.currentClick) {
case NewEncoder::UpClick:
Serial.println("at upper limit.");
break;
case NewEncoder::DownClick:
Serial.println("at lower limit.");
break;
default:
break;
}
}
}
Using a 300PPR optical encoder is a very poor choice for a manual menu selection. You can follow the advice of post #3, but you would do better to go back to the low resolution encoder with detents.
Why did you change?