so after quite a long time of trying to understand how the NewEncoder-library works I have a demo-code that show changing between two modes where each mode can have its own value.
The code is divided in serveral functions to make it easier to understand what happens inside loop
@gfvalvo : the command NewSettings does
## not
work as described in the documentation
the third parameter is **not** used to update the currentValue
the min and max-values **don't** get updated
So I guess there is something wrong in the code or your documentation is misunderstandable
updated the NewEncoder-library and now it works like expected
// start of macros dbg and dbgi
#define dbg(myFixedText, variableName) \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope
#define dbgi(myFixedText, variableName,timeInterval) \
do { \
static unsigned long intervalStartTime; \
if ( millis() - intervalStartTime >= timeInterval ){ \
intervalStartTime = millis(); \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName); \
} \
} while (false);
// usage: dbgi("2:my fixed text",myVariable,1000);
// myVariable can be any variable or expression that is defined in scope
// third parameter is the time in milliseconds that must pass by until the next time a
// Serial.print is executed
// end of macros dbg and dbgi
#include "Arduino.h"
void PrintFileNameDateTime() {
Serial.println( F("Code running comes from file ") );
Serial.println( F(__FILE__));
Serial.print( F(" compiled ") );
Serial.print(F(__DATE__));
Serial.print( F(" ") );
Serial.println(F(__TIME__));
}
boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - periodStartTime >= TimePeriod )
{
periodStartTime = currentMillis; // set new expireTime
return true; // more time than TimePeriod) has elapsed since last time if-condition was true
}
else return false; // not expired
}
unsigned long MyTestTimer = 0; // variables MUST be of type unsigned long
const byte OnBoard_LED = 13;
unsigned long buttonReleaseTimer;
void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
static unsigned long MyBlinkTimer;
pinMode(IO_Pin, OUTPUT);
if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
}
}
#include "NewEncoder.h"
const byte EncChA_Pin = 2;
const byte EncChB_Pin = 3;
const int minVal = -20;
const int maxVal = 20;
const int startVal = 2;
// Pins 2 and 3 should work for many processors, including Uno. See 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);
// 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;
NewEncoder::EncoderState myDummyState;
int16_t currentValue;
int16_t prevEncoderValue;
int16_t tempMin = 10;
int16_t tempMax = 30;
int16_t actualTemperature;
int16_t storedTemperature;
int16_t rpmMin = 40;
int16_t rpmMax = 50;
int16_t actualRpm;
int16_t storedRpm;
const byte EncBtnPin = 4;
const byte TEMPERATURE_MODE = 0;
const byte RPM_MODE = 1;
byte myMode = TEMPERATURE_MODE;
byte myLastMode = myMode;
void setup() {
pinMode(EncBtnPin, INPUT_PULLUP);
Serial.begin(115200);
PrintFileNameDateTime();
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 pushBtnTogglesMode(byte p_IO_Pin, byte &p_mode) {
static int buttonState; // the current reading from the input pin
static int lastButtonState = LOW; // the previous reading from the input pin
// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
static unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
// read the state of the switch into a local variable:
int reading = digitalRead(p_IO_Pin);
// check to see if you just pressed the button
// (i.e. the input went from LOW to HIGH), and you've waited long enough
// since the last press to ignore any noise:
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
// reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer than the debounce
// delay, so take it as the actual current state:
// if the button state has changed:
if (reading != buttonState) {
buttonState = reading;
// only toggle the mode if the new button state is HIGH
if (buttonState == HIGH) {
if (p_mode == 1) {
p_mode = 0;
}
else {
p_mode = 1;
}
}
}
}
// save the reading. Next time through the loop, it'll be the lastButtonState:
lastButtonState = reading;
}
void CheckForModeChange() {
if (myMode != myLastMode) {
myLastMode = myMode;
Serial.print("mode changed new mode ");
if (myMode == TEMPERATURE_MODE) {
Serial.println("Temperature");
}
if (myMode == RPM_MODE) {
Serial.println("rpm");
}
if (myMode == RPM_MODE) {
storedTemperature = actualTemperature; // store actual temperature for later RE-storing
myEncoderObject.newSettings(rpmMin, rpmMax, 22, myEncState); // setup encoder for rpm-mode
myEncoderObject.getAndSet(storedRpm,myDummyState,myEncState);
actualRpm = myEncState.currentValue;
dbg("RPM-Mode active", actualRpm);
Serial.println();
}
if (myMode == TEMPERATURE_MODE) {
storedRpm = actualRpm; // store actual RPM for later RE-storing
actualTemperature = storedTemperature; // restore temperature as we are changing to temperature-mode
myEncoderObject.newSettings(tempMin, tempMax, actualTemperature, myEncState); // setup encoder for temperature-mode
myEncoderObject.getAndSet(storedTemperature,myDummyState,myEncState);
actualTemperature = myEncState.currentValue;
dbg("TemperatureMode active", actualTemperature);
Serial.println();
}
}
}
void PrintEncoderValue() {
// very important ! this stores actual values into variable myEncState
if (myEncoderObject.getState(myEncState)) { //<<<== very important
Serial.print("Encoder: ");
if (myMode == TEMPERATURE_MODE) {
Serial.print("Temperature=");
}
if (myMode == RPM_MODE) {
Serial.print("rpm=");
}
currentValue = myEncState.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 (myEncState.currentClick) {
case NewEncoder::UpClick:
Serial.println("at upper limit.");
break;
case NewEncoder::DownClick:
Serial.println("at lower limit.");
break;
default:
break;
}
}
}
void loop() {
pushBtnTogglesMode(EncBtnPin, myMode); // check if button was pressed if Yes change value of variable myMode
CheckForModeChange();
PrintEncoderValue();
// update value according to active mode
if (myMode == TEMPERATURE_MODE) {
actualTemperature = myEncState.currentValue;
}
else {
actualRpm = myEncState.currentValue;
}
}
as a general hint:
This kind of code is what I define as an easy to understand example for the given functionality.
This functionality is pretty complex. This means the code is not understandable as the second exercise for somebody who just started learning coding from zero.
But it is caused by the complexity of the functionality.
Writing down minimal examples that don't use functions but instead use too similar and too generalised names like "encoder" and leaving out serial output that makes visible what is happending this kind of code is hard to understand
best regards Stefan