- LiFePO4 Speicher Test         
Ergebnis 1 bis 10 von 36

Thema: Timer und Register

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Fleißiges Mitglied Avatar von avr_racer
    Registriert seit
    01.04.2014
    Ort
    MecklenburgVorpommern
    Beiträge
    175
    ick find dit irgendwie net auf Seite 130 sind Diagramme und die Rede von OCR-1, OCR+1 usw

    hier der Link
    http://www.atmel.com/Images/Atmel-82..._datasheet.pdf

    Achtung wenn du die Includedatei des µC öffnest dann siehst du das dort an einigen Stellen MOMERY MAPPED steht diese Adressen sind nur mit LDS/STS zu erreichen.

    aber vielleicht hilft der Code ein wenig weiter

    Code:
        
            rcall        mode2_T0_init
            rcall        prescaler_T0_on
    
    start:
    
            rjmp        start
    
    mode2_T0_init:;CTC_MODE  OCRx update sofort oder im INT
            sbi            ddrd,6            ;output aktivieren wenn Toggeln am PIND6=OCR0A erwünscht
            ldi            temp0,$80        ;Toggeln oder Clr/Set aktiv muss OCR0A-Register beachtet werden um
            out            OCR0A,temp0        ;____--- oder _------ zu erreichen
        ;mit OCRyx wird die Frequenz festgelegt des Rechtecksignales
            lds            temp0,TIMSK0
            ori            temp0,(0<<OCIE0B||0<<OCIE0A|0<<TOIE0)    ;INTs aktivieren
            sts            TIMSK0,temp0
            
            ldi            temp0,(0<<COM0B1|0<<COM0B0|0<<COM0A1|1<<COM0A0|1<<WGM01|0<<WGM00)    ;zum Toggeln COMyx Einstellungen beachten!!!!!!!!!
            out            TCCR0A,temp0                                    ;
            
            ldi            temp0,(0<<FOC0A|0<<FOC0B|0<<WGM02) 
            out            TCCR0B,temp0
            ret
    
    prescaler_T0_on:
            in            temp0,TCCR0B
            ori            temp0,(0<<CS02|0<<CS01|1<<CS00) ;schmeißt den counter 
            out            TCCR0B,temp0
            sei
            ret
    
    OC0A_int:
            in            temp0,OCR0A
            out            OCR0A,temp0
            reti

  2. #2
    Neuer Benutzer Öfters hier
    Registriert seit
    05.05.2013
    Beiträge
    22
    Danke für dein Beispiel.
    In deinem Beispiel steht, das du mit OCR0A die Frequenz einstellst. In konnte mir nicht vorstellen wie du ein _------ Signal mit einem Festen Wert erzeugen möchtest. In der Doku habe ich dazu folgenden Satz gefunden:
    If the interrupt is enabled, the interrupt handler routine can be used for updating the TOP value
    Zur Erklärung, der TOP Value ist der Wert an dem Der Vergleich zwischen OCR0A und TCNT statt findet und der Wert wieder auf 0 gesetzt wird. Bedeutet ich setze in der ISR einfach einen neuen Wert bei OCR0A ein?

    Wieso nimmst du eigentlich den ORI befehl?
    Performs the logical OR between the contents of register Rd and a constant and places the result in the destination register Rd.
    Quelle: http://www.atmel.no/webdoc/avrassemb...er.wb_ORI.html

    Übriegens, dein Link führt auf die Doku, die ich weiter oben meinte.

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied Avatar von avr_racer
    Registriert seit
    01.04.2014
    Ort
    MecklenburgVorpommern
    Beiträge
    175
    > Zur Erklärung, der TOP Value ist der Wert an dem Der Vergleich zwischen OCR0A und TCNT statt findet und der Wert wieder auf 0 gesetzt wird. Bedeutet ich setze in der ISR einfach einen > neuen Wert bei OCR0A ein?

    jep so siehts aus. Aber solltest du den Mode ändern denn guck in die Tabelle welches Register als Vergleich herangezogen wird. Der Quellcode ist nur für den CTC-Modus (Autoreload) heißt, wenn OCR0A geändert wird, änderst du nur die Frequenz nicht aber das ON/OFF Verhältniss. Dafür müsstest du die FAST-PWM nutzen.

    > Wieso nimmst du eigentlich den ORI befehl?

    Der OR-Befehl bezieht sich direkt auf 2 Register die geodert werden, bei dem ORI-Befehl wird eine Konstante mit dem Register geodert. Der Klimzug mit dem ORI-Befehl habe ich nur deshalb gemacht wenn man den Timer noch andersweitig nutzt oder verändern will also kompatibel bleiben möchte.

    > Übriegens, dein Link führt auf die Doku, die ich weiter oben meinte.

    Check

    Gruß avr_racer

  4. #4
    Neuer Benutzer Öfters hier
    Registriert seit
    05.05.2013
    Beiträge
    22
    Also erste Überlegungen:
    Timer 0 kann mit einem Prescale von 1028 eine maximal Zeit von 13,15 mS erreichen bis zum Überllaufen
    Timer 1 schafft eine Zeit von 3,36s

    Meine Idee ist also, den Timer 0 auf einen Prescale von 8 einzustellen, dann ist die Laufzeit zum Overflow 102us. Das Vergleichs Register OCRA0 , stelle ich dann auf 0x64(100);
    In der Routine des Vergleichs Vergleichs Interrupts, muss ich dann prüfen ob der Pegel High oder Low war und wie häufig es Überlaufe gab.
    Code:
    ISR_Compare:
                   inc r16 ; Zähle Überläufe
                   sbic PORTB, 0 ; Prüfe ob Ausgang LOW
                   jmp Pegel_Low
                   sbis PORTB, 1 ; Überprüfe ob Ausgang High
                   jmp Pegel_High ; Wenn nicht setze Ihn High
                   reti
    Pegel_Low:
                  cpi r16, 0x05 ; Überprüfe ob Wert 5;
                  brne reti
                  ldi r16,0x00
                  cbi PORTB,0
                  reti
    
    Pegel_High:
                  cpi r16, 0x01 ; Überprüfe ob Wert 1;
                  brne reti
                  ldi r16,0x00
                  sbi PORTB,0
                  reti
    Nur mal als Idee.
    Timer 1 würde ich als ICP fahren und damit die Messwert Laufzeit erfassen.

  5. #5
    Erfahrener Benutzer Fleißiges Mitglied Avatar von avr_racer
    Registriert seit
    01.04.2014
    Ort
    MecklenburgVorpommern
    Beiträge
    175
    > Timer 0 kann mit einem Prescale von 1028 eine maximal Zeit von 13,15 mS erreichen bis zum Überllaufen
    > Timer 1 schafft eine Zeit von 3,36s

    ACHTUNG der Teiler ist max 1024 und bits max. 255bits machen 13,05...ms !!!!!! in längster Ausführung

    > Meine Idee ist also, den Timer 0 auf einen Prescale von 8 einzustellen, dann ist die Laufzeit zum Overflow 102us. Das Vergleichs Register OCRA0 , stelle ich dann auf 0x64(100);

    jo 8 ist gut und wenn du OCR0A mit 250 ($FA) beschreibts hast du alle 100µs eine OC0A Interrupt der ausgelöst wird und könntest diesen nutzen.

    Warum auf 100? denn wird doch alle 40µs einer OVFL ausgelöst oder verstehe ich das jetzt falsch?

  6. #6
    Neuer Benutzer Öfters hier
    Registriert seit
    05.05.2013
    Beiträge
    22
    Du hast natürlich recht, ich war bei einem anderen Wert in Gedanken.
    Ich habe jetzt einen Anfang gemacht und möchte das mit dem USART verbinden, allerdings klappt das nicht so wie ich das möchte.
    Die Low Time ist jetzt auf 10ms eingestellt, wie könnte ich das erweitern auf 100ms mit einem 8 Bit Timer?
    Es wäre lieb wenn Ihr einmal drüber schaut:
    Code:
    .def temp = r16
    .def value = r17
    .def timer0 = r20
    .def timer1_low = r21
    .def timer1_high = r22
    
    
    /* BEGINN DES HAUPTPROGRAMMES*/
    
    Reset:
    	ldi temp, HIGH(RAMEND)		; Stackpointer
    	out SPH, temp
    	ldi temp, LOW(RAMEND)
    	out SPL, temp
    
    	ldi temp, ( (1<<PD2) | (1<<PD3) ) ; Interrupt Pins auf Eingang, der Rest bleibt als Ausgang
    	out DDRD, temp
    	
    	ldi temp, 0xFF				; PORTB wird als Ausgang gesetzt
    	out DDRB, temp
    	ldi temp, 0x00
    	out PORTD, temp				; Alle Pins auf 0 setzen (Die beiden Eingänge bekommen keinen Pull-Up)
    
    UART_Reset:
    	ldi temp, HIGH(UBRR_VAL)
    	sts UBRR0H, temp
    	ldi temp, LOW(UBRR_VAL)
    	sts UBRR0L, temp
    	ldi temp, ( (1<<UMSEL00) | (1<<UCSZ01) | (1<<UCSZ00) ) ; synchron mit 8 Bit.
    	sts UCSR0C, temp
    	ldi temp, (1<<TXEN0)
    	sts UCSR0B, temp
    
    Timer0_Reset:
    	ldi temp, (1<<CS01)			; setze Vorteiler auf 8
    	out TCCR0B, temp
    
    	ldi temp, (1<<COM0A1)		; der Ausgang wird immer beim Oberflow
    	out TCCR0A, temp			; immer auf LOW gesetzt
    
    	ldi temp, 0xFA				; 250 Schritte entsprechen genau 100us
    	out OCR0A, temp
    
    	ldi temp, (1<<OCIE0A)		; aktiviere Compare-Overflow Interrupt
    	sts TIMSK0, temp
    
    Timer1_Reset:
    	ldi temp, (1<<ICES1)
    	sts TIMSK1, temp
    
    Loop:
    	jmp Loop
    
    isUDRclear:
    	ldi temp, UCSR0A 
    	sbis temp, 5	; Überprüfe ob das UDR Register LEER ist !!! Hier ist der Fehler :" Invalid number"
    	rjmp isUDRclear		; Wenn nicht bleibt in einer Schleife bis es so ist.
    	sts UDR0, value
    	ret nop
    
    Result_Output:
    	mov value, timer1_low		; Timerwert auf den USART geben
    	rcall isUDRclear
    	mov value, timer1_high		; Timerwert auf den USART geben
    	rcall isUDRclear
    	rcall sync_0
    	jmp Loop
    
    Sound_On:
    	cbi PORTD, 6
    	reti nop
    	
    
    TIM0_COM:
    	/*Die Pegel auf LOW setzen brauch nicht implementiert werden,
    	da das von der HArdware gemacht wird*/
    	inc timer0
    	cpi timer0, 0x64 ; Damit wird der High Timer auf 10ms festgelegt.
    	breq Sound_On
    	reti nop
    
    TIM1_CAP:
    	/*Hardware speichert Werte im RAM*/
    	ldi timer1_low, TCNT1L
    	ldi timer1_high, TCNT1H
    	reti nop
    In der Doku steht:
    Code:
    in r16, UCSRnA
    sbrs r16, UDREn
    Wenn das so eingetippt wird, ist das UCSR0A Register nicht in der Range.
    Ich muss mir noch etwas einfallen lassen, wie ich die Ausgabe zum PC mache, ohne das interrupt zu verlängern und ohne es im Main Loop die ganze Zeit ausgeben zu lassen

    Liebe Grüße

  7. #7
    Erfahrener Benutzer Fleißiges Mitglied Avatar von avr_racer
    Registriert seit
    01.04.2014
    Ort
    MecklenburgVorpommern
    Beiträge
    175
    Ich glaub ich habe dir gestern falsche Daten gegeben in meiner Tabelle verlesen und habe die Gleichung für den FAST-PWM-Mode genutzt (Asche auf mein Haupt)

    So Korrektur für den CTC-Mode bei 20Mhz für 100µs: Teiler = 8; OCR0A = $7c (124dez) = 100µs
    CTC-Mode bei 20Mhz für 100µs: Teiler = 64; OCR0A = $0f (15dez) = 104µs

    Tja und mit 100ms im CTC-Mode siehts schlecht aus.

    jetzt zum Programm...

    Versuche mal die ganze Initialisierung in kleine Unterprogramme zu packen
    z.B.:
    Code:
    init_stack:
             ldi temp, HIGH(RAMEND)		; Stackpointer
    	out SPH, temp
    	ldi temp, LOW(RAMEND)
    	out SPL, temp
            
            rcall     UART_Reset
    
    loop: jmp      loop
    
    
    UART_Reset:
              ....
             .....
             ret

    UART_Reset: ich hoffe du hast UBRR_VAL irgendwo definiert denn die Angabe fehlt in deinem Post.

    Timer0_Reset: gut wäre es den Timer erst zu starten wenn du alle Timerinitalisierungen erledigt hast und du bist auch nicht m CTC-Mode weil WGM01 nicht gesetzt ist.

    isUDRclear: sbis temp, 5 dieser Befehl bezieht sich auf die PORTS, du möchtest aber ein Register nutzen dann nutze SBRS ......

    Code:
    isUDRclear:
    	lds temp, UCSR0A        ; Hier ist der Fehler LDS weil MOMERY MAPPED
    	sbrs temp, UDRE0	        ; Überprüfe ob das UDR Register LEER ist !!! Hier ist der Fehler :" Invalid number"
    	rjmp isUDRclear		; Wenn nicht bleibt in einer Schleife bis es so ist.
    	sts UDR0, value
    	ret nop

    > Wenn das so eingetippt wird, ist das UCSR0A Register nicht in der Range.
    Code:
    in r16, UCSRnA
    sbrs r16, UDREn
    In einen meiner Posts hatte ich es geschrieben, schau dir bitte mal die Inlcudedatei an, da steht bei einigen Registern MOMERY MAPPED und diese Register
    werden mit LDS r16,UCSR0A geladen und mit STS gespeichert, einfach mal reinschauen


    > Ich muss mir noch etwas einfallen lassen, wie ich die Ausgabe zum PC mache, ohne das interrupt zu verlängern und ohne es im Main Loop die ganze Zeit ausgeben zu
    > lassen

    Naja in dem du es Anforderst, du sendest über den PC ein 'A' und vergleichst es im µC wenn es stimmt machste ne Ausgabe.

    hier mal überarbeitet
    Code:
            ldi temp, HIGH(RAMEND)		; Stackpointer
    	out SPH, temp
     	ldi temp, LOW(RAMEND)
    	out SPL, temp
    
    	ldi temp, ( (1<<PD2) | (1<<PD3) ) ; Interrupt Pins auf Eingang, der Rest bleibt als Ausgang
    	out DDRD, temp
    	
    	ldi temp, 0xFF				; PORTB wird als Ausgang gesetzt
    	out DDRB, temp
    	ldi temp, 0x00
    	out PORTD, temp				; Alle Pins auf 0 setzen (Die beiden Eingänge bekommen keinen Pull-Up)
    	
    	rcall	UART_Reset
    	rcall	Timer0_Reset
    	rcall	Timer1_Reset
            sei                                        ;sonst wirds nix mit den INTS das ist die Globale Freigabe
    Loop:
    	jmp Loop
    
    
    Result_Output:
    	mov value, timer1_low		; Timerwert auf den USART geben
    	rcall isUDRclear
    	mov value, timer1_high		; Timerwert auf den USART geben
    	rcall isUDRclear
    ;	rcall sync_0				
    	jmp Loop
    
    
    ;***Init UART
    UART_Reset:
    	ldi temp, HIGH(UBRR_VAL)
    	sts UBRR0H, temp
    	ldi temp, LOW(UBRR_VAL)
    	sts UBRR0L, temp
    	 ldi temp, ( (1<<UMSEL00) | (1<<UCSZ01) | (1<<UCSZ00) ) ; synchron mit 8 Bit.
    	sts UCSR0C, temp
    	ldi temp, (1<<TXEN0)
    	 sts UCSR0B, temp
    	ret
    
    isUDRclear:
    	lds temp, UCSR0A 
    	sbrs temp, UDRE0	; Überprüfe ob das UDR Register LEER ist !!! Hier ist der Fehler :" Invalid number"
    	rjmp isUDRclear		; Wenn nicht bleibt in einer Schleife bis es so ist.
    	sts UDR0, value
    	ret 
    
    ;****Iint_T0
    Timer0_Reset:
    	ldi temp, (1<<COM0A1|1<<WGM01)		; der Ausgang wird immer beim Oberflow
    	out TCCR0A, temp			; immer auf LOW gesetzt
    
    	ldi temp, $7c				; 250 Schritte entsprechen genau 100us
    	out OCR0A, temp
    
    	ldi temp, (1<<OCIE0A)		; aktiviere Compare-Overflow Interrupt
    	sts TIMSK0, temp
    
    	ldi temp, (0<<CS02|1<<CS01|0<<CS00)			; setze Vorteiler auf 8
    	out TCCR0B, temp
    	
    	ret
    
    ;***Init_T1
    Timer1_Reset:
    	ldi temp, (1<<ICES1)
    	sts TIMSK1, temp
    	ret
    
    ;**********UP´s INT´s*************
    Sound_On:
    	cbi PORTD, 6
    	reti 
    	
    
    TIM0_COM:
    	/*Die Pegel auf LOW setzen brauch nicht implementiert werden,
    	da das von der HArdware gemacht wird*/
    	inc timer0
    	cpi timer0, 0x64 ; Damit wird der High Timer auf 10ms festgelegt.
    	breq Sound_On
    	reti 
    
    TIM1_CAP:
    	/*Hardware speichert Werte im RAM------>> nein Das ist nicht der RAM ganz normaler RegisterBereich wenn mit .equ timer1_low = $0100 festlegen*/
    	ldi timer1_low, TCNT1L
    	ldi timer1_high, TCNT1H
    	reti
    Nachtrag: Schon mal überlegt auf´s AVR-Studio 4.19 zu wechseln ? Das 6er ist so ziemlich noch nicht das gelbe vom Ei. Funktioniert auch mit MK2.
    Geändert von avr_racer (04.05.2014 um 13:53 Uhr) Grund: Nachtrag

Ähnliche Themen

  1. gleiche register bei atmega32 und 16
    Von avrrobot im Forum C - Programmierung (GCC u.a.)
    Antworten: 1
    Letzter Beitrag: 20.02.2011, 09:19
  2. Timer-Register mögen Befüllung durch Funktion nicht
    Von stefan_Z im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 1
    Letzter Beitrag: 06.08.2007, 18:25
  3. Asuro und OSCCAL Register Taktfrequenz
    Von Winne im Forum Asuro
    Antworten: 3
    Letzter Beitrag: 11.09.2005, 08:49
  4. Interne Register und Register in SRAM
    Von FoCus im Forum AVR Hardwarethemen
    Antworten: 9
    Letzter Beitrag: 27.07.2005, 12:06
  5. ADC und USART über Register?!
    Von BASTIUniversal im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 1
    Letzter Beitrag: 29.04.2005, 13:28

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

LiFePO4 Speicher Test