Zählrichtung bei Timer5 mit externer Clock änderbar?

Hallo liebe Community,

dies hier ist mein erster Post, ich möchte also eventuelle Formfehler entschuldigen. :slight_smile:

Ich bräuchte bei folgender Problemstellung Hilfe:

Hintergrund---------------
Ich habe hier einen Setup u.A. bestehend aus

  • einem Arduino Mega 2560
  • einem Hallsensor (resultierendes Schaltverhalten Öffner) an Pin 47
  • ein Zahnrad an einer Vorschubspindel
  • auf dem Zahnrad insgesamt 8 gleichmäßig verteilte Magnete
  • Zahnrad wird mittels Ritzel eines DC-Motors angetrieben
  • DC-Motor in Richtung und Drehzahl über Power-MOSFET und 2 Relais in Polwenderverschaltung gesteuert

Bei diesem Aufbau wird derzeit die Drehrate des Zahnrades über den Hallsensor und den Magneten überwacht. Das Signal vom Hallsensor ist so sauber, dass die Verwendung eines Timers (hier Timer5) zum Inkremente zählen angewendet werden kann. Dies ist auch notwendig, da reines Polling zu langsam für die resultierende Signalfrequenz vom Hallsensor ist.
Folgender Code-(snippet) funktioniert einwandfrei. Die verwendete MsTimer2, inkl. ISR mit Serial-Output ist nur vorübergehend zur Inbetriebnahme/Überwachung gedacht.

.....
const byte HAL = 47;  //Inkremental Muss Pin47 sein, da dies der Zugang zu Timer5 für den Hardwarecount ist.
....
include <MsTimer2.h>

void printISR()
{
	const int Value=TCNT5;
	Serial.println(Value);
}

void setup() {
	....
	pinMode(HAL, INPUT_PULLUP);
	.....

	TCCR5A=0;        // reset timer/counter control register A
	bitSet(TCCR5B ,CS52);  // Counter Clock source is external pin
	bitSet(TCCR5B ,CS51);  // Clock on rising edge
	TCNT5 = 0;	//initialise Timer5

	Serial.begin(115200);
	MsTimer2::set(100, printISR);
	MsTimer2::start();
}



void loop() {
	...
	start(100,1); //userdefined function, starting Motor with velocity-value vel and direction-bit DIR -> start(vel,DIR)
	...
	stop(); //userdefined function, stopping Motor
	...
	start(100,0); //userdefined function, starting Motor with velocity-value vel and direction-bit DIR -> start(vel,DIR)
	...
	stop();
	...
}

Problemstellung ---------------------------
Es soll jetzt ein Aufwärts- oder Abwärtszählen der Inkremente am Hallsensor realisiert werden, damit direkt auf die Position der Spindel geschlossen werden kann. Dabei ist leider das Hardware-Setup extern vom Projektpartner vorgegeben, dass Nachrüsten eines zweiten Hallsensors für den Aufbau eines 2 kanaligen Inkrementalgebers ist nicht ohne erheblichen Aufwand möglich.
Daher ergibt sich für mich folgende Frage:
Kann Einfluss darauf genommen werden, ob der Timer5 bei jeder Flanke (wie üblich) inkrementiert oder aber auch dekrementiert wird?
Also im besten Falle etwas wie

	...
	bitSet(Txxx5yyy ,xyzA);  // Sets counting incrementing, Sets count direction bit
	...
	bitSet(Txxx5yyy ,xyzB);  // Sets counting decrementing, Sets count direction bit
	...

Wenn dies nicht möglich ist, gibt es Ideen zu geschickten Work-Arounds oder liegt eine entsprechend getunte "CountUpDownTimer.h"-Library vor (Also mit externer Clock auf Timer5)?
Ziel ist letztlich eine Variable, die mit jedem Puls vom Hallsensor abhängig von der Fahrtrichtung der Spindel auf- bzw. abwärts.

Vielen Dank im vorraus für eure Ideen und eure Zeit.

MfG
der Maik

Warum benutzt Du dafür einen Timer? Eine einfache ISR am Hallsensor-Eingang ist sicher schnell genug, und da bestimmst Du dann selbst ob aufwärts oder abwärts gezählt wird.
Um welche Zeiten geht es überhaupt?

AFAIR gibt es auch AVR Controller mit integrierter Encoder-Verarbeitung, die sollte dann in beiden Richtungen funktionieren.

Als Workaround die Richtung beim Umschalten der Drehrichtung des Motors merken, den Zählerstand notieren und den Zähler auf 0 setzen. Dann bei der Abfrage feststellen ob der Zählerstand zum gespeicherten Zähler addiert oder subtrahiert werden muß.

Hallo MicroBahner,

vielen Dank für die schnelle Antwort.
Die Signalfrequenz vom Hallsensor ist noch recht gemächlich, max. 300 Hz. Auf der gesamten Spindellänge kommen max. 200 Pulse zusammen, im Normalbetrieb soll vom Referenzpunkt aus immer von 0 ab immer im positiven Bereich hin und her gezählt werden.

Meine Idee hinter der Verwendung des Timers5 war, dass da meines Wissens nach sehr viel im Hintergrund / parallel abläuft ohne extra ISRen. Aber ich werde das morgen, wenn ich wieder im Labor bin, mal über eine ISR ausprobieren. Da müsste ja irgendwas ausreichen wie

....
volatile byte Inks = 0;
const byte HAL = 47;
.....

attachInterrupt(digitalPinToInterrupt(HAL), MyHallISR, rising)
....

MyHallISR() {
if(DIR) {Inks++} else {Inks--}

}

Allerdings taucht da jetzt eine andere unangenehme Sache auf. Der ganze Aufbau hat jetzt schon fertige Leiterplatten, da ursprünglich nur die Geschwindigkeit überwacht werden sollte. Und nun soll (Feature Creep beim Projektpartner sei Dank) noch auf richtungsabhängige Positionsüberwachung nachgerüstet werden. Glücklicherweise sind die Pins 18, 19, 20, 21 noch frei, man müsste aber trotzdem entweder die bestehenden Leiterplatten umlöten oder neu bestellen. Das ist zwar weit weniger Aufwand als die Vorschubeinheit wegen eines zweiten Hallsensors umzukonstruieren und umzuarbeiten, aber dennoch dazu folgende Frage: Kann man den Pin47 irgendwie davon überzeugen, ebenfalls mit attachInterrupt() zu funktionieren? Oder kann man den Pin47 intern ummappen auf psbw. Pin18?

Wenn nur die Lötnacharbeit bleibt: Meiner Meinung nach würde ja für's Erste eine Drahtbrücke zwischen Pin47 und zB. Pin18 reichen, oder?

Vielen Dank nochmal für deine Mühen,

Maik

DrDiettrich:
AFAIR gibt es auch AVR Controller mit integrierter Encoder-Verarbeitung, die sollte dann in beiden Richtungen funktionieren.

Okay, dann schau ich mal noch in diese Richtung. Aber ich kann mir vorstellen, dass dies auch nach einem 2 kanaligen Signal verlangt.

DrDiettrich:
Als Workaround die Richtung beim Umschalten der Drehrichtung des Motors merken, den Zählerstand notieren und den Zähler auf 0 setzen. Dann bei der Abfrage feststellen ob der Zählerstand zum gespeicherten Zähler addiert oder subtrahiert werden muß.

Der Workaround würde zumindest kein Umdrahten der bestehenden Leiterplatten erfordern. Werde ich morgen auf jeden Fall ausprobieren, vielen Dank für den Tipp!

Oder kann man den Pin47 intern ummappen auf psbw. Pin18?

Das Datenblatt deines µC gibt dazu eine eindeutige Auskunft.

Kann man den Pin47 irgendwie davon überzeugen, ebenfalls mit attachInterrupt() zu funktionieren?

Die Doku zu attachInterrupt() ist ebenso eindeutig.
Und das Datenblatt sagt, dass selbst PCINT auf dem Pin nicht möglich ist.

Zusammengefasst:
Nein, so nicht!

combie:
Zusammengefasst:
Nein, so nicht!

Wäre auch zu schön gewesen XD.

Dann entweder umlöten, oder...
Hab gerade nochmal nachgelesen
Pin 47 geht auf PD4 ( ICP1 ) [beim Mega]
und weiter steht geschrieben
ICP1 – Input Capture Pin 1: The PD4 pin can act as an input capture pin for Timer/Counter1.

Das würde ja heißen, ich könnte die Lösung mit der ISR (lt. MicroBahner) über Timer1 laufen lassen...

Das wäre natürlich sehr elegant... Ich hab morgen ganz schön was zu probieren ^^

Vielen Dank erstmal an alle für den Support.

MfG
Maik

Hallo,

du müßtest erstmal erklären wie du jetzt die Drehrichtung überhaupt erkennst?
Ein einziger Hallsensor von dem du bisher schreibst tuts jedenfalls nicht.
Du benötigst mindestens 2 Hallsensoren.

Doc_Arduino:
Hallo,

du müßtest erstmal erklären wie du jetzt die Drehrichtung überhaupt erkennst?
Ein einziger Hallsensor von dem du bisher schreibst tuts jedenfalls nicht.
Du benötigst mindestens 2 Hallsensoren.

Die Drehrichtung selber ist insofern bekannt, da die Ansteuerung des Motors ja aus dem Sketch heraus erfolgt. Das heißt, ich könnte da mit einem globalen Statusbit (zB. volatile boolean DIR = 1 oder eben 0) arbeiten.
Dann würde die Info RICHTUNG intern vorliegen und die Info INKREMENT käme extern von dem einen Hallsensor. Damit wiederum würde die Idee in Post #3 funktionieren.

MfG
Maik

Im Arduino Mega Pin Mapping geht Pin 47 auf PL2, und Port L hat keinen PCINT. Der Controller Pin 47 wäre je nach Gehäuse PD4/ICP1, da dürfte auch kein Interrupt gehen. oder PA4/AD4, da könnte PCINT funktionieren.

Also bitte klären, welcher Pin tatsächlich gemeint ist.

Die Drehrichtung ist nicht volatile wenn sie vom Arduino vorgegeben wird.

maikscho:
Die Signalfrequenz vom Hallsensor ist noch recht gemächlich, max. 300 Hz. Auf der gesamten Spindellänge kommen max. 200 Pulse zusammen,

Das verstehe ich jetzt nicht so ganz. max 200 Pulse bei 300Hz - das würde ja bedeuten, dass die gesamte Spindellänge innerhalb von 666ms durchfahren wird :o ?

DrDiettrich:
Also bitte klären, welcher Pin tatsächlich gemeint ist.

Der Hallsensor hängt jetzt zur Zeit an dem äußerlich mit "47" beschrifteten Anschlussheader.

Das hilft dabei auch:

Pin 47 ist T5. Der ist der externe Takt-Eingang von Timer 5 (unten mittig)

MicroBahner:
Das verstehe ich jetzt nicht so ganz. max 200 Pulse bei 300Hz - das würde ja bedeuten, dass die gesamte Spindellänge innerhalb von 666ms durchfahren wird :o ?

Nun ja, eigentlich sind es max. 168 Pulse auf dem gesamten Verfahrweg von etwa 50 mm. Das Ganze dauert bei maximaler Geschwindigkeit min. 2 s (also < 100 Hz). Aber ich habe bei sowas immer gerne ausreichend Reserve, daher gehe ich da bei der Auslegung weit über Abtasttheorem ran :wink:

maikscho:
Die Drehrichtung selber ist insofern bekannt, da die Ansteuerung des Motors ja aus dem Sketch heraus erfolgt. Das heißt, ich könnte da mit einem globalen Statusbit (zB. volatile boolean DIR = 1 oder eben 0) arbeiten.
Dann würde die Info RICHTUNG intern vorliegen und die Info INKREMENT käme extern von dem einen Hallsensor. Damit wiederum würde die Idee in Post #3 funktionieren.

Hallo,

nur ein Hallsensor, von mir aus.
Ich würde 2 verwenden und mir damit einen Drehencoder bauen, alle Sorgen und Umstände beseitigt.
https://www.mikrocontroller.net/articles/Drehgeber

ein Sensor:
Also, die Zählrichtung kannst du im "external clock source" Modus nicht vorgeben.
Ich hätte jedoch eine Idee. Du lässt ihn zählen wie er eben zählt und wenn du den Zählerstand wissen möchtest liest du ihn aus und subtrahierst ihn vom Maximum 65535. Überläufe registrierst du mit dem Overflow Interrupt und verrechnest die mit.
Mit deinem "manuellen Richtungs-Bit" legst du nur fest wie die Zählerstände verrechnet werden.
Damit haste deine Zählrichtung beeinflusst.

mega.pdf (1.92 MB)

maikscho:
Nun ja, eigentlich sind es max. 168 Pulse auf dem gesamten Verfahrweg von etwa 50 mm. Das Ganze dauert bei maximaler Geschwindigkeit min. 2 s (also < 100 Hz). Aber ich habe bei sowas immer gerne ausreichend Reserve, daher gehe ich da bei der Auslegung weit über Abtasttheorem ran :wink:

Dein Abtasttheorem gilt hier nicht, weil du zählst die Pulse an external Clock Source direkt.
Abtasttheorem wäre gültig wenn du mit fester Abtastfrequenz einen Pin abfragst, also in gleichen zeitlichen Abständen, unabhängig welches Signal gerade anliegt.

maikscho:
Wenn nur die Lötnacharbeit bleibt: Meiner Meinung nach würde ja für's Erste eine Drahtbrücke zwischen Pin47 und zB. Pin18 reichen, oder?

Ja, das würde reichen. Du kannst 2 Eingänge ohne weiteres parallel schalten.

Oder Du nimmst die Variante den Zählerstand bei Drehrichtungsumkehr auszulesen und zu nullen. Und je nach aktueller Drehrichtung werden die Zählerstände positiv oder negativ bewertet, wenn Du die aktuelle Position berechnest.

Hallo,

kann man sicherlich auch machen wenn die absolute Position beim hin- und herfahren egal ist, also nicht erhalten bleiben muss.

Nur mal ganz ehrlich, wer schaltet die Drehrichtung nur für das Programm von Hand um?
Das macht doch kein Mensch.
Wofür hat man den einen µC der alles automatisch erledigen kann wenn man ihn nur lässt.
Die manuelle Methode ist mindestens äußerst fragwürdig für mich.
Projektvorgaben hin oder her. Anders ausgedrückt, dass Projekt war von Anfang an Mist.

Ich hoffe nur für dich das die Vorgaben schon vorher klar umrissen waren und du jetzt nicht auf eigene Kosten rumeiern musst.

?? ?? wovon redest Du?

Worauf bezieht sich deine Frage?