![]() | ![]() | ![]() |
| | |||||||
| Micro Controllers Discuss all aspects of micro controllers - building them, coding them, etc. All controllers are welcome - PIC, BASIC, Z8 Encore!, etc. |
| | LinkBack | Thread Tools | Display Modes |
| | (permalink) |
| I need to get a pulse for every one second.until now i got that with delay loops,listed below.now i have to take that pulse from TMR0 without delay loops.how to do that?how the code comes?what is the meaning of prescaler? I'm using 4mhz cystal-PIC16F84A. Code: Delay MOVLW 03h
MOVWF 1Ah
Delay1 DECFSZ 1Bh,1
GOTO Delay1
DECFSZ 1Ch,1
GOTO Delay1
DECFSZ 1Ah,1
GOTO Delay1
RETURN Code: cblock d1 d2 d3 endc ;999997 cycles movlw 0x08 movwf d1 movlw 0x2F movwf d2 movlw 0x03 movwf d3 Delay_0 decfsz d1, f goto $+2 decfsz d2, f goto $+2 decfsz d3, f goto Delay_0 ;3 cycles goto $+1 nop return | |
| |
| | (permalink) |
| hi suraj, To use TMR0 interrupt, you will have to enable TMR0 intr. The clock rate into the TMR0, 8 bit counter is the crystal freq divided by 4. example if the crystal is 4mHz then the clock rate into the TMR0 reg is 1mHz. [1uSec] The prescaler is a 8 bit counter divider, which you set in combination with the TMR0 8 bit reg value. By dividing the 1uSec [1mHz] clock by the prescaler value and using the prescaler output to clock the 8 bit TMR0 reg it will give you a 'known' interrupt interval. The interrupt occurs as TMR0 reg 'fills and rolls back to zero'. As the prescaler and TMR0 reg division interrupt interval cannot have an interval as long as 1 second, you have to count the the interrupts until the count value is equivalent to 1 second. Chose a prescaler and TMR0 preset values that will give you an integer value equal to 1 second. Dont forget to allow for time that you 'use' while you are servicing the ISR [ interrupt service routine] Rough example: say your prescale and TMR0 reg combination, gave an intr every 10mSec then you would count 100 interrupts. Read the 16F84 datasheet regarding TMR0 and ALL the interrupt requirements. EricG Last edited by ericgibbs; 19th February 2007 at 10:37 AM. | |
| |
| | (permalink) | ||
| Hi erric thankx for your reply.I studied the data sheet & gathered some informations from it.I aplied it to a coding listed below. Code: ORG 0X04 ;INTERUPT VECTOR BTFSS INTCON,TOIF ;TMR0 INTERUPT? GOTO INTEND ;IF NO RETURN DECFSZ COUNTERL,1 ;DECREMENT 100 TIMES GOTO INTEND ;IF NO RETURN GOTO TURNONLED ;TURN ON LED INTEND BCF INTCON,TOIF ;CLEAR TOIF FLAG BIT RETFIE ;RETURN FROM INTERUPT ORG 0X00 MAIN BSF STATUS,RP0 ;SWITCH TO BANK 1 CLRF TRISB ;MAKE ALL PORTB PINS OUTPUT ????????????? MOVWF OPTION BCF STATUS,RP0 ;SWITCH TO BANK 0 BSF INTCON,GIE BSF INTCON,TOIE MOVLW D'100 ;(100x??=1SECOND) MOVWF COUNTERL LOOP GOTO LOOP ;WAIT UNTIL INTERUPT OCCURS Quote:
Quote:
In my codings the values that must be moved to option reg kept blanked.b'cuz I dont know how to load that.In the data sheet below option reg I see a table like this, Code: TMR0 rate 1:2 1:4 1:8 1:16 1:32 1:64 1:128 1:256 | |||
| |
| | (permalink) |
| hi As you are using a 4mHz crystal, the frequency input to the TMR0 prescaler 1mHz [1uSec] Example1: If you set the TMR0 prescaler to say 256, it would mean that the frequency input to the 8 bit TMR0 reg would be 3906.25hZ [int 3906 == 256uSec] If you now loaded the TMR0 reg with say 0x00, it would require 256 pulses of the 256uSec from the output from the prescaler to make it 'overflow', which will cause a TMR0 interrupt. So 256 * 256uSec = 65.54 milliSec period for each intr. Example2: If you had set the prescaler to say, 128, the output period from the prescaler would at 128uSec, so 128uSEc * 256 [the TMRo reg] = 32.77milliSec. Example3: Keep the prescaler set to say 128 = 128uSec and load the TMR0 reg with say, 0x80 So to make the TMR0 reg 'overflow' would now only take 128 counts, 128uSec * 128 =16.38millisSec Got the idea, choose values for the prescaler and TMR0 reg to give you the interrupt period you require. I would choose values that gave me a intr every 50milliSec, then just count 20 interrupts for 1 Sec. Don't forget to allocate the TMR0 to the prescaler, [not the WDT] Enable the intr you are using and the global. On intr in your ISR clear the T0IF flag and if you have loaded the TMR0 reg with a value, reload it. Use retfie at the end of your ISR, to re-enable intr. Regards Eric Last edited by ericgibbs; 20th February 2007 at 09:13 AM. | |
| |
| | (permalink) | ||
| Hi erric thanks for giving knowledge.Now I understood a little more.I dont like to give you more trouble but I have to ask this . for a 4mHz crystal, the frequency input to the TMR0 prescaler 1mHz [1uSec] for a 20mHz crystal, the frequency input to the TMR0 prescaler = [0.2uSec] If i choose 256 from the prescaler 256*256usec = 65.54 millisec will generate an interupt. If i choose 128 from the prescaler 128*256usec = 32.77 millisec will generate an interupt. If i choose 32 from the prescaler 32*256usec = 8.192 millisec will generate an interupt. I'm confused with your example3 Quote:
Prescaler & the TMR0 reg are two different things.If loaded TMR0 as 0x00 then I must multiply the prescaler rate from 256.can I load any value (upto 255) to the TMR0 like this? Quote:
for every 50millisec *20 = exactly 1 second.so how can I choose 50 millisec it from the prescaler its all 8 dividers like 2,4,8,16,32,128,256.there is no 50. | |||
| |
| | (permalink) |
| TMR0 reg is incremented every time the prescaler overflows. An interrupt is generated every time that TMR0 reg goes from 255 to 0. Therefore, if you set the prescaler to 128 and load TMR0 reg with 256-78 then you will get an interrupt after 78*128 clock cycles. 78*128 = 9984 - almost 10mS. The other 16clock cycles required to make this exactly 10ms can be at the start of your interrupt service routine (ISR). I thought I better test my theory and here is the result, Code: #include <P16F84A.inc> errorlevel -302 cblock 70h int_work int_status endc org 0x0000 goto Start org 0x0004 interrupt movwf int_work; 2latent +1 =3 swapf STATUS,W; +1 =4 movwf int_status; +1 =5 bcf STATUS,RP0; +1 =6 bcf STATUS,RP1; +1 =7 movlw 100h-d'78'; +1 =8 goto $+1; +2 =10 goto $+1; +2 =14 nop; +1 =15 movwf TMR0; +1 =16 + 78*128 = 10,000 bcf INTCON,T0IF; reset int flag swapf int_status,W movwf STATUS swapf int_work,F; swap to file swapf int_work,W; swap to work retfie Start bcf STATUS,RP1 bsf STATUS,RP0 bcf STATUS,IRP movlw b'00000110'; set prescaler to 128 movwf OPTION_REG bcf STATUS,RP0 movlw 0a0h; enable timer interupt movwf INTCON hang goto hang end Mike. | |
| |
| | (permalink) |
| hi suraj, Did you follow ok what Mike said ? Consider the prescaler as a programable divider of the osc/4 frequency. It can be programmed to divide the osc/4 freq by, 2 to 256 in powers of 2. The output of the prescaler divider is input the TMR0 reg [8 bit counter]. As the TMR0 counter 'fills' and rolls back to zero an interrupt is generated. You can preload the TMR0 counter with a decimal value from 0 to thru 255. Say you half 'fill' the TMR0 with 128, then it only requires 128 counts [from the prescaler output] to reach 255 counts and roll back to 000, and generate an interrupt. As I and Mike have pointed out, for accurate intr periods, count the instructions in the ISR, allow a osc/4 'time period' [ 1uSec in your example] for each instruction, then the sum of all the instruction periods is then to added to the 'prescaler and TMR0' times. Note: The label TMR0 is a dedicated/reserved register 'label', you can't use it as a interrupt counter register. Use a free ram register, example, in ASM absolute coding terms. ISR_CNT EQU 0x20 Regards Eric Thanks Mike. Last edited by ericgibbs; 21st February 2007 at 08:08 AM. | |
| |
| | (permalink) |
| Hi thanks for both of you giving me a great knowledge of TMR0.Now I understand it very well. Yes Erric I'm ok with mikes codings. It was helped me a lot. But I have a simple question to ask from mike. * 78*128 = 9984 - almost 10mS.thats correct. But why did you move like this for TMR0? movlw 100h-d'78' The result of this line will be 256-78 = 178 not d’78 Can I directly move d’78 like this movlw d'78' Thanks Mike, Thanks Erric You are really experts | |
| |
| | (permalink) |
| The reason for loading 100h-d’78’ is because TMR0 counts up. It is just a (weird) coincidence that 100h-78 = 178. If we had loaded TMR0 with 250 then the delay would have been (256-250)*128 – we load it instead with 178 which gives a delay of (256-178)*128 which happens to be 78*128. So, you can’t put movlw d’78’ but you can do movlw d’178’, but I think the way it is makes more sense. Hope that didn’t confuse you. Mike. | |
| |
| | (permalink) |
| Hi I was working with the TMR0.I added some extra lines to Mikes coding to turn on the LED for every 1 second.here I loaded counterL as D'100 so 10msx100=1second. I have added a 0.5delay in the main loop to see the LED flash.and the other 0.5 seconds will turn off the LED. But I'm having a problem in the output I cannot see the LED flash.Why is that?I think I have put that new routine in the wrong place. Code: #include <P16F84A.inc>
errorlevel -302
cblock 70h
int_work
int_status
counterL
d1
d2
d3
endc
org 0x0000
goto Start
org 0x0004
interrupt movwf int_work ;2latent +1 =3
swapf STATUS,W ;+1 =4
movwf int_status ;+1 =5
bcf STATUS,RP0 ;+1 =6
bcf STATUS,RP1 ;+1 =7
movlw 100h-d'78' ;+1 =8
goto $+1 ;+2 =10
goto $+1 ;+2 =14
nop ;+1 =15
movwf TMR0 ;+1 =16 + 78*128 = 10,000
btfss INTCON,T0IF ;Is it a TMR0 interupt?
goto intend ;return from interupt
decfsz counterL,1
goto intend ;return from interupt
bsf PORTB,0 ;turn on the LED RB0
movlw 64h ;load 100 to counterL
movwf counterL
intend bcf INTCON,T0IF ;reset int flag
swapf int_status,W
movwf STATUS
swapf int_work,F ;swap to file
swapf int_work,W ;swap to work
retfie
Start bcf STATUS,RP1
bsf STATUS,RP0
bcf STATUS,IRP
clrf TRISB
movlw b'00000110' ;set prescaler to 128
movwf OPTION_REG
bcf STATUS,RP0
movlw 0a0h ;enable timer interupt
movwf INTCON
movlw 64h ;load 100 to counterL
movwf counterL
call del ;call a 0.5 seconds delay to see the LED flash
bcf PORTB,0 ;other 0.5 seconds LED will off
Loop goto Loop ;Loop
del movlw 0x03 ;0.5 seconds delay routine
movwf d1
movlw 0x18
movwf d2
movlw 0x02
movwf d3
Delay_0
decfsz d1, f
goto $+2
decfsz d2, f
goto $+2
decfsz d3, f
goto Delay_0
goto $+1
goto $+1
goto $+1
return
end | |
| |
| | (permalink) |
| The reason your LED isn't flashing is because the IRQ won't turn on the LED until 1 second has passed and your delay is 0.5 seconds. A better way is to test counterL to see which half of the second you are in. You do this by comparing it to 50 and setting the LED dependent on the result. Something like, Code: Start bcf STATUS,RP1 bsf STATUS,RP0 bcf STATUS,IRP clrf TRISB movlw b'00000110' ;set prescaler to 128 movwf OPTION_REG bcf STATUS,RP0 movlw 0a0h ;enable timer interupt movwf INTCON movlw 64h ;load 100 to counterL movwf counterL Loop movfw counterL ;get the count sublw d'50' ;sub 50 from it btfsc STATUS,C ;if carry set bsf PORTB,0 ;turn on LED btfss STATUS,C ;if carry clear bcf PORTB,0 ;turn off LED goto Loop ;Loop | |
| |
| Bookmarks |
| Thread Tools | |
| Display Modes | |
| |
| | ||||
| Title | Starter | Forum | Replies | Latest |
| Log Data using pic16F877A | williB | Micro Controllers | 32 | 31st October 2006 10:28 AM |
| Random Numbers for PIC | PDubya | Micro Controllers | 12 | 8th July 2006 11:01 PM |
| Delay routine not working | gregmcc | Micro Controllers | 6 | 18th September 2005 06:23 PM |
| help with delay routine | JunglePython | Micro Controllers | 7 | 14th July 2005 08:46 PM |
| Effects | stephenpic | Micro Controllers | 6 | 19th January 2004 12:57 PM |