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
 
Powered by vBulletin® Version 4.1.7 Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.