logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[ATmega8][asm] Niestebilny wynik pomiaru częstotliwości

darkonel 02 Sty 2011 16:11 1691 2
  • #1 8947490
    darkonel
    Poziom 19  
    Witam. Robię miernik częstotliwości na ATmega8 z wyświetlaniem na LCD HD44780 w trybie 4-bit (mam zrobiony prototyp). Opanowałem już wyświetlanie (z obsługą BF), ale teraz przystawiło mnie z pomiarem liczby impulsów zliczanych na wejściu T1 mikrokontrolera. Wynik co prawda jest wyświetlany, lecz jest on niestabilny w taki sposób, że skaczą 2 ostatnie cyfry wyniku. Odświeżanie to czas 0,64s. W tym czasie mikrokontroler zlicza impulsy w 16-bitowym TC1 i pomocniczo w rejestrze Cnt w przerwaniu od TC1. Czas bramkowania jest generowany przez TC0 (odpowiednia liczba pustych okrążeń i precyzyjnie dobrany czas ostatniego okrążenia) tak aby sumaryczny czas okrążeń wyniósł 0,64s. Oto fragment kodu jaki stworzyłem w asm:
    
    
    .nolist
    .include "m8def.inc"
    .list
    ;-------
    .equ LCDport 	= PortD
    .equ LCDpin		= PinD
    .equ LCDio		= DDRD
    .equ RS		= 6
    .equ RW		= 4
    .equ CE		= 7
    .equ DB4 	= 3
    .equ DB5 	= 2
    .equ DB6 	= 1
    .equ DB7 	= 0
    ;-------
    .def Acc	= R16	; akumulator
    .def ref1	= R17	; rejestr pętli opóźniającej
    .def ref2	= R18	; rejestr pętli opóźniającej
    .def Func	= R15	; rejestr funkcji (rezerwa)
    .def Reg0	= R3	; zliczanie - bajt LSB do konwersji
    .def Reg1	= R4	; zliczanie - bajt do konwersji
    .def Reg2	= R5	; zliczanie - bajt MSB do konwersji
    ;-------
    .def Cnt	= R9	; dodatkowy rejestr zliczania impulsów
    .def Reg12	= R22	; rejestr przechowujacy BCD (cyfra2, cyfra1)
    .def Reg34	= R23	; rejestr przechowujacy BCD (cyfra4, cyfra3)
    .def Reg56	= R24	; rejestr przechowujacy BCD (cyfra6, cyfra5)
    .def Reg78	= R25	; rejestr przechowujacy BCD (cyfra8, cyfra7)
    .def Flag	= R19	; rejestr-flaga ostatniego okrążenia timera TC0
    .def Del	= R20	; rejestr zgrubnego ustawienia czasu bramkowania
    .equ DelVal	= 143	; wartosć zgrubnego ustawienia czasu bramkowania (puste okrążenia)
    .equ TimTC0	= 35	; wartość dokładnego ustawienia czasu bramkowania (ostatnie okrążenie)
    .cseg
    ;=============================
    .macro	tabl			; makro ładujące adres
    ldi ZL, low(@0 << 1) 	; załaduj do rejestru Z adres tablicy z tekstem
    ldi ZH, high(@0 << 1) 	; załaduj do rejestru Z adres tablicy z tekstem
    .endmacro
    ;=============================
    .org 0			rjmp reset	; External Pin, Power-on Reset, Brown-out Reset, and Watchdog Reset
    .org INT0addr	reti		; External Interrupt Request 0
    .org INT1addr	reti		; External Interrupt Request 1
    .org OC2addr	reti		; Timer/Counter2 Compare Match
    .org OVF2addr	reti		; Timer/Counter2 Overflow
    .org ICP1addr	reti		; Timer/Counter1 Capture Event
    .org OC1Aaddr	reti		; Timer/Counter1 Compare Match A
    .org OC1Baddr	reti		; Timer/Counter1 Compare Match B
    .org OVF1addr	rjmp IntT1	; Timer/Counter1 Overflow
    .org OVF0addr	rjmp IntT0	; Timer/Counter0 Overflow
    .org SPIaddr	reti		; Serial Transfer Complete
    .org URXCaddr	reti		; USART, Rx Complete
    .org UDREaddr	reti		; USART Data Register Empty
    .org UTXCaddr	reti		; USART, Tx Complete
    .org ADCCaddr	reti		; ADC Conversion Complete
    .org ERDYaddr	reti		; EEPROM Ready
    .org ACIaddr	reti		; Analog Comparator
    .org TWIaddr	reti		; Two-wire Serial Interface
    .org SPMRaddr	reti		; Store Program Memory Ready
    ;=============================
    reset:
    ;*********************************************************
    ; ustawienie portów mikrokontrolera (bit 5 wejście T1)
    ;*********************************************************
    	ldi Acc,0b11011111	; ustawienie potru LCDio jako wyjście
    	out LCDio,Acc	; 0-wejście, 1-wyjście
    	ldi Acc,0b11111111
    	out LCDport,Acc ; podciągnij wszystkie piny do plusa
    
    ;*********************************************************
    ; ustawienie stosu
    ;*********************************************************
    	ldi	Acc, low(RAMEND)
    	out	SPL, Acc
    	ldi	Acc, high(RAMEND)
    	out	SPH, Acc
    ;*********************************************************
    ; ustawienie timerów i przerwań i rejestrów
    ;*********************************************************
    	ldi Acc,1<<TOIE1|1<<TOIE0
    	out TIMSK,Acc		; ustawienie maski przerwań
    	ldi Del,DelVal		; zgrubny czas bramkowania (przerwania od TC0)
    	ldi Acc,1<<CS02|0<<CS01|0<<CS00
    	out TCCR0,Acc		; TC0 clk/256, start
    	ldi Acc,1<<CS12|1<<CS11|1<<CS10
    	out TCCR1B,Acc		; TC1 zliczanie zewnętrzne, start
    	clr Flag			; zeruj rejestr flag
    	clr Cnt
    	clr Reg0
    	clr Reg1
    	clr Reg2
    	clr Reg12
    	clr Reg34
    	clr Reg56
    	clr Reg78
    


    A przerwania wyglądają tak:
    
    
    ;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    ; Przepełnienie zliczania impulsów wejściowych
    ;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    IntT1:
    inc Cnt	;zwiększenie najstarszego licznika impulsów
    reti
    ;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    ; Zatrzymanie zliczania i wyświetlenie (co 0,64 s)
    ;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    IntT0:
    	push Acc
    	cpi Flag,0xFF		; sprawdź rejestr Flag
    	breq wykon			; jeśli ustawiony - skocz do procedury
    	dec Del				; rejestr Flag nie był ustawiony, zmniejsz Del
    	brne skip1			; jeśli Del różne od zera, wyjdź
    	ldi Acc,TimTC0		; dokładny czas bramkowania (przerwania od TC0)
    	com Acc				; zanegowanie bajtu (ujednolicenie wpisywania wartości)
    	out TCNT0,Acc		; dokładny czas bramkowania (przerwania od TC0)
    	ser Flag			; rejestr DEL=0, ustaw rejestr Flag
    	rjmp skip1			; wyjdź
    wykon:
    	ldi Acc,0<<CS12|0<<CS11|0<<CS10
    	out TCCR1B,Acc		; TC1 zliczanie zewnętrzne, wstrzymane
    	ldi Acc,0<<CS02|0<<CS01|0<<CS00
    	out TCCR0,Acc		; TC0 clk/256, stop odmierzania czasu
    	rcall konw			; konwersja BIN na BCD zliczonych 24 bitów
    ;ldi Acc,0b00000001	; wyczyść LCD
    ;rcall CmdWr			; Zapisz komendę z Acc do LCD
    tabl freq			; załaduj tablicę znaków (makro)
    ldi Acc,0x80		; załaduj początkowy adres tekstu
    rcall TekstWr		; wyświetl tekst na LCD
    ldi Acc,0xC0		; adres początku 2 linii LCD
    rcall FreqWr		; wyświetlenie częstotliwości na LCD
    	clr Cnt				; wyzerowanie rejestrów licznika impulsów
    	clr Acc				; wpisanie zera do rejestru pomocniczego
    	out TCNT1H,Acc		; wyzerowanie rejestrów licznika impulsów
    	out TCNT1L,Acc		; wyzerowanie rejestrów licznika impulsów
    	ldi Del,DelVal		; aktualizacja zgrubnego rejestru
    	clr Flag			; wyzerowanie rejestru Flag
    	ldi Acc,0
    	out TCNT0,Acc		; wyzerowanie TC0
    	ldi Acc,1<<CS02|0<<CS01|0<<CS00
    	out TCCR0,Acc		; TC0 clk/256, start
    	ldi Acc,1<<CS12|1<<CS11|1<<CS10
    	out TCCR1B,Acc		;TC1 zliczanie zewnętrzne, wznowione
    skip1:
    	pop Acc
    	reti
    


    Pierwszy listing to fragment kodu ze zdefiniowanymi rejestrami i wstępnymi ustawieniami (przed pętlą główną, w której jak dotąd nie mam nic). Drugi listing to przerwania: T1-inkrementacja licznika pomocniczego po jego przepełnieniu, natomiast T0-zliczanie impulsów zewnętrznych i wyświetlanie na LCD. Nie przedstawiłem tutaj procedur obsługujących LCD bo to akurat działa perfekcyjnie. Problem tkwi w tym, że liczba impulsów zliczonych jest za każdym razem nieco inna (odchyłka to okolo 50 impulsów przy sygnale 1,8 MHz z generatora kwarcowego przy czasie bramkowania 0,64 s). Co może być przyczyną takiego zachowania?
  • #2 8948307
    asembler
    Poziom 32  
    Czemu w przerwaniach nie zapamietujesz na stosie rejestru SREG?

    Dodano po 10 [minuty]:

    A tak na marginesie to ja bym raczej do liczenia impulsów zaprzągł przerwania a w programie głównym (który nawiasem pisząc się tutaj nie kończy )wyświetlał wyniki.
  • #3 8949725
    darkonel
    Poziom 19  
    Problem tkwił w ustawieniu wewnętrznego preskalera TC0 na fCLK/256, który wprowadzał niestabilność odczytu. Zamiana miejscami timerów i usunięcie preskalera na rzecz 16 bitów TC1 pomogła. Temat zamykam
REKLAMA