- LiFePO4 Speicher Test         
Seite 4 von 5 ErsteErste ... 2345 LetzteLetzte
Ergebnis 31 bis 40 von 47

Thema: Mit Atmega8 Hardware PWM mit Timer2

  1. #31
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.05.2004
    Alter
    39
    Beiträge
    388
    Anzeige

    Praxistest und DIY Projekte
    Mein originalercode 16Mhz:
    Code:
    #include <avr/io.h>       		  //I/O Port definitions 
    #include <avr/interrupt.h>  	 //Interrupt macros 
    #include <util/twi.h>			//TWI STATUS
    
    #define F_CPU 16000000UL		//CPU Tackt
    
    /*----------------------------------------------------------------------------------------*/
    //PWM
    /*----------------------------------------------------------------------------------------*/
    
    //1000 = 1ms(links), 1500 = 1,5ms(mitte), 2000 = 2ms(rechts)
    volatile int schulter= 0;		
    volatile int huefte = 0;			
    volatile int knie = 0;	
    
    
    void pwm_init(int schulter, int huefte, int knie);	//PWM_init Funktion		
    void pwm_chance(int schulter, int huefte, int knie);//Anpassen der PWM grössen
    
    /*----------------------------------------------------------------------------------------*/
    //MAIN AUFRUF
    /*----------------------------------------------------------------------------------------*/
    
    int main(void) 
    {
    	DDRB = 0xFF;											//B... AUSGANG
    	PORTB &= ~((1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3));	//B.. Low
    
    	sei(); 													//Globale Interupts zulassen
    	pwm_init(schulter, huefte, knie);						//PWM initialisieren
    									
    
    
    	while(1)
    	{
    
    		
    	}
    
    }
    
    
    ISR(TIMER2_OVF_vect)	//Überlaufinterupt Timer2
    {
    	TCCR2 = 0x00;	//Löschen von Timer2
    }
    
    ISR(TIMER1_CAPT_vect)	//Captureinterupt Timer1
    {
    	TCCR2 = (1<<WGM20) | (1<<WGM21) |(1<<COM21) | (1<<CS22) | (1<<CS20); 	//Setzten von Timer2
    }
    
    
    
    void pwm_init(int schulter, int huefte, int knie) //PWM initialisieren
    {
    	TIMSK |= (1<<TICIE1) | (1<<TOIE2); //Interupt initialisieren, freischalten
    
    	//Timer 1 (Port 0/1)
    	TCCR1A = (1<<COM1A1)| (1<<COM1B1); 	//Clear OC on Comp Match when up-count, set downcount
    	TCCR1B = (1<<WGM13) | (1<<CS11) ;	//PWM Phase abd Freq Correct. Prescaler 8
    	ICR1 = 20000;						//Periodendauer Servo 20ms
    	OCR1A = schulter;						//Servosignal (Port 0, Schulter)
    	OCR1B = huefte;						//Servosignal (PORT 1, Hüfte)
    
    	//Timer 2 (Port 2)
    	TCCR2 = (1<<WGM20)| (1<<WGM21) | (1<<COM21) | (1<<CS22) | (1<<CS20);	 //Fast PWM
    	OCR2 = (knie/8);							//Servosignal (Port2, Knie)
    
    }
    Ich muss den Code noch auf 8mhz anpassen. Ich versuche noch heute dazu zu kommen.

  2. #32
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    21.05.2008
    Ort
    Oststeinbek
    Alter
    35
    Beiträge
    607
    A propos... wenns nicht klappt (aus welchen Gründen auch immer), könnte ich dir auch noch ein Software-PWM anbieten. Es verbraucht zwar etwas Rechenleistung (um genau zu sein ca. 2,5 von 20ms), aber es funktioniert.

    Aber natürlich werden wir zuerst versuchen es so hinzubekommen, wie es jetzt ist.

    Ich bin gerade dabei, ein Software-PWM zu schreiben (in ASM), dass in 2,5 von 20ms gleichzeitig 18 Servos bedienen kann (für meinen Hexa). Ob es gelingt, weiß ich noch nicht, aber mit 5 von 20ms sollte es sicherlich funktionieren).
    Dann könntest auch du dieses Prog beutzen, um alle Servos gleichzeitig mit einem Controller anzusteuern. Ich schreibe das Prog für einen Atmega 644, weil der 20MHz kann und mehr pins hat.

    Gruß, Yaro

  3. #33
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.05.2004
    Alter
    39
    Beiträge
    388
    Ursprünglich habe ich auch mit einem Atmega644 mit 20Mhz gearbeitet und Software PWM eingesetzt. Das hat aber nicht zufriedenstellend funktioniert.
    Deshalb diese Lösung.......

    (Bin nicht zuhause, deshalb auch noch kein angepasster Code)

  4. #34
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.05.2004
    Alter
    39
    Beiträge
    388
    Hier der Code, sorry hat etwas gedauert:
    Code:
    #include <avr/io.h>               //I/O Port definitions 
    #include <avr/interrupt.h>      //Interrupt macros 
    #include <util/twi.h>         //TWI STATUS 
    
    #define F_CPU 16000000UL      //CPU Tackt 
    
    /*----------------------------------------------------------------------------------------*/ 
    //PWM 
    /*----------------------------------------------------------------------------------------*/ 
    
    //750 = 1.5ms 
    volatile int schulter= 750;       
    volatile int huefte = 750;          
    volatile int knie = 750;    
    
    
    void pwm_init(int schulter, int huefte, int knie);   //PWM_init Funktion       
    void pwm_chance(int schulter, int huefte, int knie);//Anpassen der PWM grössen 
    
    /*----------------------------------------------------------------------------------------*/ 
    //MAIN AUFRUF 
    /*----------------------------------------------------------------------------------------*/ 
    
    int main(void) 
    { 
       DDRB = 0xFF;                                 //B... AUSGANG 
       PORTB &= ~((1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3));   //B.. Low 
    
       sei();                                        //Globale Interupts zulassen 
       pwm_init(schulter, huefte, knie);                  //PWM initialisieren 
                                
    
    
       while(1) 
       { 
    
           
       } 
    
    } 
    
    
    ISR(TIMER2_OVF_vect)   //Überlaufinterupt Timer2 
    { 
       TCCR2 = 0x00;   //Löschen von Timer2 
    } 
    
    ISR(TIMER1_CAPT_vect)   //Captureinterupt Timer1 
    { 
       TCCR2 = (1<<WGM20) | (1<<WGM21) |(1<<COM21) | (1<<CS22) | (1<<CS20);    //Setzten von Timer2 
    } 
    
    
    
    void pwm_init(int schulter, int huefte, int knie) //PWM initialisieren 
    { 
       TIMSK |= (1<<TICIE1) | (1<<TOIE2); //Interupt initialisieren, freischalten 
    
       //Timer 1 (Port 0/1) 
       TCCR1A = (1<<COM1A1)| (1<<COM1B1);    //Clear OC on Comp Match when up-count, set downcount 
       TCCR1B = (1<<WGM13) | (1<<CS11) ;   //PWM Phase abd Freq Correct. Prescaler 8 
       ICR1 = 10000;                  //Periodendauer Servo 20ms 
       OCR1A = schulter;                  //Servosignal (Port 0, Schulter) 
       OCR1B = huefte;                  //Servosignal (PORT 1, Hüfte) 
    
       //Timer 2 (Port 2) 
       TCCR2 = (1<<WGM20)| (1<<WGM21) | (1<<COM21) | (1<<CS22) | (1<<CS20);    //Fast PWM 
       OCR2 = (knie/8);                     //Servosignal (Port2, Knie) 
    
    }
    Müsste so für 8Mhz passen

  5. #35
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    21.05.2008
    Ort
    Oststeinbek
    Alter
    35
    Beiträge
    607
    soooooooo =)
    ich hab mir das alles nochmal angeschaut, und tatsächlich hat es bei mir auch nicht funktioniert (was zu erwarten war).
    Komisch war es dennoch, denn... der Servo ließ sich per Hand zwar in die eine Richtung drehen, in die andere sperrte er aber. Ich kenn mich zwar mit der Elektronik von Servos nichtt richtig aus, aber es deutet schon darauf hin, dass da irgendwo was kleines schief läuft.
    Dann hab ich mich nochmal an deine Spannungsspitze erinnert und versucht, in der Software eine Erklärung dafür zu finden, und wurde fündig (zumindest glaube ich, dass es "diese" Spitze war (hab wie gesagt grad kein Oszi zur Hand).
    Und zwar ist das Problem folgendes: Beim Overflow-Interrupt wird ja der Timer abgestellt, was dazu führt, dass die PWM-Unit nicht mehr die Kontrolle über den Port hat, sondern sie an die normalen Portbefehle übergibt. Und dabei kommt es wahrscheinlich zu dieser Spitze.
    Wie ändert man das nun? Ganz einfach! Man schaltet den Timer nicht mit dem overflow-interrupt, sondern mit dem compare-interrupt ab. Zu den Zeitpunkt macht die Spannungsspitze nämlich nix aus =)

    Ich hab den Code ausprobiert, er funktioniert!

    Code:
    #include <avr/io.h>               //I/O Port definitions
    #include <avr/interrupt.h>      //Interrupt macros
    #include <util/twi.h>         //TWI STATUS
    
    
    /*----------------------------------------------------------------------------------------*/
    //PWM
    /*----------------------------------------------------------------------------------------*/
    
    //750 = 1.5ms
    volatile int schulter= 750;
    volatile int huefte = 750;
    volatile int knie = 750;
    
    
    void pwm_init(int schulter, int huefte, int knie);   //PWM_init Funktion
    //void pwm_chance(int schulter, int huefte, int knie);//Anpassen der PWM grössen
    
    /*----------------------------------------------------------------------------------------*/
    //MAIN AUFRUF
    /*----------------------------------------------------------------------------------------*/
    
    int main(void)
    {
       DDRB = 0xFF;                                 //B... AUSGANG
       PORTB &= ~((1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3));   //B.. Low
    
       sei();                                        //Globale Interupts zulassen
       pwm_init(schulter, huefte, knie);                  //PWM initialisieren
    
    
    
       while(1)
       {
    
    
       }
    
    }
    
    
    ISR(TIMER2_COMP_vect)   //Überlaufinterupt Timer2
    {
       TCCR2 = 0x00;   //Löschen von Timer2
    }
    
    ISR(TIMER1_CAPT_vect)   //Captureinterupt Timer1
    {
       TCNT2 = 0;
       TCCR2 = (1<<WGM20) | (1<<WGM21) |(1<<COM21) | (1<<CS22) | (1<<CS20);    //Setzten von Timer2
    }
    
    
    
    void pwm_init(int schulter, int huefte, int knie) //PWM initialisieren
    {
       TIMSK |= (1<<TICIE1) | (1<<TOIE2); //Interupt initialisieren, freischalten
    
       //Timer 1 (Port 0/1)
       TCCR1A = (1<<COM1A1)| (1<<COM1B1);    //Clear OC on Comp Match when up-count, set downcount
       TCCR1B = (1<<WGM13) | (1<<CS11) ;   //PWM Phase abd Freq Correct. Prescaler 8
       ICR1 = 10000;                  //Periodendauer Servo 20ms
       OCR1A = schulter;                  //Servosignal (Port 0, Schulter)
       OCR1B = huefte;                  //Servosignal (PORT 1, Hüfte)
    
       //Timer 2 (Port 2)
       TCCR2 = (1<<WGM20)| (1<<WGM21) | (1<<COM21) | (1<<CS22) | (1<<CS20);    //Fast PWM
       OCR2 = (knie/8);                     //Servosignal (Port2, Knie)
    
    }
    Gruß, Yaro

  6. #36
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.05.2004
    Alter
    39
    Beiträge
    388
    Vielen Dank für deine bemühungen.

    Ich habs jetzt ausprobiert. Und es hat funktioniert.. fast. Der Servo hat nicht richtig kraft und knurrt
    Was auf ein falsches Timing des Signals deutet.
    Und mit dem dem Oszi kontrolliert hat sich gezeigt, das die Perioden dauer zu kurz ist(2ms anstatt 20ms).

    Und ich frage mich wieso du TCBT2 auf 0 setzt in der Capture ISR, das führt bei mir zu einem unsymetrischen Signal...

    Ich bin heut irgendwie echt nicht ganz fit, ich versteh mein eigenes Programm nicht mehr richtig

  7. #37
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    21.05.2008
    Ort
    Oststeinbek
    Alter
    35
    Beiträge
    607
    Wir lassen den Timer ja nicht mehr zuende laufen, sondern brechen bei dem compare-Wert ab, was bedeutet dass der Timer sich nicht selber auf 0 stellt, sondern bei dem compare-Wert bleibt. Wenn wir ihn nicht zurückstellen, dann wird das Signal unregelmäßig, denn beim ertsen mal bricht er nach dem comp-Wert ab, beim zweiten läuft er erstmal zuende durch, fängt von vorne an und bricht wieder beim comp-Wert ab, was natürlich einen längeren Impuls zufolge hat.

    Bist du dir sicher, dass du das Programm richtig abgeschrieben hast? Bei mir funktioniert es nämlich so wie es ist ganz gut, und der Servo hat auch die volle Kraft. Versuch es doch mal bei dir reinzukopieren, und nur die Prescaler zu ändern.

    a propos.... ich habe auch noch die #define F_CPU 16000000UL weggenommen.....die solltest du auch wieder setzten, sonst funktioniert es nicht richtig.

    Bin mal gespannt, obs jetzt klappt.

    Gruß, Yaro

  8. #38
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.05.2004
    Alter
    39
    Beiträge
    388
    Ich denke schon das ich es richtig übernommen habe.

    Die einzigen änderungen sind ja:
    Code:
    ISR(TIMER2_COMP_vect)
    und
    in der ISR TIMER1_CAPT_vect
    TCNT2 = 0;
    die CPU definition hab ich drin und natürlich den rest an 16Mhz angepasst.

    Aber da scheint echt was nicht zu passen.
    So siehts jetzt aus:
    Code:
    #include <avr/io.h>               //I/O Port definitions 
    #include <avr/interrupt.h>      //Interrupt macros 
    #include <util/twi.h>         //TWI STATUS 
    
    #define F_CPU 16000000UL      //CPU Tackt 
    
    /*----------------------------------------------------------------------------------------*/ 
    //PWM 
    /*----------------------------------------------------------------------------------------*/ 
    
    //750 = 1.5ms 
    volatile int schulter= 1500;        
    volatile int huefte = 1500;          
    volatile int knie = 1500;    
    
    
    void pwm_init(int schulter, int huefte, int knie);   //PWM_init Funktion        
    void pwm_chance(int schulter, int huefte, int knie);//Anpassen der PWM grössen 
    
    /*----------------------------------------------------------------------------------------*/ 
    //MAIN AUFRUF 
    /*----------------------------------------------------------------------------------------*/ 
    
    int main(void) 
    { 
       DDRB = 0xFF;                                 //B... AUSGANG 
       PORTB &= ~((1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3));   //B.. Low 
    
       sei();                                        //Globale Interupts zulassen 
       pwm_init(schulter, huefte, knie);                  //PWM initialisieren 
                                
    
    
       while(1) 
       { 
    
            
       } 
    
    } 
    
    
    ISR(TIMER2_COMP_vect)   //Überlaufinterupt Timer2 
    { 
       TCCR2 = 0x00;   //Löschen von Timer2 
    } 
    
    ISR(TIMER1_CAPT_vect)   //Captureinterupt Timer1 
    { 
      TCNT2 = 0;
       TCCR2 = (1<<WGM20) | (1<<WGM21) |(1<<COM21) | (1<<CS22) | (1<<CS20);    //Setzten von Timer2 
    } 
    
    
    
    void pwm_init(int schulter, int huefte, int knie) //PWM initialisieren 
    { 
       TIMSK |= (1<<TICIE1) | (1<<TOIE2); //Interupt initialisieren, freischalten 
    
       //Timer 1 (Port 0/1) 
       TCCR1A = (1<<COM1A1)| (1<<COM1B1);    //Clear OC on Comp Match when up-count, set downcount 
       TCCR1B = (1<<WGM13) | (1<<CS11) ;   //PWM Phase abd Freq Correct. Prescaler 8 
       ICR1 = 20000;                  //Periodendauer Servo 20ms 
       OCR1A = schulter;                  //Servosignal (Port 0, Schulter) 
       OCR1B = huefte;                  //Servosignal (PORT 1, Hüfte) 
    
       //Timer 2 (Port 2) 
       TCCR2 = (1<<WGM20)| (1<<WGM21) | (1<<COM21) | (1<<CS22) | (1<<CS20);    //Fast PWM 
       OCR2 = (knie/8);                     //Servosignal (Port2, Knie) 
    
    }

  9. #39
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    21.05.2008
    Ort
    Oststeinbek
    Alter
    35
    Beiträge
    607
    hmm, das ist wirklich sehr ungewöhnlich....
    Ich weiß jetzt aber, wieso der dritte Servo bei dir um 10ms verschoben ist: das ist so, weil du beim 16bit Timer ein phase-correct PWM benutzt, da ist der Overflow natürlich in der Mitte der Ganzen Zeit, und nicht am Ende, wie beim Fast-PWM. Das sollte aber keine Probleme bereiten.

    Die Periodenlängen und so sind alle richtig umgestellt.

    Könntest du vielleicht noch einige Messungen mit dem Oszi hochladen?
    Die vom neuen Programm.
    Das ist wirklich komisch alles...

    Gruß, yaro

  10. #40
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.05.2004
    Alter
    39
    Beiträge
    388
    ok, ich stell gleich mal ein paar fotos hoch

    Der neue Code erzeugt folgendes Signal ( Bild 1 und 2)
    Bild hier  
    Bild hier  

    Und dieses Signal ist ohne das auf Null setzen von TCNT2
    Bild hier  

Seite 4 von 5 ErsteErste ... 2345 LetzteLetzte

Berechtigungen

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

LiFePO4 Speicher Test