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ě.