Okay, die Erklärung ist durchaus verständlich und nachvollziehbar, vielen Dank dafür.
Bezüglich der technischen Umsetzung:
Der erste Aufbau bezieht sich nur auf minimale Querschnitte und Einzellitzen, somit sind starke Motoren o.ä. nicht nötig. Sollte ich die Maschine irgendwann erweitern würde ich die Trommel aber ebenfalls antreiben, das ist die beste Lösung dafür anstatt "am Kabel zu ziehen" wie ein Irrer, bzw. über einen Antrieb.
Für die kleine Größenordnung aktuell (und im Bezug erstmal nur messen) brauche ich auch keine getrennte Lagerung des Messrads, überlege ich mir aber noch. Zunächst werde ich das wirklich "spartanisch" aufbauen, alles weitere dann irgendwann.
Aktuell schneide ich mehrere km Litzen von 0,5mm² - 2,5mm². Vereinzelnd ist auch 4mm² oder 10mm² dabei, die werde ich aber zunächst weiter von Hand messen. Der Vorteil der geringen Querschnitte ist es, dass die Führung für alle gleich klein sein kann, allerdings verwinden sich diese Kabel häufig in Buchten, die die Messung ungenau machen. Da überlege ich noch eine ordentliche Führungsart.
Ich bin leider heute absolut nicht dazu gekommen, ich hoffe kommende Woche etwas aufbauen zu können. Ich bin noch auf der Suche nach einem Display was hier irgendwo rumliegt aber sich einfach nicht meldet. Ich muss nämlich dann mal prüfen ob der Arduino überhaupt genügend Pins dafür hat, die Displays sind ja häufig mit etlichen Pins bestückt.
nimm ein Display mit ic2 Bus das benötigt nur 2 pins. Du musst ja dann auch noch Irgendwie die Soll Länge eingeben können.
Stimmt für die von Dir angegeben Querschnitte reicht das auf jeden Fall.
Falls Du später mal die Trommel separat antreiben willst musst Du dir gedanken um die Drehzahl für die Trommel machen ( grosser und kleiner Duchmesser) oder mit einer Schlaufe arbeiten die Du irgendwie abfragen mußt.
Dicke Kabel sind schwierig die wollen nicht so und haben meisst ein Eigenleben, aber das wirst Du ja kennen.
Naja - 10mm² automatisch abschneiden lassen - Da brauchst schon etwas Kraft.
Gehe davon aus, daß Du Verdrahtungsmaterial (H05V-K o.Ä.) meinst und, zumindest nicht direkt, Damit auch NAYY 4x150SE in handliche Happen zerteilen möchtest.
(wobei mittels Kabelschere wäre Das auch nur ein Zeitfaktor, ab bekommt man Das auch mit relativ kleinen Kräften)
Wie sehen bei Dir die Gebinde aus? Bisher kam mein Verdrahtungsmaterial als 100m-Ring, je nach Querschnitt auch ohne Karton drum herum
Dort könnte man von Innen ziehen - und sehen, ob man mit dem Drall leben kann.
spannendes Thema. Ich war der Überzeugung das es mit der Option CHANGE genauso funktioniert. Die 4 Zustände die es zu unterscheiden gilt bleiben erhalten. Wundert mich das es nicht funktioniert.
Angabe Auflösung. Demzufolge werden in den technischen Daten immer nur die "Striche" sprich Auflösung einer einzigen Spur angegeben? Ist das Standard? Scheinbar ja. Habe nochmal bei meinen Hand-Drehencodern nachgeschaut, da stehen 40 Pulse pro Umdrehung drin. Stimmt überein wenn man nur eine Spur heranzieht bzw. beide durch 4 teilt.
Was mir noch auffiel bei deiner Variante. Viele deiner Variablen müssen volatile sein. Die werden alle in der ISR geändert. Sonst geht das schief wenn es darauf ankommt. Für t, count und reverse braucht man noch atomic. Habe mir erlaubt das mit lokalen Variablen auszubessern.
#include <util/atomic.h>
const byte A = 20; // Spur A
const byte B = 21; // Spur B
unsigned long altzeit; // Anzeige
volatile unsigned long t; // Frequenzmessung
volatile long count;
volatile bool reverse;
float frequenz;
void setup() {
Serial.begin(250000);
pinMode(A, INPUT); // kann entfallen
pinMode(B, INPUT); // kann entfallen
attachInterrupt(digitalPinToInterrupt(A), isr, RISING); // nur Pos Flanke
}
void loop() {
if ( millis() - altzeit >= 200) { // Anzeige Zyklus
altzeit = millis();
unsigned long _t = 0; // atomare Hilfsvariable
ATOMIC_BLOCK (ATOMIC_RESTORESTATE) {
_t = t;
}
if ( _t > 0) {
frequenz = 1000000.0 / _t;
}
else {
frequenz = 0;
}
unsigned long _count = 0; // atomare Hilfsvariable
bool _reverse = 0;
ATOMIC_BLOCK (ATOMIC_RESTORESTATE) {
_count = count;
_reverse = reverse;
}
// Anzeige
if (_reverse) frequenz *= -1;
Serial.print(_count); Serial.print("\t"); Serial.println(frequenz);
}
}
void isr() { // Interrupt Routine
bool b = 0;
static unsigned long last_ms = 0;
t = micros() - last_ms;
last_ms = micros();
b = digitalRead(B);
if (b) {
count++;
reverse = false;
}
if (!b) {
count--;
reverse = true;
}
}
Danke für den realen Test meiner simulierten Spielerei. @Doc Arduino danke fur deine Änderungen ich bin da eigendlich nicht der Spezialist in C , muss mich dann wohl Mal richtig mit deinen Änderungen beschäftigen
Zu der Variante mit Change , es ist doch aber so
A positive Fanke B ist L = rechts herum
A negative Flanke B ist H = rechts herum
Damit geht Change eigendlich in die Hose.
Man mußte dann ehr 2 isr Routinen bauen eine für Positive Flanke eine für die Negative oder innerhalb der Change Routine den aktuellen Pegel von A nochmals abfragen.
Allerdings macht der von Dir vorgestellte Sketch das ja und hat zusätzlich noch eine logische Fehlererkennung drin. Zappeln um eine Flanke im Stillstand ist bei der von mir vorgestellten Methode in Nachteil.
Eigentlich sollte count als einzige volatile Variable ausreichen, direction ist schon ziemlich optional und sollte dann eigentlich tri-state sein: Links - Stand - Rechts, aber Stillstand kann beim Triggern auf das Signal ja garnicht erkannt werden.
Das mögliche Zappeln im Stand kann auch ohne Umschalten der Flanke richtig behandelt werden, indem auf beide Flanken (von A) getriggert wird. Wird A und B zu einem einzigen Wert (0-3) verknüpft, kann die Differenz des Zählers (+1, 0, -1) aus einem konstanten Array emittelt werden. Das geht besonders einfach, wenn A und B auf die niedrigsten Bits eines Ports gelegt werden, so daß sie gemeinsam gelesen werden können, und PCINT auf A triggern kann.
auf "eigentlich sollte" darf man sich nicht einlassen wenn man es besser weiß. Daran sind schon Mondmissionen gescheitert wegen falschen Datentyp. Jede Variable die in einer ISR (auf dem PC auch in anderen Threads) geändert wird muss das Attribut volatile bekommen. Nur dann ist gewährleistet das beim Zugriff dieser auch der aktuelle Wert ausgelesen wird. Es wird erzwungen aus dem Register zulesen. Der Compiler kann nichts wegoptimieren.
Beim Zugriff an anderer Stelle muss man wiederum sicherstellen das andere wie ISR (Thread) nicht zeitgleich den Wert ändern während man ausliest. Deswegen atomarer Zugriff. Da der µC nur Byteweise liest und schreibt, kann man das laut meiner Meinung bei Byte Variablen weglassen. Bei allen anderen ist es zwingend erforderlich. Okay, laut meiner obigen Einstellung muss man es auch für Byte machen.
Ob die Richtungsanzeige in dem Beispiel hier Kriegsentscheidend ist oder nicht spielt erstmal keine Rolle. Ich möchte auf die wichtige Bedeutung hinweisen. Deswegen muss t ebenso volatile sein inkl. atomaren Zugriff.
ich habe nicht geschrieben das man auf volatile bei Byte verzichten kann. Ich habe geschrieben das man für Byte auf atomaren Zugriff verzichten könnte.
Gegenfrage. Welche Variablen werden in loop verarbeitet die in der ISR geändert werden? Genau all diese benötigen volatile und atomar.
hab ich heute etwas schlau gemacht und bin Eurer Diskussion gefolgt.
wie ich das jetzt verstanden habe benötigt man atomic um wärend des Zugriffs auf die Variable sicherzustellen das die ISR nicht dazwiwschen funkt. Das meines Wissens fur einen Byte Zugriff ein Takt erforderlich ist kann das ja eigendlich nicht passieren. Oder bin ich da auf dem Holzweg.
Dann hab ich nochmal überlegt was man aus der ISR rausnehmen und in die Loop verlagern könnte. Dazu ist mit eine bool Variable eingefallen 0,1,2 =stillstand, vor, zurück, die im loop damit den count bedient. Hab ich aber wieder verworfen, da das nicht klappen würde wenn wärend eines loops 2mal die ISR ausgelöst würde. Ähnliches gilt für die Frequenzmessung, sie ist nur dann genau wenn sie innerhalb der ISR gemacht wird. Ansonsten wäre sie abhängig von der Loop Zeit.
Klar das hängt letztlich davon ab welche Frequenz vom Encoder kommt. Aber das sind ja schon mal schnell 10KHz wenn der an einem Motor hängt.
Aso mit den drei Variablen leben doch was fertiges nehmen
reverse kann man aus der ISR rausnehmen und in loop ermitteln, wenn man den aktuellen count mit dem letzten vergleicht. Wenn man dem Grundsatz folgt "ISR Code so kurz wie möglich".
Du wolltest das bestimmt so schreiben ... (ungetestet, ich muss sonst laufend umstecken)
// Arduino Mega2560
#include <util/atomic.h>
const byte A = 20; // Spur A
const byte B = 21; // Spur B
unsigned long altzeit; // Anzeige
volatile unsigned long t; // Frequenzmessung
volatile long count;
long old_count;
float frequenz;
void setup() {
Serial.begin(250000);
pinMode(A, INPUT); // kann entfallen
pinMode(B, INPUT); // kann entfallen
attachInterrupt(digitalPinToInterrupt(A), isr, RISING); // nur Pos Flanke
}
void loop() {
if ( millis() - altzeit >= 200) { // Anzeige Zyklus
altzeit = millis();
unsigned long _t = 0; // atomare Hilfsvariable
ATOMIC_BLOCK (ATOMIC_RESTORESTATE) {
_t = t;
}
if ( _t > 0) {
frequenz = 1000000.0 / _t;
}
else {
frequenz = 0;
}
unsigned long _count = 0; // atomare Hilfsvariable
ATOMIC_BLOCK (ATOMIC_RESTORESTATE) {
_count = count;
}
if (_count < old_count) frequenz *= -1;
old_count = _count;
// Anzeige
Serial.print(_count); Serial.print("\t"); Serial.println(frequenz);
}
}
void isr() { // Interrupt Routine
bool b = 0;
static unsigned long last_ms = 0;
t = micros() - last_ms;
last_ms = micros();
b = digitalRead(B);
if (b) {
count++;
}
if (!b) {
count--;
}
}
ich habe das mit dem Pin Change Interrupt einmal aus Herausforderung betrachtet. Bei mir funktioniert es. Dürft ihr gern testen. Etwas einlesen in die Pin/Registerbelegung ist jedoch notwendig. Ich nutze auf meinem Mega Pin A10 und A11 für die Phaseneingänge.