Incrementing count with switch/button

Status
Not open for further replies.

no1010

New Member
Hi,

I have a program running on a 16F88 that controls a stepper motor.

I now want to change it's speed (ie. delays) in ten increments using a button.

The button press should count up to ten (1001) and then reset to 1(0000).
on each level a different delay should be used between each step of the motor.

ie.

if Button_count = 0000
delay = 11mS

...

if Button_count = 1001
delay = 1mS

Loop
Step 1
call delay
Step 2
call delay
Step 3
call delay
Step 4
call delay
goto Loop

Now the problem is, I have no idea how to increment a counter with a button and secondly, I have no idea how to enable the button to be pressed at any time and have the µController reset the delay.

I suspect interrupts, but I have no clue how to set it up on the 16F88.
I'm relatively new to assembly so I'm struggling a bit with this.

Also, before the loop restarts after the delay has been given a new value, I need to turn on 4 LEDs that display the speed level in binary, how can I reference this from the delay/Button_count?

Any and all help will be appreciated, even if you can only point me in the right direction.
This has to be handed in on Friday, so I'm in a bit of a jam.
 
when you click on the microcontroler section of this forum, there is a "new to microcontroler section" there are many tutorials there that have a count up practice.. Nigels is one that i used and also gooligum and tracys. that should help get you started on the "incrementing counters" part of it.
 
Hi, thanks for the tip. I did look at Nigel's tutorials as well as Tracy's.
I also found a bunch on PICLIST.

Unfortunately, the interrupt I am trying to use... doesn't interrupt the program! (interrupt is a tactile switch - can I use it? wired with a 390R from positive to tactile switch to RB0)

My interrupt sequence is a follows:
Code:
	bsf INTCON,INT0IE	;Enables RB0 as interrupt
	bsf INTCON,GIE		;Enables interrupt globally

Count_int
	btfsc INTCON, RBIE				;Check for interrupt on RB0
		goto count_routine

ISR       ORG     0x0004            ; interrupt vector location

;         Context saving for ISR
          MOVWF   W_TEMP            ; save off current W register contents
          MOVF    STATUS,W          ; move status register into W register
          MOVWF   STATUS_TEMP       ; save off contents of STATUS register
          MOVF    PCLATH,W          ; move pclath register into W register
          MOVWF   PCLATH_TEMP       ; save off contents of PCLATH register

count_routine
		clrf	delaycnt
	btfsc	PORTA,4	;waits for button press
	goto	$-1			;else it loops
	
count_loop
	incf	delaycnt, f	;increments the counter
	incf	PORTA, f	;increments PORTA to show count on LEDs
	
	call	Temp		;...2500 operations? aint that too long?
	
	btfss	PORTA,4	;Waits for release
	goto	$-1
	
	call	Temp		;milliseconds...
	
	btfss	PORTA,4	;Tests for release again...
	goto	count_loop
	goto	Interrupt_exit

Interrupt_exit						;Restore context before returning from interrupt
          MOVF    PCLATH_TEMP,W     ; retrieve copy of PCLATH register
          MOVWF   PCLATH            ; restore pre-isr PCLATH register contents
          MOVF    STATUS_TEMP,W     ; retrieve copy of STATUS register
          MOVWF   STATUS            ; restore pre-isr STATUS register contents
          SWAPF   W_TEMP,F
          SWAPF   W_TEMP,W          ; restore pre-isr W register contents
          RETFIE                    ; return from interrupt

Delaycnt is set up top @

CBLOCK 0x20 ; Sample GPR variable registers allocated contiguously
counter0 ; Counter used for delays
counter1 ; Ditto
delaycnt ; Counter used for setting delays
ENDC

But for some reason when I press the button, it does nothing!

O yes, TRISA and TRISB are set up as follows:

banksel TRISA

movlw b'00010000' ;bit 0,1,2,3 outputs and bit4 input-count button
movwf TRISA

banksel TRISB ;Is this neccesary?

movlw b'11100001' ;Set bits 1,2,3,4 as outputs. Bit 0 is the interrupt input.
movwf TRISB
 
btfsc INTCON, RBIE ;Check for interrupt on RB0
goto count_routine

ISR ORG 0x0004 .........this is where you instruction will go if the bit tests clear????
 
Sorry, I posted snippets of my code. The entire thing looks like this:

Code:
;******************************************************************************
;                                                                             *
;    Filename:		16F88Test.asm                                             *
;    Date:			13 May 2011                                               *
;    File Version:	1.0                                                       *
;                                                                             *
;    Author:     	Chris Fourie                                              *
;                                                                             *
;******************************************************************************
;                                                                             *
;    Notes:		_25mS														  *
;					movlw   .1												  *
;        			movwf   counter0										  *
;       			nop														  *
;        			decfsz  counter1,f										  *
;        			goto    $-2												  *
;        			decfsz  counter0,f                                        *
;        			goto    $-4                                               *
;        			retlw   00												  *
;																			  *
;				Actually works @ 140mS										  *
;				At least motor turns...                                       *
;                                                                             *
;******************************************************************************

;------------------------------------------------------------------------------
; PROCESSOR DECLARATION
;------------------------------------------------------------------------------

     LIST      p=16F88              ; list directive to define processor
     #INCLUDE <P16F88.INC>          ; processor specific variable definitions

;------------------------------------------------------------------------------
; CONFIGURATION WORD SETUP
;------------------------------------------------------------------------------

     __CONFIG    _CONFIG1, _CP_OFF & _CCP1_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_OFF & _WDT_OFF & _INTRC_IO
     __CONFIG    _CONFIG2, _IESO_OFF & _FCMEN_OFF

;------------------------------------------------------------------------------
; VARIABLE DEFINITIONS
;------------------------------------------------------------------------------

    CBLOCK 0x20 ; Sample GPR variable registers allocated contiguously
        counter0  ; Counter used for delays
        counter1  ; Ditto
        delaycnt  ; Counter used for setting delays
    ENDC

W_TEMP         EQU        0x7D  ; w register for context saving (ACCESS)
STATUS_TEMP    EQU        0x7E  ; status used for context saving (ACCESS)
PCLATH_TEMP    EQU        0x7F  ; variable used for context saving

;------------------------------------------------------------------------------
; EEPROM INITIALIZATION
;------------------------------------------------------------------------------

DATAEE    ORG  0x2100
    DE    "MCHP"  ; Place 'M' 'C' 'H' 'P' at address 0,1,2,3

;------------------------------------------------------------------------------
; RESET VECTOR
;------------------------------------------------------------------------------

RESET     ORG     0x0000            ; processor reset vector
          PAGESEL START
          GOTO    START             ; go to beginning of program

;------------------------------------------------------------------------------
; INTERRUPT SERVICE ROUTINE
;------------------------------------------------------------------------------

ISR       ORG     0x0004            ; interrupt vector location

;         Context saving for ISR
          MOVWF   W_TEMP            ; save off current W register contents
          MOVF    STATUS,W          ; move status register into W register
          MOVWF   STATUS_TEMP       ; save off contents of STATUS register
          MOVF    PCLATH,W          ; move pclath register into W register
          MOVWF   PCLATH_TEMP       ; save off contents of PCLATH register

;--------
;User ISR

Count_int
	btfsc INTCON, RBIE				;Check for interrupt on RB0
	goto count_routine
		
;--------

Interrupt_exit						;Restore context before returning from interrupt
          MOVF    PCLATH_TEMP,W     ; retrieve copy of PCLATH register
          MOVWF   PCLATH            ; restore pre-isr PCLATH register contents
          MOVF    STATUS_TEMP,W     ; retrieve copy of STATUS register
          MOVWF   STATUS            ; restore pre-isr STATUS register contents
          SWAPF   W_TEMP,F
          SWAPF   W_TEMP,W          ; restore pre-isr W register contents
          RETFIE                    ; return from interrupt
		  
;-----------------
;Interrupt routine
;-----------------
count_routine
		clrf	delaycnt
	btfsc	PORTA,4	;waits for button press
	goto	$-1			;else it loops
	
count_loop
	incf	delaycnt, f	;increments the counter
	incf	PORTA, f	;increments PORTA to show count on LEDs
	
	call	Temp		;...2500 operations? aint that too long?
	
	btfss	PORTA,4	;Waits for release
	goto	$-1
	
	call	Temp		;milliseconds...
	
	btfss	PORTA,4	;Tests for release again...
	goto	count_loop
	goto	Interrupt_exit
	
;------------------------------------------------------------------------------
; EQUATES
;------------------------------------------------------------------------------
;I'm using halfsteps, to smooth the turning, otherwise it stutters
TURNA	equ b'00000010'
TURNAB	equ b'00000110'
TURNB	equ b'00000100'
TURNBC	equ b'00001100'
TURNC	equ b'00001000'
TURNCD	equ b'00011000'
TURND	equ b'00010000'
TURNDA	equ b'00010010'

;------------------------------------------------------------------------------
; MAIN PROGRAM
;------------------------------------------------------------------------------

START

;Turn interrupts on:
	bsf INTCON,INT0IE	;Enables RB0 as interrupt
	bsf INTCON,GIE		;Enables interrupt globally

; A

	banksel TRISA
	
	movlw 	b'00010000'	;2,3,4,5 > outputs
	movwf 	TRISA
	
	banksel PORTA

	clrf	PORTA		;Clears Port A
	movlw	b'00000101'	;Turns on the lights... RA5 willie werkie(heeltyd aan)
	movwf	PORTA
	
; B
	
	banksel TRISB
	
	movlw 	b'11100001'	;Set bits 0,1,2,3 as outputs
	movwf 	TRISB

	banksel PORTB
	clrf 	PORTB		;Clears Port B
	

loop

	movlw TURNA
	movwf PORTB

	call _10

	movlw TURNAB
	movwf PORTB

	call _10

	movlw TURNB
	movwf PORTB

	call _10

	movlw TURNBC
	movwf PORTB

	call _10

	movlw TURNC
	movwf PORTB

	call _10

	movlw TURNCD
	movwf PORTB

	call _10

	movlw TURND
	movwf PORTB

	call _10

	movlw TURNDA
	movwf PORTB

	call _10

	goto loop

;--------------
; Delay routine
;--------------

_1						;9000 cycles
	movlw	0x06
	movwf	counter0
	movlw	0x08
	goto	Delay_1
_2						;6000 cycles
	movlw	0xAE
	movwf	counter0
	movlw	0x05
	goto	Delay_1
_3						;4000 cycles
	movlw	0x1E
	movwf	counter0
	movlw	0x04
	goto	Delay_1
_4						;2500 cycles
	movlw	0xF2
	movwf	counter0
	movlw	0x02
	goto	Delay_1
_5						;1600 cycles
	movlw	0x3E
	movwf	counter0
	movlw	0x02
	goto	Delay_1
_6						;800 cycles
	movlw	0x9E
	movwf	counter0
	movlw	0x01
	goto	Delay_1
_7						;400 cycles
	movlw	0x83
	goto	Delay_2
_8						;200 cycles
	movlw	0x41
	goto	Delay_3
_9						;100 cycles
	movlw	0x1F
	goto	Delay_2
_10						;20 cycles
	retlw	0x00
	goto	Delay_3
	
Delay_1
	movwf	counter1
	decfsz	counter0, f
	goto	$+2
	decfsz	counter1, f
	goto	$-3
	goto	$+1
	nop
	retlw	0x00
	
Delay_2
	movwf	counter0
	decfsz	counter0, f
	goto	$-1
	goto	$+1
	retlw	0x00
	
Delay_3	
	movwf	counter0
	decfsz	counter0, f
	goto	$-1
	retlw	0x00
	
;temporary routine...
Temp
			;993 cycles
	movlw	0xC6
	movwf	counter0
	movlw	0x01
	movwf	counter1
Temp_0
	decfsz	counter0, f
	goto	$+2
	decfsz	counter1, f
	goto	Temp_0

			;3 cycles
	goto	$+1
	nop

			;4 cycles (including call)
	return

          END
 
For some reason the interrupt is completely ignored when I try to animate the code, but when I run it, it stops the rotation of the motor and just stalls. If I pause it right after the stall, I can see it has entered the interrupt routine, but completely skips over the following, even if the button is still pressed.
Count_int
btfsc INTCON, RBIE ;Check for interrupt on RB0
goto count_routine
After it exits the Interrupt routine ( RETFIE ) the loop starts once again, but PORTB does not change as it should, it stays on whatever it was when the interrupt was activated.
???
 
im new at assembly also (bout 6 months) but just a quick glance is you have the trisB set wrong ,bits 1 to 4 and i usually have me mclr in the config set to off
 
You should be testing INTCON,INT0IF not RBIE and you must clear it before leaving the interrupt.

You are waiting for A4 in your interrupt and calling a delay. This will effectively stop your program. The interrupt should be as short as possible, set a flag and use that in your main code.

Mike.
 
Your code needs some serious re-organizing. Some questions -

What delay times are you trying to accomplish with your Delay_1, Delay_2, and Delay_3 loops?

What is the purpose of your ten subroutines labeled _1 - _10?

Also, the INTCON,INT0IE bit is the RB0 Interrupt Enable Bit. The flag bit you want to poll in your interrupt handler (which you really don't need to since the INT0 interrupt is the only unmasked interrupt you're using) would be INTCON,INT0IF, which is the RB0 interrupt flag bit that indicates the state of the triggered interrupt condition itself.

About backing up the registers in the interrupt handler. When you back up the STATUS register, you have to do it by swapping the nibbles in STATUS into the W register. Otherwise you corrupt the zero bit. You have to do the same thing when restoring the pre-interrupt STATUS state. Example code -

Code:
;temp backup routine

		movwf		W_TEMP
		swapf		STATUS,W
		movwf		STATUS_TEMP
		movf		PCLATH,W
		movwf		PCLATH_TEMP

;restore/return from interrupt routine

		movf		PCLATH_TEMP,W
		movwf		PCLATH
		swapf		STATUS_TEMP,W
		movwf		STATUS
		movf		W_TEMP,W
		retfie
 
Last edited:
Hi, yes I know, it was an absolute mess. everything was trail and error, I'm currently busy with the cleanup since I just figured out how to do the interrupt a few minutes ago. It's finally working, but I have a few more things that need to happen, before I am satisfied.
See: https://www.electro-tech-online.com/threads/assembly-limit-on-counter-need-help-asap-please.118841/ if your interested.

About the subroutines. I have ten different delays, 1-10 and I just compressed all ten into a single delay routine that changes which major Delay routine is used depending on what the individual delay requires.
ie. 1-6 all link to Delay 1 to complete their loops. 7&9 link to Delay 2, 8 uses Delay three and 10 just quickly jumps back.
I did this to avoid having 10 seperate delay routines.
 

After scrutinizing the data sheet and some other examples I found on PIClist I realized that I was using the wrong bit. I changed it and it's working now! Thanks for the info though.

This is what it currently looks like:

Code:
ORG     0x0004            ; interrupt vector location

	MOVWF   W_TEMP            ; save off current W register contents
	MOVF    STATUS,W          ; move status register into W register
	clrf	STATUS
	MOVWF   STATUS_TEMP       ; save off contents of STATUS register

;--------
;User ISR

Count_int
	btfsc	INTCON,INT0IF			;Check for interrupt on RB0
	call	count_routine
		
;--------

Interrupt_exit					;Restore context before returning from interrupt
	swapf   STATUS_TEMP,w     ; retrieve copy of STATUS register
	movwf   STATUS            ; restore pre-isr STATUS register contents
	swapf   W_TEMP,f
	swapf   W_TEMP,w          ; restore pre-isr W register contents
	retfie                    ; return from interrupt
		  
;-----------------
;Interrupt routine
;-----------------

count_routine
	clrf	delaycnt
	clrf	PORTA
	btfss	PORTB,0	;waits for button press
	goto	$-1		;else it loops
	
count_loop
	call	_4
	incf	delaycnt,f	;increments the counter
	movfw	delaycnt
	movwf	PORTA
	btfsc	PORTB,0		;Waits for release
	goto	count_loop
	
	call	Temp		;milliseconds...
	
	btfsc	PORTB,0		;Tests for release again...
	goto	count_loop
	bcf		INTCON,INT0IF
	goto	Interrupt_exit
 

OK, and what are the delay times for delay 1, 2 and 3? Also, what's your external clock frequency?
 
Last edited:
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
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…