Encoders ( Yet Again )

Status
Not open for further replies.

digitalelements

Active member
Greetings !

After several days of research, Some trial and error, I've landed on using the Encoder Template written by Theremingenieur. It really does clean things up quite a bit when using not so great encoders. I dove straight into trying to add code to send USB MIDI messages. I've been successful in getting the behavior I'm looking for but fear the location of the code I added is just not the best place. Especially If I add some additional buttons to this sketch.
I'm a noob/begginer So please go easy on me ... any guidance and or suggestions would be greatly appreciated and a learning experience.


Kind Regards,


Chris

Code:
// Encoder MIDI PGC Inc Dec


#include <Bounce.h>

const int channel = 1;
byte pgcNum = 0;



template<uint8_t pinA, uint8_t pinB>
class rotKnob {
public:
  void begin(int8_t startVal, int8_t lowBound, int8_t hiBound) {
    d._sValue = startVal;
    d._lBound = lowBound;
    d._hBound = hiBound;
    d._aConf = digital_pin_to_info_PGM[(pinA)].config;
    d._bConf = digital_pin_to_info_PGM[(pinB)].config;
    pinMode(pinA, INPUT_PULLUP);
    pinMode(pinB, INPUT_PULLUP);
    delay(1);
    d._aVal = digitalReadFast(pinA);
    d._bVal = digitalReadFast(pinB);
    attachInterrupt(pinA, intPinA, CHANGE);
    attachInterrupt(pinB, intPinB, CHANGE);
  }
  void begin(int8_t startVal) {
    begin(startVal, 0, 127);
  }
  void begin() {
    begin(0, 0, 127);
  }
  void end() {
    detachInterrupt(pinA);
    detachInterrupt(pinB);
  }
  int8_t read() {
    d._avail = false;
    return d._sValue;
  }
  bool available() {
    return d._avail;
  }
private:
  struct objData {
    volatile uint32_t* _aConf, *_bConf;
    volatile int8_t _lBound, _hBound, _sValue;
    volatile bool _aVal, _bVal, _avail;
  };
  static objData d;
  static void intPinA() {
    *d._aConf &= ~0x000F0000; // disable pin A interrupts
                // decoding logic
    if (!d._aVal) {
      if ((d._sValue < d._hBound) && !d._bVal) {
        d._sValue++;
        d._avail = true;
        pgcNum++;
    usbMIDI.sendProgramChange(pgcNum,channel);
      }
      if ((d._sValue > d._lBound) && d._bVal) {
        d._sValue--;
        d._avail = true;
        pgcNum--;
    usbMIDI.sendProgramChange(pgcNum,channel);
      }
    }
    d._bVal = digitalReadFast(pinB); // read pinB which is stable after pinA transition
    *d._bConf |= 0x000B0000; // (re-) enable pinB interrupts
  }
  static void intPinB() {
    *d._bConf &= ~0x000F0000; // disable pinB interrupts
    d._aVal = digitalReadFast(pinA); // read pinA which is stable after pinB transition
    *d._aConf |= 0x000B0000; // (re-) enable pinA interrupts
  }
};
template<uint8_t pinA, uint8_t pinB>
typename rotKnob<pinA, pinB>::objData rotKnob<pinA, pinB>::d;

/* Describe your hardware connections, pins and knobs */
rotKnob<9, 10> enc1;


void setup() {
  Serial.begin(57600);
  while (!Serial)
    ;
  delay(5);
  pinMode(LED_BUILTIN, OUTPUT);
  /* Configure your encoders */
  enc1.begin();
          
}

void loop() {
  if (enc1.available()) {
    Serial.print("Encoder 1: ");
    Serial.println(enc1.read());
    
  }
  

  
  }
 
Put your usb stuff inside your if(enc1.available()) block. Your holding up your interrupts potentually missing encoder pulses where you have it now.
 
Thanks so much for the reply Gibbedy I really don't want to miss any pulses if I can help it..... The only reason I placed my USB stuff there !! (aside from being a beginner with code) was it seemed to me that it was the only place I had that could differentiate the encoder direction for the ++ or -- behavior.?

SO... your suggestion ( so I understand) is to relocate the USB stuff to inside the enc1.available block ?


Thanks !


btw ... Love Australia SO much .. I married an Aussie :)
 
Yep thats what I'm saying.
Below you will be doing your midi thing if the encoder value changes but that could be up or down.

Code:
void loop() {
  if (enc1.available()) {
    Serial.print("Encoder 1: ");
    Serial.println(enc1.read());
    usbMIDI.sendProgramChange(pgcNum,channel);  
  }

If you planned on doing something that needs to know the direction of the encoder you would have to find out that information.
You could modify the "rotKnob" class to set a flag and read that or do it in your own part of the code. I'll try todo this below:


Code:
int8_t lastEncoderValue=0;
void loop() {
  if (enc1.available()) {
    Serial.print("Encoder 1: ");
    Serial.println(enc1.read());
    if(enc1.read()>lastEncoderValue)
    {
      usbMIDI.sendProgramChange(pgcNum,channel);  
      mySpecialGoinUpStuff();
    }
    else
    {
       usbMIDI.sendProgramChange(pgcNum,channel);  
       mySpecialGoinDownStuff();
    }
    
    lastEncoderValue=enc1.read();
  }
 
Status
Not open for further replies.
Back
Top