• Die Forumsregeln und Nutzungsbedingungen findet ihr in der Navbar unter Impressum !
    Bitte unbedingt beachten!
    Wie überall im Leben gibt es Spielregeln, so auch hier!
    Die Datenschutzerklärung zum DSGVO findet ihr ebenfalls in der Navbar unter Datenschutzerklärung !
    Hinweis nach DSGVO :
    Es ist hier keinerlei Angabe erforderlich. Alle Angaben in diesem Bereich sind öffentlich sichtbar und werden freiwillig gemacht. Mit einem Eintrag in diesem Bereich erkenne ich dieses an, und bestätige die Datenschutzerklärung zur DSGVO für das Forum gelesen zu haben.

    Danke
  • Hallo Gast, beschränke dich hier bitte auf den Bereich der Elektronik. Die Fahrzeuge oder Gebäude, wo diese Elektronik eingebaut wird bitte in dem passenden Fachbereiich behandeln. Auch wenn Teile des Projektes dadurch im Forum doppelt vorhanden sind! Danke.

Arduino Auslesen von Servosignalen per Interrupt

gismow

Active member
Registriert
03.03.2012
Beiträge
2.206
Moin, moin...

Ich bastel ganz gerne an Platinen um Servosignale auszuwerten und damit dann ein bisschen Unsinn zu treiben. Ein zentrales Element ist das Auslesen der Servosignale an bestimmten Pins um diese dann weiter zu verarbeiten.

Die Funktion pulseIn() liest zwar einen Servowert, allerdings ist es blockierend, somit ist sie für meine Zwecke nicht geeignet.

Also habe ich ein bisschen gelesen und probiert. Das Ergebnis ist ein Grundgerüst zum Auslesen von Servowerten per Interrupt. Der Vorteil ist dass die Anzahl der benötigten Signale theoretisch keine Rolle spielt.

Der einzige Nachteil an der Sache ist, dass hier spezifische Defines für den ATMega328 genutzt werden. Will man einen ATTiny nutzen müssen die Defines entsprechend angepasst werden.

Hier nun ein zusammengestelltes Projekt zur Ermittlung eines Servowerts an Pin 2 eines ATMega328.

Code:
#define SERIAL_OUTPUT

//	Variablen fuer die Lenkung
volatile	uint16_t		ReceivedStearValues[4]				= {1500, 1500, 1500, 1500};	//	Die letzten 4 Werte werden gespeichert um einen 
																							//	Mittelwert zu bilden
volatile	uint16_t		ReceivedStearValuesSum				= 6000;						//	Die Summe der letzten 4 Werte
volatile	uint8_t			ReceivedStearValuesIndex			= 0;						//	Der Index des naechsten auszutauschenden Wwets

volatile	uint32_t		LastStearChange						= micros();					//	Letzter Zeitpunkt des Signalwechsels
volatile	uint16_t		ActualMeasuredStearValue			= 1500;						//	Der aktuell als letztes ermittelte Wert

volatile	uint8_t			LastInterruptState					= PIND;						//	Interruptstatus des PortD


//	Die Interrrupt Routine wird bei jedem Signalwechsel zwischen HIGH und LOW aufgerufen
//	Die Routine beruecksichtigt die HIGH Level und errechnet aus den letzten 4 HIGH Level Werten einen Mittelwert
//	Dies glättet mögliche Ausreißer und beseitigt kleinere Schwankungen. Gerade für Servos ist dies wichtig um ein stetes Zucken zu vermeiden
void InterruptStear() 
{
	uint32_t    nMicros		= micros();									//	Aktuellen Zeitstempel merken
	uint16_t    nDifference  = (uint16_t)(nMicros - LastStearChange);	//	Die Differenz zum letzten Aufruf errechnen

	LastStearChange	= nMicros;											//	Zeitstempel fuer das naechste mal merken

	if ( (nDifference > 900) && ( nDifference < 2100))					//	Zeiten zwischen 900 und 2100 Mikrosekunden sind das HIGH Signal 
	{
		//	Wert in der 4er Liste austauschen und Mittelwert errechnen. Dies erfolgt indem der alte Wert von der Summe subtrahiert wird
		ReceivedStearValuesSum							-= ReceivedStearValues[ReceivedStearValuesIndex];
		//	Der neue Wert gemerkt wird
		ReceivedStearValues[ReceivedStearValuesIndex]	 = nDifference;
		//	Den neuen Wert auf die Summe addieren
		ReceivedStearValuesSum							+= nDifference;
		//	Den Index auf die naechste Position schieben
		ReceivedStearValuesIndex						 = ( ( ReceivedStearValuesIndex + 1 ) & 0x03 );	//	Index erhoehen und ggf. von 4 auf 0 springen
		//	Den aktuellen Mittelwert errechnen indem die Summe durch 4 geteilt wird
		ActualMeasuredStearValue						 = ( ReceivedStearValuesSum >> 2 );	//	durch 4 teilen
	}
}

void setup()
{
#ifdef SERIAL_OUTPUT
	Serial.begin( 57600 );
#endif

	PCICR	|= (1 << PCIE2);		//	Interrupt Port D aktivieren
	PCMSK2	|= (1<<PCINT18);		//	Interrupts fuer Pins 2 aktivieren

	sei();
}

void loop()
{
	//	Hier kann nun mit dem Wert von ActualMeasuredStearValue gearbeitet werden
#ifdef SERIAL_OUTPUT
	Serial.println(ActualMeasuredStearValue);
#endif

	delay(20);
}

ISR(PCINT2_vect)
{
	uint8_t	PinState	= PIND;								//	Aktuellen Stetus der Interrupts lesen
	uint8_t	PinChanges	= PinState ^ LastInterruptState;	//	Mit vorherigem Wert verknüpfen
															//	Das Ergebnis ist eine Bitliste der ausgelösten Interrupts

	if (PinChanges & (1<<PCINT18))							//	Ist das Bit für Pin 2 gesetzt?
		InterruptStear();									//	Ja -> Interrupt auswerten

	LastInterruptState	= PinState;							//	Alte Bitmaske merken
}
 
Hallo Peter,

vielen Dank für Deine Mühe! :thx
Ich werde mir den Code mal in Ruhe "reinziehen" und schauen, ob meine Arduino-Kenntnisse schon weit genug sind. :cool

Herzliche Grüße von
Maik
 
Moin mein lieber Peter,
hab mal nach unserem letztem Telefongespräch das Tema mal wieder ausgegraben. Ich werd es mal nächste woche ausprobieren und mich mal hier melden. Kämpfe nämlich noch immer mit der Blinkerei. Außerdem hab ich da noch ne Idee. Ich will meine Empfänger, in meinen Auflieger und somit die ganze Elo darin über einen Fotowiederstand am Kingpin Ein/Aus schalten.
 
Hallo,

ich habe da auch schon mal was gepostet.
 
Hallo liebe Freunde des gepflegten Modellbaus,
wie ich oben schon erwähnt hab bin ich also mal an den Arduino ran gegangen und hab da also mit dem Einverständnis und der Hilfe von Peter (Gismo) auch ein kleines Video gedreht.

Um diese Inhalte anzuzeigen, benötigen wir die Zustimmung zum Setzen von Drittanbieter-Cookies.
Für weitere Informationen siehe die Seite Verwendung von Cookies.

soweit bin ich nun gekommen. Jetzt gehts darum wie ein Sketch aussehen muß das ich mit meiner Fernsteuerung auch den Arduino dazubring das zu tun was ich gerne hätte.:hfg
Da wäre ich für Beispiele wie soetws geht von eu seeehr dankbar.
 

Servonaut
Zurück
Oben Unten