Trying to countdown large number assembly pic code

Discussion in 'Programmer's Corner' started by bluebrakes, Jul 29, 2011.

  1. bluebrakes

    Thread Starter Active Member

    Oct 17, 2009
    245
    7
    I've been working on some code, which basically pulses RB0 (defined as STEPPER2) until the countsteps equal zero.

    Because I need to work with a bigger number than 255, countstepL handles the smaller digits, whilst i would like countstepH to act like the bigger number. Ideally upto 65,000

    I can't seem to see why it only allows up to 255, despite putting 255 in both countstepL and countstepH.

    any ideas? :)

    Code ( (Unknown Language)):
    1. runstepper movf countstepH, w         ; Copy contents of address to W
    2.         xorlw 0x00                         ; Is it Zero? Logical-XOR W with value, place result in W
    3.         btfsc STATUS, Z                 ; Test bit, skip next instruction if bit is 0
    4.         goto checkstepL                 ; if it is zero goto check countstepL if its zero
    5.        
    6.         checkstepL movf countstepL, w     ; Copy contents of CountstepL to W register
    7.         xorlw 0x00                         ; Is it zero? So do the opposite. If the bit is 1 then goto main
    8.         btfsc STATUS, Z                 ; Test bit, skip next instruction if bit is 1
    9.         goto main                         ; Reset the pic back to the start of the program
    10.        
    11.        
    12.         decfsz countstepL, f             ; Decrease value by 1 and skip next instruction if result is 0
    13.         goto runit                        ; If countstepL equals zero then goto runit
    14.         decf countstepH, f                ; decrement countstepH by 1
    15.        
    16.     runit BSF STEPPER2                     ; Turn on Step output
    17.         call Delay                         ; Delay by 500micro seconds
    18.         BCF STEPPER2                     ; Turn off Step Output
    19.         call Delay                         ; Delay by 500micro seconds
    20.        
    21.     goto runstepper
     
  2. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    I think this should fix it. Removing the xorlw lines makes no difference because movf sets the Zero bit anyway.
    Code ( (Unknown Language)):
    1. runstepper movf countstepH, w         ; Copy contents of address to W
    2. [B]    ;    xorlw 0x00   [/B]                      ; Is it Zero? Logical-XOR W with value, place result in W
    3.         btfsc STATUS, Z                 ; Test bit, skip next instruction if bit is 0
    4.         goto [B]continue[/B]                 ; if it is zero goto check countstepL if its zero
    5.        
    6.         movf countstepL, w     ; Copy contents of CountstepL to W register
    7. [B]    ;    xorlw 0x00[/B]                         ; Is it zero? So do the opposite. If the bit is 1 then goto main
    8.         btfsc STATUS, Z                 ; Test bit, skip next instruction if bit is 1
    9.         goto main                         ; Reset the pic back to the start of the program
    10.        
    11. [B]continue[/B]  
    12.      
    13.         decfsz countstepL, f             ; Decrease value by 1 and skip next instruction if result is 0
    14.         goto runit                        ; If countstepL equals zero then goto runit
    15.         decf countstepH, f                ; decrement countstepH by 1
    16.        
    17.     runit BSF STEPPER2                     ; Turn on Step output
    18.         call Delay                         ; Delay by 500micro seconds
    19.         BCF STEPPER2                     ; Turn off Step Output
    20.         call Delay                         ; Delay by 500micro seconds
    21.        
    22.     goto runstepper
     
  3. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    Your bit test instruction for the countstepH byte is backwards. That's very easy to do with those bit test instructions and why I prefer using skpz (skip if zero) or skpnz (skip not zero) pseudo instructions instead of the bit test instructions.

    Your counter decrement code isn't quite right either. Here's an alternative (below);

    Cheerful regards, Mike

    Code ( (Unknown Language)):
    1.  
    2. runstepper
    3.         movf    countstepH,W    ;
    4.         iorwf   countstepL,W    ; counter running (non-zero)?
    5.         skpnz                   ; yes, skip, else  (skpnz = btfsc STATUS,Z)
    6.         goto    main            ; counter = 0 so branch and restart
    7.  
    8.         movf    countstepL,W    ; is lo byte = 0?
    9.         skpnz                   ; no, skip, else
    10.         decf    countstepH,F    ; decrement hi byte
    11.         decf    countstepL,F    ; decrement lo byte
    12.  
    13.         bsf     STEPPER2        ; Turn on Step output
    14.         call    Delay           ; Delay 500 usecs
    15.         bcf     STEPPER2        ; Turn off Step output
    16.         call    Delay           ; Delay 500 usecs
    17.         goto    runstepper      ; loop        
    18.  
    19.  
     
    Last edited: Jul 30, 2011
  4. bluebrakes

    Thread Starter Active Member

    Oct 17, 2009
    245
    7
    Thanks guys.
    Mike that code works a treat! thanks very much.

    the code is coming along nicely now. although I need to work out how i'm going to make a variable delay from 1ms to 255ms based on what is in a memory address.
     
  5. bluebrakes

    Thread Starter Active Member

    Oct 17, 2009
    245
    7
    This code works great but suppose i want to choose between STEPPER1, STEPPER2 or STEPPER3 based on what the value of StepChoice is, what would be the best way to do that?
    So for example if StepChoice equals 0x31 then use STEPPER1, if it equals 0x32 then use STEPPER2, 0x33 then STEPPER3

    Code ( (Unknown Language)):
    1. runstepper
    2.         movf    countstepH,W    ; Copy contents of address to W
    3.         iorwf   countstepL,W    ; counter running (non-zero)?
    4.         skpnz                   ; yes, skip, else  (skpnz = btfsc STATUS,Z)
    5.         goto    main            ; counter = 0 so branch and restart
    6.  
    7.         movf    countstepL,W    ; is lo byte = 0?
    8.         skpnz                   ; no, skip, else
    9.         decf    countstepH,F    ; decrement hi byte
    10.         decf    countstepL,F    ; decrement lo byte
    11.  
    12.         bsf     [B]STEPPER2[/B]        ; Turn on Step output
    13.         call    Delay           ; Delay 500 usecs
    14.         bcf     [B]STEPPER2[/B]        ; Turn off Step output
    15.         call    Delay           ; Delay 500 usecs
    16.  goto    runstepper      ; loop
     
  6. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    One way you might attack the problem is to use another variable which contains a bit mask for for the selected stepper. For example, stuff the variable with a value of '0001000' (RB4), '00100000' (RB5), or '01000000' (RB6) based on your StepChoice of '1', '2', or '3'. Modify your driver to use the stepper select bit mask variable;

    Code ( (Unknown Language)):
    1. ;
    2. ;  generate a 500-us step pulse for selected stepper
    3. ;
    4.         movf    selectmask,W    ; 01000000, 00100000, or 00010000
    5.         iorwf   PORTB,F         ; turn selected stepper output "on"
    6.         call    Delay           ; Delay 500 usecs
    7.         comf    selectmask,W    ; 10111111, 11011111, or 11101111
    8.         andwf   PORTB,F         ; turn selected stepper output "off"
    9.         call    Delay           ; Delay 500 usecs
    10.         goto    runstepper      ; loop  
    11.  
     
    Last edited: Jul 31, 2011
  7. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    Delays can be tricky. If you were to implement a general purpose fixed delay subsystem, you might use it in your program like this;

    Code ( (Unknown Language)):
    1.         radix   dec
    2. runstepper
    3.         movf    countstepH,W    ;
    4.         iorwf   countstepL,W    ; steps remaining (non-zero)?
    5.         skpnz                   ; yes, skip, else
    6.         goto    main            ; counter = 0 so branch and restart
    7.  
    8.         movf    countstepL,W    ; is lo byte = 0?
    9.         skpnz                   ; no, skip, else
    10.         decf    countstepH,F    ; decrement hi byte
    11.         decf    countstepL,F    ; decrement lo byte
    12. ;
    13. ;  generate a 500-us step pulse
    14. ;
    15.         bsf     STEPPER2        ; stepper pulse "on"
    16.         DelayCy(500*usecs)      ; delay 500-us
    17.         bcf     STEPPER2        ; stepper pulse "off"
    18. ;
    19. ;  inter-step delay, 1..255 msecs ("stepdelay")
    20. ;
    21.         movf    stepdelay,W     ; inter-step delay, 1..255 msecs
    22.         movwf   count           ; local copy (preserve 'stepdelay')
    23. s1      DelayCy(1*msecs-3)      ; 1 ms minus 3 cycle loop time
    24.         decfsz  count,F         ; done? yes, skip, else
    25.         goto    s1              ; loop
    26.  
    27.         goto    runstepper      ; next step
    28.  
    Of course you could use delay code from one of those delay code generators, but if you're interested, here's a general purpose "cycle-accurate" fixed delay subsystem example in a form suitable for simulation testing with the MPLAB "stopwatch". The subsystem uses a macro front end, one 8-bit variable, and a nine word timing subroutine. It's also designed to work with almost any clock (4, 8, 12, 16, 20 MHz) according to the value in the "clock" equate.

    Code ( (Unknown Language)):
    1. delayhi equ     0x20            ; DelayCy() subsystem variable
    2.  
    Code ( (Unknown Language)):
    1.  
    2. ;******************************************************************
    3. ;  K8LH DelayCy() subsystem macro generates four instructions     *
    4. ;******************************************************************
    5.         radix   dec
    6. clock   equ     4               ; 4, 8, 12, 16, 20 (MHz), etc.
    7. usecs   equ     clock/4         ; cycles/microsecond multiplier
    8. msecs   equ     clock/4*1000    ; cycles/millisecond multiplier
    9.  
    10. DelayCy macro   delay           ; 11..327690 cycle range
    11.         movlw   high((delay-11)/5)+1
    12.         movwf   delayhi
    13.         movlw   low ((delay-11)/5)
    14.         call    uDelay-((delay-11)%5)
    15.         endm
    16. ;******************************************************************
    17.         org     0x000           ; example for simulation testing
    18. SimTest
    19.         DelayCy(200*usecs)      ; <- put simulator PC here
    20.         goto    $               ; <- put simulator break point here
    21. ;******************************************************************
    22. ;  K8LH DelayCy() 16-bit uDelay (11..327690 cycle) subroutine     *
    23. ;******************************************************************
    24.         nop                     ; entry for (delay-11)%5 == 4     |B0
    25.         nop                     ; entry for (delay-11)%5 == 3     |B0
    26.         nop                     ; entry for (delay-11)%5 == 2     |B0
    27.         nop                     ; entry for (delay-11)%5 == 1     |B0
    28. uDelay  addlw   -1              ; subtract 5 cycle loop time      |B0
    29.         skpc                    ; borrow? no, skip, else          |B0
    30.         decfsz  delayhi,F       ; done?  yes, skip, else          |B0
    31.         goto    uDelay          ; do another loop                 |B0
    32.         return                  ;                                 |B0
    33. ;******************************************************************
    34.         end
    35.  
     
    Last edited: Aug 3, 2011
  8. bluebrakes

    Thread Starter Active Member

    Oct 17, 2009
    245
    7
    blimey.... that is a massive help. Thank you so much! :)
     
  9. bluebrakes

    Thread Starter Active Member

    Oct 17, 2009
    245
    7
    OK I have a really weird problem going on with this code. When I run this code with different numbers in the countstepH and countstepL, I get really strange results.

    i.e. if want the stepper to do 14,800 steps. I put 185 into countstepL and 80 into countstepH. However, if i put 100 in and 148 in, the motor does an extra 1000 or so steps.

    i don't get it. :confused:

    the whole idea of that code is it does a countdown on the countstepL to zero and then subtracts countstepH by one until both equal zero.

    It's definately not the stepper motor skipping steps or something like that, as I can tell it to go 185x80 forward and then tell it to do the same in reverse and it always lands on the same spot it started on.... precisely.
     
  10. bluebrakes

    Thread Starter Active Member

    Oct 17, 2009
    245
    7
    ok the problem just gets weirder.
    If I ask it to do 14,500 steps the stepper motor turns the gearbox round perfectly to one revolution (countstepL = 250 countstepH = 57). Yet if i ask it do 14,400 steps (240x59) it goes further than 14,500.

    Something is getting lost in translation or something.
     
  11. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    Could it be a math problem?

    countstepH = 80, countstepL = 180 --> 80*256+185 = 20665

    countstepH = 57, countstepL = 250 --> 57*256+250 = 14842
    countstepH = 59, countstepL = 240 --> 59*256+240 = 15344

    Here's one way to setup counstepH:L for 14400 steps;
    Code ( (Unknown Language)):
    1.         radix   dec
    2.  
    3.         movlw   high(14400)     ; 0x38 or 56
    4.         movwf   countstepH      ;
    5.         movlw   low(14400)      ; 0x40 or 64
    6.         movwf   countstepL      ;
    7.  
     
    Last edited: Aug 13, 2011
  12. bluebrakes

    Thread Starter Active Member

    Oct 17, 2009
    245
    7
    Thanks for the quick reply :)

    bingo! :)

    although there still appears to be a problem and it has just turned into a can of worms this project. :(

    It's still inconsistant with the number of steps i ask it to do and yet it doesn't seem to be losing steps because i can rewind the number of steps and it lands precisely back to the point it started.

    So anyway here is an example of the problem...

    I ask the pic to step the stepper motor 15050 times, which is one complete revolution of the output shaft of the gearbox. If I ask it do 7525 steps twice (15050 / 2) it should do the same number of steps as 15050, but it doesn't. It falls short and roughly by 250 steps.

    Yet if i ask the stepper motor to do 15050 several times, it lands perfectly each time.

    However, if i ask it to do 45150 it over steps. :confused::confused:
     
  13. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    Perhaps you could show the code you're using to setup the count variable?
     
  14. bluebrakes

    Thread Starter Active Member

    Oct 17, 2009
    245
    7
    It's probably easier to post the whole program and explain how it works.

    So a little info about how it works.

    Sending a < or > tells the PIC to turn on/off RB5 which is connected to an optoisolator. This determines all the stepper motor directions, seeing as only one stepper can be driven given at one time. Not that i really need the facility to drive all three at once.

    To drive a stepper motor you need to send these three in sequence.
    Sending A, B or C selects the stepper motor you want to drive.
    Next character it receives (0-255) is the low countstep and then followed by the high countstep.

    Everytime the pic finishes a command, it sends a 'ÿ' character back to the computer, so it knows that the pic is ready for the next command.

    Sending a '?' character sends the computer the firmware version on the pic.

    See PDF copy of the program.... thanks! :)
     
    Last edited: Aug 14, 2011
  15. bluebrakes

    Thread Starter Active Member

    Oct 17, 2009
    245
    7
    p.s. it wouldn't let me copy and paste the whole code in. So i had to convert it to pdf. :)
     
  16. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    Can you send me the source file? Check your PM (private messages) for a message with my email address.

    Regards, Mike
     
  17. bluebrakes

    Thread Starter Active Member

    Oct 17, 2009
    245
    7
    thanks mike. email sent. :)
     
  18. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    Ok, this is what I was asking you to send;

    Code ( (Unknown Language)):
    1. ; -------------------------------------------------------------------------------------
    2. stepcmd1    
    3. ;
    4. ; Get the number of steps for the low Bit
    5. ;
    6.         clrf    countstepL      ; Set counter register to zero
    7.         call    receive         ; Wait for next serial instruction for the low number
    8.         movwf   countstepL      ; Copy contents of W register into memory address
    9. ;
    10. ; Get the number of steps for the high bit
    11. ;    
    12.         clrf    countstepH      ; Set counter register to zero
    13.         call    receive         ; Wait for next serial instruction for the High number
    14.         movwf   countstepH      ; Copy contents of W register into memory address
    15.    
    16.         call    runstepper1     ; Once it has all the necessary steps goto runstepper
    17.  
    What single character or value are you sending via serial that gets placed into "counterstepL"? How are you sending it (Hyperterminal or some program)? I wonder if this may be the problem?

    Good luck... Regards...
     
    Last edited: Aug 15, 2011
Loading...