[sdiy] Need goog working rotary encoder in C code..

Jean-Pierre Desrochers jpdesroc at oricom.ca
Fri Aug 6 21:35:19 CEST 2021


Here is what I’m trying so far..

 

void __interrupt() TMR1_isr (void) 

 {

  // Rotary encoder pin interrupts setup

  if(IOCBF0) // negative edge detected on RB0 (encoder A)

  { 

   TMR1IE = 0; // disable TMR1 interrupt

   encoder_in_transition = TRUE;

   manage_encoder_change(0); // 0 = encoder pin A   

   IOCBF0 = 0; // clear RB0 flag 

   //TMR1IE = 1; // enable TMR1 interrupt

  }    

      

  if(IOCBF1) // negative edge detected on RB1 (encoder B)

  { 

   TMR1IE = 0; // disable TMR1 interrupt

   encoder_in_transition = TRUE;

   manage_encoder_change(1); // 1 = encoder pin B  

   IOCBF1 = 0; // clear RB0 flag 

   //TMR1IE = 1; // enable TMR1 interrupt

  }  

  

  if(IOCBF2) // negative edge detected on RB2 (encoder SW)

  { 

   TMR1IE = 0; // disable TMR1 interrupt

   encoder_in_transition = TRUE;

   manage_encoder_change(2); // 2 = encoder pin SW  

   IOCBF2 = 0; // clear RB1 flag 

   TMR1IE = 1; // enable TMR1 interrupt  

  }

  TMR1IF = 0; // clears TMR1 interrupt flag 

 }

 

//// Functions definitions ////////////////

 

///////////////////////////////////////////////

void manage_encoder_change(unsigned char rotary_direction)

{ 

  IOCIE = 0; // disable PORTx changes interrupt temporarily

    

 if(rotary_direction == 0) // encoder 'A' pin falling edge detected so CW

  {

     while((ROTARY_A != 0) && (ROTARY_B != 0)); // while in pulses first step

     while((ROTARY_A != 1) && (ROTARY_B != 0)); // while in pulses second step     

     while((ROTARY_A != 1) && (ROTARY_B != 1)); // while in pulses third step 

     __delay_ms(1); // debounce

     

    if(SCALE_TRANSPOSE_SELECT == 0) // scale-transpose switch to 'scale' position

     { if(scale_counter < MAX_SCALE_NUMBER_VALUE) scale_counter++; }

      

    else // scale-transpose switch to 'transpose' position

       if(transpose_counter < MAX_TRANSPOSE_NUMBER_VALUE) transpose_counter++;  

  }       

    

  if(rotary_direction == 1) // encoder 'B' pin falling edge detected so CCW

  {

     while((ROTARY_A != 0) && (ROTARY_B != 0)); // while in pulses first step

     while((ROTARY_A != 0) && (ROTARY_B != 1)); // while in pulses second step     

     while((ROTARY_A != 1) && (ROTARY_B != 1)); // while in pulses third step 

     __delay_ms(1); // debounce

     

    if(SCALE_TRANSPOSE_SELECT == 0) // scale-transpose switch to 'scale' position

     { if(scale_counter > 0) scale_counter--; }

      

    else // scale-transpose switch to 'transpose' position

       if(transpose_counter > 0) transpose_counter--;  

 

  } 

        

  IOCBF0 = 0; // clear the interrupt flag RB0 (encoder A)

  IOCBF1 = 0; // clear the interrupt flag RB1 (encoder B)

  IOCBF2 = 0; // clear the interrupt flag RB2 (encoder SW)

  IOCIE = 1; // re-enable PORTx changes interrupt 

 

}

 

De : Synth-diy [mailto:synth-diy-bounces at synth-diy.org] De la part de Tom Wiltshire
Envoyé : 6 août 2021 15:22
À : John Speth
Cc : synth-diy at synth-diy.org
Objet : Re: [sdiy] Need goog working rotary encoder in C code..

 

+1 agree with these points.

 

Use polling, and make sure you can easily adjust the rate you check the inputs in case you need to slow it down. I used a loop of 2msecs, I think, and the software debounce required 4 stable reads to consider an input changed (so 8msecs in the same state). These numbers depend on the type of encoder used, and you should probably go as *slow* as you dare. Going faster is tempting as it “makes it more responsive” but at some point the bouncing will get worse, and then your code will no longer cope. Either test with half-dead, heavily-worn encoders, or work to a worse-case scenario!

The code should detect each input change, which is to say, on the encoders I used there are four changes between each detent. Keeping track of the changes allows both direction detection and some degree of error correction.

 

Interrupt based code is just going to throw a lot of unnecessary interrupts every time the input bounces, unless it’s all debounced in the hardware…in which case, what’s the software for?!?

 

My favourite debounce routine is a vertical counter debounce since it can do eight inputs in a single pass (or 16 on a word-based processor).

 

 





On 6 Aug 2021, at 19:05, John Speth via Synth-diy <synth-diy at synth-diy.org> wrote:

 

I have substantial experience with the application but not in a musical context. My extensive trials and errors has convinced me of the following:

 

1. You'll need to know when inputs change state, not just when the signals go low. Consider rising and falling edge interrupts on both inputs. You can detect rotation direction using this strategy.

 

2. There WILL be bouncing so plan for it. Contact type switches will bounce more than optical switches. Contact type switches will degrade over time.

 

3. Interrupts vs polling: Interrupts are great but they have a hidden hazard in that they can flood and overwhelm some MCUs (YMMV of course). A capacitor can help alleviate the problem but it's better to find a non-cap solution. I've found polling is better. I use a digital integration method (*) and a fast polling interval. That works so well, I automatically go to that design solution for most applications.

 

* --- A digital integration method uses a counter that counts up and down and outputs a state change signal when a count threshold is reached. Increment the counter while the input is high and decrement the counter when the input is low. Reset the count when the output state changes. Adjust the polling interval for speed and accuracy. As a frame of reference, I use a 5 msec polling interval for keyboard debouncing. You'll probably want a faster interval if your encoder can be turned fast. I'll warn you that there can be a surprisingly large number of lines of code for such a simple task like digital debouncing.

 

JJS

 

On 8/6/2021 8:46 AM, Jean-Pierre Desrochers wrote:

Hi everybody.

 

I’m doing some tests on a rotary encoder and a PIC16F1783.

A standard Bourns encoder like  <https://www.google.ca/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&ved=2ahUKEwjyoqDF3JzyAhUmhOAKHf3lAzoQFnoECAoQAw&url=https%3A%2F%2Fwww.bourns.com%2FPDFs%2Fpec11l.pdf&usg=AOvVaw2RyieyzPnujiOTS7LBcbpw> THIS .

Connected using 2 x 10k pullups with 0.01uf caps to ground

to PORTB of the micro. Interrupt calls (falling edges) used on encoder pins A & B.

I struggled so far to get clean increments/decrements out of it.

Many missing counts occur..

I tried many source codes on the web with no luck..

Is there anybody who’d have worked on this in the past
and have a working c code ?

No ARDIUNO please.

Thanks !

 

_______________________________________________
Synth-diy mailing list
Synth-diy at synth-diy.org
http://synth-diy.org/mailman/listinfo/synth-diy
Selling or trading? Use marketplace at synth-diy.org

 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://synth-diy.org/pipermail/synth-diy/attachments/20210806/56b17e70/attachment.htm>


More information about the Synth-diy mailing list