Hello,
is there a sample code for interfacing quadrature encoders[a/b channels]
I need to determine position/direction...
i searchd for posts in the pbp forum,but they were all for 1 channel
Thank you
-Gerry
Hello,
is there a sample code for interfacing quadrature encoders[a/b channels]
I need to determine position/direction...
i searchd for posts in the pbp forum,but they were all for 1 channel
Thank you
-Gerry
Here is a small example how to count up and down a position counter.
How to initialise the position counter you must do by yourself.
A_INPUT VAR PORTA.0
B_INPUT VAR PORTA.1
HULP1 VAR BIT
HULP2 VAR BIT
COUNTER VAR WORD
Clear
COUNTER = 32768
START:
HULP2 = A_INPUT & ~ HULP1 'EVERY POSITIVE GOWING EDGE OF A_INPUT
HULP1 = A_INPUT 'GIVES A PULSE OF ONE PROGRAMM CYCLE
IF HULP2 = 1 AND B_INPUT = 1 THEN 'MOTOR TURNS RIGHT
COUNTER = COUNTER + 1
ENDIF
IF HULP2 = 1 AND B_INPUT = 0 THEN 'MOTOR TURNS LEFT
COUNTER = COUNTER - 1
ENDIF
Hi!
Maybe these two links will help you out.
Nuts and Volts:
http://www.parallax.com/dl/docs/cols...l1/col/nv8.pdf
See State machine: two-bit quadrature encoder
http://www.emesystems.com/BS2fsm.htm#twobit%20encoder
Luciano
mat janssen>>
Thank yoiu very much for the code snip..but i cant understand whats going on in the code ,esp the "&~" part
I tried using the code...however ,whatever maybe the direction the motor is running ....i get the same reading ,say always "left"
Luciano>>
Thanks for the links..
i ported the foll code from nv8 [http://www.parallax.com/dl/docs/col...ol1/col/nv8.pdf --pg7]
Code:let new = pins & %11000000 ' Mask off all but bits 6 & 7 start: let old = new & %11000000 ' Mask bits and copy new into old. again: let new = pins & %11000000 ' Copy encoder bits to new. if new = old then again ' If no change, try again. let directn = bit6 ^ bit15 ' XOR right bit of new w/ left bit of old. if directn = 1 then CW ' If result=1, encoder turned clockwise. serout 0,n2400,(I,left) ' If result=0, counterclock (scroll left). goto start ' Do it again. CW: serout 0,n2400,(I,right) ' Clockwise (scroll right). goto start ' Do it again.
To pbp
with the above code...there is alot of fluctuation between the 2 directions..Code:old VAR BYTE new VAR BYTE direct VAR BIT quad: new= PORTC && %00000011 start: old=new && %00000011 again: new= PORTC && %00000011 Pause 10 LCDOut $fe,1,"no movement" IF new=old Then again direct=new.bit1 ^ old.bit0 IF direct=0 Then GoTo cw LCDOut $fe,1,"one dir" Pause 10 GoTo start cw: LCDOut $fe,1,"2nd dir" Pause 10 GoTo start
..anything going wrong in my code?.i sat on it the whole day..still cant figure out the problem
Hallo,
I completed the programm for testing and it works ok.
With the & ~ look in the manual it takes the not value of the bit.
here is the complete source and also the hex file
'PIC 16F628A test
@ DEVICE PIC16F628A,INTRC_OSC
@ DEVICE PIC16F628A,MCLR_OFF
@ DEVICE PIC16F628A,BOD_OFF
@ DEVICE PIC16F628A,LVP_OFF
@ DEVICE PIC16F628A,CPD_OFF
@ DEVICE PIC16F628A,PROTECT_OFF
DEFINE OSC 4
CMCON = 7
VRCON = 0
OPTION_REG.7 = 0
TRISA = %11111111
TRISB = %00000000
A_INPUT VAR PORTA.0
B_INPUT VAR PORTA.1
HULP1 VAR BIT
HULP2 VAR BIT
COUNTER VAR WORD
Clear
COUNTER = 128
START:
HULP2 = A_INPUT & ~ HULP1 'EVERY POSITIVE GOWING EDGE OF A_INPUT
HULP1 = A_INPUT 'GIVES A PULSE OF ONE PROGRAMM CYCLE
IF HULP2 = 1 AND B_INPUT = 1 Then 'MOTOR TURNS RIGHT
COUNTER = COUNTER + 1
EndIF
IF HULP2 = 1 AND B_INPUT = 0 Then 'MOTOR TURNS LEFT
COUNTER = COUNTER - 1
EndIF
PORTB = COUNTER
GoTo START
Hello ICE!
You need the Bitwise Operator:
&
Not the logical Operator AND:
&& (AND and && are the same)
From the PBP manual:
4.17.14. Bitwise Operators
Bitwise operators act on each bit of a value in boolean fashion.
They can be used to isolate bits or add bits into a value.
4.19. Logical Operators
Logical operators differ from bitwise operations. They yield a true/false
result from their operation. Values of 0 are treated as false. Any other
value is treated as true.
Luciano
Last edited by Luciano; - 8th April 2005 at 11:33.
Luciano,
I tried it with & [bitwise operators]...actually everything..
still no go...
mat janssen>>
are u by any chance using a dual D f/f between the encoder and the PIC,because im not..
Thanks for ur code snip
Last edited by ice; - 8th April 2005 at 12:52.
Hi mat I see you are using ASM to set up your config word, it is a greate idea, but I get a compiler error when I do it. I always edit the device include file 16F628.INC:
NOLIST
ifdef PM_USED
LIST
include 'M16F62x.INC' ; PM header
device pic16F628, intrc_osc, wdt_off, pwrt_off, mclr_off, lvp_off, protect_off
XALL
NOLIST
You can't teach an old dog new tricks, but I'm always willing to try.
Thank you for all your help.
Theres a small problem though.
The encoder program counts faster in one direction and slower in the other...
is it because ...
When im counting in one of the directions ,im utilizing the ADC[ADCIN and an IF statement]
..whereas in the other direction,im not.
The program logic is the same as above.
Last edited by ice; - 18th April 2005 at 08:38.
before i go ahead with my code....ill explain wht i have to do
I need to control the position of a DC motor[geared],using a potentiometer
I have to first detect the endpoints of a gear assembly.
say, i start with a count of 32500 and the count at one end of the gear assembly is 32600
..now i rotate it to the other side ,say the count at this point is 32400
The above was just the calibration routine.Using the above values ,i have to
scale the 200 counts[32600-32400] to a potentiometer value[0 to 255]
How am i detecting the end points?
..im using the LMD18200T motor driver .Using the current sense feature of the chip,i detect wheteher the gear assembly has reached an end point.The current sense pin is connected to an ADC port..portA.1 namely
my program flow...
1> set counter to 32500
2> move motor in one direction
3> count pulses..if CW,increment.if CCW decrement
...say it is CW and counter increments to 32600 till the end
4>counter_1 has 32600
5>move the motor to the other side,count the pulses..it is decrementing now
6>so counter_2 has 32400
7>now i have to scale the gear assembly range to a potentiometer
difference=counter_1-counter_2
=32600-32400
=200
8> scale to a pot value
pot_val holds the pot value connected to analog portA.0
hence required count value=[difference/256]*pot_val+counter_2
=[difference*pot_val]/256+counter_2 (rearranging)
example...if potvalue in 128,then
required count value=(200*128)/256+32400
=32500
now i dont know where to go from here..how do i get the motor to move to position 32500,when the pot is moved to 128
...this is a long post..but its the best i could do to explain wht im trying to do.
-Gerry
If you are losing encoder counts, then use an interrupt service routine.
Four of PORTB’s pins, RB<7:4>, have an interrupt-onchange feature.
Use two of these pins for the A/B encoder signals.
Luciano
ok,heres my program ,using interrupts..
the problems i'm encountering are below the code
..
1>The interrupts are worng fine,however the code is still unable to distinguish between CW and CCW,because of which the counting goes awry..Code:DEFINE LOADER_USED 1 led VAR PORTB.7 old VAR BYTE new VAR BYTE direction_bit VAR BIT counter VAR WORD counter_1 VAR WORD counter_2 VAR WORD direction_store VAR BIT adval VAR WORD ' Create adval to store result potval VAR WORD servo_val VAR WORD difference VAR WORD counter=32500 HPwm 0,150,20000 OPTION_REG = $7f ON INTERRUPT GoTo myint ' Define interrupt handler INTCON = $90 ' Enable INTE interrupt loop: High led ' Turn LED on LCDOut $fe,1,"count:" LCDOut $fe,$c0,DEC counter 'Pause 10 GoTo loop ' Do it forever ' Interrupt handler Disable ' No interrupts past this point myint: Low led ' If we get here, turn LED off enc: new= PORTB & %00000011 start_1: old=new & %00000011 again: new= PORTB & %00000011 'load new value of A/B channels into new by anding with HEX3 'IF new=old Then again direction_bit=old.bit1 ^ new.bit0 'check direction IF direction_bit = 1 Then LCDOut $fe,1,"Last was CW" counter = counter + 1 'increment counter LCDOut $fe,$c0,DEC counter," ",BIN direction_bit Else LCDOut $fe,1,"Last was CCW" counter = counter - 1 'decrement counter LCDOut $fe,$c0,DEC counter," ", BIN direction_bit EndIF Pause 10 INTCON.1 = 0 ' Clear interrupt flag Resume ' Return to main program Enable
2>if i remove the "if then " statement for CW/CCW direction and only put a
counter=counter+1,it works well
The whole problem seems to be the direction decoding part..
..i cant seem to find a solution to it..
Last edited by ice; - 3rd May 2005 at 13:00.
Luciano,
Thank you for the clarity and detail with which you answered Ice's questions. I was able to get my own optical encoder running using your guidance and assembly language code.
Is it possible to increment/decrement enc_counter by 10's or 100's once some threshold has been reached? My encoder is a front panel switch with pushbutton which is used to select and change setpoints, turning the switch 32000 times can't be good for its lifetime not to mention my hand.
Hi,
I'm not sure I understand your problem.
* * *
Set the variable enc_counter to 30000.
If the encoder does one step you will
have either 29999 or 30001 in enc_counter. (CCW or CW).
The interrupt assembly code only decrements or increments
the 16 bit value stored in the variable enc_counter.
Is up to your PicBasic code in the main program loop to do
something with the value stored in the variable enc_counter.
Best regards,
Luciano
Last edited by Luciano; - 29th October 2005 at 21:44.
Bookmarks