- 3D-Druck Einstieg und Tipps         
Ergebnis 1 bis 10 von 22

Thema: Atmega Timer problem

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    06.09.2013
    Beiträge
    18
    Also als erstes habe ich das das langsamer drehen des Servos mit delay_ms ausprobiert mit erfolg.
    Des weiteren hab ich das Programm nach den Tipps von Searcher angepasst.
    Als nächstes habe ich jetzt mal versucht einen einen Timer für dieses delay_ms zu programmieren.
    Wenn in die variable us_counter eine 1 geschrieben wird, soll das 1µs entsprechen (d.h. us_counter =1000 = 1000µs).
    Kann das so funktionieren?

    Eine Frage habe ich noch: Warum wird erst in der if-Abfrage (if (us_counter == 0)) der Wert von us_counter mit einem Wert beschrieben (us_counter = 1000; ) und nicht schon davor?


    Code:
    #define F_CPU 8000000UL
    #include <avr/io.h>
    #include <stdint.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <stdio.h>
    #include "ADC.h"
    
    ISR TIMER0_OVF_vect			//interrupt für timer 0
    {
    	if (us_counter > 0)		//wenn us_counter größer als 0 ist, dann...
    	{
    		us_counter--;		//us_counter-1
    	}
    }
    int main(void)
    {
         uint16_t	Servo_soll = 512, Servo_ist;
         volatile uint16_t us_counter;
    
         ADC_Init(); 					//ADC initialisieren
    	
    	//############################ TIMER1 Einstellen für PWM der Nachführung #######################################
    	
    	ICR1 = 19999;	 // ICR1 = 19999 als TOP-Wert, hier werden die 20ms gebildet (8MHz / 8 * (1 + 19999)) = 50Hz
    	OCR1A = 1499; 	// OCR1A = 1499, Servomittelstellung, (8MHz / 8 * (1 + 1499)) = 666,6Hz = 1,5ms
    	TCCR1A = (1<<COM1A1) | (1<<WGM11); 		//clear OC1A on compare match, set at bottom (non-inverting)
    	TCCR1B = (1<<WGM12) | (1<<WGM13) | (1<<CS11);	//WGM12,WGM13,WGM11 -> Mode14 -> Fast PWM, ICRn, set OCR1A at Bottom | prescaler = 8
    	DDRD = (1<<PIND5); 			//PORTD pin 5 auf ausgang
    	
    	//############################ TIMER0 Einstellen für Millisekunden #######################################
    	
    	OCR0A = 3; 			//OCR0A = 3 als TOP-Wert festlegen
    	TCCR0A = (1<<WGM01) | (1<<WGM00);		//Topwert = 3, CTC-Modus,bei overflow den Timer0 auf 0 setzen
    	TCCR0B = (1<<CS00); 				//prescaler = 1 -> (8MHz/(2*1*(1+3))=1MHz = 1µs
    	TCNT0 = 0;						
    	TIMSK0 = (1<<TOIE0); 		//interrupts freischalten
    	
    	_delay_ms(2000);	 // kurz warten bis der Servo sich ausgerichtet hat
    		
        while(1)
        {
    		//########################################### Nachführung des Panels #######################################
    		if (us_counter == 0)
    		{
    			us_counter = 1000;
    			//_delay_ms(1);				//der Motor brauch 2s um sich um 180° zu drehen -> (2000 schritte und je schritt 1ms)
    			Servo_ist = ADC_Read(1);	//ADC kanal 1 auslesen und in die variable adcwert_1_LDRs speichern
    			if (Servo_ist != Servo_soll)	//Wenn der ADC-Wert der LDRs nicht mit dem Servo_soll Wert von 512 überein stimmt, dann...
    			{
    				if (Servo_ist < Servo_soll && OCR1A > 600)	//Wenn der ADC-Wert kleiner ist als 512 und 0,6ms noch nicht erreicht sind...
    				{
    					OCR1A = OCR1A--;			//verringere OCR1A um 1
    				}
    				if (Servo_ist > Servo_soll && OCR1A < 2600)	//Wenn der ADC-Wert größer ist als 512 und 2,6ms noch nicht erreicht sind...
    				{
    					OCR1A = OCR1A++;			//erhöhe OCR1A um 1
    				}
    			}
    		}
        }
    }
    Gruß

    Technik_Amateur
    Geändert von Technik_Amateur (21.11.2013 um 15:40 Uhr)

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.715
    Blog-Einträge
    133
    Hallo,
    ich kann erstmal nur auf die Timer0 Konfiguration eingehen. Leider paßt die Timer0 Konfiguration nicht mit Deinen Kommentaren zusammen.

    Nach DB "Table 13-8. Waveform Generation Mode Bit Description" hast Du nicht CTC sondern Fast PWM eingestellt.

    Wenn Mode 2 (CTC mit OCR1A als TOP) eingestellt wäre, wäre OCR0A mit 3 für 1µs Interruptfrequenz falsch belegt.
    Zur Berechnung hast Du die Formel der Frequenz an OC0A genommen, wenn Du diesen über OCR0A mit COM0A0=1 toggeln läßt.
    Für den 1µs Interruptabstand braucht der Timer nur halb so schnell laufen.

    Auch ist das falsche Interrupt Enable Bit gesetzt. In DB "Table 13-8. Waveform Generation Mode Bit Description" letzte Spalte, wird das TOV bei MAX gesetzt. MAX wäre beim 8Bit Timer0=0xFF. Du müßtest den Timer/Counter0 Compare Match A interrupt verwenden.


    Gruß
    Searcher
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    06.09.2013
    Beiträge
    18
    oh bei dem Modus bin ich wohl in der Zeile verrutscht.

    Aber wie kommst du darauf, dass der Timer nur halb so schnell laufen muss?
    Ich habe im CTC Modus nur eine Formel gefunden. Im Datenblatt steht nur, dass wenn keine prescaler oder ein niedriger verwendet wird, der CTC Modus keine double buffering funktion mehr hat. Heisst das das die 2 in der Formel raus muss und man nur noch den fclk/(N*(1+OCR0A)) benutzt? Ich kann es mir nicht so richtig erklären.

    Ok das mit dem Interrupt leutet mir ein, allerdings muss ich dann zusätzlich noch das OCF0A im TIFR0-Register setzen?

    Und die ISR heißt dann so?: ISR TIMER0_COMPA_vect

    Gruß

    Technik_Amateur

  4. #4
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.715
    Blog-Einträge
    133
    Zitat Zitat von Technik_Amateur Beitrag anzeigen
    Aber wie kommst du darauf, dass der Timer nur halb so schnell laufen muss?
    Im Mode 2 läuft der Timer immer von 0 nach OCR0A. Bei OCR0A setzt er das OCF0A Flag und toggelt, falls eingestellt, den OC0A Pin. Für die Frequenz an OC0A beginnt eine Periode. Timer0 springt nach 0 und läuft wieder nach OCR0A. Bei Erreichen OCR0A wird OCF0A Flag wieder neu gesetzt, wenn es zwischendurch gelöscht wurde und OC0A getoggelt. Frequenz: 1/2 Priode ist um und zweite Halbperiode beginnt. Timer -> 0 -> OCR0A. Nun ist eine Periode der Frequenz um, das OCF0A Flag wurde zweimal gesetzt. Also für eine Periodendauer von 1µs durch Toggeln gibt es zwei Compare A Interrupts. -> Läuft Timer halb so schnell, dann Compare A Interrupt Abstand 1µs.

    Ich habe im CTC Modus nur eine Formel gefunden. Im Datenblatt steht nur, dass wenn keine prescaler oder ein niedriger verwendet wird, der CTC Modus keine double buffering funktion mehr hat. Heisst das das die 2 in der Formel raus muss und man nur noch den fclk/(N*(1+OCR0A)) benutzt? Ich kann es mir nicht so richtig erklären.
    Ja, die 2 muß raus. Siehe Erklärung oben. Für eine Frequenzperiode durch Toggeln gibt es zwei Compare A Interrupts. (Ist anders als im Fast PWM Modus, wenn dort die Frequenz nicht durch Toggeln erzeugt wird. Ist aber weiteres Thema)
    Sacken lassen ...

    Ok das mit dem Interrupt leutet mir ein, allerdings muss ich dann zusätzlich noch das OCF0A im TIFR0-Register setzen?
    Na ja, vermutlich meinst Du das Richtige. Statt des TIMSK0 = (1<<TOIE0); muß es TIMSK0 = (1<<OCIE0A); sein. Das OCF0A Flag wird ja von der HW gesetzt. Man kann es durch setzen nur löschen.

    Und die ISR heißt dann so?: ISR TIMER0_COMPA_vect
    Ja. (Wenn das der korrekte Name in C für den Timer0 Compare Interrupt A ist - ich kann nicht wirklich C)

    PS. ...und das "sei;" zum globalen Interrupt Enable nicht vergessen ...

    Gruß
    Searcher

    Geändert von Searcher (21.11.2013 um 22:30 Uhr) Grund: sei hinzugefügt
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

  5. #5
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.698
    ... die ISR heißt dann so?: ISR TIMER0_COMPA_vect ...
    Heißt schon so, wird aber im AVR-GCC so geschrieben :

    Code:
    ISR(TIMER0_COMPA_vect)
    Ciao sagt der JoeamBerg

  6. #6
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    2.242
    Eine Frage habe ich noch: Warum wird erst in der if-Abfrage (if (us_counter == 0)) der Wert von us_counter mit einem Wert beschrieben (us_counter = 1000; ) und nicht schon davor?
    Eigentlich ganz einfach.
    Wenn die Variable us_couter den Wert 0 hat, dann wird die darunter stehende Routine aufgerufen.
    Als ersten wird dann innerhalb dieser Routine der Variable us_couter der Wert 1000 zugewiesen und dann der Rest der da stattfinden soll ausgeführt.
    Nun wird diese Routine so lange nicht mehr aufgerufen, bis die Variable us_couter wieder den Wert 0 erreicht.
    us_couter wird in einem Timer Overflow Interrupt heruntergezählt, somit hat man eine Zeitverzögerung erreicht.

    Würde man die Variable us_couter ausserhalb der if Abfrage auf 1000 setzen, wäre sie praktisch immer grösser als 0, da sie ja ständig neu gesetzt würde.

    Übrigens teste ich meine Programme gerne mit der Simulator Funktion von AVR Studio 4.
    Damit kann man das Timing wunderbar mit dem Timer und Cycle Conter überprüfen und gucken ob in der Simulation die Ausgänge auch das tun was man erwartet.
    Das Prog hat da zwar ein paar kleinere Bugs, funktioniert aber ansonsten super.

    Der Aufruf bzw. das Einbinden von Interrupts ist Compilerabhängig und sollte sich im Tutorial des jeweiligen Compilers finden lassen. Bei ACR GCC hätt ich jetzt nachschauen müssen.

  7. #7
    Neuer Benutzer Öfters hier
    Registriert seit
    06.09.2013
    Beiträge
    18
    So, also es scheint alles soweit zu Klappen. Beim ersten Versuch hab ich die Freigabe der Interrupts via sei() ; nicht ganz an den richtigen Stellen geschrieben. Aber das ist mir sofort aufgefallen und habe sie richtig setzen können.
    Viele Dank für eure Hilfe! Habe wieder einiges dazu lernen können

    Ganz besonderer Dank geht an Searcher und wkrug!

    Gruß

    Technik_Amateur

Ähnliche Themen

  1. ATMEGA 16 TIMER-Problem
    Von fulltime im Forum C - Programmierung (GCC u.a.)
    Antworten: 29
    Letzter Beitrag: 16.03.2012, 14:36
  2. [ERLEDIGT] ATMega 16 Timer 1 CTC Probleme
    Von Franky55555 im Forum C - Programmierung (GCC u.a.)
    Antworten: 4
    Letzter Beitrag: 14.06.2011, 17:18
  3. Atmega 8 Timer
    Von woodeye im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 15
    Letzter Beitrag: 25.09.2009, 15:44
  4. Atmega mit >3 Timer
    Von manhunt im Forum AVR Hardwarethemen
    Antworten: 12
    Letzter Beitrag: 14.12.2008, 14:10
  5. Atmega 32 8-Bit Timer Interrupt
    Von Benni im Forum C - Programmierung (GCC u.a.)
    Antworten: 5
    Letzter Beitrag: 23.07.2007, 21:08

Berechtigungen

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

12V Akku bauen