- MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad         
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
    Ok vielen Dank! Jetzt weiß ich schon ein bisschen besser bescheid, wie ich mit den Registern umzugehen habe. EIGENTLICH gar nicht so schwer
    Dann werde ich mal das Programm schreiben und nochmal hier posten. Testen kann ich dieses leider erst am Wochenende mit oszi.

    Gruß

    Technik_Amateur

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.715
    Blog-Einträge
    133
    ist auch EIGENTLICH nicht schwer. Man muß nur einmal den Dreh raus haben und beachten, daß es für die verschiedenen Timer Betriebsmodi (non PWM, Fast PWM, Phase Correct PWM) verschiedene Tabellen gibt und verschiedene TOP Werte, die auch noch variabel sein können und die man nicht vergessen darf zu initialisieren Außerdem die Qual der Wahl, welcher Modus denn nun am besten für das Vorhaben ist.

    Hatte am Anfang auch schon viele Fehlversuche hinter mir und vertue mich immer noch.

    Viel Erfolg und 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
    Soo ich habe jetzt den Code geschrieben und hoffe, dass es so funktionieren könnte.

    Da ich ein Panel zur Sonne ausrichten lassen will (programmtechnisch), hoffe ich das meine Idee auch so funktionieren kann.

    Code:
    #define F_CPU 8000000UL
    #include <avr/io.h>
    #include <stdint.h>
    #include <util/delay.h>
    #include <stdio.h>
    #include "ADC.h"
    
    DDRD = (1<<PIND5);			//PORTD pin 5 auf ausgang
    
    uint16_t	Servo_soll = 512, Servo_ist;
    
    ADC_Init();					//ADC initialisieren
    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
    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	
    _delay_ms(2000);	// kurz warten bis der Servo sich ausgerichtet hat
    Da ich auch noch nicht so sehr mit C++ vertraut bin, Bitte ich euch mir zu sagen, welche Variante besser wäre, also nicht so rechenlastig für den µC.
    Diese mit if?:

    Code:
    while(1)
        {
    		//########################################### Nachführung des Panels #######################################
    		
    		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
    			}
    		}
        }
    Oder Diese mit while?:

    Code:
    while(1)
        {
    		//########################################### Nachführung des Panels #######################################
    
                    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 < 500 || Servo_ist > 524)			//Tolleranzbereich, sodass der Servo nich bei jeder kleinen Änderung dreht
    			{
    				while(Servo_ist < Servo_soll && OCR1A > 600)	//Solange der ADC-Wert kleiner ist als 512 und 0,6ms noch nicht erreicht sind...
    				{
    					OCR1A = OCR1A--;						//verringere OCR1A um 1
    				}
    				while(Servo_ist > Servo_soll && OCR1A < 2600)	//Solange 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

  4. #4
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    2.243
    Im Prinzip dürfte es egal sein, welche Variante Du benutzt.
    Ich würde die if Variante bevorzugen.
    Begründung:
    Ich vermute diese Programmschleife wird so schnell durchlaufen, das dein Servo ohnehin mit der Stellgeschwindigkeit nicht mitkommt.
    Das bedeutet Du wirst immer A/D Wandler Werte kriegen die nicht den aktuellen Stand der PWM widerspiegeln, da das Servo hinterherhängt.
    Bei der if Variante kannst Du Verzögerungsglieder ( Zähler der im Timer hochgezählt wird ) reinbauen.

    Was soll das Ganze denn werden? Ein Lichtsucher? Eine Solarzellen Nachführung? Eine Laser Kanone?

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.715
    Blog-Einträge
    133
    Hallo Technik_Amateur,
    den Ablauf der Timerkonfiguration sehe ich folgendermaßen:

    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

    Der Timer läuft durch das CS11 los, ICR1 ist aber noch auf seinem Initialwert 0.

    ICR1 = 19999; // ICR1 = 19999 als TOP-Wert, hier werden die 20ms gebildet (8MHz / 8 * (1 + 19999)) = 50Hz
    Erst hier wird der richtige TOP-Wert definiert. Keine Ahnung was passiert, wenn der Timer versucht mit TOP Wert 0 loszulaufen. Wird vermutlich keine spürbaren Auswirkungen haben. Logischer wäre, das ICR1 vor Start des Timers zu setzten.

    OCR1A = 1499; // OCR1A = 1499, Servomittelstellung, (8MHz / 8 * (1 + 1499)) = 666,6Hz = 1,5ms
    1499 für 1500µs Pulsweite stimmt. Hab ich mal mit einem Mega88 getestet; ist zwar ein anderer µC aber die Timerbeschreibung ist sehr ähnlich, wenn nicht gleich. Ist in meinem ersten Post falsch aufgeführt

    EDIT: Wenn der Timer läuft und OCR1A auf 0 ist und bleibt, gibt es in diesem Fall 1µs spikes bei jedem Durchlauf am OC1A Pin (alle 20ms).

    Man sollte auch noch beachten, wann das OCR1A Register upgedatet wird. Im Mode 14 ist es bei TCNT1=0 (BOTTOM). Wenn der Timer schon läuft, wird beim Schreiben auf OCR1A der wert gepuffert und erst bei Erreichen von TCNT1=BOTTOM dann übernommen und aktiv.

    Logischer wäre auch hier, das OCR1A vor Starten des Timers zu initialisieren.

    Auch könnte man sich überlegen, ob man das COM1A1 Bit erst zum Schluß setzt und damit PD5 auf die Compare Unit/waveform Generation Unit durchschaltet, wenn der Timer komplett initialisiert ist und läuft.

    Das meiste ist für den Betrieb nicht so wichtig, da es nur den ersten Timerzyklus betrifft und man hier Unsauberkeiten am Servo wahrscheinlich nicht erkennen kann. Könnte aber hilfreich bei der Bugsuche sein.

    Möchte noch sagen, daß ich auch noch Amateur bei der µC Programmierung bin und nicht alles richtig sein muß, was ich hier geschrieben habe. C verstehe ich auch nur rudimentär und enthalte mich auch erstmal einem Kommentar zu Deinem restlichen Programm.

    Gruß
    Searcher
    Geändert von Searcher (20.11.2013 um 12:06 Uhr)
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

  6. #6
    Neuer Benutzer Öfters hier
    Registriert seit
    06.09.2013
    Beiträge
    18
    Ich habe jetzt den Code mit der "if-Variante" benutzt und konnte heute schon testen ob alles ok ist. laut oszi werden jetzt PWM-Signale zwischen 0,6 und 2,6ms erzeugt. Darauf hin habe ich den Servo angeschlosse nund siehe da, alles funktioniert super. Eine
    Sache stört mich aber immernoch. Der Servo dreht sich etwas zu schnell. Kann ich die geschwindigkeit denn jetzt noch irgendwie beeinflussen, ohne das ich die 20ms-Periode und die pulsbreite zerstöre? Ich habe es mit delays versucht, aber dann beeinflusse ich doch die Periode und somit die Signale oder? Gibt es da eine möglichkeit dies zu umgehen?

    @wkrug: Was meinst du genau mit Verzögerungsglieder? Die Drehgeschwindigkeit verändern?
    Ja das ganze wir eine Solarzellen Nachführung. Der Sonnenstand wird mithilfe von 2 LDRs als Spannungsteiler ermittelt und diese Spannung (0...5V) geht an den ADC.

    @Searcher: Hallo Searcher!
    Ja das klingt logisch, dass beim ersten initialisieren die TOP-Werte warscheinlich unsauber sind. Auch wenn ich diese heute beim Test nicht bemerken konnte. Ich werde sie trotzdem anpassen!


    Gruß

    Technik_Amateur
    Geändert von Technik_Amateur (20.11.2013 um 16:42 Uhr)

Ä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