Autor Tema: Base tiempos de 1 segundo con TMR0 MUY EXACTA  (Leído 6813 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado pibe

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 635
Base tiempos de 1 segundo con TMR0 MUY EXACTA
« en: 09 de Enero de 2009, 08:21:31 »
Aqui os dejo un programa basado en el 16f84 a 4mhz, pero puede ir para cualquier micro y cualquier frecuencia.
 Es extremadamente exacto, al menos simulado en MPLAB me da un error de 0 us en un minuto porque se autocorrige!!!
Entiendo que en la realidad puede ser otra cosa, pero vamos... que aún no enviaremos ningún cohete a Marte tripulado con un pic  :mrgreen:

El siguiente setup es para 4 mhz, entonces el valor a cargar en los 3 bytes de corrección es 1.000.000, o sea 0F 42 40 en hexa. Pero si quereis por ejemplo usar un xtal de 20mhz no teneis más que cambiar esos valores por algo 5 veces mas grande, o sea 5.000.000 que serían 4C 4B 40 en hexa.

Tomado de la web http://www.romanblack.com/one_sec.asm



;******************************************************************************
; ZERO-ERROR ONE SECOND TIMER
; (Roman Black 2001, public domain, use it as you like)
;
; INTERRUPT VERSION
;
; for PIC 16F84 at 4 MHz (or most PICs)
; (this code has been assembled with MPLAB and hardware tested)
; (for best viewing set TABS=5 in MPLAB editor)
;
; Note! See text: www.RomanBlack.com/one_sec.htm
;
; Generates an event every second (or other period) from any PIC
; with any clock frequency.
;
; This version uses the timer0 overflow interrupt.
; Code can be adapted for different clock speeds, period lengths
; and accuracy levels.
;
;******************************************************************************


;==============================================================================
; processor defined ;
   include <p16f84.inc>

;==============================================================================
; MPLAB stuff here

   LIST b=5, n=97, t=ON, st=OFF
   ; absolute listing tabs=5, lines=97, trim long lines=ON, symbol table=OFF

   __CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
   ; config for 16F84; code protect OFF, watchdog OFF, powerup timer ON,
   ; oscillator is XT ready for 4 MHz crystal or resonator.

;==============================================================================
; Variables here

   CBLOCK 0x20         ; start of ram in 16F84

      bres_hi         ; hi byte of our 24bit variable
      bres_mid         ; mid byte
      bres_lo         ; lo byte
                  ; (we only need 3 bytes for this system)

      status_temp      ; used for interrupt servicing
      w_temp         ; used for interrupt servicing

   ENDC


;==============================================================================
; Code here

   org 0x000          ; Set program memory base at reset vector 0x000
reset
   goto setup         ; set up ints and port stuff

   org 0x004            ; Interrupt vector, int handler code comes next.
;==============================================================================


;******************************************************************************
;  INTERRUPT HANDLER     (runs this code each timer0 interrupt)
;******************************************************************************
;
;------------------
int_handler            ;
;------------------

   ;-------------------------------------------------
                  ; first we preserve w and status register

   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

   ;-------------------------------------------------
   ; Note! we get here every 256 instructions, we
   ; can now do our special one second timing system.            

   ; This consists of three main steps;
   ; * subtract 256 counts from our 24bit variable
   ; * test if we reached the setpoint
   ; * if so, add 1,000,000 counts to 24bit variable and generate event.
   ;-------------------------------------------------
                  ; * optimised 24 bit subtract here
                  ; This is done with the minimum instructions.
                  ; We subtract 256 from the 24bit variable
                  ; by just decrementing the mid byte.

   tstf bres_mid         ; first test for mid==0
   skpnz            ; nz = no underflow needed
   decf bres_hi,f         ; z, so is underflow, so dec the msb

   decfsz bres_mid,f      ; dec the mid byte (subtract 256)

                  ; now the full 24bit optimised subtract is done!
                  ; this is about 4 times faster than a "proper"
                  ; 24bit subtract.

   goto int_exit         ; nz, so definitely not one second yet.
                  ; in most cases the entire int takes
                  ; only 16 instructions.
   ;------------------------
                  ; * test if we have reached one second.
                  ; only gets here when mid==0, it MAY be one second.
                  ; only gets to here 1 in every 256 times.
                  ; (this is our best optimised test)
                  ; it gets here when bres_mid ==0.

   tstf bres_hi         ; test hi for zero too
   skpz               ; z = both hi and mid are zero, is one second!
   goto int_exit         ; nz, so not one second yet.

   ;-------------------------------------------------
   ; Only gets to here if we have reached one second.

   ; now we can generate our one second event, like add
   ; one second to our clock or whatever.
   ; (in this example we toggle a led)

   ; The other thing we need to do is add 1,000,000 counts
   ; to our 24bit variable and start all over again.
   ;-------------------------------------------------
                  ; Add the 1,000,000 counts first.
                  ; One second = 1,000,000 = 0F 42 40 (in hex)

                  ; As we know hi==0 and mid==0 this makes it very fast.
                  ; This is an optimised 24bit add, because we can
                  ; just load the top two bytes and only need to do
                  ; a real add on the bottom byte. This is much quicker
                  ; than a "proper" 24bit add.

   movlw 0x0F         ; get msb value
   movwf bres_hi         ; load in msb

   movlw 0x42         ; get mid value
   movwf bres_mid         ; load in mid

   movlw 0x40         ; lsb value to add
   addwf bres_lo,f      ; add it to the remainder already in lsb
   skpnc            ; nc = no overflow, so mid is still ok

   incf bres_mid,f      ; c, so lsb overflowed, so inc mid
                  ; this is optimised and relies on mid being known
                  ; and that mid won't overflow from one inc.

                  ; that's it! Our optimised 24bit add is done,
                  ; this is roughly twice as quick as a "proper"
                  ; 24bit add.
   ;-------------------------
                  ; now we do the "event" that we do every one second.

                  ; Note! for this example we toggle a led, which
                  ; will give a flashing led which is on for a second
                  ; and off for a second.
                  ; Add your own code here for your one second event.

                  ; Note! My led is on porta,3
                  ; your led may be on a different pin.
   movlw b'00001000'      ; mask for bit 3
   xorwf PORTA,f         ; toggle PORTA,bit3 (toggle the led)
                  
   ;-------------------------------------------------
   ; now our one second event is all done, we can exit the
   ; interrupt handler.
   ;-------------------------------------------------
                  ; finally we restore w and status registers.
                  ; also clears TMRO int flag now we are finished.
int_exit
   BCF INTCON,T0IF      ; reset the tmr0 interrupt flag

   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
;------------------------------------------------------------------------------



;******************************************************************************
;  SETUP     (runs this only once at startup)
;******************************************************************************
;
;------------------
setup               ; goto label
;------------------

   ;-------------------------------------------------
   ; Note! 16F84 version.
   ; Note! here we set up peripherals and port directions.
   ; this will need to be changed for different PICs.
   ;-------------------------------------------------
                  ; OPTION setup
   movlw b'10001000'      ;
      ;  x-------      ; 7, 0=enable, 1=disable, portb pullups
      ;  -x------      ; 6, 1=/, int edge select bit
      ;  --x-----      ; 5, timer0 source, 0=internal clock, 1=ext pin.
      ;  ---x----      ; 4, timer0 ext edge, 1=\
      ;  ----x---      ; 3, prescaler assign, 1=wdt, 0=timer0
      ;  -----x--      ; 2,1,0, timer0 prescaler rate select
      ;  ------x-      ;   000=2, 001=4, 010=8, 011=16, etc.
      ;  -------x      ;
                  ; Note! We set the prescaler to the wdt, so timer0
                  ; has NO prescaler and will overflow every 256
                  ; instructions and make an interrupt.
                  ;
   banksel OPTION_REG      ; go proper reg bank
   movwf OPTION_REG      ; load data into OPTION_REG
   banksel 0            ; back to normal bank 0
   ;-------------------------------------------------
                  ; PORTB pins direction setup
                  ; 1=input, 0=output
   clrf PORTB         ;
                  ;
   movlw b'00000000'      ; all 8 portb are outputs
                  ;
   banksel TRISB         ; go proper reg bank
   movwf TRISB         ; send mask to portb
   banksel 0            ; back to normal reg bank
   ;-------------------------------------------------
                  ; PORTA pins direction setup
                  ; 1=input, 0=output
   clrf PORTA         ;
                  ;
   movlw b'00000000'      ; all 5 porta are outputs,
                  ; (with 16F84 porta only has lower 5 bits)
                  ;
   banksel TRISB         ; go proper reg bank
   movwf TRISA         ; send mask to porta
   banksel 0            ; back to normal reg bank
   ;-------------------------------------------------
                  ; INTCON setup
                  ;
                  ; for this code example, we enable the timer0
                  ; overflow interrupt.
                  ;
                  ; enable interrupts last
                  ; interrupt setup
   movlw b'10100000'      ; GIE=on TOIE=on (timer0 overflow int)
   movwf INTCON         ; set up.

   ;-------------------------------------------------
   ; Note! Now the hardware is set up we need to load the
   ; first count for one second into our 24bit bres variable.
   ;-------------------------------------------------
                  ; Note! This example uses 4 MHz clock, which is
                  ; 1,000,000 counts per second.
                  ;
                  ; We require a 1 second period, so we must load
                  ; 1,000,000 counts each time.
                  ; 1,000,000 = 0F 42 40 (in hex)
                  ;
                  ; We also need to add 256 counts for the first time,
                  ; so we just add 1 to the mid byte.
                  ; Check mid overflow if needed.

                  ; here we load the 24bit variable.
   movlw 0x0F         ; get msb value
   movwf bres_hi         ; put in hi

   movlw 0x42 +1         ; get mid value (note we added 1 to it)
   movwf bres_mid         ; put in mid

   movlw 0x40         ; get lsb value
   movwf bres_lo         ; put in mid

                  ; now setup is complete, we can start execution.
   ;-------------------------------------------------
   goto main            ; start main program

;------------------------------------------------------------------------------



;******************************************************************************
;  MAIN     (main program loop)
;******************************************************************************
;
;------------------
main                  ; goto label
;------------------

   ;-------------------------------------------------
   ; Note! This example uses the timer0 overflow interrupt.
   ; This will interrupt our main program every 256 instructions
   ; and do the one second timer system.
   ;-------------------------------------------------
main_loop               ;
                  ; Note! here you have your main program code,
                  ; or calls to the main program pieces.
                  ; The interrupt does all the one second timer stuff.
   ; stuff
   ; stuff
   ; stuff
   ; stuff

   ;-------------------------------------------------
   goto main_loop         ; keep running the main code.

;------------------------------------------------------------------------------


;==============================================================================
   end               ; no code after this point.
;==============================================================================

Mi jefe mirando el prototipo que estoy creando: "Y eso va a funcionar?"

Desconectado Leon Pic

  • Colaborador
  • DsPIC30
  • *****
  • Mensajes: 3610
    • Impresiones en 3D
Re: Base tiempos de 1 segundo con TMR0 MUY EXACTA
« Respuesta #1 en: 09 de Enero de 2009, 12:24:03 »
Muchas gracias por publicarlo. Es una rutina muy buena y muy útil.  :-/
Jesús dijo, yo soy el CAMINO, la VERDAD y la VIDA, nadie llega al PADRE si no es por mi.

Desconectado MAXI

  • PIC10
  • *
  • Mensajes: 34
Re: Base tiempos de 1 segundo con TMR0 MUY EXACTA
« Respuesta #2 en: 03 de Noviembre de 2009, 17:40:13 »
Pibe: Muchisimas gracias por tu aporte!!!!. Soy bastante nuevo en el foro y espero en alguna oprtunidad poder ayudar como lo haz hecho conmigo esta vez. Saludos.


 

anything