Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 7 of 7

Thread: Encoders ( Yet Again )

  1. #1
    Junior Member
    Join Date
    Nov 2019
    Location
    Johnson City TN
    Posts
    10

    Encoders ( Yet Again )

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

  2. #2
    Senior Member
    Join Date
    Feb 2016
    Location
    Australia
    Posts
    231
    Put your usb stuff inside your if(enc1.available()) block. Your holding up your interrupts potentually missing encoder pulses where you have it now.

  3. #3
    Junior Member
    Join Date
    Nov 2019
    Location
    Johnson City TN
    Posts
    10
    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

  4. #4
    Junior Member
    Join Date
    Nov 2019
    Location
    Nizhny Novgorod, Russia
    Posts
    10
    BTW, at least in Teensy4 there is hardware encoders support, with debouncing and automatic step count.
    Did someone try to use it?

  5. #5
    Junior Member
    Join Date
    Nov 2019
    Location
    Johnson City TN
    Posts
    10
    Hi Vadim,

    Thanks for the info. Thats very good to know ... Although I do believe we're waiting on USB_MIDI for the Teensy 4?

  6. #6
    Senior Member
    Join Date
    Feb 2016
    Location
    Australia
    Posts
    231
    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();
      }

  7. #7
    Junior Member
    Join Date
    Nov 2019
    Location
    Johnson City TN
    Posts
    10
    Thanks Gibbedy !!! ... I'll try and recreate the Inc/Dec behavior inside enc1.available block with your suggestions

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •