- 3D-Druck Einstieg und Tipps         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 22

Thema: Atmega Timer problem

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.708
    ... Ich habe ein Verständnisproblem bezüglich der Timer (8 u. 16 bit) ...
    Mir gings ne Zeitlang nicht besser *grins*.

    ... Ich habe versucht ein PWM-Signal zu generieren, jedoch zeigt das oszi keins an ...
    Hier (klick) steht meine Servo-Timer-Initialisierung für nen 1284P/20 MHz (zwanzig, mit Quarz!!). Damit fahre ich die Servosteuerung vollständig über die beiden 16bittigen Timer. ALLERDINGS für acht, aktuell für zehn Servos, d.h. um auf die 20 ms zu kommen, muss der Timer1 mehrfach (sollte mindestens 8 mal) aufgerufen werden. ACHTUNG - der Hintergrund der Sache ist mein Wunsch die Servod von minimal möglicher GEschwindigkeit in SlowMotion bis zu full speed fahren zu könnnen. Die Initialisierung des Timer/Counter 1 ist für ne CTC, das wäre gerade für Dich vielleicht als Codebeispiel von Interesse. Entsprechend den 20 MHz sind natürlich die Werte für Prescaler, OCR1A und OCR1B.

    PS: Mein C ist nicht das Beste, insbes. nicht für alle Compiler wasserdicht :-/
    Ciao sagt der JoeamBerg

  2. #2
    Neuer Benutzer Öfters hier
    Registriert seit
    06.09.2013
    Beiträge
    18
    Vielen Dank für die schnellen und hilfreichen Antworten!

    @Searcher:
    Ich habe deine vorgeschlagenen Werte selber nochmal mit Hilfe des Datenblattes nachvollziehen können.
    Wenn ich alles richtig verstanden habe, ist ICR1 also mein TOP-Wert für den Timer der die ganze Zeit durchläuft und mit dem OCR1A-Register kann ich festlegen wann er das HIGH auf LOW schalten soll (HIGH auf LOW durch setzen von COM1A1) ? Sprich der Timer gibt von Anfang an ein HIGH-Signal und wenn er auf den OCR1A-Wert trifft geht das Signal auf LOW, so lange bis der TOP-Wert von ICR1 erreicht ist, dann wieder automatisch auf HIGH usw.?

    Mit freundlichen Grüßen

    Technik_Amateur

  3. #3
    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
    Wenn ich alles richtig verstanden habe, ist ICR1 also mein TOP-Wert für den Timer der die ganze Zeit durchläuft
    Ja, im Timer1 Mode 14 ist ICR1 der TOP-Wert nach Datenblatt "Table 14-5. Waveform Generation Mode Bit Description".

    und mit dem OCR1A-Register kann ich festlegen wann er das HIGH auf LOW schalten soll (HIGH auf LOW durch setzen von COM1A1) ?
    Ja, wenn das PWM-Signal an OC1A (PD5) ausgegeben werden soll -> nach DB "Table 14-3. Compare Output Mode, Fast PWM".
    Für PWM an OC1B (PD4) müßte man die COM1Bx Bits verwenden und das OCR1B Register.

    Sprich der Timer gibt von Anfang an ein HIGH-Signal und wenn er auf den OCR1A-Wert trifft geht das Signal auf LOW, so lange bis der TOP-Wert von ICR1 erreicht ist, dann wieder automatisch auf HIGH usw.?
    Ja, solange der Timer (TCNT1) unterhalb von OCR1A ist, ist der Output (OC1A) HIGH. Mit Erreichen von OCR1A (Compare Match) wird OC1A LOW. Allerdings wird OC1A nicht bei Erreichen von ICR1 wieder HIGH, sondern erst einen Timertick später, wenn TCNT1 0 ist.

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

  4. #4
    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

  5. #5
    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

  6. #6
    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

  7. #7
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    2.256
    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?

  8. #8
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.708
    Zitat Zitat von oberallgeier Beitrag anzeigen
    ... Hintergrund ... Servos von minimal möglicher Geschwindigkeit ... bis zu full speed fahren zu können ...
    Zitat Zitat von Technik_Amateur Beitrag anzeigen
    ... Der Servo dreht sich etwas zu schnell. Kann ich die geschwindigkeit denn jetzt noch irgendwie beeinflussen ...
    Siehe oben.
    Ciao sagt der JoeamBerg

  9. #9
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.715
    Blog-Einträge
    133
    Das Servo versucht möglichst schnell die Position zu erreichen, die ihm die Pulsweite vorgibt. Man müße also die Sollpulsweite, die durch die ADC Messung vorgegeben wird, von der Istpulsweite aus langsam erreichen. Deine If Bedingung, in der OCR1A um eins verändert wird, steht vermutlich in einer Schleife, die "irre schnell" immer wieder durchlaufen wird. Schneller, als das Servo der durch OCR1A veränderten Pulsweite folgen kann und deshalb versucht es also so schnell es ihm möglich ist, ihr zu folgen.

    Gibt sicher viele Möglichkeiten, die Pulsweite von Ist nach Soll langsam zu verändern. Eine simple wäre, die Schleife, in der die IF Abfragen stehen einfach durch ein delay zu verzögern. Welches delay passend ist müßte man ausprobieren. Schätze mal so mit 5ms bis 20ms könnte man anfangen. Dadurch würde auch die ADC Abfrage verlangsamt, sollte aber bei dem Sonnenfolger und den langsamen LDR keine Rolle spielen.

    Eine ausgefeilte Möglichkeit bietet oberallgeier an, bedeutet aber auch schon einiges an Einarbeitungszeit.

    @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!
    Kann man auch meistens vernachlässigen. Nur wenn unerklärbare Problem auftauchen, sollte man auch an so etwas denken.


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

  10. #10
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    2.256

    Beitrag

    Was meinst du genau mit Verzögerungsglieder? Die Drehgeschwindigkeit verändern?
    Die Impulsaufbereitung findet komplett in der Hardware statt, soweit ich das kapiert habe.
    Die verzögerung kann also nur auf der Eingabeseite für die Servoimpulslänge erfolgen.
    Am einfachsten wäre es einfach vor die if Abfrage ein delay_ms einzufügen und zusätzlich die geänderten Werte nur um wenige Werte zu erhöhen bzw. zu erniedrigen.
    Über die Anzahl der maximalen änderbaren Schrittweite und der delayzeit kann man die maximale Geschwindigkeit des Servos dann einstellen.

    delay_ms hat aber leider den fiesen Nachteil, das dadurch das komplette Hauptprogramm verzögert wird.
    Ich benutze dazu dann lieber einen zusätzlichen Timer, der in seinen Overflow Interrupts eine Variable runterzählt.
    Wenn die Variable den Wert 0 hat wird die if abfrage durchlaufen, die Variable wieder auf den Initialwert gesetzt und die Impulsweite eingestellt.
    Den Grad der Servoverzögerung kann man dabei über den Initialwert der Variable verändern.

    Dann wird die if abfrage nicht mehr durchlaufen, bis die Variable wieder den Wert 0 hat.

    Will man weitere zeitabhängige Vorgänge Triggern kann man das mit zusätzlichen Variablen in diesem Timer Overflow Interrupt realisieren.
    Die Variablen sollten aber als volatile definiert werden, da sie sich ja in einem Interrupt ändern können ( und sollen ).


    Diese Methode hat den Vorteil, das das restliche Hauptprogramm nicht ausgebremst wird, wie das bei delay_ms der Fall wäre.
    Code:
    // Timer 0 overflow interrupt service routine
    interrupt [TIM0_OVF] void timer0_ovf_isr(void)
    {
        if (uc_sectimer>0)
        {
            uc_sectimer--;
        }
    }
    ...
    
    
    // Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: 7,813 kHz
    TCCR0=0x05;
    TCNT0=0x00;
    
    // Timer(s)/Counter(s) Interrupt(s) initialization
    TIMSK=0x01;
    
    while (1)
          {
          if (uc_sectimer==0)
          {
          uc_sectimer=10;
          if(....//Dein Code
          }....
    Die konkreten Werte für die Timer Register müsstest Du selber mal imDatenblatt nachschauen.
    Die Aufrufe für die Interrupts sind bei AVR GCC anders, das Beispiel ist für CodeVision AVR.

    Für das Hauptprogramm "sieht" es so aus, als ob sich diese Variablen wie von Geisterhand in festen Zeitabständen verringern würden.


    Ich würde in deinem System auch ne Realtime Clock ( als externer Chip ) einsetzten um bei ungünstigen Witterungsverhältnissen ( bewölkter Himmel ) eine Position aus einer Tabelle ansteuern zu können.
    Die Tabelle kann auch bei gutem Wetter dafür genutzt werden die Werte der Lichtsensoren zu verifizieren und das System am Morgen in eine definierte Startposition zu bringen.

    Das hört sich vieleicht ein wenig "Oversized" an aber zumindest im Platinenlayout würd ich diese Option mal vorsehen.

    Zudem würde ich mir überlegen einen Getriebemotor mit Spindelantrieb vorzusehen.
    Dieser braucht im Ruhezustand keinen Strom und hat dann auch ein relativ gutes Haltemoment.
    Als Ansteuerung könnte dann eine H-Brücke dienen.
    Servos brauchen auch wenn sie sich nicht bewegen einen Strom für das Haltemoment und die interne Elektronik.
    Geändert von wkrug (20.11.2013 um 23:18 Uhr)

Seite 1 von 2 12 LetzteLetzte

Ä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