Home - Search - Members
Full Version: a code for the shaft encoder
nicholastyc
Jun 16 2008, 3:33 AM
Hi,

I have problem writing a code for the shaft encoder to decode for my PIC to read the direction.
Can some one please give me a sample code of the shaft encoder decodes the direction?

thanks.
nicholastyc
Jun 16 2008, 3:51 AM
Ajay, i know you already told me about this...but i try to work it out on ASM code...it doesnot work..

can u give me a sample code of how to decode the shaft encoder direction?

nicholastyc
Jun 16 2008, 4:14 AM
GPIO 4 is the channel A of the shaft encoder
GPIO 5 is the channel B of the shaft encoder
below is part of the program code for the encoder to decode the 4 binary bit to determine the direction.
shaft encoder used Bourns ECW- Digital Contacting Encoder
CODE:

START
        btfsc   GPIO,4;    waiting for the encoder changes
        goto START; keep check for the changes
        call    SHAFT_0; changes detected
SHAFT_0:
        CLRF    A11             ; clear memory A11
        CLRF    A21             ; clear memory A21
        BCF     STATUS,C; clear carry flag incase there is carry
        BTFSC   GPIO,4          ; check on the changes, 0 or 1
        GOTO    SAVEBIT_A11     ; if 1 go savebitA11
        GOTO    SAVEBIT_A10     ;if 0 go savebit A10
SHAFT_1
        BTFSC   GPIO,5          ; check on gpio 5 changes, channel B
        GOTO    SAVEBIT_B11     ;if 1 go savebit B11
        GOTO    SAVEBIT_B10     ;if 0 go savebit B10
SHAFT_2
        BTFSC   GPIO,4          ;same as above to check to the 4th bit
        GOTO    SAVEBIT_A21     ;
        GOTO    SAVEBIT_A20     ;
SHAFT_3
        BTFSC   GPIO,5          ;
        GOTO    SAVEBIT_B21     ;
        GOTO    SAVEBIT_B20     ;
SAVEBIT_A11
        MOVLW   b'00000001'     ; if 1 received on shaft channel A move 1 to A11 memory
        MOVWF   A11             ;
        RLF     A11,1           ; rotate left to make bit 0 avaible for channel B
        GOTO    SHAFT_1         ;
SAVEBIT_A10
        MOVLW   b'00000000'     ;if 0 received on shaft channel A move 1 to A11 memory
        MOVWF   A11             ;
        RLF     A11,1           ;rotate left to make bit 0 avaible for channel B
        GOTO    SHAFT_1         ;
SAVEBIT_B11
        MOVLW   b'00000001'     ; if 1 received on shaft channel B move 1 to A11 memory
        IORWF   A11,1           ;added up with channel B to form 1 complete bit for
        RLF     A11,1           ;each turn, rotate left 2 times for next bit of turn
        RLF A11,1       ;                                            of the encoder
        GOTO    SHAFT_2         ;
SAVEBIT_B10
        MOVLW   b'00000000'     ; same as above ...for 0 bit on channel B
        IORWF   A11,1           ;
        RLF     A11,1   ;
        RLF A11,1
        GOTO    SHAFT_2         ;
SAVEBIT_A21
        MOVLW   b'00000001'     ;if 1 received on shaft channel A move 1 to A21 memory
        MOVWF   A21             ;
        RLF     A21,1           ;rotate left to make bit 0 avaible for channel B
        GOTO    SHAFT_3         ;
SAVEBIT_A20
        MOVLW   b'00000000'     ;
        MOVWF   A21             ;same as above
        RLF     A21,1           ;
        GOTO    SHAFT_3         ;
SAVEBIT_B21
        MOVLW   b'00000001'     ;bit 1 , added up with channel A to form 1 complete bit for
        IORWF   A21,0           ;each turn
        IORWF   A11,0           ;at here, add up 2 complete bit to determine the
        GOTO    DIRECTION       ; direction of the shaft encoder...
SAVEBIT_B20
        MOVLW   b'00000000'     ;same as above, but 0 bit received from previous action
        IORWF   A21,0           ;
        IORWF   A11,0           ;
        GOTO    DIRECTION       ;
DIRECTION
        CALL    TABLE_1 ; call table to check on the direction after the total 4bit added
ANTI_CLOCKWISE
        BSF     GPIO, 0; set gpio 0 high
                     BCF               GPIO,1; clear gpio 1
        goto    START;
CLOCKWISE
        BSF     GPIO,1;set gpio 1 high
        BCF     GPIO,0;clear gpio 0
        GOTO    START;
RESTART_PWM
        GOTO    START; no changes go back to start

        RETURN
;************************************************
;**** DIRECTION TABLE****************************
;************************************************

TABLE_1:
        ADDWF   PCL,1   ;
        GOTO    RESTART_PWM     ;
        GOTO    ANTI_CLOCKWISE  ;
        GOTO    CLOCKWISE       ;
        GOTO    RESTART_PWM     ;
        GOTO    CLOCKWISE       ;
        GOTO    RESTART_PWM     ;
        GOTO    RESTART_PWM     ;
        GOTO    ANTI_CLOCKWISE  ;
        GOTO    ANTI_CLOCKWISE  ;
        GOTO    RESTART_PWM     ;
        GOTO    RESTART_PWM     ;
        GOTO    CLOCKWISE       ;
        GOTO    RESTART_PWM     ;
        GOTO    CLOCKWISE       ;
        GOTO    ANTI_CLOCKWISE  ;
        GOTO    RESTART_PWM     ;
        RETURN
 
Ajay
Jun 16 2008, 7:45 AM
Welcome back nich well in your program you have used so many returns.. i really have no idea where you're returning

Well minute changes will make your program work..
like..
CODE:

START
        btfsc   GPIO,4;    waiting for the encoder changes
        goto START; keep check for the changes
        ;call   SHAFT_0; changes detected
        ;No need to call the next statement is same you are going to execute
 

I found that there is no while(1) kind of loop in your program.

please tell me what your application is or what you are trying to do in your program, so that i can optimize it better. and please review your code and remove the unwanted returns, because they will make your program to go mad and hang!!
nicholastyc
Jun 16 2008, 8:17 AM
hihi, ajay,
my application is for the LED dimmer, i need to know when i am turning clockwise or anti clockwise of the encoder, the light is either dimmer or brighter.

i want to know the changes of direction, so i can set the PWM.

Thanks

Ajay, the main problem i m having now is, how to detect the changes of the encoder signal bits, and how to save them efficiently and bring them to determine the direction using IOR table i am using.
thanks...

shyam
Jun 17 2008, 6:23 AM
hi
nicholastyc
if u had searched the forum u wud have found an earlier post on the similar topic.
still lemme tell u one technique which i use..

u get two o/p lines
say A and B
u get data in gray code format (cyclic).

thhere will be two sets of data
1. clockwise (depends on what pin A or B is)
A|B
0|0
0|1
1|1
1|0
and
2. anticlockwise
A|B
0|0
1|0
1|1
0|1

now u wud have observed the difference just compare any two occurance of data and u will find the direction...
hope that helps...
Ajay
Jun 17 2008, 7:41 AM
like you have done in C already, here also you need to make a look up table for encoder to detect the change in direction.

or... what you can do is.. create three states (CLOCK, ANTICLOCK, NOCHANGE)
like this:
CODE:
CLOCK equ 1H
ANTICLOCK equ 2H
NOCHANGE equ 3H
 

if encoder can be connected to interrupt pins of controller or periodic polling on any two pins, then whenever you sense a change in encoder o/p you can switch between states according to current state of encoder bits.
hence in your main loop when a state changes you can do work according to that state.

I hope you have got my idea?
nicholastyc
Jun 18 2008, 1:11 AM
I was using both of your idea in my design, i make it working on hardware now...but littlt buggy is that...when u over turned the shaft encoder, the light from the dimmest will changed to Brightest ...lol...
little buggy with my code here...need to prevent it to overshoot....

thanks anyway...i will figure it out...
nicholastyc
Jun 19 2008, 9:02 AM
CODE:

for example:

START
        btfss             GPIO,4; check encoder changes
                     goto       START
        clrf    SWDAT2; clear reg
                     btfss   GPIO,4             ; if bit A lo
                     bsf     SWDAT2,0         ; set SWDAT2 bit 0
                     btfss   GPIO,5  ; if bit B lo
                     bsf     SWDAT2,1         ; set SWDAT2 bit 1
        movf    SWDAT2,W        ; load switch data                |B0
        andlw   b'00000011'     ; mask encoder B and A switches   |B0
        xorwf   ENCOLD,W        ; same as last reading?           |B0
        bz      START     ; yes, branch (no change), else   |B0
        xorwf   ENCOLD,W        ; restore encoder bits in W       |B0
        rrf     ENCOLD,f        ; prep for B-old ^ A-new          |B0
        xorwf   ENCOLD,f        ; ENCOLD bit 0 = direction        |B0
        rrf     ENCOLD,f        ; now Carry bit = direction       |B0
        movwf   ENCOLD          ; update ENCOLD (new BA bits)     |B0
        btfss   STATUS,C;
        goto    ANTI_CLOCKWISE;
        goto    CLOCKWISE;
 


i m using pic12f629...
can some one suggest me a WORKED code?
nicholastyc
Jun 19 2008, 2:59 PM
Shyam , Ajay...Arun...

i really need help on the encoder part...please help..i already tried my best !
i still cant get the right direction ... i m using pic12f629 ...
i am using Gpio,4 and gpio,5 as Bit A and Bit B of encoder.
1. clockwise
A|B
0|0
0|1
1|1
1|0
and
2. anticlockwise
A|B
0|0
1|0
1|1
0|1

how to make a correct table? i m trying to make 1...its works on the simulation but failed on hardware...dunno y...
do i need the interrupt routine? because i m using the btfss gpio,4 to enter the direction loop and then check on the bit on A and B. same as the code in the thread above...

pplease have a look...or give me a code to try...i m so so so depressed!

thanks
shyam
Jun 19 2008, 10:57 PM
hi nic,
well u do need those A and B pin as interrupt pins.. or else u may miss the step changes..


or u can try one thing....

wait until states are 1,1
wait for either 0,1 or 1,0

accordigly u wud come 2 know the direction of rotation..

one more point to note..
the shaft is usually very sensitive...
if u are rotating by self (ur hand) well u might observe both the direction so dont panic .. stay calm cause u are using the right procedure..



off topic: any new development regarding your job searh?
all the best.
nicholastyc
Jun 20 2008, 12:04 AM
Hi Shyam, wat is mean by
wait until states are 1,1 , 0,1 or 1,0 ?

is it i need to test the both bit in order to enter the loop for testing the direction?


off topic: i havent start to look for job now...i will start this weekend. do u know any job related in UK? thanks...
shyam
Jun 20 2008, 12:23 AM
is it i need to test the both bit in order to enter the loop for testing the direction?


nic,


take a variable say
int EncCount_int.
int EncStateClk_int[]= {3,2,0,1};
int EncStateAntiClk_int[]= {3,1,0,2};
since the encoder is fast enough .. there is no harm in waiting for that particular stste that u can mark as START.
case1.
if u r not using the pins as interrupt.
start loop.
now u will have to make the uC idle untill the next state change.. i.e. keep checking for the pins untill u notice a change in either of the pin.

read the pins and store in a vriable
int Pinval_int;
int index =1;

now check
if Pinval_int = EncStateClk_int[index]
// clock wise rotation
//decrease EncCount_int
EncCount_int = EncCount_int -1;
else
// anticlock wise rotation
//increase EncCount_int
EncCount_int= EncCount_int+1;
//increment index;
if ( index ==4)
index =0;

get back to the loop



sorry for not being clear enough... am amidst a project needing some attention...
please se if it helps...

nicholastyc
Jun 20 2008, 4:32 AM
i think something is wrong with my code that its only detects 1 direction!!
i have made my program on interrupt on change to the both input port,
the will go into the ISR to save the bit data...
but its still failed to detect the correct direction.

why?

thanks Shyam for your times...i still failed..
Ajay
Jun 20 2008, 8:26 AM
can i see your code again?
shyam
Jun 20 2008, 8:36 AM
yes lets see the code again.. the interrupt one.
sashijoseph
Jun 20 2008, 11:26 PM
Hi Nic,
This is a small adaptation of your polling routine using a single variable A11.It savs the current and previous AB values in this manner as a nibble....



CODE:
START
        CLRF    A11             ; clear memory A11
       
        BCF     STATUS,C; clear carry flag incase there is carry

SHAFT_0        
        BTFSC   GPIO,4          ; check on the changes, 0 or 1
        GOTO    SAVEBIT_A11     ; if 1 go savebitA11
        GOTO    SAVEBIT_A10     ;if 0 go savebit A10
SHAFT_1
        BTFSC   GPIO,5          ; check on gpio 5 changes, channel B
        GOTO    SAVEBIT_B11     ;if 1 go savebit B11
        GOTO    SAVEBIT_B10     ;if 0 go savebit B10
SHAFT_2
        BTFSC   GPIO,4          ;same as above to check to the 4th bit
        GOTO    SAVEBIT_A21     ;
        GOTO    SAVEBIT_A20     ;
SHAFT_3
        BTFSC   GPIO,5          ;
        GOTO    SAVEBIT_B21     ;
        GOTO    SAVEBIT_B20     ;
SAVEBIT_A11
        MOVLW   b'00000001'     ; if 1 received on shaft channel A move 1 to A11 memory
        MOVWF   A11             ;
        RLF     A11,1           ; rotate left to make bit 0 avaible for channel B
        GOTO    SHAFT_1         ;
SAVEBIT_A10
        MOVLW   b'00000000'     ;if 0 received on shaft channel A move 1 to A11 memory
        MOVWF   A11             ;
        RLF     A11,1           ;rotate left to make bit 0 avaible for channel B
        GOTO    SHAFT_1         ;
SAVEBIT_B11
        MOVLW   b'00000001'     ; if 1 received on shaft channel B move 1 to A11 memory
        IORWF   A11,1           ;added up with channel B to form 1 complete bit for
        RLF     A11,1           ;each turn, rotate left 2 times for next bit of turn
                                                  of the encoder
        GOTO    SHAFT_2         ;
SAVEBIT_B10
        MOVLW   b'00000000'     ; same as above ...for 0 bit on channel B
        IORWF   A11,1           ;
        RLF     A11,1   ;
       
        GOTO    SHAFT_2         ;

SAVEBIT_A21
        MOVLW   b'00000001'     ;if 1 received on shaft channel A move 1 to A21 memory
        IORWF   A11,1           ;
        RLF     A11,1           ;rotate left to make bit 0 avaible for channel B
        GOTO    SHAFT_3         ;
SAVEBIT_A20
        MOVLW   b'00000000'     ;
        IORWF   A11,1           ;same as above
        RLF     A11,1           ;
        GOTO    SHAFT_3         ;
SAVEBIT_B21
        MOVLW   b'00000001'     ;bit 1 , added up with channel A to form 1 complete bit for
        IORWF   A11,1

        GOTO    DIRECTION       ; direction of the shaft encoder...
SAVEBIT_B20
        MOVLW   b'00000000'     ;same as above, but 0 bit received from previous action
        IORWF   A11,1           ;
       
        GOTO    DIRECTION       ;


RET_FROM_DIRECTION
        RLF     A11,1
        MOVLW   b'00000110'
        ANDWF   A11,1
        GOTO    SHAFT_2







DIRECTION
        ......
        ......

        GOTO RET_FROM_DIRECTION
sashijoseph
Jun 20 2008, 11:40 PM
Now for the nibble A11 you can have the following valid values
0x01,0x07,0x08 and 0x0E representing clockwise direction
and
0x2,0x04,0x0B,0x0D representing anticlock direction.

Thus you need to check the nibble for 1,7,8 or E (hex) for a clockwise rot and 2,4,B or D for anti.
Any other value means either no change or invalid... so you need to ignore.

In the 'direction' part of the code you need to implement this logic.

After that the nibble is rotated left once and 'anded' with 00000110 to save the current AB value(which will now become the previous AB value) and the loop is started again for acquiring the current AB value.
Arun Kumar V
Jun 21 2008, 4:55 AM

Hi nic,

i think SJ nailed it !


Arun
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Rickey's World © 2003 - 2007