- fchao-Sinus-Wechselrichter AliExpress         
Seite 1 von 3 123 LetzteLetzte
Ergebnis 1 bis 10 von 22

Thema: Atmega Timer problem

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    06.09.2013
    Beiträge
    18

    Atmega Timer problem

    Anzeige

    Praxistest und DIY Projekte
    Hallo liebes Forum,

    Ich habe ein Verständnisproblem bezüglich der Timer (8 u. 16 bit).
    Ich habe versucht ein PWM-Signal zu generieren, jedoch zeigt das oszi keins an.

    Was ich erwartet habe: alle 20ms wird eine entsprechende Pulsbreite von den Timern erzeugt. 0,6ms bis 2,6ms sollte die range der Breite sein.
    Die pulsbreite wird über LDRs realisiert, die einen Spannungsteiler bilden. So liegen am ADC1 werte von 0V bis 5V an. Wenn beide LDRs gleich stark beleuchtet sind, liegen ca. 2,5V am ADC1 an. Der Teil des Speicherns in eine Variable funktioniert soweit (0...1024 -> 2,5V = 512).

    Ich habe es versucht mit einem Timer1 (16-Bit) zu realisieren aber ich bekomme es einfach nicht hin.
    Ich benutze einen Atmega1284p-pu der mit dem internen Clock von 8Mhz arbeitet.

    Hier mein Code:

    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	(TIMER1_COMPA_vect)		 //Interrupt sub routine 
    {
    	OCR1A = 10000 - OCR1A;	 // hier werden die 20ms erzeugt die der servo benötigt
    }
    
    int main(void)
    {	
            DDRD = (1<<PIND5);                  //Der Ausgang
    
    	ADC_Init();					//ADC initialisieren
    
            double	adcwert_1_LDRs;        //speicherort für den ADCwert
    
            TCCR1A = (1<<COM1A1) | (1<<COM1B1);		//CTC Modus (Clear OC1A on compare match), set OC1A at bottom non-inverting
    	TCCR1B = (1<<WGM13) | (1<<CS11);	               //(1<<WGM12) vllt raus, (ICRn aktivieren), OCR1A auf direkt, TOV1 Flag auf MAX, prescaler=8
            OCR1A = 799;		                                      //(8Mhz/(2*8*(1+799)))=625Hz=1,6ms Mittelstellung, (8Mhz/(2*8*(1+750)))=665,7Hz=1,5ms Mittelstellung,
    	TIMSK1 = (1<<OCIE1A);//(1<<TOIE1); 		      //Timer-compare-Interrupt an 
    
     	_delay_ms(2000);
    
            while(1)
            {
    		adcwert_1_LDRs = ADC_Read(1);
    		if (adcwert_1_LDRs <= 490 && OCR1A > 301)	          //servo dreht links bis max. 0,6ms
    		{					//(8MHz/(2*8*(1+9699)))=51,54Hz;20ms-0,6ms=19,4ms->1/19,4ms=51,54Hz->(8MHz/(2*8*51,54Hz))-1=9699->10000-9699=301!
    							 //(8MHz/(2*8*(1+301)))=1655,6Hz=0,6ms
     			cli();			        //interrupts global deaktivieren 
    			OCR1A -= 5;		//OCR1A so lange um 5 verringern, bis panel direkt zur sonne gerichtet ist				
    			sei();			        //interrupts globl aktiviren
    			_delay_ms(50);	        //50ms warten
    		}
    		
    		if (adcwert_1_LDRs >= 530 && OCR1A < 1301)	//servo dreht rechts
    		{
    			cli();
    			OCR1A += 5;		//1301;
    			sei();
    			_delay_ms(50);
    		}
            }
    }
    Ich hoffe Ihr könnt mir helfen.

    Mit freundlichen Grüßen

    Technik_Amateur

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.703
    Blog-Einträge
    133
    Hi,
    ich blick nicht durch, wie Dein Programm funktioniert/funktionieren soll. Deshalb mal ein Alternativvorschlag für die Timereinstellung:

    OCR1A mit 1500 initialisieren (Mittelstellung für Servo)
    Für Timer1 im Fast PWM Modus mit ICR1 als Top (Mode 14)
    Im TCCR1A WGM11 setzen
    Im TCCR1B WGM12 und WGM13 setzen

    ICR1 auf 19999 setzen UND Prescaler auf 8 (im TCCR1B zusätzlich noch das CS11 setzen)
    Mit CS11 läuft der Timer1 los und benötigt für eine "Runde" 20ms und eine Einheit im OCR1A entspricht einer µs.

    Für PWM Modus "non inverting" in TCCR1A noch zusätzlich das COM1A1 setzten (clear OC1A on compare match, set at bottom)

    Nun brauchst Du nur noch OCR1A entsprechend zu setzen und an PD5 erscheint das benötigte PWM Signal für den Servo wenn der, wie in Deinem Programm, auf OUTPUT geschaltet ist.

    zB OCR1A auf 500 = Servopulsweite von 0,5ms
    zB OCR1A auf 1500 = Servopulsweite von 1,5ms

    Dann wird keine ISR benötigt und in der Haupschleife dann nur ADC auswerten und das OCR1A entsprechend setzten.

    Alles nach Datenblatt für ATmega1284P_doc8059 und nicht getestet, soll heißen ohne Gewehr


    Gruß
    Searcher
    Geändert von Searcher (19.11.2013 um 14:05 Uhr) Grund: Timing für Puls berichtigt (OCR1A)
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

  3. #3
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Zitat Zitat von Technik_Amateur Beitrag anzeigen
    Ich habe versucht ein PWM-Signal zu generieren, jedoch zeigt das oszi keins an.
    Du hast einen PWM-Modus mit variablem TOP-Wert ausgewählt, lässt diesen TOP-Wert dann aber auf 0. Wie soll da dann auch irgendein PWM-Signal raus kommen.
    MfG
    Stefan

  4. #4
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.686
    ... 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

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

  6. #6
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.703
    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

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

  8. #8
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.703
    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

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

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

Seite 1 von 3 123 LetzteLetzte

Ähnliche Themen

  1. ATMEGA 16 TIMER-Problem
    Von fulltime im Forum C - Programmierung (GCC u.a.)
    Antworten: 29
    Letzter Beitrag: 16.03.2012, 15: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, 18:18
  3. Atmega 8 Timer
    Von woodeye im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 15
    Letzter Beitrag: 25.09.2009, 16:44
  4. Atmega mit >3 Timer
    Von manhunt im Forum AVR Hardwarethemen
    Antworten: 12
    Letzter Beitrag: 14.12.2008, 15:10
  5. Atmega 32 8-Bit Timer Interrupt
    Von Benni im Forum C - Programmierung (GCC u.a.)
    Antworten: 5
    Letzter Beitrag: 23.07.2007, 22:08

Berechtigungen

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

Labornetzteil AliExpress