Странное поведение поворотного энкодера

У меня проблема с результатами (на последовательном мониторе) поворотного энкодера.

Я использую Arduino UNO и библиотеку RotaryEncoder. Когда я запускаю пример кода, показывать правильное отображение значения при вращении с любой скоростью. Я хочу использовать кодировщик для изменения громкости в Df-плеере. Проблема начинается, когда я хочу использовать этот код вместе с более сложным - MP3-плеером. На самом деле это работает, только когда я очень-очень медленно вращаю энкодер.


#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();
  }
}

Есть идеи, что не так?


person mmacin    schedule 01.03.2021    source источник


Ответы (1)


У вас есть delay(1000) в вашем основном цикле, и поскольку вашему объекту RotaryEncoder, похоже, нужна функция tick(), я предполагаю, что он не управляется прерываниями. Это означает, что он будет проверять только один раз в секунду, перешел ли он к следующему шагу.

Если поворотный энкодер переключается дважды, а средний шаг пропускается микроконтроллером, последний не имеет возможности узнать, в какую сторону повернулся энкодер.

В этом случае вы можете поворачивать его только на один шаг в секунду.

Вам также понадобится:

  • свободный основной цикл, который повторяется не менее 100 раз в секунду. (менее приятно)
  • драйвер энкодера, управляемый прерыванием. (очень хорошо)

Я не знаю, существует ли такая библиотека, потому что я обычно не использую библиотеки arduino, но это очень хорошее упражнение для написания собственной с использованием прерываний GPIO.

person David van rijn    schedule 01.03.2021
comment
Спасибо за ответ! Я удалил все задержки и ничего не изменилось: / - person mmacin; 03.03.2021
comment
Что ж, попробуйте переключить светодиод рядом с encoder.tick. Таким образом, вы уверены, что оно выполняется достаточно часто. Это должно быть (почти) слишком быстро, чтобы увидеть мигание. ›50 Гц Так что это похоже на половинную мощность. - person David van rijn; 03.03.2021