3 Simple Ways to
Share What You Make

With Instructables you can share what you make with the world — and tap into an ever-growing community of creative experts.

PhotosPhotos

Share one or more photos of a project, recipe, or whatever you've made, quickly and easily.

Step by StepStep-By-Step

Share your step-by-step photos with text instructions of what you made so others can do it too!

VideoVideo

Share your how-to video. You'll need your embed code from a video site such as YouTube.

How to interpret the direction of rotation from a digital rotary switch with a PIC

Step 5Software

Software
«
  • ISR Graphic.jpg
  • Interrupt Handler Set Up Table.jpg
I did not use the built in interrupts in PIC Basic Pro. I used a couple of files that I included in my code from Darrel Taylor to drive the routine. This is where a huge credit to Darrel belongs! The files are free. Just visit his website for more information, other applications and to download the files. You can skip this part if you aren't using a PIC with Darrel Taylor interrupts. Just set up the interrupts as necessary on the platform you're using.

To get the Darrel Taylor (DT) interrupts set up there are two things to do:

1.) Include the DT_INTS-14.bas and ReEnterPBP.bas files in your code.

2.) Copy and paste this into your code.

ASM
INT_LIST macro ;IntSource, Label, Type, ResetFlag?
INT_Handler RBC_INT, _ISR, PBP, yes
endm
INT_CREATE
ENDASM

Insert tabs and spaces like the graphic at the end of the Instructable so you can see things a little easier in your code. You'll need to modify it slightly to fit your needs. Under Label, replace ISR with the name of the subroutine that is your ISR. Don't forget the underscore! You need it!

To get the interrupts working, there are two more things to do:

1.) Write the ISR. You'll write this just like you were going to write a PBP subroutine except that you will need to insert @ INT_RETURN at the end of the subroutine instead of RETURN. This will acknowledge the interrupt and return program execution to where it left off in the main loop.

Inside the ISR, you need to clear the interrupt flag so your program does not get caught in a recursive interrupt. Simply reading PORTB is all that needs to be done to clear the interrupt flag on the PIC16F877A. Each different microcontroller has a different way of clearing interrupt flags. Check the data sheet for your microcontroller.

2.) When you reach the point in your code that you want to enable the interrupt, use this line of code:

@ INT_ENABLE RBC_INT

When you want to disable the interrupt simply use:

@ INT_DISABLE RBC_INT

There's a lot of stuff packed into what I just covered so I'll summarize quickly. So far, your program should look something like this:

; Any needed set up or code

INCLUDE "DT_INTS-14.bas"
INCLUDE "ReEnterPBP.bas"

ASM
INT_LIST macro ;IntSource, Label, Type, ResetFlag?
INT_Handler RBC_INT, _myISR, PBP, yes
endm
INT_CREATE
ENDASM

; Any other needed set up or code

@ INT_ENABLE RBC_INT
; Code that needs to know which way the knob is rotating
@ INT_DISABLE RBC_INT

; Other code

END ; End of program

myISR:
;ISR code here
@ INT_RETURN

(Interrupt Handler Set Up Table)

I think this is where anyone who is not using a PIC or DT interrupts can join in again. Now, we need to actually write the ISR so the microcontroller knows which way the knob is rotating. Recall from the software theory section that we can deduce the direction of rotation if we know the input that caused the interrupt, its new value and the value of the other input. Here's the pseudocode:

Read PORTB into a scratch variable to clear the interrupt flag
Check if A caused the interrupt.
If true,
Compare A and B.
Check if different, if different,
It was clockwise rotation
Else,
It was counterclockwise
Endif

Check if B caused the interrupt.
If true,
Compare A and B
Check if different, if same,
It was clockwise rotation
Else,
It was counterclockwise
Endif

Return from interrupt

How do we know if a change on A or B caused the interrupt? Discovering the new value of the changed input and the other (unchanged) input is easy because we can read them inside the ISR. We need to know what the state of each one was before execution gets sent to the ISR. This happens in the main routine. The main routine sits and waits for a byte variable that we called CWflag to be set to 1 or cleared to 0 by the ISR. After each acknowledged change of the knob or if there is no knob activity, the variable is set to 5 to indicate an idle state. If the flag gets set or is cleared, the main routine immediately increments or decrements the set point pressure appropriately based on the rotation and then sets the CWflag variable back to 5 because the knob is now idle again. As the main routine is checking the CWflag, it is also documenting the state of the A and B rotary switch values. This is really simple and looks like this:

oldA = A
oldB = B

There really is nothing super fancy here. Just include those two lines at the beginning of the loop that checks the CWflag for rotation. We're just updating the logic values of the inputs from the rotary knob inside the increment/decrement loop in the main routine so that we can see what input caused the interrupt when the ISR is executed. Here is the ISR code:

ABchange:
scratch = PORTB ' Read PORTB to clear interrupt flag

' If A causes the interrupt, check B for direction of rotation
IF oldA != A THEN
' If A and B are different, it was clockwise rotation
IF A != B THEN
GOTO CW
' Otherwise, it was counter-clockwise rotation
ELSE
GOTO CCW
ENDIF
ENDIF

' If B causes the interrupt, check A for direction of rotation
IF oldB != B THEN
' If A and B are the same, it was clockwise rotation
IF A == B THEN
GOTO CW
' Otherwise, it was counter clockwise rotation
ELSE
GOTO CCW
ENDIF
ENDIF

CW:
CWflag = 1
@ INT_RETURN

CCW:
CWflag = 0
@ INT_RETURN

I've included the ISR code in a AB_ISR.bas file because the tabs in the code aren't showing up the way they should.

Now, because the ISR has the old values for inputs A and B it can determine which input caused the interrupt, compare it to the other (unchanged) input and determine the direction of rotation. All the main routine has to do is check the CWflag to see which direction the knob has turned (if it has) and increment or decrement a counter, set point or whatever you like or need.

I hope this helps and hasn't been too confusing. This type of interface is especially useful if your system is already using interrupts as this is only one more interrupt to add. Enjoy!
AB_ISR.bas671 bytes
« Previous StepDownload PDFView All StepsNext Step »

Pro

Get More Out of Instructables

Already have an Account?

close

All Steps Viewing
View all steps of an Instructable on the same page when you're a Pro Member.

Upgrade to Pro today!
0
Followers
1
Author:hw640