Hallo zusammen, ich bitte um Euere Mithilfe bzw Rat weil ich im Augenblick nicht mehr weiter weiß. Ich möchte mit dem 8 Bit Timer des ATTiny2313 (der 16 Bit ist schon belegt) einen Servopuls für Modellbau Servos erzeugen, also 1 ... 2 msec breit, Wiederholung ca alle 20 msec. Der angehängte Code (bitte um Nachsicht wenn er vielleicht etwas umständlich und nicht den gültigen C-Programmier Regeln entsprechend geschrieben ist) funktioniert auch soweit, allerdings sehe ich mit dem Osci quasi "im Hintergrund" des Servosignals völlig konstant Rechteckpulse mit 4,25 µsec Länge und 1:1 Tastverhältnis. Ich habe absolut keine Idee warum und woher die kommen. Bisher probiert ohne Ergebnis: anderer Baustein, Baustein in eigener Schaltung (nicht STK), anderer Port, Port mit und ohne Last Für Ratschläge oder Abhilfe oder andere Lösungen schon mal besten Dank im voraus Horst
Wenn Du Dein Programm lesbar formatierst, kann man vermutlich erkennen, daß Puls_High immer 0 bleibt.
Horst A. schrieb: > Ich habe absolut keine Idee warum und woher die kommen. Du kommen daher, weil > wenn er vielleicht etwas umständlich So ganz kann ich noch nicht erkennen, was eigentlich die Idee bei dieser Pulsgenerierung ist. Aber egal was die Idee ist, sie ist deutlich zu kompliziert und umständlich. Viel einfacher. Dein Timer erreicht ...
1 | 8000000 / 8 // wegen Vorteiler |
2 | 1000000 / 256 // wegen 8 Bit Timer und Overflow Interrupt |
3 | = 3906.25 |
... mal pro Sekunde den Overflow. In Zeiteinheiten sind das
1 | 1/3906 = 0.000256 Sekunden oder 0.256 Millisekunden |
gut. Um damit 20 Millisekunden abzuzählen, muss also eine Variable in diesem Takt bis 78 zählen. Der Zeitbereich 1 bis 2 Millisekunden wird dabei durch Zählerwerte von ca 4 bis ca. 7 abgedeckt (was für eine Servolösung deutlich zuwenig sein wird. Aber seis drumm, wenn du das Servo nur so ungefähr von einer Endstellung zur anderen fahrn lassen willst, dann reicht das erst mal. Ausserdem gehts ums Prinzip) Damit haben wir mal die relevanten Zahlen. d.h. du lässt im Timer Interrupt eine Variable hochzählen. Wenn die den Wert 78 erreicht hat, dann lässt du sie wieder bei 0 anfangen. Wenn du bei einem Wert von 0 in dieser Variablen den Pin auf 1 setzt und bei einem Wert von 4 wieder auf 0, dann hast du damit am Pin einen Puls erzeugt, der ca 1 Millisekunde lang ist und der sich (weil die Variable alle ca 20ms wieder auf 0 gesetzt wird und von dort wieder hochzählt) alle ca 20ms wiederholt. (Ich nenne die Variable mal timeCnt)
1 | uint8_t timeCnt; |
2 | |
3 | ISR(TIMER0_OVF_vect) |
4 | {
|
5 | |
6 | timeCnt++; |
7 | if( timeCnt == 78 ) |
8 | timeCnt = 0; |
9 | |
10 | if( timeCnt <= 4 ) |
11 | PORTD |= ( 1 << PD1 ); |
12 | else
|
13 | PORTD &= ~( 1 << PD1 ); |
14 | }
|
Ich hab absichtlich hier die Sache nicht ganz zeiteffizient gemacht. Das Prinzip ist einfach. Ich teile die 20ms (repräsentiert durch timeCnt, das bis 78 zählt) einfach auf. jedesmal wenn timeCnt verändert wird, sehe ich nach, in welchem 'Bereich' sich die aktuelle Zeit befindet. Muss der Pin auf 1 gesetzt werden oder auf 0, abhängig davon, ob wir noch im 'Pulsteil' des Signals sind, oder ob wir schon im Pausenteil sind. Die Pulslänge wird durch die '4' eingestellt. Wenn die noch variabel sind, dann kann man von 'ausserhalb' der ISR mitteilen, wie lange diese Pulslänge sein soll.
1 | volatile uint8_t pulsLaenge = 4; |
2 | uint8_t timeCnt; |
3 | |
4 | ISR(TIMER0_OVF_vect) |
5 | {
|
6 | |
7 | timeCnt++; |
8 | if( timeCnt == 78 ) |
9 | timeCnt = 0; |
10 | |
11 | if( timeCnt <= pulsLaenge ) |
12 | PORTD |= ( 1 << PD1 ); |
13 | else
|
14 | PORTD &= ~( 1 << PD1 ); |
15 | }
|
Verändere die Variable pulsLänge (mit Werten zwischen 4 und 7) und die ISR generiert dir entsprechende Servopulse.
1 | ...
|
2 | |
3 | // Testprogramm: lässt das Servo alle 5 Sekunden in die
|
4 | // jeweils andere Endstellung fahren
|
5 | |
6 | int main() |
7 | {
|
8 | DDRD |= ( 1 << PD1 ); // Pin auf Output |
9 | |
10 | ....
|
11 | |
12 | while( 1 ) { |
13 | |
14 | pulsLaenge = 4; // Endstellung links |
15 | delay_ms( 5000 ); |
16 | |
17 | pulsLaenge = 7; // Endstellung rechts |
18 | delay_ms( 5000 ); |
19 | }
|
20 | }
|
Hallo Karl Heinz, vielen Dank für die schnelle Antwort, werde ich mir zu Gemüte führen und ausprobieren. Die ursprüngliche Idee war die Anzahl der Timer Overflow Interrupts zu zählen, und entsprechend den Pin low oder high zusetzen, aber das ist wohl von der Sorte "von hinten durch die Brust ins Auge". Ich bin auch absoluter Anfänger im Programmieren, deswegen meine Fragen. beste Grüße Horst P.S. Aber was in meinem Code erzeugt die Rechteck Pulse ?
Hallo Karl Heinz, SW soeben ausprobiert, war super nachzuvollziehen, nochmals vielen Dank. Grundidee war die gleiche, nur von Dir viel viel effizienter gelöst. Läuft perfekt (und ohne störende Rechteckpulse über den Servopulsen) ! Eine abschließende Frage habe ich noch: wie ließe sich mit dem 8 Bit Timer eine bessere Stellgenauigkeit erreichen, wenn überhaupt ? Ich hab die Suche schon bemüht, aber irgendwie nicht richtig fündig geworden. viele Grüße Horst
Danke an die Moderatoren und andere, die sich auch scheinbar unlesbaren Quellcode antun und etwas sinnvolles erkennen. 73 Wilhelm
Horst A. schrieb: > wie ließe sich mit dem 8 Bit Timer eine bessere Stellgenauigkeit > erreichen, wenn überhaupt ? das geht nur, indem du den Timer schneller laufen lässt. zb 8 mal so schnell (weil es keinen anderen Vorteiler mehr gibt als 1) Die jetzigen 78 werden dann zu 8*78 oder eben 624 ISR AUfrufen nach denen das Rücksetzen des timeCnt auf 0 erfolgt (und die dann eine uint16t Variable werden muss). Im Gegenzu dazu hast du dann allerdings auch zulässige Werte für pulsLänge, die nicht mehr von 4 bis 7 laufen, sondern von 8*4 = 32 bis 8*7 = 56. Das sind dann immerhin schon 56-32 = 24 Abstufungen. Mehr ist da jetzt mit der simplen Timer-Overflow Systematik nicht mehr drinnen. Will man noch mehr, dann könnte man den Timer zb in der ISR vorladen, so dass er nicht mehr 256 Zählschritte bis zum nächsten Overflow benötigt, sondern eben weniger, was dann wieder einen zusätlichen Faktior in den Zahlen einbringt. Allerdings ist das irgenwann nicht mehr sinnvoll, denn dann beschäftigt sich der µC nur noch mit der Timer-ISR um dort drinnen einen Zähler hochzuzählen. Irgendwann muss man die Systematik radikal umstellen und zb. mit einem Compare Match Interrupt weiter arbeiten, wobei das bei einem 8 Bit Timer aufgrund des kleinen Zählumfangs dann schon knifflig werden kann. Geht aber.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.