Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Dear senior assemblers.. nned ur hlp regarding pic16f876a timers..

Status
Not open for further replies.

peter002

Member level 3
Joined
Mar 18, 2013
Messages
56
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,286
Location
Hindusthaan
Activity points
1,765
Dear senior assemblers.. nned ur hlp regarding pic16f877a timers..

hello big brothers, i ve been trying to make a speedometer for my bike using the hall effect sensor connected on porta,0, sensor's output pin is pulled hingh using around 7k resistance,

i hav made a six digit counter that seems to be working fine when i try using it by taking a meganet near to the sensor so the meter gets incremented, but for measuring the speed i need refference time counter, so i tried to configure the timer so i can count for one second atleast but it isnt working..

can anyone plz post any timer1 tested routine here??? i ll change the prescalar value and tmr1h and tmr1l values acc. to my needs after calculations..

here is a code tht i tried but didnt seems to be working good, its made for delay around 29us

Code:
TIMR1        BCF    PIR1,TMR1IF    ;Reset the TMR1IF flag bit
        MOVLW    H'FF'
        MOVWF    TMR1H        ; Set initial value for the Timer1
        MOVLW    H'ED'
        MOVWF    TMR1L
        BSF    T1CON,3
        BCF    T1CON,TMR1CS    ; Timer1 counts pulses from internal oscillator
        BSF    T1CON,T1CKPS0    ; Assigned prescaler rate is 1:8
        BSF    T1CON,T1CKPS1
        BSF    PIE1,TMR1IE    ; Enable interrupt on overflow
        MOVLW    H'C0'
        MOVWF    INTCON        ; Enable interrupt (bits GIE and PEIE)
        BSF    T1CON,TMR1ON    ; Turn the Timer1 on
        BTFSS    PIR1,TMR1IF
        GOTO    $-1
        RETURN
thanx in advance
wbr..
 

Attachments

  • Untitled.jpg
    Untitled.jpg
    174 KB · Views: 59
Last edited:

I changed your quote tags to code tags.

I'm not really sure what you are trying to do there. A speedometer of that type measures the number of pulses in a given period. The best way to do that is to use an interrupt to establish a time period, and count the number of pulses between interrupts. You seem to be using the interrupt registers but do not have an interrupt service routine.

Basics:
1. write an ISR. Inside it, snapshot the current hall effect pulse count, zero the original count, reset the timer for the next period then exit.
2. in the main code, read the hall sensor pulses as they arrive and display the 'snapshot' number the ISR generated.

For example, if your timer is set to generate an interrupt every second, the hall sensor produces say 15 pulses per second so the counter has reached 15. The ISR copies the '15' somewhere safely, sets the counter back to zero so it is ready for the next interrupt. The main code picks up the '15' from where you stored it and displays it. What you get is a display showing the number of pulses per second which you can convert to a real speed if you wish with some math.

Question: Can you really cycle so fast that you need a six-digit speedometer? :grin:

Brian.
 

I changed your quote tags to code tags.

I'm not really sure what you are trying to do there. A speedometer of that type measures the number of pulses in a given period. The best way to do that is to use an interrupt to establish a time period, and count the number of pulses between interrupts. You seem to be using the interrupt registers but do not have an interrupt service routine.

Basics:
1. write an ISR. Inside it, snapshot the current hall effect pulse count, zero the original count, reset the timer for the next period then exit.
2. in the main code, read the hall sensor pulses as they arrive and display the 'snapshot' number the ISR generated.

For example, if your timer is set to generate an interrupt every second, the hall sensor produces say 15 pulses per second so the counter has reached 15. The ISR copies the '15' somewhere safely, sets the counter back to zero so it is ready for the next interrupt. The main code picks up the '15' from where you stored it and displays it. What you get is a display showing the number of pulses per second which you can convert to a real speed if you wish with some math.

Question: Can you really cycle so fast that you need a six-digit speedometer? :grin:

Brian.

:-D six digit meter is count the distance that my bike vl cover, total distance... and i ll save tht distance either in eeprom memory or the flash memory, for speed i ll use another part of lcd that vl show the km/hrs meter..., just wanna know that the routine i posted for the timer is correct or not, i m not having my osscilloscope right now..i ll add a isr to repeat tht routine for say 20 or more time to get the desired delay..
 

Don't try to repeat the ISR, that won't work.
Keep a counter inside the ISR to keep track of how many times it has been called. For example if the timer causes an interrupt 10 times a second, load '10' into a variable, count it down and if it has reached zero, set a flag (another variable or a bit inside a variable) to say the period has finished the reload the counter with 10 again.

In the main code, check the variable (or bit) to see if the period has elapsed, then do whatever you have to do and finally reset the variable for next time.

If you do that, the timing is controlled by the ISR and it will never be slowed down by any other routines you run.

Brian.
 

Don't try to repeat the ISR, that won't work.
Keep a counter inside the ISR to keep track of how many times it has been called. For example if the timer causes an interrupt 10 times a second, load '10' into a variable, count it down and if it has reached zero, set a flag (another variable or a bit inside a variable) to say the period has finished the reload the counter with 10 again.

In the main code, check the variable (or bit) to see if the period has elapsed, then do whatever you have to do and finally reset the variable for next time.

If you do that, the timing is controlled by the ISR and it will never be slowed down by any other routines you run.

Brian.

same delay timer1 routine is used for ultrasonic distance meter, the routine is made to creat 29 microseconds delay, i m calling it for 2 times in isr named as GDP to creat 58 us for sound to get back to the sensor after intracting with obstacle, but it doesnt seems to be working, plz take a look at code if u can and spot me is i m doing smthing wrong..

main routines for code are
TIMR1
GDP
TRIGGER
SENDINST made to send instructions to 2x16 jhd162a lcd
SENDDT is made to send data to lcd

DISTTMP is the variable to hold the value that increments after completion of 2 calls of TIMR1.

THANX IN ADVANCE
wbr
 

Attachments

  • hc-sr04.txt
    7.3 KB · Views: 73

@peter002,

What you have posted in your topic so far looks like an assignment for students of an assembly language programming course.

The code file you have attached shows a badly organized implementation of:
  1. An 8-bit interface to an ASCII character LCD module using an HD44780 controller chip.
  2. An asynchronous UART at 9600 baud.
  3. Various width pulses on PORTD bit 0.
  4. Use of hardware TIMER1 to assert an interrupt.
  5. Functions to write ASCII digits to the character LCD module.
There are many bugs and serious problems with your assembly language source code.

It would seem that you do not yet have enough understanding of the fundamentals of how to work with microcontrollers using assembly language.

Has the course instruction covered these topics:
  • Essential ideas for embedded controller application design and implementation.
  • Architecture of a process loop.
  • Hardware timer initialization and usage.
  • Handling interrupt requests.
  • Declaring symbols for storing data in RAM.
If you can please tell me more about the tools you have available and the tasks you need to complete.
 

and to add to that... I still can't see any ISR.
I'm also trying to work out why an ultrasonic range finder is being used on a bike!

I can't tell what language it is written in, possibly MPSIM which went obsolete over 20 years ago. I would strongly advise re-writing it to work with XC8 or a similar modern assembler.

Brian.
 

and to add to that... I still can't see any ISR.
I'm also trying to work out why an ultrasonic range finder is being used on a bike!

I can't tell what language it is written in, possibly MPSIM which went obsolete over 20 years ago. I would strongly advise re-writing it to work with XC8 or a similar modern assembler.

Brian.

i m sorry to mix them up, the timer routine i took from the ultra sonic distance meter asm file, in what ever project i need my timer routine to be wroking well, i m using MPASMWIN.exe to compile the .asm files, plz suggest me better tools if i m lacking, but in that compiler i m able to use all 36 commands recomended by microchip without any problem, i learned everything online so yes my code is not arranged in a better way.. plz enlighten me..

- - - Updated - - -

@peter002,

What you have posted in your topic so far looks like an assignment for students of an assembly language programming course.

The code file you have attached shows a badly organized implementation of:
  1. An 8-bit interface to an ASCII character LCD module using an HD44780 controller chip.
  2. An asynchronous UART at 9600 baud.
  3. Various width pulses on PORTD bit 0.
  4. Use of hardware TIMER1 to assert an interrupt.
  5. Functions to write ASCII digits to the character LCD module.
There are many bugs and serious problems with your assembly language source code.

It would seem that you do not yet have enough understanding of the fundamentals of how to work with microcontrollers using assembly language.

Has the course instruction covered these topics:
  • Essential ideas for embedded controller application design and implementation.
  • Architecture of a process loop.
  • Hardware timer initialization and usage.
  • Handling interrupt requests.
  • Declaring symbols for storing data in RAM.
If you can please tell me more about the tools you have available and the tasks you need to complete.

those are only subroutines that i kept for other uses wen ever i need, various width pulses are to creat diff delays that i can chk using the osscilloscope, from now on i ll try to make my code presented in a better way, i m sorry for tht
 

@peter002,

What you have posted in your topic so far looks like an assignment for students of an assembly language programming course.

The code file you have attached shows a badly organized implementation of:
  1. An 8-bit interface to an ASCII character LCD module using an HD44780 controller chip.
  2. An asynchronous UART at 9600 baud.
  3. Various width pulses on PORTD bit 0.
  4. Use of hardware TIMER1 to assert an interrupt.
  5. Functions to write ASCII digits to the character LCD module.
There are many bugs and serious problems with your assembly language source code.

It would seem that you do not yet have enough understanding of the fundamentals of how to work with microcontrollers using assembly language.

Has the course instruction covered these topics:
  • Essential ideas for embedded controller application design and implementation.
  • Architecture of a process loop.
  • Hardware timer initialization and usage.
  • Handling interrupt requests.
  • Declaring symbols for storing data in RAM.
If you can please tell me more about the tools you have available and the tasks you need to complete.

and to add to that... I still can't see any ISR.
I'm also trying to work out why an ultrasonic range finder is being used on a bike!

I can't tell what language it is written in, possibly MPSIM which went obsolete over 20 years ago. I would strongly advise re-writing it to work with XC8 or a similar modern assembler.

Brian.

well thanx for ur humble support brothers... i solved the issue and found the problem and step where i was wrong. i wud love to share my experience about that.

in the starting i have posted the sub that i wrote to initialised and use the timer1, in a single routine i configure the timer1 as well as i turned it on too, mistakenly i was rewriting the prescalar everytime i called that routine and result was that with what ever value i load timr1h and timr1l registers the time delay was fix, even if diff values were loaded in the registers the delay was stills same, i just wanted to know the initialisation method of timer module,

so i made two parts of routine, i m defining the prescalar in a single routine and in another routine i doing the left part of loading the registers and clearing the bit timer1if that is interrupt flag.. it looks like below..
Code:
TIMR1		BCF	T1CON,TMR1CS	; Timer1 counts pulses from internal oscillator
		BSF	T1CON,T1CKPS0	; Assigned prescaler rate is 1:8
		BSF	T1CON,T1CKPS1
		BSF	PIE1,TMR1IE	; Enable interrupt on overflow
		RETURN

and
Code:
TIMR11		BCF	PIR1,TMR1IF	;Reset the TMR1IF flag bit
		MOVLW	H'FF'
		MOVWF	TMR1H		; Set initial value for the Timer1
		MOVLW	H'9D'
		MOVWF	TMR1L
		MOVLW	H'C0'
		MOVWF	INTCON		; Enable interrupt (bits GIE and PEIE)
		BSF	T1CON,TMR1ON	; Turn the Timer1 on
		BTFSS	PIR1,TMR1IF
		GOTO	$-1
		RETURN
now i m calling timr1 for once and timer11 for many times as i want..
so i m getting my desired delay by repeating timer11 as much i want,, vl soon post further progress..
thanx a lot :thumbsup:
 

This is really bad programming technique and enabling interrupts without an ISR makes it extremely likely to crash. Every time T1 overflows it will force a call to address 0x004, if you are lucky that address may contain code it can survive from but each time you run the assembler it may change the code at that address.

Also the "GOTO $-1" should be avoided if possible as it is non-portable. Use a label at the jump target and "GOTO" that instead. It will ensure the assembler goes to the right place in all eventualities.

I strongly suggest you structure your code like this:
1. At 'org 0x0000' place a jump to the initializing code.
2. At 'org 0x0004' write the ISR. End it with a 'retfie' instruction.
3. Write the initialization code next, this is where step 1. jumps to.

Use the timer and ISR to generate regular timing periods and count them if you need longer times. The other advantage in this method is you can create more than one delay from the same routine and they can be for different periods and even overlap each other.

Brian.
 
This is really bad programming technique and enabling interrupts without an ISR makes it extremely likely to crash. Every time T1 overflows it will force a call to address 0x004, if you are lucky that address may contain code it can survive from but each time you run the assembler it may change the code at that address.

Also the "GOTO $-1" should be avoided if possible as it is non-portable. Use a label at the jump target and "GOTO" that instead. It will ensure the assembler goes to the right place in all eventualities.

I strongly suggest you structure your code like this:
1. At 'org 0x0000' place a jump to the initializing code.
2. At 'org 0x0004' write the ISR. End it with a 'retfie' instruction.
3. Write the initialization code next, this is where step 1. jumps to.

Use the timer and ISR to generate regular timing periods and count them if you need longer times. The other advantage in this method is you can create more than one delay from the same routine and they can be for different periods and even overlap each other.

Brian.

really very healthy suggessions bro, thans a lot bro,but i m already using these steps
Code:
ORG	0

		GOTO 	RESET
but reset starts main code, i ll make other changes as u suggested bro..

- - - Updated - - -

This is really bad programming technique and enabling interrupts without an ISR makes it extremely likely to crash. Every time T1 overflows it will force a call to address 0x004, if you are lucky that address may contain code it can survive from but each time you run the assembler it may change the code at that address.

Also the "GOTO $-1" should be avoided if possible as it is non-portable. Use a label at the jump target and "GOTO" that instead. It will ensure the assembler goes to the right place in all eventualities.

I strongly suggest you structure your code like this:
1. At 'org 0x0000' place a jump to the initializing code.
2. At 'org 0x0004' write the ISR. End it with a 'retfie' instruction.
3. Write the initialization code next, this is where step 1. jumps to.

Use the timer and ISR to generate regular timing periods and count them if you need longer times. The other advantage in this method is you can create more than one delay from the same routine and they can be for different periods and even overlap each other.

Brian.

u mean all the routines tht i ll use for interrupts must be written from the address 0x0004 and so on and they must be ended with the command retfie.. so wen i call then in the place of goto $-1 command they shud be terminated with retfie...???
 

u mean all the routines tht i ll use for interrupts must be written from the address 0x0004 and so on and they must be ended with the command retfie.. so wen i call then in the place of goto $-1 command they shud be terminated with retfie...???
No! The 16F876A only has one level of interrupts so you cannot write more than one ISR.

'org' is a directive to the assembler, it means this is the address this code should be placed. When you use 'org 0' it tells it to place the code at the first address. If you use another 'org' with a different number it means place the code there instead. From wherever the 'org' address is, the following instructions are placed in the next memory addresses consecutively.

The ISR is special, it is a software routine that gets called by a hardware event. That event can be any of the interrupt sources, either external or internal to the processor. The one you are using is caused by TMR1 overflowing. It means that whenever the timer reaches 0xFFFF and rolls over to zero and the interrupt is enabled, the ISR routine gets called. The important thing here is that the ISR has a fixed built-in address in the PIC, it is address 4 (0x0004).

Now look at beginning of your code:
Code:
    ORG    0

        GOTO     RESET              000

;LCD INITIALISATION TABLE------------------------------------------
LCDINITTBL    ADDWF    PCL,F          0002
        RETLW    D'56'                0003
        RETLW    D'12'                0004
        RETLW    D'6'                  0005
        RETLW    D'1'                  0006

LCDINIT        MOVLW    D'0'          0007
          MOVWF    INTC                0008
IO        MOVF    INTC,W
        CALL    LCDINITTBL
        MOVWF    PORTB
        CALL    SENDINST
I have marked the addresses after the instruction. You will see that you have "RETLW D'12'" at the address the ISR should be at. So if an interrupt occurs your program will jump into the LCD initialization table and not even land on a valid instruction.

What you should do is this:
Code:
    ORG    0

        GOTO     RESET
        
  ORG 4
  < Place the ISR code here and end it with a 'retfie' instruction >
  

;LCD INITIALISATION TABLE------------------------------------------
LCDINITTBL    ADDWF    PCL,F
        RETLW    D'56'
        RETLW    D'12'
        RETLW    D'6'
        RETLW    D'1'

LCDINIT        MOVLW    D'0'
        MOVWF    INTC
IO        MOVF    INTC,W
        CALL    LCDINITTBL
        MOVWF    PORTB
        CALL    SENDINST

The reason not to use $-1 is it means "jump back one address", that works for some instructions on some processors but leave you open to problems if the instruction is more than one address long . It is more of a problem on PIC18 code but should still be avoided. The better method is to code it like this:
Code:
        MOVWF    INTCON        ; Enable interrupt (bits GIE and PEIE)
        BSF    T1CON,TMR1ON    ; Turn the Timer1 on
TIMR1_LOOP
        BTFSS    PIR1,TMR1IF
        GOTO    TIMR1_LOOP
        RETURN
so the assembler works out the correct address for you. However in your code if you use interrupts properly there would be no need to keep reading the PIR1 register anyway.

Brian.
 
Brian,

I think you have opened a can of worms. Now you will need to tell peter002 what execution context is and how the Interrupt Service Routine need to preserve it. That's going to grow in to the discussion about memory banks in the PIC16F876A and the 16 byte region of RAM that is common to all banks. After all that you may as well touch on how the program flash storage come in pages that are kind of like banks of RAM only different and that gets into the issue of the PCLATH register and writing a byte to the low 8-bits of the program counter.

These oid RISC chips can be more that a little strange.
 

Actually, the easiest way to write code by far is to copy the template from the assembler files and build upon it. The template already has a skeleton ISR with the context saving and restoration inside it.

The problem I have is I use Linux and MPLABX, if Peter002 is using MPASMWIN it implies they are using Windows. I think (but please check) it is at: C:/program files/Microchip/mpasm/templates/code/16f876TEMP.ASM but obviously with a different file structure my copy is elsewhere.

Brian.
 

Question: Can you really cycle so fast that you need a six-digit speedometer? :grin:
It would be convenient for displaying speeds up to 100 Kilometers per hour with a resolution reaching to millimeters.
 

Actually, the easiest way to write code by far is to copy the template from the assembler files and build upon it. The template already has a skeleton ISR with the context saving and restoration inside it.

The problem I have is I use Linux and MPLABX, if Peter002 is using MPASMWIN it implies they are using Windows. I think (but please check) it is at: C:/program files/Microchip/mpasm/templates/code/16f876TEMP.ASM but obviously with a different file structure my copy is elsewhere.

Brian.

BRO indeed i m working in a template that was obtained from microchip website, i tried your way too,, means if i place my main code just below org 0 and after that i place my sub routines then the copiler doesnt see the subroutines, perhaps coz the main code ends with command end and compiler doesnt seeks anything below 'end'.i m using mpasmwin.exe to compile the code,

- - - Updated - - -

Actually, the easiest way to write code by far is to copy the template from the assembler files and build upon it. The template already has a skeleton ISR with the context saving and restoration inside it.

The problem I have is I use Linux and MPLABX, if Peter002 is using MPASMWIN it implies they are using Windows. I think (but please check) it is at: C:/program files/Microchip/mpasm/templates/code/16f876TEMP.ASM but obviously with a different file structure my copy is elsewhere.

Brian.

yes i m using windows, win7 indeed bro, i just completed the ultrasonic code, i made a subroutine to convert bcd to ascii but having an issue, when distance is above 9 it starts to show decimal 58 and above as distance increases, i m attatching the code, plz hav a look if possible, i hav remove all useless code of sub routines...
 

Attachments

  • hc-sr04.asm.TXT
    5.7 KB · Views: 71
Last edited:

That code is horrible!
That is not an ISR and you can't loop back to the entry point of an ISR either. You are enabling interrupts but have no ISR to service it.

An ISR MUST comply with the following:
1. It MUST be located at address 0x0004, it is built into the silicon, you can't change it.
2. when you enter it you almost certainly have to save at least the current W and STATUS register values.
3. you then do whatever the ISRs purpose is, in your case to make a delay.
4. you MUST then restore the registers saved in step 2.
5. you end the ISR with a 'retfie' instruction.

What you must consider is that an interrupt can occur at any time, for example whenever TMR1 rolls over. You don't ever call the ISR directly in your program, it gets called automatically by whatever triggers the interrupt. When an interrupt occurs, the present location in the program (the PCL register contents) is saved to the stack and the next instruction to be executed is at address 4. When the 'retfie' is reached at the end of the ISR, the PCL is restored and the program continues from where it was before. The reason for steps 2 and 4 is that if you change the values in W or STATUS they will be different when you return to normal program flow and this will obviously cause problems.

Here is a sample of some code I wrote for a 16F877A (nearly 10 years ago!):
Code:
;***** VARIABLE DEFINITIONS
w_temp        EQU    0x7D        ; variable used for context saving 
status_temp    EQU    0x7E        ; variable used for context saving
pclath_temp    EQU    0x7F        ; variable used for context saving            

;**********************************************************************
    ORG    0x000                    ;processor reset vector

    nop                            ;nop required for icd
    call    setup                ;initialise registers
    goto    main                ;go to beginning of program


    ORG        0x004                ;interrupt vector location

[COLOR=#FF0000]    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[/COLOR]
    
    banksel    PIR1
    [COLOR=#008000]btfss    PIR1,TMR1IF            ;check if TMR1 roll over interrupt
    goto    ISR_restore            ;no, so restore and exit
[/COLOR]
    call    step_to_target        ;advance all the present values
    movlw    0xF6                ;preset for timer1 MSB register (250Hz when xtal = 20MHz)
    movwf    TMR1H
    movlw    0x3C                ;preset for timer1 LSB register
    movwf    TMR1L
    bcf        PIR1,TMR1IF            ;clear the interrupt flag
    
ISR_restore
    [COLOR=#FF0000]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
[/COLOR]
setup
    movlw    0x55                ;seed the random number generator
    movwf    random

It is only a small part of much bigger code, I have colored the context saving in red to make it obvious. The green part is to check that the interrupt really was caused by TMR1 because all the different interrupt triggers cause a jump to the same ISR on that processor.

Your BCD to decimal code is correct, but consider that BCD does not include numbers greater than 9. I think you really want code to convert hexadecimal to ASCII so you have to add the difference between ASCII 9 and ASCII A if the value is greater than 9.

Brian.
 
That code is horrible!
That is not an ISR and you can't loop back to the entry point of an ISR either. You are enabling interrupts but have no ISR to service it.

An ISR MUST comply with the following:
1. It MUST be located at address 0x0004, it is built into the silicon, you can't change it.
2. when you enter it you almost certainly have to save at least the current W and STATUS register values.
3. you then do whatever the ISRs purpose is, in your case to make a delay.
4. you MUST then restore the registers saved in step 2.
5. you end the ISR with a 'retfie' instruction.

What you must consider is that an interrupt can occur at any time, for example whenever TMR1 rolls over. You don't ever call the ISR directly in your program, it gets called automatically by whatever triggers the interrupt. When an interrupt occurs, the present location in the program (the PCL register contents) is saved to the stack and the next instruction to be executed is at address 4. When the 'retfie' is reached at the end of the ISR, the PCL is restored and the program continues from where it was before. The reason for steps 2 and 4 is that if you change the values in W or STATUS they will be different when you return to normal program flow and this will obviously cause problems.

Here is a sample of some code I wrote for a 16F877A (nearly 10 years ago!):
Code:
;***** VARIABLE DEFINITIONS
w_temp        EQU    0x7D        ; variable used for context saving 
status_temp    EQU    0x7E        ; variable used for context saving
pclath_temp    EQU    0x7F        ; variable used for context saving            

;**********************************************************************
    ORG    0x000                    ;processor reset vector

    nop                            ;nop required for icd
    call    setup                ;initialise registers
    goto    main                ;go to beginning of program


    ORG        0x004                ;interrupt vector location

[COLOR=#FF0000]    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[/COLOR]
    
    banksel    PIR1
    [COLOR=#008000]btfss    PIR1,TMR1IF            ;check if TMR1 roll over interrupt
    goto    ISR_restore            ;no, so restore and exit
[/COLOR]
    call    step_to_target        ;advance all the present values
    movlw    0xF6                ;preset for timer1 MSB register (250Hz when xtal = 20MHz)
    movwf    TMR1H
    movlw    0x3C                ;preset for timer1 LSB register
    movwf    TMR1L
    bcf        PIR1,TMR1IF            ;clear the interrupt flag
    
ISR_restore
    [COLOR=#FF0000]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
[/COLOR]
setup
    movlw    0x55                ;seed the random number generator
    movwf    random

It is only a small part of much bigger code, I have colored the context saving in red to make it obvious. The green part is to check that the interrupt really was caused by TMR1 because all the different interrupt triggers cause a jump to the same ISR on that processor.

Your BCD to decimal code is correct, but consider that BCD does not include numbers greater than 9. I think you really want code to convert hexadecimal to ASCII so you have to add the difference between ASCII 9 and ASCII A if the value is greater than 9.

Brian.

thanx bro, it cleared a lot, so my code wud look like below..??
Code:
	ORG	0

		GOTO 	RESET

	ORG	4

		MOVWF	W_TMP
		MOVF	STATUS,W
		MOVWF	STATUS_TMP
		MOVF	PCLATH,W
		MOVWF	PCLATH_TMP

		BANKSEL	PIR1
		BTFSS	PIR1,TMR1IF
		GOTO	NO_INT
		GOTO	ISR

ISR		CALL	TIMR11
		INCF	TSTTMP,F
		BTFSC	PORTC,5
		GOTO	ISR


		MOVF	PCLATH,W
		MOVWF	PCLATH
		MOVF	STATUS_TMP,W
		MOVWF	STATUS
		SWAPF	W_TMP,F
		SWAPF	W_TEMP,W
		RETFIE


NO_INT		MOVF	PCLATH,W
		MOVWF	PCLATH
		MOVF	STATUS_TMP,W
		MOVWF	STATUS
		SWAPF	W_TMP,F
		SWAPF	W_TEMP,W
		RETFIE

one more point...if the isr is automaticall called then it means i do not to call isr?? i shud just keep writing the value on lcd and if an interrupt occurs then the program simply jumps to isr address 4 and three value r saved and tmr1if is polled that if the interrupt was due to timer1 then 'goto isr' is executed and if not then simply three values are restored and th program jumps back to the values stored in stack due to retfie..??

onre more thing.. to push the contents of w_tmp in to the w register is that necessary that we must use swapf command??? i think using the swapf w_tmp firstly the contents of w_tmp are sent to w and then they are swapped and sent back to w_tmp and then another swapf w_tmp,w is used to keep the contents into the w.. why cant we simply use movf w_tmp,w??? :thinker:
 

Hi,

At least it looks like an ISR now.

I did't go deeper in code...
But I assume you do some "waiting" within the ISR. Thus is not how an ISR shoukd work. An ISR should be very short in time. It reacts on "edges", "events" or "changes", not on levels.
This means:
* it triggers on the falling edge (while running mains code)...
* on trigger it runs for a very short time ....then leaves the ISR....(it does not wait for the signal to become high within the ISR), but sets to trigger on rising edge
* on trigger it runs for a very short time ....then leaves the ISR....

Within the ISR it captures/saves all the necessary data for later processing, it does not do heavy processing within the ISR.

But all this is written in every ISR tutorial. Go through a couple of them. There are internet pages, PDFs, videos,...use them, they are for free. There are thousands...

Klaus
 
You are starting to get there!
You are actually duplicating some of your code, if you move "NO_INT" to above the previous "MOVF PCLATH,W" you can remove everything after the first RETFIE.

However, you still miss the point about what interrupts are for and the first line "GOTO ISR" should not be there as it simply jumps to the next instruction. Unless you are very sure PORTC,5 is going to change faster than TMR1 rolls over, you shouldn't use the loop inside the ISR either.

if the isr is automaticall called then it means i do not to call isr??
That is correct. A subroutine is called from within your program, an interrupt is triggered by some hardware event. In your program, that event is TMR1 rolling over. It means that whenever it rolls over, regardless of where the program is running at the time, an immediate call to address 4 is made. Inside the PIC the difference is that a 'call' instruction saves the address of the next instruction to be executed on the stack so that when you 'return', it continues from after the call. An interrupt is similar except that as well as the address being saved to the stack, the interrupts are also disabled. That is because on PIC16 devices you can't interrupt a running interrupt. When you use RETFIE it is like a normal 'return' instruction but it also re-enables any interrupts again.

onre more thing.. to push the contents of w_tmp in to the w register is that necessary that we must use swapf command??? i think using the swapf w_tmp firstly the contents of w_tmp are sent to w and then they are swapped and sent back to w_tmp and then another swapf w_tmp,w is used to keep the contents into the w.. why cant we simply use movf w_tmp,w??
It might be possible to do it that way, it depends on your program but the safe way is to use that specific code using swap instructions. The reason is that because an ISR can be triggered at any time, it is essential that AFTER the ISR has finished (after the retfie), things carry on as before. If you change W, PCLATH or the STATUS register in the ISR code they will still be different when the main code resumes and that could have bad consequences in your program. Using the swap method rather than movwf does not change any of the bits in the STATUS register so it helps to preserve them before returning.

Brian.
 
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top