rotary encoder noise (arduino nano) - Page 1
Forum section: electronics / projects

author: m3vuv
author_rank: Super Contributor
timestamp: December 30, 2020, 02:55:32 pm
content: Hi all,im building this battery tester/charger( see pdf),so far ive built it all except the discharge section,the issue i have is when i fire it all up the display cursor for the mode selection is fine untill i turn the rotary encoder then it goes nuts,any idea whats the cause,i guess i should have 100nf caps on the arduino inputs well between d2+3 and ground?,also it plays up selecting the charging mode,im thinking q3 p channel fet needs to be logic level,as far as i can tell the irf9540nbpf isnt,?,any comments welcome,cheers m3vuv.73

author: S. Petrukhin
author_rank: Super Contributor
timestamp: December 30, 2020, 03:24:27 pm
content: If the movement of the encoder produces a spontaneous movement of several positions, you need to study what is the contact bounce. If the program fails, there may be an error in your code or in the library used, including stack overflow.

author: phil from seattle
author_rank: Super Contributor
timestamp: December 30, 2020, 03:43:49 pm
content: There is at least one encoder library that uses the quadrature state machine to handle bounce. Sorry, I can't point you to the specific one.If you are going add caps, at least make it a proper RC LPF with a relatively aggressive cutoff frequency.

author: tooki
author_rank: Super Contributor
timestamp: December 30, 2020, 04:25:28 pm
content: Yep. Look at a Bourns encoder datasheet; it has a recommended filter circuit.

author: Peabody
author_rank: Super Contributor
timestamp: December 31, 2020, 12:12:54 am
content: The rotary encoder problem is likely switch bounce. These days that's usually taken care of in software. How are you reading the encoder - polling or interrupts? You might want to post the part of your code that deals with the encoder, and we can take a look. You can also try to deal with bounce in hardware, but there's no point in adding extra parts if software will work just as well.That mosfet might work ok for a 5V Pro Mini, but it would depend on how much current you need to pass through it. The maximum GS threshold voltage is 4V, but that's just where it starts to conduct, not where it's fully on. Of course that's the maximum threshold voltage. Typical would be somewhat less, and a specific copy might work fine. The test would be to use your voltmeter to see the voltage drop across the mosfet when it's on. Should be .1V or less.

author: m3vuv
author_rank: Super Contributor
timestamp: December 31, 2020, 12:13:30 am
content: its as if im turning the knob when im not,also what about the p fet?

author: m3vuv
author_rank: Super Contributor
timestamp: December 31, 2020, 12:23:46 am
content: heres the code:Code:#include <jm_LiquidCrystal_I2C.h>#include <jm_Scheduler.h>#include <jm_Wire.h>#include <LiquidCrystal.h>//-----------------------------------------------------Youtube Channel Sasiskas------------------------------------------------------------------------//-----------------------------------------------------Battery Capacity tester and more V1.1-----------------------------------------------------------#include <SPI.h>#include <stdlib.h>#include <LiquidCrystal_I2C.h>LiquidCrystal_I2C lcd(0x27, 16, 2);unsigned long previousMillis = 0;unsigned long millisPassed = 0;unsigned long BatFull = 0;float BatVoltQuiescent = 0; // The battery voltage when there is no load on the batteryfloat Capacity = 0.0; // The calculated capacity of the battery, measured wile dischargingfloat mA=0;float SetI = 0; // The setpoint for the discharging current. Remember you can adjust the discharging current using the 500K trimpot.float ChargeI = 0;float CurTP4056 = 0;float ResTP4056 = 0;float ratioRI = 0;float BatLevel = 0; // The percentage of battery charge/levelfloat BatVoltCorrected = 0; // The voltage of the battery, measured based on the arduino internal referencefloat A2VoltCorrected = 0;float VoltTP4056Pin2 = 0;float Rprog = 0;float BatRes = 0; // The internal battery resistanceconst float RES = 1; // Value of your resistor. Suggested Value is 1 Ohm. Change it, if you use a different resistor value#define clk 2#define dt 3#define sw 4#define MOSFET_Discharge 9 // It is an N-MOSFET, so HIGH is ON and LOW is OFF#define MOSFET_Charge 8 // It is a P-MOSFET, so HIGH is OFF and LOW is ONchar screen = 0;char arrowpos = 0;char charging = 0;char discharging = 0;char storage = 0;char storagecharge = 0;char storagedischarge = 0;char BatVoltQuiescentValue = 0; // Whether there is a value for "the battery voltage with no load" (BatVoltQuiescent) or not. 1 for yes and 0 for no.//char nointermediate = 0;const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);volatile boolean TurnDetected = false;volatile boolean up = false;volatile boolean button = false;byte OhmChar = {B00000,B01110,B10001,B10001,B10001,B01010,B11011,B00000};byte customChar1 = {0b10000,0b11000,0b11100,0b11110,0b11110,0b11100,0b11000,0b10000};ISR(PCINT2_vect) {if (digitalRead(sw) == LOW) {button = true;}}void isr0 () {TurnDetected = true;up = (digitalRead(clk) == digitalRead(dt));}void setup() {lcd.begin();lcd.setCursor(0, 0);pinMode(MOSFET_Discharge, OUTPUT);pinMode(MOSFET_Charge, OUTPUT);digitalWrite(MOSFET_Discharge, LOW);digitalWrite(MOSFET_Charge, HIGH);pinMode(sw, INPUT_PULLUP);pinMode(clk, INPUT);pinMode(dt, INPUT);PCICR |= 0b00000100;PCMSK2 |= 0b00010000; // turn o PCINT20(D4)attachInterrupt(0, isr0, RISING);lcd.createChar(0, customChar1);lcd.createChar(1, OhmChar);lcd.clear();screen0();lcd.setCursor(0, 0);lcd.write((uint8_t)0);}void loop() {int in0 = analogRead(A0); //read the A0 pin valueint sensorValue1 = analogRead(A1); //read the A1 pin valuefloat val0 = in0 * 5.0 / 1024.0;float supply = readVcc() / 1000.0;SetI = sensorValue1 * (5.00 / 1024.00) / RES * 1000; // Calculate the discharge rate of the batteryif (SetI <= 1200){SetI = SetI;}else{SetI = 1200;}BatVoltCorrected = supply / 5 * val0 * 4.35; //In case you use different voltage dividers, you need to change the number 4.3 accordingly.millisPassed = millis() - previousMillis;previousMillis = millis();//------------------------------------------------------------------- calculates the charging current ------------------------------------------------------------------------int in2 = analogRead(A2); //read the A2 pin valueint in3 = analogRead(A3); //read the A3 pin valuefloat val2 = in2 * 5.0 / 1024.0;float val3 = in3 * 5.0 / 1024.0;A2VoltCorrected = supply / 5 * val2; //calculates reading of pin A2 based on internal voltage referenceVoltTP4056Pin2 = supply / 5 * val3;//calculates reading of pin A3 based on internal voltage referenceRprog = 1220 + (A2VoltCorrected * 1220 / (VoltTP4056Pin2 - A2VoltCorrected)); //calculates the Rprog of TP4056 module//calculates the Charging current based on numbers from TP4056 datasheetif (Rprog >= 10000) {CurTP4056 =130 ;ResTP4056 =10000 ;ratioRI = 0.107 ;}else if (Rprog < 10000 && Rprog >= 5000){CurTP4056 = 250 ;ResTP4056 = 5000 ;ratioRI = 0.024 ;}else if (Rprog < 5000 && Rprog >= 4000){CurTP4056 = 300 ;ResTP4056 = 4000 ;ratioRI = 0.050 ;}else if (Rprog < 40000 && Rprog >= 3000){CurTP4056 = 400 ;ResTP4056 = 3000 ;ratioRI = 0.100 ;}else if (Rprog < 30000 && Rprog >= 2000){CurTP4056 = 580 ;ResTP4056 = 2000 ;ratioRI = 0.180 ;}else if (Rprog < 20000 && Rprog >= 1660){CurTP4056 = 690 ;ResTP4056 = 1660 ;ratioRI = 0.324 ;}else if (Rprog < 10000 && Rprog >= 1500){CurTP4056 = 780 ;ResTP4056 = 1500 ;ratioRI = 0.563 ;}else if (Rprog < 10000 && Rprog >= 1330){CurTP4056 = 900 ;ResTP4056 = 1330 ;ratioRI = 0.706 ;}else if (Rprog >= 1220){CurTP4056 = 995 ;ResTP4056 = 1220 ;ratioRI = 0.864 ;}if (Rprog < 1220){ChargeI = 1000 ;}else {ChargeI = (CurTP4056 - ((Rprog - ResTP4056) * ratioRI));}if (ChargeI > 0){ChargeI = ChargeI;}else{ChargeI = 0;}//------------------------------------------------------------------- battery percentage - linear calculation based on voltage (linear does NOT represent the REAL percentage)if (BatVoltCorrected < 2.5) {BatLevel = 0;}else if (BatVoltCorrected > 4.2){BatLevel = 100;}else {BatLevel = (BatVoltCorrected - 2.5 ) / 1.7 * 100 ;}//----------------------------------------------------------------------------------------------------------------------------------------------------------------------if (BatVoltCorrected <= 3.70 && BatVoltCorrected >= 3.65){ // For 3400mAh batteries storage voltage is 3.6-3.7V, for batteries below 2600mAh it should be higher.storagedischarge = 0;storagecharge = 0;}if (BatVoltCorrected <= 3.75 && BatVoltCorrected > 3.7){ // Set these numbers +0.5V of your batteries storage voltagestoragedischarge = 1;storage = 2;storagecharge = 0;}if (BatVoltCorrected >= 3.6 && BatVoltCorrected < 3.65){ // Set these numbers -0.5V of your batteries storage voltagestoragecharge = 1;storage = 2;storagedischarge = 0;}if (BatVoltCorrected > 3.75 || BatVoltCorrected < 3.6){ // Set these numbers +0.5V and -0.5V of your batteries storage voltagestorage = 0;storagedischarge = 0;storagecharge = 0;}if (BatVoltCorrected <= 3.75 && BatVoltCorrected >= 3.6){ // Set these numbers +0.5V and -0.5V of your batteries storage voltagestorage = 1;}//------------------------------------------------------------------------------------------------------------------------------------------------------if (screen == 0) {//delay(500);BatVoltQuiescent = BatVoltCorrected;BatVoltQuiescentValue = 1;BatFull = 0;}//----------------------------------------------------------------------------------------Capacity test mode-------------------------------------------------------if (screen == 1) {if (BatVoltCorrected <= 2.3){Capacity = Capacity;BatVoltQuiescentValue = 0;digitalWrite(MOSFET_Discharge, LOW);// buz();lcd.setCursor(0,0);lcd.print("V:");lcd.print(BatVoltCorrected);lcd.print("V ");lcd.setCursor(8,0);lcd.print("I:");lcd.print(SetI,0);lcd.print("mA ");lcd.setCursor(0,1);lcd.print("C:");lcd.print(Capacity,0);lcd.print("mAh ");lcd.setCursor(10,1);lcd.print("R:");lcd.print(BatRes,0);lcd.print("m");lcd.print(char(1));delay(100);}if (BatVoltCorrected > 2.3 && BatVoltQuiescentValue == 0 ) {BatRes = (BatVoltQuiescent - BatVoltCorrected) / (BatVoltCorrected / SetI); //Calculates the internal battery resistance in mOhmsCapacity = Capacity + (SetI * (millisPassed / 3600000.0));BatVoltQuiescent = BatVoltCorrected;BatVoltQuiescentValue = 1;digitalWrite(MOSFET_Discharge, HIGH);lcd.setCursor(0,0);lcd.print("V:");lcd.print(BatVoltCorrected);lcd.print("V ");lcd.setCursor(8,0);lcd.print("I:");lcd.print(SetI,0);lcd.print("mA ");lcd.setCursor(0,1);lcd.print("C:");lcd.print(Capacity,0);lcd.print("mAh ");lcd.setCursor(10,1);lcd.print("R:");lcd.print(BatRes,0);lcd.print("m");lcd.print(char(1));delay(500);}else if (BatVoltCorrected > 2.3 && BatVoltQuiescentValue == 1 ) {BatRes = (BatVoltQuiescent - BatVoltCorrected) / (BatVoltCorrected / SetI); //Calculates the internal battery resistance in mOhmsCapacity = Capacity + (SetI * (millisPassed / 3600000.0));digitalWrite(MOSFET_Discharge, HIGH);lcd.setCursor(0,0);lcd.print("V:");lcd.print(BatVoltCorrected);lcd.print("V ");lcd.setCursor(8,0);lcd.print("I:");lcd.print(SetI,0);lcd.print("mA ");lcd.setCursor(0,1);lcd.print("C:");lcd.print(Capacity,0);lcd.print("mAh ");lcd.setCursor(10,1);lcd.print("R:");lcd.print(BatRes,0);lcd.print("m");lcd.print(char(1));delay(500);}}//----------------------------------------------------------------------------------------Charge mode-------------------------------------------------------else if (screen == 2) {if (BatVoltCorrected >= 4.15) {lcd.setCursor(0,0);lcd.print("Full Battery");lcd.setCursor(12,0);lcd.print("100% ");lcd.setCursor(0,1);lcd.print("V:");lcd.print(BatVoltCorrected);lcd.print("V ");lcd.setCursor(8,1);lcd.print("I:");lcd.print(ChargeI,0);lcd.print("mA ");digitalWrite(MOSFET_Charge, HIGH);delay(500);BatFull = BatFull + 1;}else if (BatVoltCorrected == 0 ){BatFull = 0;lcd.setCursor(0,0);lcd.print("No Battery ");lcd.setCursor(12,0);lcd.print(BatLevel,0);lcd.print("% ");lcd.setCursor(0,1);lcd.print("V:");lcd.print(BatVoltCorrected);lcd.print("V ");lcd.setCursor(9,1);lcd.print("I:");lcd.print(ChargeI,0);lcd.print("mA ");digitalWrite(MOSFET_Charge, HIGH);//delay(9000);//digitalWrite(MOSFET_Charge, HIGH);delay(500);}else if (BatVoltCorrected < 4.15 && BatFull < 10 && BatVoltCorrected > 0 ) {lcd.setCursor(0,0);lcd.print("Charging... ");lcd.setCursor(12,0);lcd.print(BatLevel,0);lcd.print("% ");lcd.setCursor(0,1);lcd.print("V:");lcd.print(BatVoltCorrected);lcd.print("V ");lcd.setCursor(8,1);lcd.print("I:");lcd.print(ChargeI,0);lcd.print("mA ");digitalWrite(MOSFET_Charge, LOW);//delay(9000);//digitalWrite(MOSFET_Charge, HIGH);delay(500);}else if (BatVoltCorrected < 4.15 && BatFull >= 10) {lcd.setCursor(0,0);lcd.print("Full Battery");lcd.setCursor(12,0);lcd.print("100% ");lcd.setCursor(0,1);lcd.print("V:");lcd.print(BatVoltCorrected);lcd.print("V ");lcd.setCursor(8,1);lcd.print("I:");lcd.print(ChargeI,0);lcd.print("mA ");digitalWrite(MOSFET_Charge, HIGH);delay(500);}}//----------------------------------------------------------------------------------------Storage mode-----------------------------------------------------------------------------------------// You need to adjust your voltages according to your batteries, for 3400mAh batteries storage voltage (50% capacity) is 3.6-3.7V, for batteries below 2600mAh it should be higher.// For more info visit this:https://lygte-info.dk/info/BatteryChargePercent%20UK.htmlelse if (screen == 3) {delay(100);if (BatVoltCorrected <= 1.5 ) {lcd.setCursor(0,0);lcd.print("No battery ");lcd.setCursor(0,1);lcd.print("V:");lcd.print(BatVoltCorrected);lcd.print("V ");digitalWrite(MOSFET_Discharge, LOW);digitalWrite(MOSFET_Charge, HIGH);charging = 0;discharging = 0;storage = 0;storagecharge = 0;storagedischarge = 0;}else if (BatVoltCorrected > 3.75 && charging == 0) { // Checks if the "quiescent voltage" of the battery is above 3.7V and Starts the discharge.lcd.setCursor(0,0);lcd.print("Discharging ");lcd.setCursor(0,1);lcd.setCursor(0,1);lcd.print("V:");lcd.print(BatVoltCorrected);lcd.print("V ");lcd.setCursor(9,1);lcd.print("I:");lcd.print(SetI,0);lcd.print("mA ");digitalWrite(MOSFET_Charge, HIGH);delay(100);discharging = 1;digitalWrite(MOSFET_Discharge, HIGH);delay(9000);digitalWrite(MOSFET_Discharge, LOW);}else if (storagedischarge == 1 && discharging == 1){ // Intermediate step before stopping the dischargelcd.setCursor(0,0);lcd.print("RDY for storage");lcd.setCursor(0,1);lcd.print("V:");lcd.print(BatVoltCorrected);lcd.print("V ");discharging = 1;digitalWrite(MOSFET_Charge, HIGH);delay(100);digitalWrite(MOSFET_Discharge, HIGH);delay(9000);digitalWrite(MOSFET_Discharge, LOW);}else if (BatVoltCorrected >= 1.5 && BatVoltCorrected < 3.6) { // Checks if the "quiescent voltage" of the battery is between 1.5V and 3.6Vif (discharging == 1 && BatVoltCorrected < 3.0){ // Stops discharging if the "discharge voltage" of the battery is below 3.0Vlcd.setCursor(0,1);lcd.print("V:");lcd.print(BatVoltCorrected);lcd.print("V ");lcd.setCursor(9,1);lcd.print("I:");lcd.print(SetI,0);lcd.print("mA ");digitalWrite(MOSFET_Discharge, LOW);}if (discharging == 1 && BatVoltCorrected > 2){ // Prevents from charging (continues discharging) even if the "quiescent voltage" is below 3.6Vlcd.setCursor(0,1);lcd.print("V:");lcd.print(BatVoltCorrected);lcd.print("V ");lcd.setCursor(9,1);lcd.print("I:");lcd.print(SetI,0);lcd.print("mA ");}else if (discharging == 0 && BatVoltCorrected < 3.6){ // Starts to charge the batterylcd.setCursor(0,0);lcd.print("Charging ");lcd.setCursor(0,1);lcd.print("V:");lcd.print(BatVoltCorrected);lcd.print("V ");digitalWrite(MOSFET_Discharge, LOW);delay(100);digitalWrite(MOSFET_Charge, LOW);charging = 1;delay(1000);}else { // used for debugginglcd.setCursor(0,0);lcd.print("error? ");}}else if (storagecharge == 1 && charging == 1){ // Intermediate step before stopping the charge. (not actually stopping the charge)lcd.setCursor(0,0);lcd.print("RDY for storage");lcd.setCursor(0,1);lcd.print("V:");lcd.print(BatVoltCorrected);lcd.print("V ");charging = 1;//nointermediate = 1;digitalWrite(MOSFET_Discharge, LOW);delay(100);digitalWrite(MOSFET_Charge, LOW);delay(1000);}else if (charging == 1 && BatVoltCorrected > 3.65 ){ // Stops charge . This step is used if the Intermediate stop of charge was used.lcd.setCursor(0,0);lcd.print("RDY for storage");lcd.setCursor(0,1);lcd.print("V:");lcd.print(BatVoltCorrected);lcd.print("V ");digitalWrite(MOSFET_Discharge, LOW);digitalWrite(MOSFET_Charge, HIGH);delay(1000);}else if (storage == 1 && charging == 0){ // For 3400mAh batteries sorage voltage is 3.6-3.7V, for batteries below 2600mAh it should be higher.lcd.setCursor(0,0); // This step is used if the Intermediate stop of charge was NOT used. Or after intermadiate stop of discharge.lcd.print("RDY for storage");lcd.setCursor(0,1);lcd.print("V:");lcd.print(BatVoltCorrected);lcd.print("V ");digitalWrite(MOSFET_Discharge, LOW);digitalWrite(MOSFET_Charge, HIGH);delay(1000);}}//-------------------------------------------------------------------------------- TURN -------------------------------------------------------------------------------------------------------if (TurnDetected) {delay(200);switch (screen) {case 0:switch (arrowpos) {case 0:if (!up) {screen0();lcd.setCursor(0, 1);lcd.write((uint8_t)0);arrowpos = 1;}else {screen0();lcd.setCursor(8, 1);lcd.write((uint8_t)0);arrowpos = 2;}break;case 1:if (up) {screen0();lcd.setCursor(0, 0);lcd.write((uint8_t)0);arrowpos = 0;}else {screen0();lcd.setCursor(8, 1);lcd.write((uint8_t)0);arrowpos = 2;}break;case 2:if (up) {screen0();lcd.setCursor(0, 1);lcd.write((uint8_t)0);arrowpos = 1;}else {screen0();lcd.setCursor(0, 0);lcd.write((uint8_t)0);arrowpos = 0;}break;}break;}TurnDetected = false;}//-------------------------------------------------------------------------------------------- BUTTON PRESS --------------------------------------------------------------------------------------------if (button) {delay(200);switch (screen) {case 0:if (arrowpos == 0) {screen = 1;screen1();}else if (arrowpos == 1){screen = 2;screen2();}else {screen = 3;screen3();}break;case 1:screen = 0;screen0();lcd.setCursor(0, 0);lcd.write((uint8_t)0);break;case 2:screen = 0;screen0();lcd.setCursor(0, 0);lcd.write((uint8_t)0);break;case 3:screen = 0;screen0();lcd.setCursor(0, 0);lcd.write((uint8_t)0);break;}arrowpos = 0;button = false;}}//-----------------------------------------------------------------------------------------------------SCREENS-------------------------------------------------------------------------------------void screen0() {lcd.clear();lcd.setCursor(1, 0);lcd.print("Capacity test");lcd.setCursor(1, 1);lcd.print("Charge");lcd.setCursor(9, 1);lcd.print("Store");digitalWrite(MOSFET_Discharge, LOW);digitalWrite(MOSFET_Charge, HIGH);charging = 0;discharging = 0;storage = 0;storagecharge = 0;storagedischarge = 0;}void screen1() {lcd.clear();}void screen2() {lcd.clear();}void screen3() {lcd.clear();}//-------------------------------------------------------------------voltage based on internal reference-------------------------------------------------------------long readVcc() {long result;// Read 1.1V reference against AVcc#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)ADMUX = _BV(MUX5) | _BV(MUX0);#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)ADMUX = _BV(MUX3) | _BV(MUX2);#elseADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);#endifdelay(2); // Wait for Vref to settleADCSRA |= _BV(ADSC); // Convertwhile (bit_is_set(ADCSRA, ADSC));result = ADCL;result |= ADCH << 8;result = 1126400L / result; // Calculate Vcc (in mV); 1126400 = 1.1*1024*1000return result;}//void buz()// {// digitalWrite(9, HIGH);// delay(100);// digitalWrite(9, LOW);// delay(10);//}

author: Peabody
author_rank: Super Contributor
timestamp: December 31, 2020, 02:24:26 pm
content: I'm assuming you have the type of encoder which has an equal number of pulses per revolution as detents per revolution. Both switches would be open at every detent (as opposed to alternating between both open and both closed).The changes I would suggest for the encoder are shown below. I've changed the trigger to FALLING, and the interrupt is turned off in the ISR, and not re-enabled until 200mS has passed and both pins are high again. Hopefully that will prevent bouncing from triggering interrupts.Code:attachInterrupt(digitalPinToInterrupt(clk), isr0, FALLING);...void isr0 () {TurnDetected = true; // triggered when clk goes lowup = (digitalRead(dt) == HIGH); // if direction is backwards, change to LOWEIMSK = 0; // turn off interruptEIFR = 1; // clear any flag}...if (TurnDetected) {delay(200);...}// check for both high on each loop before reenable - looking for detentif (!EIMR && digitalRead(clk) && digitalRead(dt)) {EIFR = 1; // clear any flagEIMSK = 1; // turn on interrupt}For the button it would work the same way - disable the interrupt in the ISR, and re-enable it after the button has been released.Code:ISR(PCINT2_vect) {if (digitalRead(sw) == LOW) {button = true;PCMSK2 &= 0b11101111; // turn off PCINT20(D4)PCIFR = 0b00000100; // clear any flag}}...if (button) {// delay(200);switch (screen) {...}// wait for button to be released and remain high for 100mSunsigned long oldMilli = millis(); // wait for releaseint countdown = 100;while (countdown) {unsigned long newMilli = millis();if (newMilli != oldMilli) {oldMilli = newMilli;countdown--;if (digitalRead(button) == LOW) countdown = 100;}}arrowpos = 0;button = false;PCIFR = 0b00000100; // clear any flagPCMSK2 |= 0b00010000; // turn on PCINT20(D4)}I don't have your libraries so I don't have any way to test these change. But hopefully they will work better. If you really get interrupts just touching the encoder, you should check your wiring, and you could even have a flaky encoder. I haven't looked at what your code does in response to a button press or encoder turn, so I don't have any comments about that.

author: chris_leyson
author_rank: Super Contributor
timestamp: December 31, 2020, 02:53:08 pm
content: QuoteReading rotary encoder on Arduino by Oleg Mazurovhttps://chome.nerpa.tech/mcu/reading-rotary-encoder-on-arduino/

author: m3vuv
author_rank: Super Contributor
timestamp: December 31, 2020, 03:02:14 pm
content: i dont know if your all missing this but it is going crazy at the startup menue only,as soon as an option is selected it works as expected,as i say its on the startup options menue that it goes nuts on,its as if the encoder is being turned when its stationary,its like the wires to it are picking up noise and causing false triggering.

author: PaulAm
author_rank: Frequent Contributor
timestamp: December 31, 2020, 04:51:02 pm
content: You'd think encoder software would be pretty cut and dried by now, but a lot of the code floating around is complete garbage.I had a project the other year and I went through a lot of libraries trying to find something that worked reliably. I likely spent more time doing that than if I had just written it myself. Just garbage, missed transitions, phantom pulses, you name it.Here's a library that actually worked:https://github.com/thomasfredericks/Bounce2The hardware is trivial. If you think you're getting noise or random transitions because of the hardware, look for a wiring error somewhere. There is more likely a software error that is not at all obvious. And if you're trying to track down a software error on a particular piece of hardware, don't use the entire program. Build a small test program by using a subset of your code that expresses the error and then fix that. If you can't do that, then there might be an interaction with some other part of your program. Keep adding back code until it breaks.Edit: Also don't discount the possibility of a bad encoder. Put it on a scope and verify the output. I haven't run into a bad one, but these things are dirt cheap and there's always a possibility.

author: Peabody
author_rank: Super Contributor
timestamp: December 31, 2020, 06:25:49 pm
content: Quote from: m3vuv on December 31, 2020, 03:02:14 pmDoes this happen if the encoder is disconnected from the circuit?

author: Datman
author_rank: Regular Contributor
timestamp: December 31, 2020, 07:05:32 pm
content: Don't use float variables if they are not needed!- They are huge- Floating point calculations are slower- Floating point calculations are not accurate: 2+2 could be a bit different than 4, i.e. 3.99999999, then if (2+2 == 4) would be false!