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.

[SOLVED] how to make delay using timer0 in pic 16f877a

Status
Not open for further replies.

imnimn

Junior Member level 3
Joined
Jul 19, 2011
Messages
31
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,296
Activity points
1,481
i wrote a prgram to run with asecound delay but it take more than 1000 sec

and this is the code
give me your opinion please


Code:
sec_delay: movlw 0xd0
movwf temp
calling: call T0_delay 
decfsz temp
goto calling
return 

T0_delay: movlw 0x04;0x38;0x28;0x21
movwf OPTION_REG
movlw 0x6a

movwf TMR0
chIF:btfss INTCON,2
goto chIF
return
 

That code simply doesn't make sense.
Starting from the top:

"decfsz temp" should have a second parameter, file or W as the destination. I'm guessing you want 'f' as you are using it as a counter.
"movlw 0x04;0x38;0x28;0x21" puts 0x04 into W, what are the other numbers? They will be seen as comments by the assembler.

You then load 0x6A into TMR0 and loop until the T0IF flag sets. It would make the program more readable if you used "INTCON,TOIF" instead of the bit number but that isn't the real problem. The interrupt flag is sticky, you have to clear it in software. You also have to be aware that the interrupt occurs when he timer has counted up to 0XFF and then rolled over to zero so the value you use is the number of remaining ticks before roll-over and not the number of ticks counting up from zero. Try this:
Code:
  movlw 0x6A
  movwf TMR0
  bcf INTCON,T0IF
chIF
  btfss INTCON,TOIF
  goto chIF
  return

Without knowing the clock speed I can't confirm the values you have used are correct.

Brian.
 
  • Like
Reactions: imnimn

    imnimn

    Points: 2
    Helpful Answer Positive Rating
Obviusly Brian give you the same code that you has... Jejej. What I see is that youre using a call routine to invoke n times the delay using the timer 0. Well you should use "goto" in a bucle of n times. This is because the goto use 1 instruction cylcle and the call routine uses 2 machine times.

Good Luck!
 
  • Like
Reactions: imnimn

    imnimn

    Points: 2
    Helpful Answer Positive Rating
The difference in the code, apart from naming the bits is I cleared the interrupt flag before the loop, otherwise it would still be set from the last time TMR0 rolled over.

Using "goto $+1" to create delays can be dangerous if you are not careful. It works on some PICs but if the same code is tried on other PICs it may not work. The reason is that "goto $+1" is meant to refer to the next value in the program counter. On some PICs it simply wastes an extra cycle as it would arrive at the next instruction anyway but on other PICs where the instruction width is 16 bits, it jumps only half an instruction ahead. This may or may not cause a program crash but it certainly messes up the timing.

A much better way to make delays is to use TMR0 (or one of the other timers) to continually cause interrupts and then count a variable down to zero inside the ISR. This method isn't blocking, it allows the PIC to carry on doing other things while waiting if this is desired and it also lets you set how long you want the delay in real-time rather than hard coding it. For example:

<interrupt entry-code>
is T0IF set ?
if it isn't go to interrupt exit.
reload the timer again
clear the T0IF flag
if Variable isn't zero, decrement it
<interrupt exit-code>

Now all you do is put a value in 'Variable' to set the delay and check in the program if it is zero or not. It will count down from whatever value you give it at fixed intervals until zero and then stay at zero.
So if your interrupt period was 10mS and you load Variable with 25 it would count down to zero in 250mS.

Brian.
 
  • Like
Reactions: imnimn

    imnimn

    Points: 2
    Helpful Answer Positive Rating
The first PIC I programmed was the PIC1650 over 20 years ago so I would say I have had lots of experience with them!

To waste cycles, the safe way is to use "goto <label>" where label is the next line of the program, it works then for all PIC types.

The method I was suggesting for non-blocking delays uses timer interrupts to set a unit of period then a variable to count as many of those units as needed. It can be used to set several different delays and intervals simultaneously so it is very versatile. The method in the original code and in the code lucho1045 shows, uses the interrupt flag but does not use an interrupt routine. You can do exactly the same by checking TMR0 for value zero although it takes one more instruction to do that.

Brian.
 

thank you for your help
this problem is solved. the problem was that the interrupt flag is sticky as brain said and also in banks that INTCON not in the same bank as OPTION_REG and other registers
thank you for yor help Brain and lucho1045
 

INTCON is mapped into all banks so you do not have to worry about which bank is currently selected.

Brian.
 
  • Like
Reactions: imnimn

    imnimn

    Points: 2
    Helpful Answer Positive Rating
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top