-
        

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 20

Thema: Atmega8 mit 16Mhz betreiben.

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

    Atmega8 mit 16Mhz betreiben.

    Anzeige

    Guten morgen.

    Ich habe einen Atmega 8 den ich mit 16Mhz betreibe.
    Das wäre aufhedenfall der Wunsch.



    Mit Hilfe des Timers null löse ich alle 0.01ms einen Interrupt aus.
    Code:
    F_CPU = 16000000
    timer = (256-F_CPU/8/100000)
    TCCR0 |= (1<<CS01) | (!(1<<CS00)) | (!(1CS02));
    TCNT0 = timer;
    TIMSK |= (1<<TOIE0);
    TIFR |= (1<<TOV0);
    Setzte den Pin auf High
    Anschliessen zähle ich pro Interrupt eine Variable hoch bis 150.
    Setzte den Pin auf Low und lösche die Variable.
    Das sollte mir ein Rechtecksignal von 1.5ms geben.

    Leider stimmts nicht genau(Zeitlich), woran könnte das lieben.

    Falsche Fusebit einstellungen?
    Ich bin mir dort nicht ganz sicher wie man 16Mhz einstellt.

    Danke fürs lesen und mögliche Tipps

    EDIT:
    Ich glaube mein ATMEGA läuft wirklich nicht auf 16Mhz.
    Ich habe ihn jetzt so eingestellt.
    16Mhz / 8(Prescaler) = 2Mhz
    Code:
    TCCR |= (1<<CS01);
    Ich möchte alle 0.01ms einen Interupt
    1s/0.00001 = 100000
    2000000 / 100000 = 20
    256 (8Bit)-20 = 236 (Vorladen)
    Code:
    TCNT0 = 236;
    Wen ich nun den Pin für 150 Interupts auf High lege sollte das doch 1.5ms erben?
    Ich kriege aber ein High von 2ms???

    Oder mein Oszi stimmt überhaupt nicht mehr, was ich aber nicht glaube.

  2. #2
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Das ist mehr ein Software Problem. Die einstelling des Timers sollte nicht stimmen:
    TCCR0 |= (1<<CS01) | (!(1<<CS00)) | (!(1CS02));

    sollte TCCR0 = 255 setzen. Das wird wohl kaum gewollt sein.

  3. #3
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    25.11.2003
    Beiträge
    1.111
    Hi!
    erstens:
    "TCCR0 |= (1<<CS01) | (!(1<<CS00)) | (!(1CS02));"
    Das führt nicht zum gewünschten Effekt, da Du mit einem "NOR" die Bits nicht 0 setzen kannst.
    Du meinst zB
    TCCR0 &= 0b11111010;
    Ist aber egal, da die Biits von vornherein ohnehin 0 sind.
    Das ist aber auch falsch, da Du einen Prescaler von 0 brauchst und das geht bei Timer 0 so:
    TCCR0 &= 0b11111001;
    Du willst also nach 150 Takten den T0OVF IRQ auslösen, also:
    Timer = 256 - 150;
    Das hier:
    "timer = (256-F_CPU/8/100000);"
    geht auch nicht, wenn es zeitkritisch ist, weil die Berechnung verhältnismäßig lange dauern kann. Sowas wenns geht vermeiden.
    Durch 8 teilen sollte man auch eher mit >> 3.
    Fusebits sollte man natürlich richtig einstellen, aber da Du nichts nähres beschreibst...
    Gruß

  4. #4
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.05.2004
    Alter
    31
    Beiträge
    388
    Danke für eure Antworten. ich hätte nicht gedacht, das so viel nicht stimmt.
    Dein mein Ausgangssignal stimmt fast, ich bin nur microsekunden von meinem 1.5ms entfernt.

    mit timer = (256-16000000/8/100000)
    und
    TCNT0 = timer
    lade ich doch meinen Timer mit 236 vor.
    Damit ich alle 0.01ms einen Interupt kriege.

    Wie müsste ich den Den Timer einstellen damit ich auf meine 0.01ms käme und wieso bin ich den jetzt nur etwas daneben?

  5. #5
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    25.11.2003
    Beiträge
    1.111
    Achso, Du willst mit einem Prescaler 8 auf 20...ich hatte da doch etwas von 150 gelesen und dann bräuchtest Du einen anderen TCNT0 Wert und Presaler 1. Hab da was korrigiert, aber so ginge es auch.
    Wertest Du das hier
    timer = (256-16000000/8/100000)
    jedemal aus oder nur einmal am Anfang? Startest Du den Timer danach?
    Und von welchem Typ ist eigentlich Timer???
    Wenn Du den Timer nach der Berechnung startest, entsteht ein Fehler von der Dauer der Berechnungszeit.
    Ich glaube diese wenigen Programmfragmente reichen nicht aus, um genaueres zu sagen.
    Gruß

  6. #6
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.05.2004
    Alter
    31
    Beiträge
    388
    Ich habs jetzt neu so versucht geht aber auch nicht, irgendwas habe ich scheinbar nicht begriffen.

    Code:
    #include <avr/io.h>         // I/O Port definitions 
    #include <avr/interrupt.h>   // Interrupt macros 
    
    #define F_CPU 16000000 
    
    #define timer 96							//0.01ms
    //
    
    volatile int ms1 = 0;
    volatile int ms2 = 0;
    volatile int ms3 = 0;
    
    void timer_init(void) 
    {
    	TCCR0 |= (1<<CS00);		//Prescaler 1
    	TCNT0 = timer;
    	TIMSK |= (1<<TOIE0);									//Interupts aktivieren
    	TIFR |= (1<<TOV0);
    
    };
    
    ISR(TIMER0_OVF_vect) 
    {
    
    	//Endausschlag LINKS
    	if(ms1>150)
    		PORTB &= ~(1<<PORTB1);
    	else
    		PORTB |= (1<<PORTB1);
    	if(ms1<2000)
    		ms1++;
    	else
    		ms1 = 0;
    
    	TCNT0 = timer;			
    
    	//Endausschlag MITTE	
    	if(ms2>150)
    		PORTB &= ~(1<<PORTB2);
    	else
    		PORTB |= (1<<PORTB2);
    	if(ms2<2000)
    		ms2++;
    	else
    		ms2 = 0;
    
    	//Endausschlag RECHTS	
    	if(ms3>150)
    		PORTB &= ~(1<<PORTB3);
    	else
    		PORTB |= (1<<PORTB3);
    	if(ms3<2000)
    		ms3++;
    	else
    		ms3 = 0;
    };
    
    int main(void) 
    {
    
    	DDRB |= (1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3);			//B... AUSGANG
    	PORTB &= ~((1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3));		//B.. Low
    
    	sei();													//GLOBALE INTERUPTS AKTIVIERT
    
    	timer_init();											//FUNKTIONSAUFRUF
    
    }
    Ziel des Codes ist es, mir die Ports für 1.5ms auf High zu ziehen und 18.5ms auf Low (Servomittelposition)

    Mit dem Wert von 150 wollte ich auf die 1.5ms kommen.
    Und dort wo jetzt 96 steht hatte ich die Berrechnung der timer variable

  7. #7
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    25.11.2003
    Beiträge
    1.111
    Das ist das ganze Programm?
    Das geht aber ohne Compilerfehler nicht durch, oder?
    Prinzipiell fehlt die Endlosschleife while(1) in main und der Rückgabewert return 0.
    TCNT0 solltest Du am Anfang der ISR zurücksetzen, sonst bekommst Du 150mal die Rechendauer bis dorthin als Fehler. Größer Vergleiche sollte man vermeiden und lieber größergleich nehmen.
    Dass Endsusschlag mitte und Rechts eigentlich das gleiche machen wie links ist Dir klar, oder?
    Warum machst Du es DIr eigentlich so kompliziert. Es gibt viele Tutorials, wie man einen Servo an einen OC Ausgang eines AVRs aschlißt. der Rest sind wenige Zeilen Code, wenn man die OutputCompareEinheit nutzt.
    Gruß

  8. #8
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.05.2004
    Alter
    31
    Beiträge
    388
    Vielen dank für deine Hilfe

    Ja das ist alles und funktioniert. Ich habe das programm jetzt angepasst aber die High low stimmen noch immer nicht.
    Die Kommentare kannst du ignorieren die sind falsch.

    Betreffend Hardware PWM sagt jeder etwas anderes, die meisten sagen Hardware PWM sei nicht zu ansteuerung von Servos geeignet.

    Ich verstehe nur nicht was da schief läuft.
    Dies Fuses habe ich bei Quarz auf
    Ext.Crysatl Res. HighFreq. Startup 16K +64ms
    Und CKOPT ist drin

  9. #9
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    25.11.2003
    Beiträge
    1.111
    Den Post versstehe ich nicht.
    Hast Du die Codeoptimierung eingeschaltet? Womit progst Du (AVRStudio?), welches Board hast Du und welchen Programmer?
    Gruß

  10. #10
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Solche Ausdrücke wie

    "timer = (256-F_CPU/8/100000);"

    Sind an sich kein Problem. Da sind zwar divisionen drin, aber es sind alles Konstanten und die Berechung macht also schon der Compiler auf dem PC. Das einzige wo man drauf achten muß ist das Runden der zahlen, und das normalerweise mit integer Werten gerechent wird. Ggf. also noch ein L anhängen damit wenigsten Longint benutzt wird für die Rechnung.

    Wenn der Timer 16 Bit PWM kann, dann geht Hardware PWM oft recht gut. Wenn die Taktfrequenz ungünstig liegt, dann hat man allerdings nicht besonders viel Auflösung. Bei 16 MHz kann man Prescaler 8 und einen normalen PWM mode (kein fast PWM) nehmen, dann kommt die Frequenz ganz gut hin.

    Wenn man das nicht will, kann man wenigstens den Timer Direkt nutzen für die ganze Verzögerung.

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

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