Forum: Compiler & IDEs Servo Verzögerung


von Patrick (Gast)


Lesenswert?

Hallo, ich möchte eine Schaltung mit einem Tiny aufbauen die mir zum 
einen den Servoimpuls des Empfängers misst und diesen dann verzögert auf 
einem Port ausgibt. Damit soll dann das Fahrwerk langsam ausfahren.

Das Messen des Pulses mit einem Portinterupt klappt gut, allerdings 
benötige ich dazu ja schon den ersten Timer. Wie bekomme ich möglichst 
Ressourcensparend die verzögerte Ausgabe hin?? da stehe ich auf dem 
Schlauch.. einen zweiten Timer wird man wohl schon brauchen oder ginge 
es mit einem Kunstgriff auch nur mit einem?

Gruss Patrick

von Karl H. (kbuchegg)


Lesenswert?

Patrick schrieb:

> Das Messen des Pulses mit einem Portinterupt klappt gut, allerdings
> benötige ich dazu ja schon den ersten Timer.

Wie misst du?

> Wie bekomme ich möglichst
> Ressourcensparend die verzögerte Ausgabe hin??

Wenn dein 'Pulsmesstimer' ein durchlaufender Timer ist, dann hast du 
doch schon einen Zeitgeber, mit dem du zusätzlich noch eine Verzögerung 
realisieren kannst.

Hängt aber davon ab, wie du Pulse misst.

Übrigens: Verzögern des Pulses wird dir nicht helfen. Dann fährt das 
Fahrwerk einfach nur einen Tick später aus. Was du brauchst ist: Die 
Pulslänge an das Servo wird nicht in einem Schlag von 1ms auf 2ms 
gesetzt, sondern in mehreren Schritten.
Ändert aber nicht viel daran, dass du auch dieses Grundtiming 
wahrscheinlich im bereits benutzten Timer unterbringen kannst.

von Patrick (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Patrick schrieb:
>
>> Das Messen des Pulses mit einem Portinterupt klappt gut, allerdings
>> benötige ich dazu ja schon den ersten Timer.
>
> Wie misst du?

im Prinzp so:

/*********************************************************************** 
***********************/
/*                                   SIGNAL  Interupt0 
*/
/*********************************************************************** 
***********************/
SIGNAL(SIG_INTERRUPT0)
{
  if( MCUCR == 0x03) // Testen auf steigende Flanke
  {
  steigende_Flanke();
  return;
  }

  if( MCUCR == 0x02 ) // Testen auf fallende Flanke
  {
  fallende_Flanke();
  return;
  }
}


>
>> Wie bekomme ich möglichst
>> Ressourcensparend die verzögerte Ausgabe hin??
>
> Wenn dein 'Pulsmesstimer' ein durchlaufender Timer ist, dann hast du
> doch schon einen Zeitgeber, mit dem du zusätzlich noch eine Verzögerung
> realisieren kannst.
>
> Hängt aber davon ab, wie du Pulse misst.

im Moment läuft der Timer nicht durch sondern wird ja über den Interrupt 
getriggert


>
> Übrigens: Verzögern des Pulses wird dir nicht helfen. Dann fährt das
> Fahrwerk einfach nur einen Tick später aus. Was du brauchst ist: Die
> Pulslänge an das Servo wird nicht in einem Schlag von 1ms auf 2ms
> gesetzt, sondern in mehreren Schritten.
> Ändert aber nicht viel daran, dass du auch dieses Grundtiming
> wahrscheinlich im bereits benutzten Timer unterbringen kannst.

war falsch ausgedrückt.. klar muss der Impuls dann verlängert werden 
aber wie?

von Karl H. (kbuchegg)


Lesenswert?

Patrick schrieb:

>> Hängt aber davon ab, wie du Pulse misst.
>
> im Moment läuft der Timer nicht durch sondern wird ja über den Interrupt
> getriggert

D.h. Du setzt den Timer bei 'steigender Flanke' auf 0 und startest ihn. 
Und bei einer fallenden Flanke stoppst du ihn wieder?

Kann man so machen. Muss man aber nicht.
Der Timer kann auch ständig laufen. Bei einer steigenden Flanke merkst 
du dir den Timerwert, bei einer fallenden Flanke ziehst du dann vom dann 
vorliegenden Timerwert den gemerkten Startwert ab und schon hast du die 
Anzahl der Timerticks zwischen den beiden 'Ereignissen'

>> gesetzt, sondern in mehreren Schritten.
>> Ändert aber nicht viel daran, dass du auch dieses Grundtiming
>> wahrscheinlich im bereits benutzten Timer unterbringen kannst.
>
> war falsch ausgedrückt.. klar muss der Impuls dann verlängert werden
> aber wie?

möchte man haben, dass sich ein Wert langsam an einen anderen anpasst 
und nachzieht, dann geht das zb so

   while( 1 ) {

     if( aktueller_Wert < Soll_Wert )
       aktueller_Wert++:

     if( aktueller_Wert > Soll_Wert )
       aktueller_Wert--:

     mach was mit aktueller_Wert
   }

Wann immer sich der Sollwert ändert, wird der Wert den du im weiteren 
benutzt (zb bei dir eben die Servoposition) in jedem Schleifendurchlauf 
nur ein Stückchen in Richtung des Sollwerts verändert. Bei vielen 
Schleifendurchläufen wird der tatsächlich benutzte Wert aktueller_Wert 
irgendwann den Soll_Wert erreichen. Aber eben nicht sofort, sondern in 
vielen kleinen Stufen. Ob man dann als Stufenbreite 1 nimmt (wie hier) 
oder ob man da in größeren Schritten operiert, hängt von der Anwendung 
ab bzw. davon wie schnell die Schleife dann tatsächlich durchläuft.

Bei dir wäre zb Soll_Wert die Pulslänge, die du gemessen hast. 
Aktueller_wert ist die Pulslänge, wie du sie generierst und zum Servo 
schickst. Und die Hauptschleife führt den einen Wert dem anderen nach 
und schon läuft dein Servo langsam in die durch den Sollwert vorgegebene 
Position. Ist das Servo novh unterwegs und ändert sich der Soll_wert ist 
das auch kein Problem, die Schleife führt den aktuellen Wert dann eben 
auf einen anderen Soll_wert nach.

von Patrick (Gast)


Lesenswert?

Hallo Karl Heinz,

herzlichen Dank, das ist eine sehr gute Idee!

ich könnte zb. den Timer mit 10us laufen lassen, dh. bei einer Pulslänge 
zwischen 1-2ms hätte ich eine Auflösung zwischen 100-200 Tics... sollte 
reichen.

den gleichen Timer muss ich halt durch einen Teiler im Interrupt 
verlangsamen so dass ich zb. 1sec (100.000tics) Hoch/Runter Zählimpulse 
bekomme.

Den Ausgabe Impuls müsste ich dann daraus berechnen indem ich den max 
wert der Periodendauer = 20ms = 2000tics minus dem der gerechneten 
Pulslänge verwende und auch wieder über den gleichen Zähler ausgebe. Ich 
dachte mir quasi immer dann eine Ausgabe zu starten wenn der Port wieder 
auf 0 geht und die Impulsdauer gemessen wurde.

Gruss Patrick

von Patrick (Gast)


Lesenswert?

Hallo,

ich hab die Umsetzung mittels zweitem Timer1 versucht. Theoretisch 
funktionierte auch alles, aber leider tut sich mein Tiny25 mit den 
kurzen Zeiten schwer. Er läuft intern mit dem 8Mhz RC Oszilator, normal 
nochmal mit einer Fuse durch 8 geteilt. D.h wenn der Timer1 mit 10us 
laufen soll geht quasi nichts mehr. Ich denke dass die Abarbeitungszeit 
dann länger braucht als der Timerinterrupt. Ich hab den Teiler /8 auch 
mal abgeschaltet so dass ich die vollen 8Mhz zur Verfügung habe, aber 
auch damit komme ich nicht auf einen so schnelle Abarbeitung. Gibts dazu 
einen Trick oder mache ich was falsch?

Gruss Patrick

von Karl H. (kbuchegg)


Lesenswert?

Patrick schrieb:
> Hallo,
>
> ich hab die Umsetzung mittels zweitem Timer1 versucht. Theoretisch
> funktionierte auch alles, aber leider tut sich mein Tiny25 mit den
> kurzen Zeiten schwer.
> Ich hab den Teiler /8 auch
> mal abgeschaltet so dass ich die vollen 8Mhz zur Verfügung habe, aber
> auch damit komme ich nicht auf einen so schnelle Abarbeitung. Gibts dazu
> einen Trick oder mache ich was falsch?

Du willst mir doch nicht ernsthaft erzählen, dass ein mit 8Mhz 
getakteter Prozessor Schwierigkeiten mit einem Timing hat, welches sich 
im Millisekundenbereich bewegt. Nur zu Veranschaulichung: In 1 
Millisekunde bearbeitet dein Tiny rund 7-Tausend Befehle!

Da wirst du wohl etwas falsch machen.

von Rolf Magnus (Gast)


Lesenswert?

Naja, mich wundert's nicht, wenn er einen Timer so einstellt, daß er 
alle 10 µs einen Interrupt auslöst. Dann hat man bei 8 Mhz pro Interrupt 
80 Taktzyklen, die vermutlich größtenteils in der ISR selbst schon 
verbraucht werden. Bei 1 Mhz wären es noch 10 Taktzyklen pro Interrupt, 
was gar nicht reichen kann, weil es schon unter dem liegt, was eine 
komplett leere ISR braucht.

von Patrick (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Naja, mich wundert's nicht, wenn er einen Timer so einstellt, daß er
> alle 10 µs einen Interrupt auslöst. Dann hat man bei 8 Mhz pro Interrupt
> 80 Taktzyklen, die vermutlich größtenteils in der ISR selbst schon
> verbraucht werden. Bei 1 Mhz wären es noch 10 Taktzyklen pro Interrupt,
> was gar nicht reichen kann, weil es schon unter dem liegt, was eine
> komplett leere ISR braucht.

Genau, wenn ich den Puls von 2ms Länge mit einer Auflösung von 200 
Schritten auflösen möchte brauch ich halt die 10us für eine Timer ISR. 
Per Flankentriggerung gehts natürlich aber dann kann ich den Timer ja 
für nichts anderes mehr verwenden.

Gruss Patrick

von Peter D. (peda)


Lesenswert?

Pseudocode:
1
externer_Interrupt // oder input-capture interrupt
2
{
3
  if( inputpin == 1 ) 
4
    anfang = timer;
5
  else
6
    in_pulsdauer = timer - anfang;
7
{
8
9
output_compare_Interrupt
10
{
11
  if( outputpin == 0 ){
12
    OCR1A = timer + pausen_dauer;
13
    setze_pin_bei_compare();
14
  }else{
15
    OCR1A = timer + out_pulsdauer;
16
    loesche_pin_bei_compare();
17
  }
18
}

Nimm am einfachsten nen ATtiny24, dann hast Du nen 16Bit Timer, da 
sollte die Auflösung dicke reichen.


Peter

von Patrick (Gast)


Lesenswert?

ok, die Output Compare Funktion muss ich mir noch durchlesen.. damit 
hatte ich noch nichts gemacht.

Folgender Ansatz, im Prinzip wie oben. Ich starte den Timer mittels Pin 
ISR bei steigender Flanke, wenn die fallende Flanke erkannt wird merke 
ich mir nur den Wert des Timers für die Impulslänge stoppe diesen aber 
noch nicht sondern benutze Ihn weiter um quasi im Anschluss den 
"veränderten" Ausgangsimpuls zu erzeugen. Dadurch bräuchte ich quasi 
immer nur auf das Ende zu warten um die Pins zu toggeln.. vlt. geht so.

Gruss Patrick

von Ole (Gast)


Lesenswert?

Hallo Patrick,

ich habe das gleiche vor wie du. Bist du mit deinem Ansatz schon weiter 
gekommen?

VG Ole

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.