Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Interrupt counter

Status
Not open for further replies.

Andy_123

Member
Need some help with to make short/fast assembler code for revesable counter. Using PIC 18F242 or 18F2550 for now.

- Interruput routine using INT0
- 16 bit counter counting from 0 to 2499
- If RA1 is ON then counter+1, roll back to 0 if>= 2500
- IF RA1 if OFF then counter-1, roll to 2499 if <0

Also:
- If counter =0 to 3 then set RB1=1, else RB1=0

2500 I used as an example, it can be any number from 1000 to 10000

Counter can count from 1 to 2500 if it will be easy.

Again, need very short and fast code, can't spend too much time servicing this interrupt.

Any help or ideas will be helpful.
Thanks
 
Here is what I cooked up for desert. I just had lunch and some time to kill.

Code:
MAX_COUNT       equ     d'2500'-1

        org     08h

INT_SERVE:
        btfss   PORTA,1
        bra     DO_DECR
DO_INCR:
        movlw   low MAX_COUNT
        cpfseq  COUNTER+0
        bra     DO_INCR2
;
        movlw   high MAX_COUNT
        cpfseq  COUNTER+1
        bra     DO_INCR2
;
        clrf    COUNTER+0
        clrf    COUNTER+1
;
        bsf     PORTB,1
;
        retfie  fast
DO_INCR2:
        infsnz  COUNTER+0,f
        incf    COUNTER+1,f
;
        tstfsz  COUNTER+1
        retfie  fast
;
        movlw   4
        cpfseq  COUNTER+0
        retfie  fast
;
        bcf     PORTB,1
;
        retfie  fast
DO_DECR:
        movlw   -1
        addwf   COUNTER+0,f
        addwfc  COUNTER+1,f
        btfsc   STATUS,C
        bra     DO_DECR2
;
        movlw   low  MAX_COUNT
        movwf   COUNTER+0
;       
        movlw   high MAX_COUNT
        movwf   COUNTER+1
;       
        bcf     PORTB,1
;
        retfie  fast
DO_DECR2:
        tstfsz  COUNTER+1
        retfie  fast
;
        movlw   3
        cpfseq  COUNTER+0
        retfie  fast
;
        bsf     PORTB,1
;
        retfie  fast
 
Thanks Motion for quick response!

This program much faster than the one I wrote ;)
With 40MHz clock it should take no longer than 2usec to execute this interrupt. This leaves me with 60% headroom worst case for continious task! Great!
I will try it this weekend.
Thanks
 
Motion

Do I need use
BCF INTCON, INT0IF
before RETFIE FAST ?

This is the only interrupt in the program.

Also:
- how to declare COUNTER as 16 bit value?
- Should I use LATB instead of PORTB?
Thanks.
 
Do I need use
BCF INTCON, INT0IF
before RETFIE FAST ?
This is the only interrupt in the program.
Oops. Yes you need to clear the source of the interrupt before retfie. You may do that at the start of the interrupt service routine. Should a second clock edge occur within the interrupt service, the PIC will be interrupted again on retfie.

how to declare COUNTER as 16 bit value?

There are many ways to do it depending upon the way you assign memory locations. Of course you can use the common EQU directive:

Code:
COUNTER   equ 20h
COUNTERL equ 20h  ; to access the low byte
COUNTERH equ 20h ; to access the low byte

Or the cblock directive:

Code:
 cblock   20h
COUNTER : 0
COUNTERL
COUNTERH
 endc

Or the "classic" way done in older processors like the Motorola 6800's.

Code:
     org 20h

COUNTER RES 2

"The most common usage for res is for data storage in relocatable code." - MPASM user's guide.


Should I use LATB instead of PORTB?

Oops, yeah that is a better register to use specially for bsf and bcf.

Finally, I tweaked the code a little bit. I don't test it so it may have errors.

Code:
MAX_COUNT       equ     d'2500'-1

        org     08h

INT_SERVE:
        BCF     INTCON, INT0IF 
;
        btfss   PORTA,1
        bra     DO_DECR
DO_INCR:
        movlw   low MAX_COUNT
        cpfseq  COUNTER+0
        bra     DO_INCR2
;
        movlw   high MAX_COUNT
        cpfseq  COUNTER+1
        bra     DO_INCR2
;
        clrf    COUNTER+0
        clrf    COUNTER+1
;
        bsf     LATB,1
;
        retfie  fast
DO_INCR2:
        infsnz  COUNTER+0,f
        incf    COUNTER+1,f
;
        movlw   b'11111100'
        andwf   COUNTER+0,w
        iorwf   COUNTER+1,w
        btfss   STATUS,Z
        bcf     LATB,1
;
        retfie  fast
DO_DECR:
        movlw   -1
        addwf   COUNTER+0,f
        addwfc  COUNTER+1,f
        btfsc   STATUS,C
        bra     DO_DECR2
;
        movlw   low  MAX_COUNT
        movwf   COUNTER+0
;
        movlw   high MAX_COUNT
        movwf   COUNTER+1
;
        bcf     LATB,1
;
        retfie  fast
DO_DECR2:
        movlw   b'11111100'
        andwf   COUNTER+0,w
        iorwf   COUNTER+1,w
        btfsc   STATUS,Z
        bsf     LATB,1
;
        retfie  fast
 
motion said:
Code:
COUNTER   equ 20h
COUNTERL equ 20h  ; to access the low byte
COUNTERH equ 20h ; to access the low byte

Obviously a typo, but the OP may not realise. It should read COUNTERHI equ 21h.

I like the cblock with a length of zero to assign 2 names to the same location. I can see me using that in the future.

Mike.
 
quick reply:

Tested the original code with changes I made mysef: LATB, clear interrupt.
Looks like it counts one direction correct , anoter - something is wrong looks like. Can't say what direction + or - as it was errelevant at this point.
Now I moved to 18F452 that has LCD connected, so I can see and compare.
I may use this new code as well
I'll let you know.
 
Here is a status update:
I added LCD indicator so I can see data.

I found why it did not work before.
I have more interrupt code before this additional section.
By the time we checking direction bit it may not be the same as it was during intrrupt.

So I am saving direction bit at the first line of interrupt and checking this saved value later.

I also realized that another interrupt pulse (that I can ignore) may come faster that full code executed, so I have to enable next interrupt only at the end.

Any way the last posted code with minor changes explaned above working exactly as expected.

Thanks !
 
Status
Not open for further replies.

Latest threads

Back
Top