One more question on Delays. Since I'm a starter my head aching around the calculations of delay. I understand delay when somebody explaining it in their code. But when it comes to my code Im totally a mess. (Calculating a delay for 2 days). this is the code; I want to blink-Led in every 1 second on any port pin on pic16f676:
#include "p16F676.inc"
; CONFIG
; __config 0xFFFC
__CONFIG _FOSC_INTRCIO & _WDTE_ON & _PWRTE_OFF & _MCLRE_ON & _BOREN_ON & _CP_OFF & _CPD_OFF
usec EQU 0x20
sec EQU 0x23
UNKNOWN EQU 0x5F
org H'0000' ;Origem no endereço 00h de memória
goto INIT ;Desvia para a label início
; --- Vetor de Interrupção ---
org H'0004'
isr:
MOVWF 0x5E
; Reinit TMR0 : TMR0 = 8
MOVLW 8
MOVWF TMR0
; CLEAR TMR FLAG T0IF : T0IF=0
BCF INTCON, 2
; increase 1 microsec
; usec++; increase
;-----------------------------------------------------------------------------------------------------
MOVLW 0x1
ADDWF usec, F
MOVLW 0x0F
SUBWF usec, 0
MOVWF 0x51
BTFSS STATUS, 0
GOTO mangata
lalaind:
BCF STATUS, RP0 ; RA0=~RA0; // togle RA0
MOVLW 0x01
(MOVWF PORTA ); XORWF PORTA, F ==> replaced both
MOVLW 0
MOVWF usec
mangata:
BCF STATUS, 0x5
RETFIE
INIT:
BSF STATUS, 5
CLRF TRISA
; TRISA = 0x00;
CLRF TRISC
BCF STATUS, 5
CLRF PORTA
; PORTC = 0;
CLRF PORTC
; GIE = 1;
BSF INTCON, 7
; T0IF = 0;
BCF INTCON, 2
; T0IE = 1;
BSF INTCON, 5
; T0CS = 0;
BSF STATUS, 5
BCF OPTION_REG, 5 ;(INternal instruuction cycle clock) (clkout)
; PSA = 1;
BSF OPTION_REG, 3 ;Prescalar applied to WDT
; TMR0 = 8;
MOVLW 8
BCF STATUS, 0x5
MOVWF TMR0
CLRF usec
; while(1);
loop:
GOTO loop
end
The code works fine except delay(In MPLAB(MPASM)).after normal 255 counts timer0 call interrupt. there usec is subtracted with 15: to check is it ignited (i think status carry will toggle when usec > 15) and led on on pin RA0. I assumed the DELAY = 255*(15*10) = 38250cycles(Sorry if im wrong).
Let's start with the calculation for your existing code.
The figure 4-1 on page 31 of the data sheet shows the relevant details:
T0CS(timer 0 clock select) to 0, selecting Fosc/4 as input frequency. As you commented in your other question, the oscillator frequency is 4 MHz, thusCLKOUTis 1 MHz. This is one clock tick per cycle.PSA(prescaler assignment) to 1, assigning the prescaler to the watchdog. We can see in the schematic, that this routes the input clock undivided to the timer.SYNCblock is for the cases if you clock the timer from pinT0CKI. In this case, it does not change the frequency, so the timer is clocked by 1 MHz. The only "visible" consequence is a start delayed by 2 cycles after writing to theTMR0register, according to the data sheet.T0IF. You have enabled the interrupts by settingT0IEandGIEaccordingly.TMR0and 0 tousec.TMR0with 8. With the interrupt latency of 3 cycles, 3 instructions of 1 cycle each, and the mentioned synchronization delay of 2 cycles, this adds up to 8 cycles. By chance (or by purpose?) this is exactly the value you write intoTMR0.FT0int =
CLKOUT/ 256 = 1,000,000 Hz / 256 = = 3906.25 HzOr you can think of 256 cycles per interrupt trigger.
useccounting from 0 to 14. The PIC has a kind of "inverted" carry logic, settingCto 0 if it has a borrow. In contrast to your analysis, the carry flag is cleared as long asusecis smaller than 15.subwfsubtractsWfrom the variable, andCis set ifusecis 15 (or greater).256 cycles per interrupt * 15 interrupts = 3840 cycles.
Or as frequency:
Ftoggle = FT0int / 15 = 260,4166... Hz
Now to your goal, you want a 1 second toggle. For this you have several alternatives. These are some:
PS2:PS0to 111, selecting 1:256. The input frequency of the timer is divided by 256.The result is not exactly 1 second, but quite near. A human will not note a difference on a first glance.
Notes:
You might want to postpone the enabling of the interrupts until everything is prepared. Else depending on the situation, an unwanted interrupt might occur.
Since you write 8 to
TMR0at each overflow, you can consider to avoid this and let the timer run through. It will generate the same overflow rate.If you want exact times (as much as the crystal allows), change the reload value of the timer so that it interrupts for example every 200 cycles. Then divide by variables for another 5000 (200 * 5000 = 1000000). Or use a prescaler of 1:64 and let the timer divide by 125. With a software divider of another 125 you reach the same goal (64 * 125 * 125 = 1000000). The secret is in integer factors that multiply to 1000000.