enjoyneering / RotaryEncoder

This is small and fast Arduino library for Rotary Encoder with interrupts.
77 stars 21 forks source link

ATSAMD21 #6

Closed koogar closed 3 years ago

koogar commented 3 years ago

Hi,

Thanks for you work on the library

I noticed in the Sketch

"This sketch uses interrupts, specials pins are required to interface Board: Zero, ATSAMD21G18........................ all digital pins, except pin 4"

Do you have an example for the ATSAMD21 or is it a work in progress.

Many thanks

Rupert

enjoyneering commented 3 years ago

Hi Rupert,

I don't have Zero (ATSAMD21G18), but I have STM32 which is also ARM Cortex family. It works well on STM32, so I assumed it should work on Zero as well. If you have one, please test and let me know.

koogar commented 3 years ago

Hi ,

Thanks for the reply.

Could I ask how I would change the sketch for CCW and CW actions.

As I intend to use it with a HID library for volume .

Sorry, I tried to muddle through it but I failed

Might be a good example for noobs like me who just want it to do something when turned either direction, rather than one output.

Cheers

Rupert

enjoyneering commented 3 years ago

To get CCW & CW try this workaround

declare new variables int8_t cw_ccw_idle; int16_t encoderPosition;

in the loop


encoderPosition = encoder.getPosition();

if (encoder.getPosition() > encoderPosition)
{
  cw_ccw_idle = 1;  //encoder rotating CW
}
else if (encoder.getPosition() < encoderPosition)
{
  cw_ccw_idle = -1; //encoder rotating CCW
}
else
{
  cw_ccw_idle = 0;  //encoder idle
}

switch (cw_ccw_idle)
{
  case 1: //CW
    volume++;
    break;

  case -1: //CCW
    volume--;
    break;
}
enjoyneering commented 3 years ago

Hi koogar,

Any success?

koogar commented 3 years ago

yes and no :)

Thanks for the reply

On your original example, on the STM32 (Roger Clark's Arduino_STM32 core) and the ATSAMD I had to use RISING and ADD PIN_B to RISING as below to get it to work.

attachInterrupt(digitalPinToInterrupt(BUTTON), encoderButtonISR, FALLING); attachInterrupt(digitalPinToInterrupt(PIN_A) , encoderISR, RISING);
attachInterrupt(digitalPinToInterrupt(PIN_B) , encoderISR, RISING);

"To get CCW & CW try this workaround"

This works but is unreliable on both the STM32 and the ATSAMD. "CCW" is pretty good but "CW" is not good

#include <RotaryEncoder.h>

#define ATSAMD
//#define STM32

#ifdef ATSAMD //(Feather M0 Express /ky-040)
#define PIN_A   16 //ky-040 clk pin, add 100nF/0.1uF capacitors between pin & ground!!!
#define PIN_B   15 //ky-040 dt  pin, add 100nF/0.1uF capacitors between pin & ground!!!
#define BUTTON  14 //ky-040 sw  pin, add 100nF/0.1uF capacitors between pin & ground!!!
#endif

#ifdef STM32 //(BluePill F1 /ky-040)
#define PIN_A   PB8 //ky-040 clk pin, add 100nF/0.1uF capacitors between pin & ground!!!
#define PIN_B   PB9 //ky-040 dt  pin, add 100nF/0.1uF capacitors between pin & ground!!!
#define BUTTON  PB7 //ky-040 sw  pin, add 100nF/0.1uF capacitors between pin & ground!!!
#endif

int16_t position = 0;
int8_t cw_ccw_idle; int16_t encoderPosition;

RotaryEncoder encoder(PIN_A, PIN_B, BUTTON);

void setup()
{
  Serial.begin(115200);
  encoder.begin();                                                           //set encoders pins as input & enable built-in pullup resistors

  //FIX   https://www.stm32duino.com/viewtopic.php?t=365
  attachInterrupt(digitalPinToInterrupt(BUTTON), encoderButtonISR, FALLING); //call pushButtonISR() every high->low              changes
  attachInterrupt(digitalPinToInterrupt(PIN_A),  encoderISR,       RISING);  //call encoderISR()    every low->high change
  attachInterrupt(digitalPinToInterrupt(PIN_B),  encoderISR,       RISING);  //call encoderISR()    every low->high change
}

void loop()
{
  encoderPosition = encoder.getPosition();

  if (encoder.getPosition() > encoderPosition)
  {
    cw_ccw_idle = 1;  //encoder rotating CW
  }
  else if (encoder.getPosition() < encoderPosition)
  {
    cw_ccw_idle = -1; //encoder rotating CCW
  }
  else
  {
    cw_ccw_idle = 0;  //encoder idle
  }

  switch (cw_ccw_idle)
  {
    case 1: //CW
      Serial.println("volume++");
      break;

    case -1: //CCW
      Serial.println("volume--");
      break;
  }

  if (encoder.getPushButton() == true) Serial.println(F("PRESSED"));         //(F()) saves string to flash & keeps dynamic memory free
}

void encoderISR()
{
  encoder.readAB();
}

void encoderButtonISR()
{
  encoder.readPushButton();
}
enjoyneering commented 3 years ago

have you installed 0.1uF capacitors?

koogar commented 3 years ago

yes I have it makes it worse.

enjoyneering commented 3 years ago

I'll try to test it on STM32 today. Thank you.

koogar commented 3 years ago

Cheers

Here is the same problem, just in case you didn't see the link

https://www.stm32duino.com/viewtopic.php?t=365

Thanks

Rupert

enjoyneering commented 3 years ago

Hi Rupert,

Just tested "STM32RotaryEncoderInterruptsLCD.ino" on STM32 Blue Pill, stm32duino framework v1.9.0 - works perfect.

Delete B pin interrupt, return back "CHANGE" for pin A & add debounce capacitors (see picture).

Also added direction example (not tested, may not work)- "STM32RotaryEncoderInterruptsSerialDirection.ino"

Also found that PD13 and PD14 in examples also used by STLink. Disconnect it after programming or use another pins.