Stránka 1 z 2
Pic a vteřinové pulzy
Napsal: 16 zář 2012, 14:26
od dracekvo
Zdravím,
dělám první pokusy s pic a zkouším si udělat počítání vteřin a minut, ale trošku se mi to předchází a chtěl bych požádat o radu.
Mám interní oscilátor na 4mhz a počítal sem následně
TMR0 za vteřinu udělá 15625 přičtení s děličkou 64.
Takže pokud tmr0 posunu tak, aby počítal do 125 udělá mi 125x za vteřinu přerušení. V každém přerušení k tmr0 tedy přičítám číslo 131.
A pak mi stačí v každém přerušení inkrementovat o 1 v nějaké proměné a když dosáhne 125 mám vteřinu.
Celé jsem to nějak udělal, připomínám, že to je můj druhý program v životě, takže tam bude asi řada blbostí.
Vím, že to nebude nikdy přesné, ale předchází se mi to za 20 min asi o 7 vteřin proti stopkám, což mi příde hodně.
Kód: Vybrat vše
LIST P=16F628
INCLUDE<P16F628A.INC>
__CONFIG _PWRTE_ON & _WDT_OFF & _MCLRE_OFF & _BODEN_OFF & _LVP_OFF & _INTRC_OSC_NOCLKOUT
;RAM
w_zaloha equ 20h
status_zaloha equ 21h
pcl_zaloha equ 22h
fsr_zaloha equ 23h
cislo1 equ 24h
cislo2 equ 25h
cislo3 equ 26h
cislo4 equ 27h
cislo_cek equ 28h
cislo_tmr0 equ 29h
;-----------------------------------------------------
;definice
#DEFINE disp1 PORTA,0
#DEFINE disp2 PORTA,1
#DEFINE disp3 PORTA,2
#DEFINE disp4 PORTA,3
#DEFINE zn_a PORTB,0
#DEFINE zn_b PORTB,1
#DEFINE zn_c PORTB,2
#DEFINE zn_d PORTB,3
#DEFINE zn_e PORTB,4
#DEFINE zn_f PORTB,5
#DEFINE zn_g PORTB,6
#DEFINE zn_h PORTB,7
#DEFINE c STATUS,0
#DEFINE tl1 PORTA,4
;-----------------------------------------------------
;zacatek programu
org 00h
goto INIT
;-----------------------------------------------------
;preruseni
org 04h
goto PRERUS
;-----------------------------------------------------
PRERUS
movwf w_zaloha ;zaloha registru
movf STATUS,W
clrf STATUS
movwf status_zaloha
movf PCLATH,w
movwf pcl_zaloha
movf FSR,w
movwf fsr_zaloha
;--------
btfsc INTCON,2 ;preruseni je od TMR0
goto TMR_0
TMR0_ZPET nop
;--------
BSF STATUS,RP0 ;obnova registru po preruseni
MOVLW B'10100000'
MOVWF INTCON
BCF STATUS,RP0
clrf STATUS
movf fsr_zaloha,w
movwf FSR
movf pcl_zaloha,w
movwf PCLATH
movf status_zaloha,w
movwf STATUS
swapf w_zaloha,f
swapf w_zaloha,w
retfie
TMR_0 bcf INTCON,2 ;reset priznaku preruseni tmr0
movlw d'131' ;pricteni 131 k tmr0
addwf TMR0,1
incf cislo_tmr0 ;pokud je napocitano do 125 skok na pricti
movlw d'125'
subwf cislo_tmr0,W
btfsc c
goto pricti
goto KONEC
pricti clrf cislo_tmr0 ;pricteni vteriny do pameti
incf cislo1
movlw D'10'
subwf cislo1,W
btfss c
goto KONEC
clrf cislo1
incf cislo2
movlw D'6'
subwf cislo2,W
btfss c
goto KONEC
clrf cislo2
incf cislo3
movlw D'10'
subwf cislo3,W
btfss c
goto KONEC
clrf cislo3
incf cislo4
movlw D'6'
subwf cislo4,W
btfss c
goto KONEC
call smazat
KONEC goto TMR0_ZPET
;-----------------------------------------------------
INIT movlw B'00000111' ; nastaveni komparatoru (off)
movwf CMCON
bsf STATUS,RP0 ;prepnui bank 1
movlw B'00010000' ;nastaveni vstupy vystupy
movwf TRISA
movlw B'00000000'
movwf TRISB
movlw B'10000101' ;nastaveni option
movwf OPTION_REG
bcf STATUS,RP0 ;prepnuti bank 0
MOVLW B'10100000' ; povoleni preruseni pouze od RB0
MOVWF INTCON
MOVLW B'00001111' ;reset vystup portu
MOVWF PORTA
MOVLW B'11111111'
MOVWF PORTB
clrf cislo_tmr0 ;smazani
MAIN
movf cislo4,w ;zobrazeni 1 segment
call segment
MOVWF PORTB
bcf disp1
call cekej
bsf disp1
movf cislo3,w ;zobrazeni 2 segment
call segment
MOVWF PORTB
bcf disp2
call cekej
bsf disp2
movf cislo2,w ;zobrazeni 3 segment
call segment
MOVWF PORTB
bcf disp3
call cekej
bsf disp3
movf cislo1,w ;zobrazeni 4 segment
call segment
MOVWF PORTB
bcf disp4
call cekej
bsf disp4
btfsc tl1 ;pri stisku tlacitka smazat cisla
call smazat
GOTO MAIN
segment
addwf PCL,F
retlw B'11000000' ;0
retlw B'11111001' ;1
retlw B'10100100' ;2
retlw B'10110000' ;3
retlw B'10011001' ;4
retlw B'10010010' ;5
retlw B'10000010' ;6
retlw B'11111000' ;7
retlw B'10000000' ;8
retlw B'10010000' ;9
smazat
clrf cislo1
clrf cislo2
clrf cislo3
clrf cislo4
return
cekej
clrf cislo_cek
cekej_zpet incfsz cislo_cek,1
goto cekej_zpet
return
END
Napsal: 16 zář 2012, 17:03
od Atlan
Aco na to hovoria stopky v mplabe od mikrocipu? Pri simulacii? Interny oscilator tusim ma rozptyl 10% tak ze asi ani pri 20st nekmita presne na 4Mhz. Vid datasheet,specifikacia a grafi.
Napsal: 16 zář 2012, 17:04
od procesor
Použi Xtal 4194304 Hz.
Preddeličku 256/128/64/32....
TMR0 na plných 256...netreba nič prepisovať, či resetovať. Prescaler sa resetuje pritom tiež, čím sa strácajú takty a tie sa nedajú jednoducho kompenzovať.
Do sekundy napočítaš 16/32/64/128... prerušení.
Takto sa dostaneš na presnosť toho kryštálu
Napsal: 16 zář 2012, 17:24
od dracekvo
No, já sem právě do datasheetu koukal a tam píšou že 1%. Se simulátorem si nějak nerozumím.
Jinak krystal na takové zvláštní frekvenci nemám.
Spíše mi šlo o to, jestli jdu na to správně a nemám chybu v programu.
Napsal: 16 zář 2012, 18:59
od procesor
Chyba je v tom obnovovaní TMR0. Výsledný čas nie je len funkciou oscilátora.
Taký kryštál je bežne dostupný.
1% pri hodinách je strašne veľa...cca za štyri dni jedna hodina.
Napsal: 17 zář 2012, 07:32
od dracekvo
Aha, dobrá. Mám tu 4mhz krystal, takže to můžu zkusit s ním. Tamten budu muset objednat, ale to až časem až budu mít k objednání víc věcí.
Napsal: 17 zář 2012, 07:47
od procesor
Podstata presnosti spočíva v tom, aby TMR0 sa točil dookola (delil 1:126) a do sekundy tých prerušení vyšlo binárnym delením celé číslo.
Napsal: 17 zář 2012, 13:46
od Hill
Jestli to máš na opravdové měření času a ne jen jako hračku, tak nezapomínej, že i přesnost ±1% znamená odchylku téměř ±15 minut za 24 hodin!
V tom případě je skutečně nejpřesnější externí časovač (třeba i z krystalem 32768 Hz řízeného budíku, lepší z budíku s krystalem 4,194304 MHz, případně použít normální binární děličku z některého z uvedených krystalů, a nejpřesnější by byl z budíku synchronizovaného z DCF77) a pocíkem si jen osahávat jeho výstupy, případně výstupními impulsy z děličky vyvolávat přerušení programu.
Ale, jesti to má měřit jen v řádu několika málo jednotek minut, pak ta nepřesnost nebude asi tolik rušit.
Napsal: 17 zář 2012, 14:36
od Atlan
32khz by mali mat najmensiu teplotnu zavislost nie? Kedze sa predpklada ako zdroj pre hodiny. Zapni si debuger, a najdi polozku stopwach, F9 spusta program,F6 je tusim stop, F5 reset... fF7 krokovanie po prikazoch, aspon sa nieco naucis.
Napsal: 17 zář 2012, 23:03
od Hill
Teplotní závislost krystalu závisí na směru jeho řezu a směru jeho kmitů. Takže bych se nějakému hodnocení stability vyhnul, pokud tyto faktory neznám.
Napsal: 18 zář 2012, 07:36
od frpr666
Jak se psalo výše, interní osc. u 16F628 má svůj rozptyl. Pro přesné časování použij krystal.
Pro generování přesných vteřinových pulsů lze samozřejmě použít i ten 4MHz krystal.
(Making a 1 second period with any PIC (assembler),
http://www.romanblack.com/one_sec.htm
Jinak pic 16F628 má pro časovací účely ještě jeden oscilátor Timer 1 oscilator - It is primarily intended for a 32 kHz crystal.
Napsal: 18 zář 2012, 08:08
od dracekvo
Krystal 4mhz i 32khz mám. O moc velkou přesnost mi nejde, na hodiny tu mám obvod reálného času. Spíše si tak hraju, abych se s tím seznámil.
O víkendu to tedy pustím v simulátoru a uvidím.
Napsal: 18 zář 2012, 12:46
od psychosalam
->dracekvo to je dobre ze si hrajes, aspon se neco naucis a kdo hraje, tak nezlobi.
Ale vazne, ono se ti to bude vzdycky predchazet nebo zpozdovat. Delat hodiny nebo jen zdroj presnych pulzu s mikropocitacem moc nejde. Teda jde, ale zalezi na tom, kdo cemu rka presnost.
Existuje MCU od Microchip, s kterym jakz takz lze generovat pulzy z 10 MHz oscilatoru tim, ze se vyuziva presne delky instrukce. Jedna se PIC16F84.
Ten program je tu, vyzkousej ho, objevil jsem ho kdysi davno na netu, napsal ho nejaky holandan a sveho casu ho vsichni oslavovali. Dners uz ho tak neoslavuji, protoze ma to hacek. Az to naprogramujes, tak si ty signaly z PICu pripoj na citac. Citac synchronizuj externe z 10 MHz signalem z GPS, aby jsi dostal standard a zacni merit kmitocet jednotlivych vystupnich signalu z PICu. Az do 100 Hz dolu to jde, 10Hz uz je problem, 1Hz je o nicem a ty nizsi signaly ... radeji nemluvit.
; ----------------------------------------------------------------------
;
; Title:
;
; 10 MHz frequency divider
;
; Function:
;
; This PIC 16C84 program is designed to divide a 10 MHz frequency
; source down to 1 Hz (1 PPS).
; The PIC 16C84 could be substitued a 16F84A flash chip.
;
; Since several extra output pins are available the program creates
; a total of 9 square wave outputs -- one for each frequency decade
; from 100 kHz to 0.001 Hz (1000 s).
;
; A STOP input and a 1 PPS synchronization input are also provided.
; Raising the STOP input high stops and resets the divider. The
; divider resumes on the leading edge of the 1 PPS SYNC input. The
; 1 PPS output will be synchronized to the 1 PPS SYNC input to less
; than 1.2 us (three PIC instructions at 10 MHz).
;
; The following chip schematic shows the assignment of each pin.
;
; ------ ------
; 100 kHz <- RA2 |1 --- 18| RA1 -> Red LED
; Green LED <- RA3 |2 17| RA0 <= Stop input
; 1PPS SYNC => T0CKI/RA4 |3 16| OSC1/CLKIN <= 10 MHz input
; +5 VDC -> /MCLR |4 15| OSC2/CLKOUT -- N/C
; GND -> Vss |5 16C84 14| Vdd <- +5 VDC
; 10 kHz <- INT/RB0 |6 13| RB7 -> 1000 s
; 1 kHz <- RB1 |7 12| RB6 -> 100 s
; 100 Hz <- RB2 |8 11| RB5 -> 10 s
; 10 Hz <- RB3 |9 10| RB4 -> 1 Hz / 1 PPS
; ---------------
;
; Implementation:
;
; To generate a 10 kHz square wave at 50% duty cycle an output pin
; must be flipped every 50 us (125 instructions at 10 MHz clock).
; This program does not use TMR0, the pre-scaler, or interrupts.
; Instead it relies on the fact that given an accurate 10 MHz clock
; each PIC instruction takes precisely 400 ns and the main loop has
; been designed to use exactly 125 instructions.
;
; The 100 kHz frequency (10 us period) is generated by setting an
; output pin on and off every 25 cycles. Since 25 is an odd number
; it is not possible for the PIC to generate this square wave with
; a 50% duty cycle. Instead a 20% duty cycle (5 cylcles on and 20
; cycles off) was chosen for this frequency output. A total of 5
; pairs of 100 kHz bit set/clear code are carefully interspersed
; within the 50 us main loop.
;
; Pins RA0 and RA4 are not used to drive a LED. RA4 is a Schmidt
; trigger input and O.C. output. It is used as the SYNC input.
; The data sheet says not to toggle RA0 under some conditions so
; it is used as the STOP input.
;
; Version:
;
; 1998-Aug-05, Version 4, tvb
;
; ----------------------------------------------------------------------
; Using Microhip assembler.
list p=16c84
STATUS set 3
PORTA set 5
PORTB set 6
BASE2 equ 2
HALF2 equ 1
BASE10 equ 0x0a
HALF10 equ 0x05
; STATUS bit definitions
Zero Equ 2
; PORTA bit definitions
Stop Equ 0
Red Equ 1
F100k Equ 2
Green Equ 3
Sync Equ 4
; Temporary register definitions
OutByte equ 0x0c
DelayTemp equ 0x0d
; Decade counter register definitions
Digit0 equ 0x10
Digit1 equ 0x11
Digit2 equ 0x12
Digit3 equ 0x13
Digit4 equ 0x14
Digit5 equ 0x15
Digit6 equ 0x16
Digit7 equ 0x17
; ----------------------------------------------------------------------
org 0
Start GOTO Init
org 4
Interrupt GOTO $
Init CLRF PORTA ; set pins low by default
BCF PORTA, Green
BCF PORTA, Red
BSF PORTA, F100k ; start with 100 kHz high
MOVLW 0x11 ; set RA0/RA4 input
TRIS PORTA
MOVLW 0xff ; start with outputs high
MOVWF PORTB
MOVLW 0x00 ; set all pins output
TRIS PORTB
CLRF Digit0
CLRF Digit1
CLRF Digit2
CLRF Digit3
CLRF Digit4
CLRF Digit5
CLRF Digit6
CLRF Digit7
MOVLW 0xff ; start with outputs high
;
; The following implements a software decade divider chain much like
; a string of 7490 decade counter chips or an odometer.
;
; The low-order digit is incremented and when it wraps the carry is
; propagated to the next higher-oder digit. Since square waves are
; being generated in this particular case the low-order digit is
; incremented from 0 to 1 to 0. All remaining digits count from
; 0 to 9 and wrap back to 0. The STATUS Z bit is used to propagate
; carry into the next digit: Z mean carry and not-Z means no carry.
;
; The low order digit toggles every 125 instructions (50 us) for
; a period of 100 us and a frequency of 10 kHz. Each next higher
; order digit counts at 1/10 the rate of the preceding digit.
; The 100 kHz output changes too rapidly for the main loop so it
; is implemented independently.
;
; Note all 8 bits of PORTB are set at the same time so that the
; PIC acts like a synchronous, rather than an asynchronous, decade
; counter. The 100 kHz output pin is in PORTA so the phase of the
; 100 kHz frequency output lags the other outputs by one cycle.
;
Loop MOVWF PORTB
BSF PORTA, F100k ; set 100 kHz high for 5 cycles (1 of 5)
INCF Digit0
MOVLW BASE2
SUBWF Digit0, W
NOP
BCF PORTA, F100k ; set 100 kHz low for 20 cycles
BTFSC STATUS, Zero
CLRF Digit0
Loop1 BTFSC STATUS, Zero
INCF Digit1
MOVLW BASE10
SUBWF Digit1, W
BTFSC STATUS, Zero
CLRF Digit1
BTFSC STATUS, Zero
INCF Digit2
MOVLW BASE10
SUBWF Digit2, W
BTFSC STATUS, Zero
CLRF Digit2
BTFSC STATUS, Zero
INCF Digit3
MOVLW BASE10
SUBWF Digit3, W
NOP
BSF PORTA, F100k ; set 100 kHz high for 5 cycles (2 of 5)
BTFSC STATUS, Zero
CLRF Digit3
BTFSC STATUS, Zero
INCF Digit4
BCF PORTA, F100k ; set 100 kHz low for 20 cycles
MOVLW BASE10
SUBWF Digit4, W
BTFSC STATUS, Zero
CLRF Digit4
BTFSC STATUS, Zero
INCF Digit5
MOVLW BASE10
SUBWF Digit5, W
BTFSC STATUS, Zero
CLRF Digit5
BTFSC STATUS, Zero
INCF Digit6
MOVLW BASE10
SUBWF Digit6, W
BTFSC STATUS, Zero
CLRF Digit6
BTFSC STATUS, Zero
INCF Digit7
MOVLW BASE10
BSF PORTA, F100k ; set 100 kHz high for 5 cycles (3 of 5)
SUBWF Digit7, W
BTFSC STATUS, Zero
CLRF Digit7
;
; Now compress 8 digits into one byte of 50% duty cycle bits. If the
; odometer digit is less than 5 create a one bit and if the odometer
; digit is 5 or more create a zero bit.
;
MOVLW HALF2
BCF PORTA, F100k ; set 100 kHz low for 20 cycles
SUBWF Digit0, W
RRF OutByte, 1
MOVLW HALF10
SUBWF Digit1, W
RRF OutByte, 1
MOVLW HALF10
SUBWF Digit2, W
RRF OutByte, 1
MOVLW HALF10
SUBWF Digit3, W
RRF OutByte, 1
MOVLW HALF10
SUBWF Digit4, W
RRF OutByte, 1
MOVLW HALF10
SUBWF Digit5, W
RRF OutByte, 1
MOVLW HALF10
SUBWF Digit6, W
BSF PORTA, F100k ; set 100 kHz high for 5 cycles (4 of 5)
RRF OutByte, 1
MOVLW HALF10
SUBWF Digit7, W
RRF OutByte, 1
BCF PORTA, F100k ; set 100 kHz low for 20 cycles
MOVLW 0xff
XORWF OutByte
;
; Add delays so that the loop takes exactly 125 cycles (50 us).
;
CALL Delay10
CALL Delay6
NOP
BSF PORTA, F100k ; set 100 kHz high for 5 cycles (5 of 5)
CALL Delay4
BCF PORTA, F100k ; set 100 kHz low for 20 cycles
CALL Delay10
CALL Delay4
;
; Check STOP signal once per loop then exit the loop with the next
; version of OutByte in W. The top of the loop writes PORTB.
;
MOVF OutByte, W
BTFSS PORTA, Stop ; is STOP pin high?
GOTO Loop ; no, continue
;
; STOP-SYNC protocol:
;
; 1) Divider free running (No LEDs)
; - User sets STOP pin high.
; - PIC stops frequency generator.
;
; 2) Divider stopped (Red LED)
; - PIC waits for STOP pin to go low again.
; - User sets STOP pin low.
; - PIC resets counter and output lines.
;
; 3) Waiting for SYNC (Red and Green LEDs)
; - PIC waits for SYNC pin to go from low to high.
; - User sends 1 PPS pulse to SYNC pin.
; - PIC resumes frequency generator.
;
; 4) Divider running in sync (Green LED)
;
BCF PORTA, Green
BSF PORTA, Red
BTFSC PORTA, Stop ; is STOP pin low?
GOTO $-1 ; no, keep checking
BSF PORTA, Green
CLRF Digit0
CLRF Digit1
CLRF Digit2
CLRF Digit3
CLRF Digit4
CLRF Digit5
CLRF Digit6
CLRF Digit7
MOVLW 0xff ; start with outputs high
MOVWF PORTB
BSF PORTA, F100k ; start with 100 kHz high
;
; Resume on leading edge of SYNC pin. The PIC will be one to three
; instructions behind the actual 1 PPS sync pulse.
;
BTFSC PORTA, Sync ; is 1 PPS sync low?
GOTO $-1 ; no, keep checking
BTFSS PORTA, Sync ; is 1 PPS sync high?
GOTO $-1 ; no, keep checking
;
; Now synchronously rejoin main loop.
;
BCF PORTA, Red
INCF Digit0
NOP
BCF STATUS, Zero
BCF PORTA, F100k ; set 100 kHz low for 20 cycles
GOTO Loop1
; ----------------------------------------------------------------------
;
; Delay routines.
;
; - To delay 1 cycle use NOP.
; - To delay 2 cycles use GOTO $+1.
; - To delay 3 cycles use NOP and GOTO $+1.
; - To delay 4 cycles use CALL Delay4.
; - To delay 10 cycles use CALL Delay10, etc.
;
; For other delays use a combination of the above.
;
Delay100 GOTO $+1
Delay98 MOVLW 24
MOVWF DelayTemp
DECFSZ DelayTemp
GOTO $-1
Delay25 GOTO $+1
Delay23 MOVLW 4
MOVWF DelayTemp
DECFSZ DelayTemp
GOTO $-1
Delay10 GOTO $+1
Delay8 GOTO $+1
Delay6 GOTO $+1
Delay4 RETURN
END
Napsal: 21 zář 2012, 13:30
od ZdenekHQ
Ono, když se používá přerušení ke generování přesných pulsů, tak se dopočítává korekce - t.j. zohledňuje se doba, která uplynula od vyvolání přerušení do jeho obsluhy (dá se vyčíst z časovače) a ta se následně odečte od hodnoty nového nastavení časovače. Pak to tiká přesně.
Napsal: 21 zář 2012, 13:35
od Andrea
Pokud se rovnou nepoužije režim, kdy se hodnota čítače obnovuje na konci periody hardwarově.