Rotary encoder strange behaviour

Hi,

I have problem with results (on serial monitor) of rotary encoder.

I am using Arduino UNO and RotaryEncoder library.
When I am running example code serial monitor show proper values when rotating with any speed.
I want to use encoder to change volume in Df-player.
Problem starts when I want to use this code together with more complicated one - Mp3 player.
It actually works only when I am rotating encoder very very slowly

#include <SPI.h>
#include <MFRC522.h>
#include <Arduino.h>
#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>
#include <RotaryEncoder.h>

#define RST_PIN         9           // Configurable, see typical pin layout above
#define SS_PIN          10          // Configurable, see typical pin layout above

#define PIN_IN1 2
#define PIN_IN2 3

#define ROTARYSTEPS 1
#define ROTARYMIN 0
#define ROTARYMAX 30

const int playPauseButton = 4;
const int shuffleButton = 5;

boolean isPlaying = false;

MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance

SoftwareSerial mySoftwareSerial(5, 6); // RX, TX

DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);

// Setup a RotaryEncoder with 2 steps per latch for the 2 signal input pins:
RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);

// Last known rotary position.
int lastPos = -1;

//*****************************************************************************************//
void setup() {
  Serial.begin(9600);                                           // Initialize serial communications with the PC, COMMENT OUT IF IT FAILS TO PLAY WHEN DISCONNECTED FROM PC
  mySoftwareSerial.begin(9600);
  SPI.begin();                                                  // Init SPI bus
  mfrc522.PCD_Init();                                              // Init MFRC522 card

  while (! Serial);
  encoder.setPosition(5 / ROTARYSTEPS); // start with the value of 5.

  pinMode(playPauseButton, INPUT_PULLUP);
  pinMode(shuffleButton, INPUT_PULLUP);




  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));

  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
  }
  Serial.println(F("DFPlayer Mini online. Place card on reader to play a spesific song"));

  //myDFPlayer.volume(15);  //Set volume value. From 0 to 30 
  //volumeLevel = map(analogRead(volumePot), 0, 1023, 0, 30);   //scale the pot value and volume level
  myDFPlayer.volume(5);
  //prevVolume = volumeLevel;

  //----Set different EQ----
  myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
  //  myDFPlayer.EQ(DFPLAYER_EQ_POP);
  //  myDFPlayer.EQ(DFPLAYER_EQ_ROCK);
  //  myDFPlayer.EQ(DFPLAYER_EQ_JAZZ);
  //  myDFPlayer.EQ(DFPLAYER_EQ_CLASSIC);
  //  myDFPlayer.EQ(DFPLAYER_EQ_BASS);

}



//*****************************************************************************************//
void loop() {
  encoder.tick();

  // get the current physical position and calc the logical position
  int newPos = encoder.getPosition() * ROTARYSTEPS;
  
  if (newPos < ROTARYMIN) {
    encoder.setPosition(ROTARYMIN / ROTARYSTEPS);
    newPos = ROTARYMIN;

  } else if (newPos > ROTARYMAX) {
    encoder.setPosition(ROTARYMAX / ROTARYSTEPS);
    newPos = ROTARYMAX;
  } // if

  if (lastPos != newPos) {
    Serial.println(newPos);
    myDFPlayer.volume(newPos);
    lastPos = newPos;
  } // if


  // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
  MFRC522::MIFARE_Key key;
  for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;

  //some variables we need
  byte block;
  byte len;
  MFRC522::StatusCode status;



  if (digitalRead(playPauseButton) == LOW) {
    if (isPlaying) {
      myDFPlayer.pause();
      isPlaying = false;
      Serial.println("Paused..");
    }
    else {
      isPlaying = true;
      myDFPlayer.start();
      Serial.println("Playing..");
    }
    delay(500);
  }


  if (digitalRead(shuffleButton) == LOW) {
    myDFPlayer.randomAll();
    Serial.println("Shuffle Play");
    isPlaying = true;
    delay(1000);
  }


  //-------------------------------------------

  // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
  if ( mfrc522.PICC_IsNewCardPresent()) {



    // Select one of the cards
    if ( ! mfrc522.PICC_ReadCardSerial()) {
      return;
    }

    Serial.println(F("**Card Detected:**"));

    //-------------------------------------------

    mfrc522.PICC_DumpDetailsToSerial(&(mfrc522.uid)); //dump some details about the card

    //mfrc522.PICC_DumpToSerial(&(mfrc522.uid));      //uncomment this to see all blocks in hex

    //-------------------------------------------

    Serial.print(F("Number: "));


    //---------------------------------------- GET NUMBER AND PLAY THE SONG

    byte buffer2[18];
    block = 1;
    len = 18;

    status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 1, &key, &(mfrc522.uid)); //line 834
    if (status != MFRC522::STATUS_OK) {
      Serial.print(F("Authentication failed: "));
      Serial.println(mfrc522.GetStatusCodeName(status));
      return;
    }

    status = mfrc522.MIFARE_Read(block, buffer2, &len);
    if (status != MFRC522::STATUS_OK) {
      Serial.print(F("Reading failed: "));
      Serial.println(mfrc522.GetStatusCodeName(status));
      return;
    }


    //PRINT NUMBER
    String number = "";

    for (uint8_t i = 0; i < 16; i++)
    {
      number += (char)buffer2[i];
    }
    number.trim();
    Serial.print(number);

    //PLAY SONG

    myDFPlayer.play(number.toInt());
    isPlaying = true;



    //----------------------------------------

    Serial.println(F("\n**End Reading**\n"));

    delay(1000); //change value if you want to read cards faster

    mfrc522.PICC_HaltA();
    mfrc522.PCD_StopCrypto1();
  }
}

Please help :slight_smile:

You have delay()s in your code - lose them if you want your encoder to remain active
continuously.

Perhaps some of the other calls are blocking, or taking significantly long to run?

Try cutting your delay times in half and if you get some improvement you are on the track. Set them back to the original settings and eliminate them one by one. The Arduino delay() function locks the Arduino for the duration of the delay and blocks your code from running until it is finished.

gilshultz:
Try cutting your delay times in half and if you get some improvement you are on the track. Set them back to the original settings and eliminate them one by one. The Arduino delay() function locks the Arduino for the duration of the delay and blocks your code from running until it is finished.

I did cut all delay's and still the same situation :confused: even removing them didn't helped.

I would like to know how much time is spent in loop(). Please add this piece of code into the beginning of loop():

void loop() {
  static unsigned long prevMillis;
  Serial.println(millis() - prevMillis);
  prevMillis = millis();

  ... etc. (your original code)

Let us know what you see on the serial monitor!

You are doing way too much and in the wrong place.

For example you don’t need to do this bit every time round the loop:-

// Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
  MFRC522::MIFARE_Key key;
  for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;

  //some variables we need
  byte block;
  byte len;
  MFRC522::StatusCode status;

Stuff like this needs to be done once only so do it in the setup function, and those byte definitions should be outside any function so they are global variables.

// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
  if ( mfrc522.PICC_IsNewCardPresent()) {



    // Select one of the cards
    if ( ! mfrc522.PICC_ReadCardSerial()) {
      return;
    }

    Serial.println(F("**Card Detected:**"));

Really every time round the loop.
Remove all delays - you said it didn’t make any difference so why have them. It actually does though.
Remove all print statements, printing takes time and you do not have it.

Basically you are spending too long between calls to encoder.tick() so try and think about what your code is doing. Break things up into functions, do you have to check for a new card as often as an encoder change - well no every second or two is enough.

Software serial is also slow and eats time, try and use an Arduino with a spare serial port, like a Micro, mega or Leonardo.

Be aware of how often you need to do things and only do them as often as you need.

P.S. It is universally true here that if someone mentions “strange behavior” the behavior turns out to be exactly as expected.

Erik_Baas:
I would like to know how much time is spent in loop(). Please add this piece of code into the beginning of loop():

void loop() {

static unsigned long prevMillis;
  Serial.println(millis() - prevMillis);
  prevMillis = millis();

... etc. (your original code)



Let us know what you see on the serial monitor!

it shows 42 all the time

if ( mfrc522.PICC_IsNewCardPresent()) - is not fired at all as I am not testing card right now as I would like to make encoder work first so it not causing any delay - when I remove this whole mfrc522 related code encoder is starting to work

it seems that both encoder and mfrc522 libraries wont work together

mmacin:
it seems that both encoder and mfrc522 libraries wont work together

Have you fixed your bloated loop() function as advised in Reply #5?

Assuming you’re not using Pins 2 & 3 on the Uno, you could also move to an interrupt-based encoder library.

Or you could move these lines to a new function:

  encoder.tick();

  // get the current physical position and calc the logical position
  int newPos = encoder.getPosition() * ROTARYSTEPS;
 
  if (newPos < ROTARYMIN) {
    encoder.setPosition(ROTARYMIN / ROTARYSTEPS);
    newPos = ROTARYMIN;

  } else if (newPos > ROTARYMAX) {
    encoder.setPosition(ROTARYMAX / ROTARYSTEPS);
    newPos = ROTARYMAX;
  } // if

  if (lastPos != newPos) {
    Serial.println(newPos);
    myDFPlayer.volume(newPos);
    lastPos = newPos;
  } // if

and call that function more than once from loop(). I think that when the encoder is checked more often during your (rather time-consuming) loop(), you will be able to rotate it faster.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.