Forum: Mikrocontroller und Digitale Elektronik ATTiny 2313 mit 4,25 µsec Puls auf Port


von Horst A. (datafix)


Angehängte Dateien:

Lesenswert?

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

von m.n. (Gast)


Lesenswert?

Wenn Du Dein Programm lesbar formatierst, kann man vermutlich erkennen, 
daß Puls_High immer 0 bleibt.

von Karl H. (kbuchegg)


Lesenswert?

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
}

von Horst A. (datafix)


Lesenswert?

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 ?

von Horst A. (datafix)


Lesenswert?

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

von Wilhelm S. (wilhelmdk4tj)


Lesenswert?

Danke an die Moderatoren und andere, die sich auch scheinbar
unlesbaren Quellcode antun und etwas sinnvolles erkennen.

73
Wilhelm

von Karl H. (kbuchegg)


Lesenswert?

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
Noch kein Account? Hier anmelden.