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.
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.
Setzte den Pin auf HighCode:F_CPU = 16000000 timer = (256-F_CPU/8/100000) TCCR0 |= (1<<CS01) | (!(1<<CS00)) | (!(1CS02)); TCNT0 = timer; TIMSK |= (1<<TOIE0); TIFR |= (1<<TOV0);
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
Ich möchte alle 0.01ms einen InteruptCode:TCCR |= (1<<CS01);
1s/0.00001 = 100000
2000000 / 100000 = 20
256 (8Bit)-20 = 236 (Vorladen)
Wen ich nun den Pin für 150 Interupts auf High lege sollte das doch 1.5ms erben?Code:TCNT0 = 236;
Ich kriege aber ein High von 2ms???
Oder mein Oszi stimmt überhaupt nicht mehr, was ich aber nicht glaube.
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.
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ß
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?
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ß
Ich habs jetzt neu so versucht geht aber auch nicht, irgendwas habe ich scheinbar nicht begriffen.
Ziel des Codes ist es, mir die Ports für 1.5ms auf High zu ziehen und 18.5ms auf Low (Servomittelposition)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 }
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
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ß
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
Den Post versstehe ich nicht.
Hast Du die Codeoptimierung eingeschaltet? Womit progst Du (AVRStudio?), welches Board hast Du und welchen Programmer?
Gruß
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.
Lesezeichen