Instant Int and encoder (Elect. Gearing)


Closed Thread
Results 1 to 14 of 14
  1. #1
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    231

    Default Instant Int and encoder (Elect. Gearing)

    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

  2. #2
    skimask's Avatar
    skimask Guest


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by boroko View Post
    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.

  3. #3
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    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,
    DT

  4. #4
    skimask's Avatar
    skimask Guest


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Darrel Taylor View Post
    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...

  5. #5
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    231


    Did you find this post helpful? Yes | No

    Default

    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

  6. #6
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    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>
    DT

  7. #7
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    231


    Did you find this post helpful? Yes | No

    Default Progress, but not right yet...

    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
    Code:
    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
    Last edited by boroko; - 21st March 2008 at 08:14. Reason: Add Processor Info

  8. #8
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    The interrupt type should be PBP.
    Code:
    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.
    DT

  9. #9
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    231


    Did you find this post helpful? Yes | No

    Default

    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/show...9510#post49510

    Does that help this make sense a bit more?

    Thanks
    Bo

  10. #10
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by boroko View Post
    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 ...
    Code:
    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>
    DT

  11. #11
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    231


    Did you find this post helpful? Yes | No

    Default servo feed revisited

    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.
    Code:
    ' 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?

  12. #12
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    231


    Did you find this post helpful? Yes | No

    Default

    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

  13. #13
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    231


    Did you find this post helpful? Yes | No

    Default

    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.
    Code:
    '****************************************************************
    '*  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

  14. #14
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    231


    Did you find this post helpful? Yes | No

    Default Gotta learn the hard way....

    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) 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

Similar Threads

  1. Using PICBASIC PRO in MPLAB IDE
    By jblackann in forum General
    Replies: 8
    Last Post: - 4th May 2008, 10:20

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts