- MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad         
Seite 2 von 2 ErsteErste 12
Ergebnis 11 bis 20 von 22

Thema: Atmega Timer problem

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    2.236

    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)

  2. #2
    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)

Seite 2 von 2 ErsteErste 12

Ä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
  •  

Solar Speicher und Akkus Tests