Assembly limit on counter. Need help ASAP please!

Status
Not open for further replies.

no1010

New Member
Hi,

I've literally spent the entire night figuring out how to use interrupts. I have finally managed to get it working and to have a counter count while I keep a button pressed.

The problem is, the counter is obviously 8 bits, which can go to 255(256) but I want to limit it to go only to 9(10). How do I achieve that? So basically, count up to ten and then reset to 0 instead of incrementing to 11.

The loop that runs while the button is pressed, looks like this:
Code:
count_loop
	call	_4 ;Delay to decrease speed, so that you can see the register increment.
	incf	delaycnt,f	;increments the counter
	movfw	delaycnt
	movwf	PORTA
	btfsc	PORTB,0		;Waits for button release
	goto	count_loop
I thought there might be a way to 'force' a loop to quit after x amount of runs? but this is a bit impractical, since the button would still be pressed and that could cause problems.

Lastly, and this is the tricky part (I think), I want to change the delay that is being called in the main loop according to the value of delaycnt. ie. when delay count is 10, I call the shortest delay, and when it is one, I call the longest.
Is this possible?

Thanks in advance!
 
Last edited:
Here's one section of a clock interrupt routine I'm using, it performs a seconds count, and resets to zero at 60 seconds

Code:
        		clrf    MSecs
        		bsf		Flags,FlagSecs	; set seconds flag

        		incf    Secs,F			; increment 1 second counter
        		movlw   d'60'           ; Is Secs = 60 yet?
        		subwf   Secs,W
        		btfss   STATUS,Z        ; If Secs is not 60, end ISR.
        		bra	    EndTimer1Interrupt
; Reinitialize Secs
        		clrf    Secs
 
The problem is, the counter is obviously 8 bits, which can go to 255(256) but I want to limit it to go only to 9(10). How do I achieve that? So basically, count up to ten and then reset to 0 instead of incrementing to 11.
You could compare the counter value with 11 & clear it if it's equal. e.g.

Code:
count_loop
	call	_4 ;Delay to decrease speed, so that you can see the register increment.
	incf	delaycnt,f	;increments the counter

	movlw  11
        xorwf   delaycnt,w
	btfsc   status,z       ; if it's equal to 11 now, reset it to 0
        clrf      delaycnt

	movfw	delaycnt
	movwf	PORTA
	btfsc	PORTB,0		;Waits for button release
	goto	count_loop

I thought there might be a way to 'force' a loop to quit after x amount of runs? but this is a bit impractical, since the button would still be pressed and that could cause problems.
There is many ways to do that. I'm guessing you just want to limit the maximum count; i.e. while the button is pressed, the counter counts up to a maximum of, say, 10 - then the counter just sits at 10 until the button is released. The code for this could be:


Code:
count_loop
	call	_4 ;Delay to decrease speed, so that you can see the register increment.

	movlw  10
        xorwf   delaycnt,w
	btfss   status,z       ; if it's not equal to 10 now, then increment it
	incf	delaycnt,f	;increments the counter

	movfw	delaycnt
	movwf	PORTA
	btfsc	PORTB,0		;Waits for button release
	goto	count_loop

Just subtract: delayCounts = 11 - delaycnt; this will give a delayCounts value of 1 if delaycnt is 10, and delayCounts of 10 when delaycnt is 1
 
Hi, thanks for the reply!
That first bit of code to limit it delaycnt to 10 is exactly what I was looking for!
This last bit is also very usefull, except I'm not so sure how to do subtraction in assembly.
What does xorfw, delaycnt, w do exactly?
Status,z?

The last bit of info I need is this,
How do I change the delays depending on what delaycnt is?
Ie. If delaycnt = 10, the shortest delay is called in my stepper motor loop.
I cant just use delaycnt since a label cannot start with a number. Thus I need to call _10 when delaycnt is 10. How would I manage that?
 
This last bit is also very usefull, except I'm not so sure how to do subtraction in assembly.
Use sublw or subwf or subfw.

What does xorfw, delaycnt, w do exactly?
Status,z?
movlw 11 puts 11 in w
xorwf delaycnt,w xors the 11 (in w) with the value in delaycnt (result goes into w, but we don't need it)
if delaycnt was 11, the xor operation above would set the zero bit in the status register. We could have used the subtraction to the same effect (11 xor 11 is 0; 11 - 11 is also 0)

Well, you haven't shown what your delay function is... so I'll just assume you have one called Delay. The usual way to have a variable delay is to pass a parameter to the delay function (e.g. in the w register). I'm guessing you've never done that, so I'll show you another way:

Code:
; ok, so we just exited the loop and have the value of delaycnt in w
  sublw 11   ; subtract w from 11
  movwf loopsToRun   ; store the value in a new variable 'loopsToRun'

loop:
  call Delay              ; call the delay function
  decfsz loopsToRun  ; once for every count in loopsToRun
  goto loop              ; goto loop (until the above line decreases loopsToRun to 0)
 

Thanks for al the help and info, it is much appreciated.

The sublw that you mentioned is exactly what I need. The problem is, it does not seem to do anything!

My code is as follows.
Code:
Speed_Set_rt
	clrf	Speed_cnt		;Clears Speed_cnt to start counting again... can be commented out to keep on counting instead of resetting.
	clrf	PORTA			;Clears the LEDs
	btfss	PORTB,0			;waits for button press
	goto	$-1				;else it loops
	
Speed_set_loop
	call	_400			;The delays slows the program down so that the register increments are visible on LEDs
	call	_400			;2500 cycles (roughly)
	call	_400
	call	_400
	call	_400
	call	_400
	call	_100
	incf	Speed_cnt,f		;increments the Speed counter

	movlw	d'11'			;used to stop Speed_cnt from going higher than 10
	xorwf	Speed_cnt,w		;XORs Speedcnt
	btfsc	STATUS,Z		;If it is equal to 11, reset it
	clrf	Speed_cnt		;Clears Speedcnt if it is 11

	movfw	Speed_cnt		;Writes Speed_cnt to work register
	movwf	PORTA			;Outputs work on PORTA
	btfsc	PORTB,0			;Waits for release of button
	goto	Speed_set_loop	;otherwise it loops
	
	call	Bounce			;Runs  delay to account for 'bounce' of tactile switch
	
	btfsc	PORTB,0			;Tests for release again...
	goto	Speed_set_loop	;If still pressed, loop again
	bcf		INTCON,INT0IF	;Clears interrupt
	sublw	d'11'			;Subtracts work from 11, to invert Speed, its not working atm
	movwf	Speed			;Moves inverted value to speed
	goto	Interrupt_exit	;Exits interrupt routine

And my delay:

Code:
Delay
	movfw	speed
	movwf	counter0
	decfsz	counter0,f
	goto	$-1				;NB, if something goes wrong... add this: movfw	Speed_cnt & movwf	speed
	retlw	0x00

I can comment sublw 11 out, and it still runs, from 1 to ten instead of ten to 1.
Not sure why?
 
try
movfw speed_cnt
sublw 11

Will do thanks, unfortunately it seems my motor has somehow de-magnetized (the only plausible reason for it's sudden strange behaviour).
It was working fine until a wire came loose from the 24V power supply. After fixing it and plugging it back in, the motor was making stuttering turns. I thought it might be the transistors, but I've replaced all of them and it still stuttering.
So I'll have to go buy a new one, since it is a Uni project and we have to present at 12noon. No shops open yet (5:30am) so I'll have to wait a bit.

Will try it asap though.

Once again, thank you very much for the guidance, you helped me get a critical part of the project working!

Chris
 
I just want to say thank you to everyone that had a hand in helping me with my project. I learned quite a bit thanks to all of you!

Regards,
1010
 
I can comment sublw 11 out, and it still runs, from 1 to ten instead of ten to 1.
Not sure why?

Code:
Delay
	movfw	speed
	movwf	counter0
	decfsz	counter0,f
	goto	$-1				;NB, if something goes wrong... add this: movfw	Speed_cnt & movwf	speed
	retlw	0x00

It's because you're DECREMENTING instead of INCREMENTING, and with the "decfsz" instruction you don't need to compare because the instruction says to "DECriment the value in File address that is defined in operand, Skip if value in file = Zero". Incrementing up from zero to 10 is the exact same thing as decrementing from 10 to zero, and the instruction already states to branch if the register equals zero (which it automatically checks the Z bit every time it decrements to see if the result of the decrement = 0), so you no longer need to subtract/check the Z bit continuously.
 
Last edited:
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…