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

Thread: Rotary Encoder and Interrupts

  1. #1
    Junior Member
    Join Date
    Mar 2019
    Location
    Germany
    Posts
    18

    Rotary Encoder and Interrupts

    Hi,

    I got a rotary encoder working, but only by polling (like the example in the tutorial).
    Can I use the encoder lib with interrupts? Or is there a data lost of the first bit of grey code?

    Thanks for help!

  2. #2
    Senior Member
    Join Date
    Apr 2013
    Posts
    1,874
    Which tutorial are you following?

    For all current generation Teensy most/all the pins will default to interrupt operation
    https://www.pjrc.com/teensy/td_libs_Encoder.html
    If you are seeing more than one step per click for a basic knob encoder most likely cause is the number of steps on the encoder wheel not match the detents on the shaft.

  3. #3
    Junior Member
    Join Date
    Mar 2019
    Location
    Germany
    Posts
    18
    Hi GremlinRrangler,

    Yesterday I was tired and I forgot the code samples

    that's the exact tutorial which I followed.

    Code:
    /* USB MIDI AnalogControlChange Example
    
       You must select MIDI from the "Tools > USB Type" menu
       http://www.pjrc.com/teensy/td_midi.html
    
       This example code is in the public domain.
    */
    #include <Encoder.h>
    #include <Bounce.h>
    
    // the MIDI channel number to send messages
    const int channel = 1;
    
    // the MIDI continuous controller for each analog input
    Encoder myEnc(0, 1);
    
    const int controller0 = 21; // 10 = pan position
    float multi = 4; // 0.5 = 16 steps; 1 = 32 steps; 2 = 64 steps; 4 = 127 steps; 8 = 256 steps (2 steps for one increase)
    
    void setup() {
      pinMode(13, OUTPUT);
      digitalWrite(13, HIGH);
    }
    
    // store previously sent values, to detect change
    long previous0 = -1;
    long sent0 = -1;
    
    elapsedMillis msec = 0;
    
    void loop() {
      long raw = myEnc.read();
      if (raw % 4 == 0) {
        long n0 = raw/multi;
        if (n0 > 127) {
          myEnc.write(127*multi);
          n0 = 127;
        }
        if (n0 < 0) {
          myEnc.write(0);
          n0 = 0;
        }
        if (n0 != previous0) {
          previous0 = n0;
        }
        // only check the analog inputs 50 times per second,
        // to prevent a flood of MIDI messages
        if (sent0 != previous0) {
          if (msec >= 20) {
            msec = 0;    
            // only transmit MIDI messages if analog input changed
            usbMIDI.sendControlChange(controller0, n0, channel);
            sent0 = previous0;
          }
        }
        // MIDI Controllers should discard incoming MIDI messages.
        // http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash
        while (usbMIDI.read()) {
          // ignore incoming messages
        }
      }
    }
    This is the code I wrote. It works fine but If I want to use some more rotary encoders I need interrupts. I was trying it with this code:

    Code:
    #define ENCODER_OPTIMIZE_INTERRUPTS
    #include <Encoder.h>
    #include <Bounce.h>
    
    // the MIDI channel number to send messages
    const int channel = 1;
    const int controller0 = 21; // 10 = pan position
    
    // Encoder
    Encoder myEnc(0, 1);
    
    // store current, previously read values and previously sent values, to detect change
    long n0 = 0;
    long previous0 = -1;
    long sent0 = -1;
    
    // MIDI overflow variable
    elapsedMillis msec = 0;
    
    // steps to MIDI value 127
    float multi = 4; // 0.5 = 16 steps; 1 = 32 steps; 2 = 64 steps; 4 = 127 steps; 8 = 256 steps (2 steps for one increase)
    
    void interrupt_rutine() {
      long raw = myEnc.read();
      if (raw % 4 == 0) {
        n0 = raw/multi;
        if (n0 > 127) {
          myEnc.write(127*multi);
          n0 = 127;
        }
        if (n0 < 0) {
          myEnc.write(0);
          n0 = 0;
        }
        if (n0 != previous0) {
          previous0 = n0;
        }
      }
    }
    
    void setup() {
      // to check teensy has power
      pinMode(13, OUTPUT);
      digitalWrite(13, HIGH);
      // interrupts
      attachInterrupt(digitalPinToInterrupt(0), interrupt_rutine, CHANGE);
      attachInterrupt(digitalPinToInterrupt(1), interrupt_rutine, CHANGE);  
    }
    
    void loop() {
        // only transmit MIDI messages if rotary encoder input changed
        if (sent0 != previous0) {
          // only check the analog inputs 50 times per second,
          // to prevent a flood of MIDI messages
          if (msec >= 20) {
            msec = 0;    
            usbMIDI.sendControlChange(controller0, n0, channel);
            sent0 = previous0;
          }
        }
      
        // MIDI Controllers should discard incoming MIDI messages.
        // http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash
        while (usbMIDI.read()) {
          // ignore incoming messages
        }
    
    }
    I got only one event in KMidimon (Midi monitor in Linux). So I guess the encoder lib and interrupt lib need a special configuration.

  4. #4
    Senior Member
    Join Date
    Apr 2013
    Posts
    1,874
    Confirm this is a Teensy LC or 3.2? Below assumes the newer flavours, if you are using a T2 that will change things.

    For midi control type inputs you should be running out of pins before you run out of interupts/performance capacity (since you are only turning them slowly and at most two at a time) So the expected design is you just define inputs and encoders until you are done. You should not need to use encoder_optimize_interrupts unless you are working with a T2, and you should not need to manually attach interupts or write interupt handlers either unless you are planing to fully strip out the encoder library and handle the IO yourself. Doing both on a T3 or LC is going to get interesting results.

    Would suggest reverting to the USB_midi example, and just adding extra encoders there.

    A suggestion as you add encoders would be to add Serial.begin() to your code and each second print the current Raw encoder values and adjusted midi values to the serial port to make it clearer what is going on. Blinking the LED can also be useful as you get more complex wiring.

  5. #5
    Junior Member
    Join Date
    Mar 2019
    Location
    Germany
    Posts
    18
    I using the T3.2.



    But I have the same problem like in this thread: https://forum.pjrc.com/threads/43167...-1-serial-port

    I tried it with the T3.2, T3.5 and T3.6 and I get 2 lines of serial but nothing more. I used many tools and many configurations. Midi works and I made it without the serial.

    You mean there is no need to use interrupts, isn't it?

  6. #6
    Senior Member
    Join Date
    Apr 2013
    Posts
    1,874
    For a T3.2 it should be using interrupts by default without any action from you, as I understand it the code you had was intended for T1/T2 8 bit Teensyies. If you were using the encoders on say a CNC machine you might need to play with the priority level of those interrupts but you do not appear to be turning them at khz pulse rates so just using them as per the example should just work.

    So most likely problem here is something else in the setup/code, especially if Serial is also not firing. Suggest trying the two knobs examples from the encoder page, which will confirm this is actually about the encoders and not the USB midi end of things.
    https://www.pjrc.com/teensy/td_libs_Encoder.html.
    With testing serial did you code to update on the state change or every second? If you had every second and it stops something more catastrophic is going on that hangs the Teensy. To get every second response you could use
    https://www.pjrc.com/teensy/td_timin...pedMillis.html

    and define
    elapsedMillis oneSecondStatusUpdateTimer = 0;
    then put
    Code:
    if (oneSecondStatusUpdateTimer>1000){
       oneSecondStatusUpdateTimer=0;// reset the timer, otherwise will only fire once  
       Serial.println("encoder values are");
       Serial.print(previous0);
       Serial.print(" "); //add a space between numbers
       Serial.print(previous1);
       Serial.println(); //put a line feed at the end of encoder values
    }

  7. #7
    Junior Member
    Join Date
    Mar 2019
    Location
    Germany
    Posts
    18
    I've tried some more simple code on the T3.2, T3.5 and T3.6.
    Code:
    if (oneSecondStatusUpdateTimer>1000){
       oneSecondStatusUpdateTimer=0;// reset the timer, otherwise will only fire once  
       Serial.println("Hello ");
       Serial.print("World!");
       Serial.print(" "); //add a space between numbers
       Serial.print("more Text");
       Serial.println(); //put a line feed at the end of encoder values
       if (led == 1) {
          digitalWrite(13, HIGH);
          led = 0;
       }
       else {
          digitalWrite(13, LOW);
          led = 1;
       }
    }
    The output only prints "Hello" and nothing else. But the LED is blinking every second. I guess this serial problem is a Linux problem.

    After studying the code I undersand what you mean with "For a T3.2 it should be using interrupts by default without any action from you". The myEnc.read() take the value which was written by the interrupt.

    Now everything is clear. Thank you for your help!

  8. #8
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,415
    Quote Originally Posted by Dinera View Post
    The output only prints "Hello" and nothing else. But the LED is blinking every second. I guess this serial problem is a Linux problem.
    (...)
    Now everything is clear. Thank you for your help!
    By surfing around in these forums, you might discover that there are in fact issues with some Linux distributions and serial communication. It's not the Teensy or your code to blame.

  9. #9
    Junior Member
    Join Date
    Mar 2019
    Location
    Germany
    Posts
    18
    Quote Originally Posted by Theremingenieur View Post
    By surfing around in these forums, you might discover that there are in fact issues with some Linux distributions and serial communication. It's not the Teensy or your code to blame.
    I've tried to fix it but after many hours I've accepted that it is not working. In a quiet hour I will take care of the issue

Posting Permissions

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