0
\$\begingroup\$

I'm trying to interface a rotary encoder with my pic18f4550. Just trying to get it to increase/decrease the variable output and then display that value through the LATD pins.

The code does not seem to be working at all, and was just wondering if I could get some help from you guys as to where I'm going wrong.

#include <xc.h>
#include "config.h"
#define _XTAL_FREQ 8000000
unsigned int output;
void main(void)
{
 OSCCON = 0b01110010; // Oscillator setup
 TRISB = 0b00110000; //Set RB4 & RB5 as input
 TRISD = 0x00; //All D pins set as output
 //Port B interrupts
 INTCONbits.RBIE = 1; //Enable port B interrupts; interrupt flag is not cleared so interrupt is triggered instantly, allowing us to record initial value
 INTCONbits.GIE = 1; //Enable general interrupts
 //Port B pull-ups
 INTCON2bits.RBPU = 0;
 while(1)
 {
 if(INTCONbits.RBIF==1)
 {
 static unsigned char prevState = 0xFF;
 unsigned char state = (PORTBbits.RB4 | PORTBbits.RB5 << 1); //Get value 0-3 from rotary encoder bits
 if(prevState != 0xFF)//If this is not the first time we enter the interrupt, process the gray codes
 {
 if(((prevState == 0b00) && (state == 0b01)) //Turn counterclockwise
 || ((prevState == 0b01) && (state == 0b11))
 || ((prevState == 0b11) && (state == 0b10)) 
 || ((prevState == 0b10) && (state == 0b00))) 
 {
 output--;
 }
 else if(((prevState == 0b00) && (state == 0b10)) //Turn clockwise
 || ((prevState == 0b10 && state == 0b11))
 || ((prevState == 0b11 && state == 0b01)) 
 || ((prevState == 0b01 && state == 0b00))) 
 { 
 output++;
 }
 }
 prevState = state; //Save previous port b state.
 INTCONbits.RBIF=0; //Clear port B interrupts flag
 }
 LATD = output; //Display value on LED's on D pins
 }
 }
asked Apr 30, 2020 at 15:18
\$\endgroup\$
3
  • 3
    \$\begingroup\$ So you enable interrupts, but you have no interrupt handler? \$\endgroup\$ Commented Apr 30, 2020 at 15:33
  • 1
    \$\begingroup\$ your code in unnecessarily complex .... just monitor one encoder data pin ... when it changes state, check the other encoder data pin .... the state of the second pin is directly related to the direction the encoder is moving \$\endgroup\$ Commented Apr 30, 2020 at 15:59
  • \$\begingroup\$ @jsotola thanks for your help mate, you helped me figure it out. \$\endgroup\$ Commented May 1, 2020 at 11:31

2 Answers 2

2
\$\begingroup\$

Your code looks complex.

If the encoder frequency is not too high it's just a matter of keeping track of the count using an up-down counter and two general purpose input pins.

schematic

simulate this circuit – Schematic created using CircuitLab

Figure 1. 2-bit rotary encoder waveforms.

The program logic is very simple.

  • Track the current state of 'A'. If the state changes to 'high' then:
  • Look at input 'B'. If 'B' is low then count up. If 'B' is high then count down.
  • Update the 'lastState' of 'A'.

Pseudo code

void loop(){
 if(A && not prevA){
 if(B){
 cnt--;
 } else {
 cnt++;
 }
 } else {
 prevA = A;
}

You'll probably need to debounce the inputs to prevent spurious triggering.

answered May 1, 2020 at 12:17
\$\endgroup\$
3
  • \$\begingroup\$ I followed a similar vibe with my answer. I added a delay, then it waits before the switch is clicked, then it flips the edge triggering mode of the interrupt and clears the flags. What do you think? \$\endgroup\$ Commented May 2, 2020 at 0:19
  • \$\begingroup\$ With the lack of comments following the variable names in your code is hard work so I don't know what's going on. I don't see any interrupt disable inside the routine so I suspect that it could get retriggered while it's running. I also see delays inside the routine which means the controller can't do anything else while these are running - generally a bad thing. (I haven't done any PIC coding for 15 years and I was an amateur.) \$\endgroup\$ Commented May 2, 2020 at 8:33
  • \$\begingroup\$ I’ve totally revised my solution. Just decided to go with hardware for debouncing to keep things simpler in the code, and added comments. Works like a treat, thanks again! \$\endgroup\$ Commented May 4, 2020 at 1:39
0
\$\begingroup\$

Here's my solution.

Encoder is plugged into RB1 & RB2.

It works by looking at which interrupt flag was triggered first and using that to decide on the direction. Once direction is calculated, it flips the edge trigger bit from rising/falling to the opposite so the encoder can continue rotating the same way and continue adding/subtracting numbers.

I decided to go for the RC filter approach (0.22uf & 22kOhm) for debouncing for simplicity and to save CPU.

Hope this helps everyone.

#include <xc.h>
#include "config.h"
#define _XTAL_FREQ 8000000
unsigned int count;
void main(void)
{ 
 OSCCON = 0b01110010; // Internal Oscillator setup
 TRISB = 0b00000110; // Set RB1 & RB2 as input
 TRISD = 0x00; // Set all D pins as outputs
 RCONbits.IPEN = 1; // Enable interrupt priority levels
 INTCON = 0b10000000; // Interrupt setup
 INTCON2 = 0b10000000; // Interrupt setup
 INTCON3 = 0b11011000; // Interrupt setup
 while(1)
 {
 LATD = count; // Display count as binary through D pins
 }
}
void __interrupt() rotaryISR(void) // ISR executed once rotary encoder is twisted
{
 if (INTCON3bits.INT1IF > INTCON3bits.INT2IF) // If RB1 interrupt flag gets raised before RB2
 {
 count++; // Increase count value
 INTCON2bits.INTEDG1 = ~INTCON2bits.INTEDG1; // Flip RB1 and RB2 trigger edges
 INTCON2bits.INTEDG2 = ~INTCON2bits.INTEDG2; //
 INTCON3bits.INT1IF = 0; // Clear interrupt flags
 INTCON3bits.INT2IF = 0; //
 }
 if (INTCON3bits.INT2IF > INTCON3bits.INT1IF) // If RB2 interrupt flag gets raised before RB1
 {
 count--; // Decrease count value
 INTCON2bits.INTEDG1 = ~INTCON2bits.INTEDG1; // Flip RB1 and RB2 trigger edges
 INTCON2bits.INTEDG2 = ~INTCON2bits.INTEDG2; //
 INTCON3bits.INT1IF = 0; // Clear interrupt flags
 INTCON3bits.INT2IF = 0; //
 }
 else 
 {}
}
answered May 1, 2020 at 12:00
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.