PulseIn im Fahrtenregler

Für mein Fahrtenreglerprojekt nutze ich zu Erzeugung des PWM-Signal eine interruptgesteuerte PWM. Diese funktioniert recht gut. Das Problem ist, dass in dem Augenblick, wenn ich im Code die pulseIn Methode verwende, um die Signale aus dem Fernsteuerempfänger zu lesen, die Software-PWM nicht mehr funktioniert! Woran liegt das? Was macht pulseIn im Hintergrund mit meinen Interrupteinstellungen? (Läuft als CTC mit 1 als Vorteiler und 100 als TopWert, OCR0A sozusagen.)

Wer kann helfen, was macht PulseIn?

ArduStemmi:
Wer kann helfen, was macht PulseIn?

Hallo ArduStemmi,

pulseIn() wartet in einer Schleife ganz brutal, bis sich der Zustand des Pins auf LOW/HIGH ändert und dann wieder bis sich der Zustand des Pins zum anderen Pegel HIGH/LOW ändert. So richtig fies in einer Dauerschleife. Na ja, eigentlich sind es sogar fast 3 fiese Schleifen.
Siehe Code:

/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
 * or LOW, the type of pulse to measure.  Works on pulses from 2-3 microseconds
 * to 3 minutes in length, but must be called at least a few dozen microseconds
 * before the start of the pulse. */
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
{
	// cache the port and bit of the pin in order to speed up the
	// pulse width measuring loop and achieve finer resolution.  calling
	// digitalRead() instead yields much coarser resolution.
	uint8_t bit = digitalPinToBitMask(pin);
	uint8_t port = digitalPinToPort(pin);
	uint8_t stateMask = (state ? bit : 0);
	unsigned long width = 0; // keep initialization out of time critical area
	
	// convert the timeout from microseconds to a number of times through
	// the initial loop; it takes 16 clock cycles per iteration.
	unsigned long numloops = 0;
	unsigned long maxloops = microsecondsToClockCycles(timeout) / 16;
	
	// wait for any previous pulse to end
	while ((*portInputRegister(port) & bit) == stateMask)
		if (numloops++ == maxloops)
			return 0;
	
	// wait for the pulse to start
	while ((*portInputRegister(port) & bit) != stateMask)
		if (numloops++ == maxloops)
			return 0;
	
	// wait for the pulse to stop
	while ((*portInputRegister(port) & bit) == stateMask) {
		if (numloops++ == maxloops)
			return 0;
		width++;
	}

	// convert the reading to microseconds. The loop has been determined
	// to be 20 clock cycles long and have about 16 clocks between the edge
	// and the start of the loop. There will be some error introduced by
	// the interrupt handlers.
	return clockCyclesToMicroseconds(width * 21 + 16); 
}

Dazwischen passiert dann sonst nichts mehr, wenn der restliche Code nicht mit Interrupts arbeitet (vollständig und zuverlässig!). Kann deine PWM-Signal-Erzeugung es vertragen, dass da unter Umständen für etliche Millisekunden nichts passiert. Bist du mit deiner Interrupt-Programmierung ganz konsequent?

Du weißt ja schon, dass der Controller ein PWM-Signal rein hardwaremäßig erzeugen kann, wenn man den Counter/Timer zuvor mit den passenden Werten gefüttert hat? Dann kann ein noch so stures Programm ihn nicht dabei stören (mal von Extremfällen abgesehen)!

Ich sehe sonst nichts, wie pulseIn() deine Interrupts stören könnte.

Gruß
Wolfgang

Danke für diese ausführliche Erklärung. Ich wusste schon, dass PulseIn den Programmablauf stört. Das es aber auch wartet, bevor etwas passiert, war mir neu. Damit ist das für mich völlig ungeeignet. Das bedeutet nämlich schon im Normalfall, dass die Schleife erst alle 20 ms weiterläuft. Wenn dann noch ein Puls nicht ordnungsgemäß erkannt wird, läuft die PWM mit 40 oder 60 ms alten Werten. Angenommen das Auto fährt 45 km/h, dann bewegt sich die Karre in 60 ms schon 750 mm weit. Zu weit für das Fähren in einer Halle.

Ich werde also auf den Einsatz von PulseIn verzichten und das Gänze mit Externen Interrupts regeln.