PDA

View Full Version : Instant Int and encoder (Elect. Gearing)



boroko
- 13th March 2008, 19:06
Hi all,

I have been working on this for too long and I'm starting to chase my tail.

I'm to the point that I can remember the post numbers, but I'm still overlooking something.

The purpose is this:
1) Read Encoder #1 to measure direction and distance of a linear movement.
2) If travel is +, do nothing
3) if travel is -, feed pulses to a servo driver to move a motor (feed material at same rate as linear retract).
4) there a couple of lines I left in for adding manual over-ride.
5) testing on a 877 with a X-1 board but the target can be anything.

Thanks for taking a look.
Bo

' 1)Quadrature encoder reading direction and speed of mechanical slide.
' 2) Motor (servo) driven in ONE direction of slide movement,
' not driven for other direction. Pulse & Direction drive.
' 3) Overide switches to drive servo either direction manually.
'
A_INPUT VAR PORTB.4 'encoder A input
B_INPUT VAR PORTB.5 'encoder B input
F_Sw var PORTB.6 'Foward switch input
R_sw var PORTB.7 'Reverse Sw input
P_out var PORTA.0 'Pulse out to motor
D_out var PORTA.1 'level out for direction
'only for manual Sw
' drive. Implement Ltr.
LED1 var PORTA.5 'heartbeat for INT
RdEnc1 VAR BIT
RdEnc2 VAR BIT
COUNTER VAR WORD

TRISA = %00000000
TRISB = %11111111
TRISD = %00000000
OPTION_REG.7 = 0 'enable POTRB pull-ups

INCLUDE "DT_INTS-14.bas" 'Base Inturrupt program
include "ReEnterPBP.pbp" 'allow PBP int

ASM
INT_LIST macro ;IntSource, Label, Type, ResetFlag?
INT_Handler RBC_INT, _MotorDrive, PBP, yes
INT_Handler INT_INT, _ToggleLED1, PBP, yes
endm

INT_ENABLE RBC_INT ;enable RB change int
INT_ENABLE INT_INT ; enable external (INT) interrupts
ENDASM

Start
RdEnc2 = A_INPUT & ~ RdEnc1 'EVERY POSITIVE GOWING EDGE OF A_INPUT
RdEnc1 = A_INPUT 'GIVES A PULSE OF ONE PROGRAM CYCLE

IF RdEnc2 = 1 AND B_INPUT = 1 Then 'Encoder TURNS CW: UP
COUNTER = 1
EndIF

IF RdEnc2 = 1 AND B_INPUT = 0 Then 'Encoder TURNS CCW: DN
COUNTER = 0
EndIF

counter = portb & %00000011 'for troubleshooting: strip i/p.
PORTD = counter 'for troubleshooting: to see i/p.

goto start

'+++++++++++++++++
'Motor Drive Pulse Out inturrupt handler
'++++++++++++++++++
MotorDrive:
if counter = 1 then
pulsout P_out,100
endif
@ INT_RETURN
'---[INT - interrupt handler]---------------------------------------------------
ToggleLED1:
TOGGLE LED1
@ INT_RETURN
end

skimask
- 13th March 2008, 20:34
pulsout P_out,100
pulsout is a 'blocking' statement, a 'synchronous' statement.
In other words, if you're trying to do something at the same time as you're trying to 'pulsout', that something might not get done until the pulsout is done doing what it has to do.

Darrel Taylor
- 13th March 2008, 20:56
Pay no attention to the man behind the curtain. (or was that a mask)

With DT_INTS, nothing is "blocking" except the interrupt handlers themselves.

And if the conditions that generated the interrupt are not cleared, the handler will continue "blocking" everything.

In your MotorDrive routine (RBC_INT handler), you MUST read PORTB to end the mismatch condition.

Additionally, the statements to read the encoder should be in that handler too.

Here's a snippet from SteveB for 2 rotary encoders, may give you some ideas.
http://www.picbasic.co.uk/forum/showthread.php?p=25396

hth,

skimask
- 14th March 2008, 12:45
Pay no attention to the man behind the curtain. (or was that a mask)
With DT_INTS, nothing is "blocking" except the interrupt handlers themselves.

DOH!!! no kidding...

boroko
- 14th March 2008, 17:49
Thanks for the replys Darrell and Skimask.
I so hate asking for help for something thats likely to be an oversight on my part. I don't ever want to abuse the list's willingness to help.

I'm going through your suggestions and the first thing that I don't understand in http://www.picbasic.co.uk/forum/showthread.php?p=25396 is this:
================
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler INT_INT, _Rot_Encoder, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

@ INT_ENABLE RBC_INT ;RB Port Change Interrupt
==============

My understanding was that the INT_INT was for RB0 (external Int) only and that RBC_INT was for the "change on RB 4-7".
I'm going to test and try to answer my own question, but I thought it should be answered in print. I know I have spun in small circles after looking for stuff like this.

Bo

Darrel Taylor
- 19th March 2008, 23:27
My understanding was that the INT_INT was for RB0 (external Int) only and that RBC_INT was for the "change on RB 4-7".
Correct!

Steve had found that bug later in the thread. I forgot to mention it.

It should be RBC_INT.
<br>

boroko
- 21st March 2008, 07:12
Hi All,
Been banging my head for a while now and I am getting closer. Thank you for the time you have taken to add life to this forum.

The Travel encoder section works pretty well, but the Manual encoder is erratic and sometimes take over the travel section and not let it work. A bump on Manual, and the Travel works again.

As a reminder. The Travel generates Pulse and Direction in one direction only. The Manual is for bi-directional fine adjustment after the Travel section's movement is complete (automatic). Target: 12F675 @ 4mHz INT_OSC

Anybody see what I'm missing?
Thanks
Bo


A_trav VAR GPIO.0 'Travel encoder A input
B_trav VAR GPIO.1 'Travel encoder B input
A_man var GPIO.2 'Manual Encoder A input
B_man var GPIO.3 'Manual Encoder B input
P_out var GPIO.4 'Pulse output to motor
D_out var GPIO.5 'level output for direction
Dir VAR bit 'Direction
Scratch var byte 'dummy byte
Old_Bits VAR BYTE
New_Bits VAR BYTE
TravEncOld var byte 'TRAVel Measurement ENCoder
TravEncNew Var byte '
ManEncOld var byte 'MANual input ENCoder
ManEncNew var byte '

P_out = 1 'servo I/P = LO pulse, start HI

INTCON = %10001000 'GLOBAL ON, GPIO Int ON
CMCON = 7 'Comparator off, Digital I/O
OPTION_REG = %00000000 'GPIO Pull-up Enabled
TRISIO = %001111
WPU = %000111 'pull-ups 0-2 (3 added on board)
IOC = %001111 'Int On Change GPIO 1-3
ANSEL = 0

INCLUDE "DT_INTS-14-0.bas" '..-14-0 = ALL Banks REM'd

ASM
INT_LIST macro ; IntSource, label, Type, ResetFlag?
INT_Handler RBC_INT, _EncChg, ASM, yes
endm
INT_CREATE ; Creates the interrupt processor
INT_ENABLE RBC_INT ;RB Port Change Interrupt
ENDASM

Old_Bits = GPIO & (%001111) 'Get initial inputs

Main:

GOTO Main

'---[RBC - interrupt handler]---------------------------------------------------
EncChg:
New_Bits = GPIO & (%001111) 'Get inputs
TravEncNew = New_Bits & (%000011) 'strip New Travel encoder
TravEncOld = Old_Bits & (%000011) 'Strip Old Travel Encoder
if TravEncNew = TravEncOld then ManEnc ' If no chg -> Manual Encoder
Dir = TravEncNew.1 ^ TravEncOld.0 'Check direction
D_out = Dir 'Direction LEVEL out
if Dir = 1 then 'Only travel 1 direction
pulsout P_out,20 'drive servo controller
Endif 'Controller is STEP/DIRECTION I/P
goto DoneRotEnc 'skip Manual Encoder

ManEnc:
ManEncNew = New_Bits & (%001100) 'strip Manual Encoder
ManEncOld = Old_Bits & (%001100)
Dir = ManEncNew.3 ^ ManEncOld.2 'Direction of Manual input
D_out = Dir
pulsout P_out,20 'Pulse for either direction

DoneRotEnc:
Old_Bits = New_Bits 'reset reference
Scratch = GPIO 'read GPIO to clear mis-match
@ INT_RETURN

Darrel Taylor
- 21st March 2008, 09:06
The interrupt type should be PBP.
ASM
INT_LIST macro ; IntSource, label, Type, ResetFlag?
INT_Handler RBC_INT, _EncChg, PBP, yes
endm


And you'll need to INCLUDE "ReEnterPBP.bas", for it to work.

boroko
- 21st March 2008, 15:55
Thanks,
I need to point out that this in on a 12F675.

I commented out the bank lines in DT_INTS-14 (hence the "DT_INTS-14-0.bas" on the include)
and removed ReEnterPBP

I tried to use things in the way that was discussed in http://www.picbasic.co.uk/forum/showthread.php?p=49510#post49510

Does that help this make sense a bit more?

Thanks
Bo

Darrel Taylor
- 21st March 2008, 22:04
Does that help this make sense a bit more?
Yes it does.

Since you don't have anything in the Main loop, you can probably get away with it.
But the PULSOUT statement uses PBP system vars. So if you add anything to the the Main loop, something will need to be changed.

I'm wondering how you got past the GPIF/GPIE problem. Should have been something like this ...
ASM
RBIF = GPIF
RBIE = GPIE
INT_LIST macro ; IntSource, label, Type, ResetFlag?
INT_Handler RBC_INT, _EncChg, ASM, yes
endm


As for the main problem, the only thing I can see that might cause it is the Scratch = GPIO at the end of the handler.

The mismatch is cleared in the first line New_Bits = GPIO & (%001111)

Reading it again at the end of the handler, may be causing it to miss changes on the port. Try commenting it out.

Still looking.
<br>

boroko
- 8th November 2009, 12:47
Back to this project.
Imagine a sewing machine. When the needle goes down, the thread is held steady and travels with the needle. When the needle goes up, the thread is fed out at the same rate that it travels up, feeding slack. There is a servo motor with an encoder feeding the thread and a matching encoder reading the travel distance and speed. There is also an aux encoder (ManDrive) that can be used to retract or feed the thread to trim or allow for excess so you can cut the thread. The manual feed/trim works as expected, but after a manual encoder change, sometimes the travel feed operates on both directions of input from the travel encoder instead of just retract. The feed is the correct direction, but when bad, the "down" feeds at twice the input rate while the "up" feeds normally. A change on the Man encoder allows it to work correctly again.

' 1) Quadrature encoder reading direction and speed of mechanical slide.
' 2) Motor (servo) driven in ONE direction of slide movement,
' not driven for other direction. Pulse & Direction drive LOW.
' 3) Manual Encoder to drive servo either direction manually.
' ADD pull-up to GPIO.3 on 12F675
' DEBUG splash on power-up on GPIO.5
' 12F675
' -----------u----------
' -|Vdd(+) (-)Vss |-
' D_out -|GP5 GP0/PGD|- A_trav
' P_out -|GP4 GP1/PGC|- B_trav
' B_man -|GP3/MCLR/Vpp GP2/INT|- A_man
' ----------------------
DEFINE DEBUG_REG GPIO
DEFINE DEBUG_BIT 5
DEFINE DEBUG_BAUD 2400 '
DEFINE DEBUG_MODE 0
DEFINE OSC 4
clear
A_trav VAR GPIO.0 ' Travel encoder A input
B_trav VAR GPIO.1 ' Travel encoder B input
A_man var GPIO.2 ' Manual Encoder A input
B_man var GPIO.3 ' Manual Encoder B input
P_out var GPIO.4 ' PULSE output to motor, Active LOW
D_out var GPIO.5 ' LEVEL output for direction
AutoCnt var word 'preprogrammed feed @ end of cycle
Dir VAR byte 'Direction
EncOld var byte
EncNew var byte
ManCnt var byte 'Counter for recent Man Pulses
TrvCnt var byte ' Travel Encoder before change
INTCON = %10001000 ' GLOBAL ON, GPIO Int ON
CMCON = 7 ' Comparator off, Digital I/O
OPTION_REG = %00000000 ' GPIO Pull-up Enabled
TRISIO = %001111
WPU = %11111111 ' weak p/u on 0-2,4,5, GPPU must be enabled for p/u
IOC = %00001111 ' Interrupt on Change for GPIO: 0-3
ANSEL = 0 ' Analog off
ManCnt = 0
TrvCnt = 0
P_out = 1 ' start out HI. Moves on LOW pulse
INCLUDE "DT_INTS-14-0.bas" 'Base Inturrupt program:0 banks
'include "ReEnterPBP-0.pbp" 'allow PBP int

ASM
RBIF = GPIF
RBIE = GPIE
INT_LIST macro ;IntSource, Label, Type, ResetFlag?
INT_Handler RBC_INT, _EncChg, ASM, yes
endm
INT_CREATE ;creates the INT processor
INT_ENABLE RBC_INT ;enable RB change int
ENDASM
debug "LW-FiberDrive-7"

Main:
ManualDrive: ' MANUAL first: set direction bit
if ManCnt > 0 then
Dir = EncNew.3 ^ EncOld.2 ' XOR new L bit > Old Rt bit=Direction
D_out = Dir 'set direction pin
pauseus 2
P_out = 0 'send drive pulse either dir
pauseus 2
P_out = 1 'reset drive pulse
ManCnt = ManCnt - 1 ' empty out pulse counter
endif
D_out = 1 'set direction pin
TravelDrive:
D_out = 1 'set direction pin
if TrvCnt > 0 then
Dir = EncNew.1 ^ EncOld.0 ' XOR new L bit > Old Rt bit=Direction
If DIR = 0 then TravDown 'end if travel DOWN

pauseus 2
P_out = 0 'send drive pulse retract only
pauseus 2
P_out = 1 'reset drive pulse
TravDown:
TrvCnt = TrvCnt - 1
endif
goto main

'++++++++ Motor Drive Pulse Out interrupt handler ++++++++++++++++++
EncChg: 'got here if GPIO 0-3 changed
EncOld = EncNew
EncNew = GPIO
if (EncNew & (%00001100)) = (EncOld & (%00001100))then ' man enc same?
TrvCnt = TrvCnt + 1 ' trav moved: count travel interrupts
endif
ManCnt = ManCnt + 1 ' else: Man moved:count man interrupts
@ INT_RETURN
end
Anyone care to take another look?

boroko
- 12th November 2009, 09:27
HI all,
I'm in the process of moving this over to a larger PIC so that I can have a chance to get some debugging info out of it. I have some 16F627's that will run at 20MHz instead of the 12F675 @ 4MHz. That will allow some HSEROUT data to give me a better look at what's happening and some headroom in the speed area. Thought I could just whip this one out, but alas, too big for my pants again...
Bo

boroko
- 24th November 2009, 22:01
HI all,
I moved this to a 16F627 and made the code as straight as I could.

The problem is much like it has been for a while: The direction signal is erratic and can be tricked by interaction with the other encoder.

Any thoughts would be appreciated.

'************************************************* ***************
'* Notes : 16F627@20mhz, HS_OSC *
'* : PBP 2.50c, MPASM: 5.11,
' 1) Quadrature encoder reading direction and speed of mechanical slide.
' 2) Motor (servo) driven in ONE direction of slide movement,
' not driven for other direction. Pulse & Direction drive LOW.
' 3) Manual Encoder to drive servo either direction manually.
' 16F627
' ----------------u-----------------
' -1|RA2/AN2/Vref RA1/AN1 |18- direction LEVEL output
' -2|RA3/AN3/CMP1 RA0/AN0 |17- Step PULSE o/p, Active LOW
' -3|RA4/TOCKI/CMP2 RA7/OSC1/CLKIN |16-
' -4|RA5/MCLR/vpp RA6/OSC2/CLKOUT |15-
' -5|-- VSS VDD++ |14-
' -6|RB0/INT RB7/T1OSI/PGD |13- Manual Encoder B input
' -7|RB1/RX/DT RB6/T1OSCO/T1CKI/PGC |12- Manual Encoder A input
' -8|RB2/TX/CK RB5 |11- Travel encoder B input
' -9|RB3/CCP1 RB4/PGM |10- Travel encoder A input
' ----------------------------------

DEFINE OSC 20
INCLUDE "AllDigital.pbp"
clear
P_out var PORTA.0 ' Step PULSE output to motor, Active LOW
D_out var PORTA.1 ' LEVEL output for direction
syncM var PORTA.2 ' output for testing timing
syncI var PORTA.3
Dir VAR byte ' Direction
EncOld var byte
EncNew var byte
OPTION_REG = %00000000 ' Pull-up Enabled
TRISA = %00000000
TRISB = %11110000
TravEnc con %00110000
ManEnc con %11000000
P_out = 1 ' start out HI. Moves on LOW pulse
goto Main
'********** Subs ***************************
ManDrive:
Dir = EncNew.7 ^ EncOld.6 ' XOR new L bit > Old Rt bit=Direction
D_out = Dir ' set direction pin
pauseus 2 ' minimum 3.5uS for Gecko drive
P_out = 0 ' send drive pulse either dir
pauseus 2
P_out = 1 ' reset drive pulse
return
TravDrive:
D_out = 1 ' set direction pin
Dir = EncNew.5 ^ EncOld.4 ' XOR new L bit > Old Rt bit=Direction
If DIR = 0 then ' end if travel DOWN
P_out = 0 ' send drive pulse retract only
pauseus 2
P_out = 1 ' reset drive pulse
endif
return
'******* MAIN ***********************************************
Main:
'TOGGLE syncM ' pulse to time Main loop
EncNew = PORTB ' get the new state of both encoders
if (EncNew & ManEnc) != (EncOld & ManEnc) then ' man not same? Drive Man
gosub ManDrive
endif
if (EncNew & travEnc) != (EncOld & TravEnc) then ' Trav not same? Drive Trav
GOSUB TravDrive
endif
EncOld = EncNew ' save the previous state of both encoders
goto main
end
Thanks
Mark

boroko
- 29th November 2009, 02:29
Well, this one has been quite a ride.... I've spent weeks trying to figure this out. I was in the middle of trying to craft a more detailed question that might generate some interest. One encoder was working wonderfully the way I expected, and the other, with almost the exact same code was causing all kinds of problems. I was in the process of using my Logic pod (which I love BTW: www.Saleae.com (http://www.Saleae.com)) to see if I could describe the problem better. I had a heartbeat pulse in the main and noticed that it would cut out for almost 3 mS when RB.4 changed. After looking at the datasheet for the ump-teenth time, I realized that I hadn't disabled the Low Voltage Programming option. That was it. Bet I won't take this long to look at that again!
Thanks for all of you who looked at it, and especially those that took the time to give some feedback.
Bo