Interrupt nach 10.000 Impulsen auslesen (an die Arduino/AVR cracks)

Hallo liebe Programmiercracks,
ich habe vor ein Messgerät zu bauen mit dem man Abweichungen von Verschiedenen Walzen einer Wickelmaschine messen kann.
Da ich aus der SPS Programmierung komme ist das doch ne ganze andere Welt als dir "c" welt des Arduinos.
So nun die gegebenheiten. Ich habe auf einer Walze meine Master-Encoder drauf. Die Walze läuft min. 100m/min. Ich muss jetzt die Walzen vor und hinter dem Master messen mit einer genauigkeit von 0,01%.
Montiert sind Drehgeber mit 0,2m Umfang auf 1000Imp./Umdr. Encoder.
Das macht
100m/min0,2m=500U/min das Laufrad
500/60=8,33333 U/sek
1000=8,333kHz.
Ich will jetzt das Master-Signal auf einen der beiden Arduino Interrupt Eingänge setzten und der Soll den Internen Zähler über irgendwie über Extern Clock Source einen Interrupt nach genau 10.000 Impulsen auslösen. Während der Zeit 10.000 Impulsen vom Master zähle ich über den Normalen Interrupt Routine die Impulse vom Slave.
Jetzt will ich wenn der Interrtupt des Master ausglöst hat die Interrput deaktivieren und mit den gezählten den Impulsen den vom Slave die Differenz zur Master messen. Da ich ja im Interrupt "stecke" Weiss ich das der Master die 10k Pulse schon hat.
Dann die Ausgabe auf dem Display den master Counter auf Null Slave Counter auf Null
Interrupts aktivieren und Weiter (dies gibt bei den Gegebenheiten 1Messung alle 1,2s was ausreichend ist)

So das mal der umriss nun zu meiner Frage.
Wie bekomme ich das mit den AVR Inntereien so das ich einen Timerüberlauf mit externem takt genau alle 10.000 Impulse bekomme?
Ich hab schon was gelesen über Timer Catch Interrupt bin da aber nicht schlau geworden.

Und ja es gibt Fertige Messegeräte aber die beginnen bei >2k€

hi, dani,

schau mal hier rein, ob es das ist, was Du suchst:

dort "hier reinlesen und suchen" und da bei kapitel 2.6 timer/counter.
falls es interessant ist, kann ich Dir das kapitel einscannen und schicken (falls bei amazon nicht alles einzusehen ist).

gruß stefan

hi nochmal,

oder schau hier:
http://www.rn-wissen.de/index.php/Timer/Counter_(Avr)#CTC_Modus_.28Clear_Timer_on_Compare_Match_mode.29
bei CTC-modus.

gruß stefan

0.01% bedeutet 10e-4 oder 100ppm Genauigkeit, richtig?

--> Du musst sicherstellen, daß Dein Arduino mit Quarz läuft und nicht mit einem Resonator. Ältere Designs die noch nicht ganz so auf Kostenersparnis getrimmt sind wie der Uno sind zu bevorzugen. Denn der Uno läuft nur mit einem Resonator.

Udo ich jane doch bei 8,5khz eine prioden dauer von 120ns und meine Ardus sind nano und 2k9 er mit echt. Quarzen. Aber da es doch gelöst ist vom internen takt dürfte ich doch keine Probleme haben

Ah OK, da war ich kurz auf dem Schlauch gestanden. Schau mal hier für die genauen Stellen im Datenblatt: http://forum.arduino.cc/index.php/topic,19671.0.html. Wenn Du den 16bit Zähler nimmst ist es überhaupt kein Problem alle 10000 Pulse einen Interrupt auszulösen.

Das ist mir na klar da aber in der orginal pdf con atmel alles in asm gesetzt ist und ich aus diversen foren nicht wirklich schlau geworden bin dachte ich schreibe mal hier wegen der besonderen aufgabenstellung.

volvodani:
genauigkeit von 0,01%.
...
Ich will jetzt das Master-Signal auf einen der beiden Arduino Interrupt Eingänge setzten
...
Während der Zeit 10.000 Impulsen vom Master zähle ich
...
Jetzt will ich wenn der Interrtupt des Master ausglöst hat die Interrput deaktivieren

Vorsicht, Dein Messprinzip erreicht nicht die geforderte Genauigkeit!

So wie Du es machst, mit ständigem attachInterrupt/detachInterrupt, erfaßt Du die Impulse an jeder Walze mit einer Genauigkeit von +/-1 Impuls pro Messperiode pro Walze. Also kann z.B. eine Walze mit 10000 gemessen werden und die andere hat 10002 oder 9998, obwohl sie "fast gleich" laufen.

Messfehler 2 pro Zehntausend = 0,2 pro Tausend = 0,02 pro Hundert = 0,02%

Das ist als Messfehler schon mal doppelt so viel wie von Dir vorgegeben ist.
Die Anzeige kann im 1,2-Sekundentakt springen und zeigt nacheinander kleine Plus- und Minustoleranzen im Hundertstelbereich an.
+0,01, -0,01, +0,01, -0,01, -0,01, -0,01, +0,01, -0,02, +0,01
Wenn jemand das Display im Sekundentakt abliest, soll er dann seine Schlüsse daraus ziehen?
Oder weiß er dann einfach nur, dass kleine Ungenauigkeiten zum Messprinzip dazugehören?

Ich würde es anders lösen, so dass die Interrupts nicht ständig ein- und abgeschaltet werden:

  • Intrrupts ständig eingeschaltet
  • In der ISR ==> einen long-Zähler hochzählen
  • In der loop ==> einmal pro Tag den long-Zähler zurücksetzen, Differenzwerte berechnen und ausgeben
    (z.B. Änderung pro Sekunde, Änderung mit exponentieller Glättung über verschiedene Zeiträume (z.B. 10s, 100s).

Die Ungenauigkeit der Taktfrequenz ist meiner Meinung nach völlig belanglos, da es hier nur im die Messung von Geschwindigkeitsunterschieden geht. Es sollen ja nicht die absolute Drehzahlen der Walzen auf 0,01% Genauigkeit erfaßt werden, sondern nur der Drehzahlunterschied zwischen beiden Walzen soll auf 0,01% Genauigkeit herauskommen.

Die Frage ist wie kann ich diese sache mit dem count interrupt in arduino bzw c umsetzten oder muss ich es doch halt asm machen.
Gruß
Der Dani

Bin zwar kein crack, und muss noch viel lernen - Antworte aber trotzdem :wink:

Warum soll das in Arduino C nicht gehen.
In der ISR eine long hochzählen (volatile definiert)

In der Main Loop die Variable verarbeiten und dazu die Interrupts kurz stoppen, ist nötig da es sich um keine Byte variable handelt.

Danke rudi für den Tip. Mit deiner Varinante habe ich zwei ISR´s für die beiden Encoder und bei zwei ISR der beiden Interrupts habe ich bei 8khZ schon mal das Problem das ich im einen ISR hänge und der andere Interrupt in der Que hängt und dann der erste Interupt kommt.
Deswegen will ich einen Interrupt haben der erst nach 10.000 >Impulsen an dem einen Eingang eine ISR startet.
Der Slave Encoder zählt eine volatile Variable (innerhalb der Zeit bis der andere 10.000Imps) über eine Raising Interrupts Routine hoch. Ich denke mit dem Ansatz komme ich +/-1Imp vom Slave
Wird jetzt der 10k Int ausgelöst:

  1. deaktivere ich die Interrupts
  2. mache meine Berechnungen
  3. gebe auf dem Display aus
  4. Speichere meine Werte
  5. Setzte meine Zähler zurück.
    Während der letzten 5 Schritte dürfen ruhig sämtliche Impulse verloren gehen ich will erst nach dem Neustart alle Impulse haben.
    Ich habe es glaube ich gefunden auf Seite 12 den 16Bit-Timer mit dem Takt der Pins TSOC füttern und für den Rest den Interen Clock zu nehemen.
    http://www.atmel.com/Images/doc2505.pdf

Gruß
Der Dani

hi,

versteh ich das richtig? zwei impulsgeber miteinander vergleichen?
ich würde für jede walze eien 328er nehmen, und den 16bit timer auf externen takt (eben die impulse) stellen. außerdem den timer auf compare mode und in die vergleichsregister 10.000 reinschieben. dann kommt alle 10.000 impulse ein interrupt, der einen impuls auf irgendeinen pin ausgibt. diese impulse würde ich auf einem dritten 328er auswerten.
der kann dann auch gemütlich die LCD-anzeige ansteuern. außerdem müßte er auch die beiden ersten 328er synchronisieren, also mit einem impuls die zähler auf beiden gleichzeitig auf 0 setzen.

gruß stefan

volvodani:
Deswegen will ich einen Interrupt haben der erst nach 10.000 >Impulsen an dem einen Eingang eine ISR startet.

Was machst Du eigentlich, wenn die Maschine mal nicht mit 500 UPM dreht, sondern nur mit 10 UPM?

Ist es wirklich optimal, die Aktualisierungshäufigkeit der Anzeige von der Drehzahl der Walzen abhängig zu machen?

Ich würde es anders machen, die Anzeige immer im gleichmäßigen Takt aktualisieren.
Und habe dazu mal was vorbereitet.

Da ich keine Maschine und keine Walzen und keine Signalgeber habe, habe ich einen Simulator-Sketch gemacht, der gleichzeitig Impulsgenerator ist und pro Minute 500000 Impulse pro "Walze" erzeugt (und damit die Maschine mit Master- und Slavewalze simuliert) und auch das Messen der Impulse und feststellen der Geschwindigkeitsdifferenz übernimmt.

Verwendet habe ich einen UNO, der externe Interrupts an Pin-2 und Pin-3 erkennen kann.
#define Walze1Signal 2
#define Walze2Signal 3

Mein "Impulsgenerator" erzeugt Impulse an Pin-4 und Pin-5
// Pins für den simulierten Signalgeber
#define Walze1Geber 4
#define Walze2Geber 5

Für den Sketch zur Simulation wird also direkt Pin-4 ("Impuls von der Master-Walze") mit Pin-2 verbunden und Pin-5 ("Impuls von der Slave-Walze") mit Pin-3. Es ist natürlich keine optimale Simulation, da die Impulse von der loop aus mit einer Funktion generiert werden, aber besser als gar nichts. Wenn Du hast, kannst Du natürlich auch Rechteck-Signalgeneratoren anschließen. Oder Deine Maschine.

Ein paar Tricks mußte ich einbauen, damit es von der Geschwindigkeit her ausreicht, mit dem Sketch sowohl die Signale ausreichend schnell zu erzeugen als auch auszuwerten. Der Haupttrick in der loop ist, die Auswertung alle 1024 Millisekunden zu machen, weil sich sehr schnell ermitteln läßt, ob der millis-Zähler einen neuen durch eine Zweierpotenz teilbaren Wert erreicht hat. Die Drehzahl pro Minute ergibt sich dadurch nicht über eine Multiplikation mit 60 wie es bei einer Aktualisierung im Sekundentakt der Fall wäre, sondern über eine Multiplikation mit 58.59375, da 1,024 s * 58.59375 = 60 Sekunden ergibt.

In meinem Sketch wird die Anzeige nicht "nach 10000 Impulsen", sondern immer nach 1,024 Sekunden auf den aktuellen Stand gebracht.

Wie man sieht, produziert mein Sketch kleine Drehzahlunterschiede, die sich daraus ergeben, dass mal ein Impuls mehr oder weniger gezählt wird.

Für eine optimale Darstellung würde ich empfehlen, den Anzeigewert exponentiell zu glätten. Parameter für die Glättung nach Bedarf.
Der Sketch ist so ja erstmal sehr experimentell.
Aber ausbaufähig. :wink:

/* Walzendrehzahlen einer Maschine messen,
   die Maschine habe eine Masterwalze und eine Slavewalze, 
   die je 1000 Impulse pro Umdrehung abgeben und mit ca. 500 Umdrehungen pro Minute laufen
   ermittelt werden soll der Drehzahlunterschied in %
   
   Der Sketch erzeugt simulierte Walzenimpulse an Pin-4 und -5.
   Verkabelung zur Simulation: 
   - eine Drahtbrücke zwischen Pin-2 und Pin-4
   - eine Drahtbrücke zwischen Pin-3 und Pin-5
   
   Verkabelung im Betrieb mit Maschine:
   - Impuls der Masterwalze an Pin-2
   - Impuls der Slavewalze an Pin-3
   
   Zielplattform: Arduino UNO mit Interrupt-0 an Pin2 und Interrupt-1 an Pin-3
*/   

// Eingangspins für das Walzensignal
#define Walze1Signal 2
#define Walze2Signal 3

// Pins für den simulierten Signalgeber
#define Walze1Geber 4
#define Walze2Geber 5

// Zähler für die Impulse volatile deklarieren, da in Interrupt verwendet
volatile long w1counter;
volatile long w2counter;

void setup()
{
  Serial.begin(9600);
  pinMode(Walze1Signal,INPUT);
  pinMode(Walze2Signal,INPUT);
  pinMode(Walze1Geber,OUTPUT);
  pinMode(Walze2Geber,OUTPUT);
  attachInterrupt(0,Walze1ISR,RISING);
  attachInterrupt(1,Walze2ISR,RISING);
}

void Walze1ISR()
// Interrupt-Serviceroutine für die Master-Walze
{
  w1counter++;
}

void Walze2ISR()
// Interrupt-Serviceroutine für die Slave-Walze
{
  w2counter++;
}


// Drehzahl festlegen, "Nanosekunden zwischen zwei Impulsen"
// 60000 Nanosekunden entspricht 500 U/min bei 1000 Impulsen pro Umdrehung
// hier für die Simulation vorgegeben: kleiner Drehzahlunterschied
#define w1mus 60002L
// kleinere Zahlen stehen für höhere Drehzahlen, größere Zahlen für nierigere Drehzahlen
#define w2mus 60004L

void impulsGenerator()
{
  static long nano1rest, nano2rest, alteMicros;
  unsigned long neueMicros,nanodiff;
  neueMicros=micros();
  nanodiff=1000*(neueMicros-alteMicros);
  alteMicros=neueMicros;
  nano1rest+=nanodiff;
  nano2rest+=nanodiff;
  if (nano1rest>w1mus)
  {
    digitalWrite(Walze1Geber,!digitalRead(Walze1Geber));
    nano1rest-=w1mus;
  }  
  if (nano2rest>w2mus)
  {
    digitalWrite(Walze2Geber,!digitalRead(Walze2Geber));
    nano2rest-=w2mus;
  }  
}


long alteSekunde, sekunde;
void loop()
{
  impulsGenerator(); // Simulation der Walzenimpulse durch die Funktion "impulsGenerator()"
  sekunde=millis()/1024; // Aus Gründen der schnelleren Berechnung 1024 Millisekunden
  if (sekunde!=alteSekunde) // Ca. einmal pro Sekunde (alle 1024ms) die Anzeige aktualisieren
  {
    alteSekunde=sekunde;
    // Zuerst bei deaktivierten Interrupts die volatile-Variablen umkopieren und zurücksetzen
    noInterrupts(); // Interrupts sperren
    long W1impulse=w1counter;
    w1counter=0;
    long W2impulse=w2counter;
    w2counter=0;
    interrupts(); // Interrupts zulassen
    // Drehzahl pro Minute ermitteln bei 60 Sek/Min und 1000 Impulse/Umdrehung
    // Eine Minute besteht aus 58.59375 * 1024 ms
    float Drehzahl1=W1impulse*58.59375/1000.0;
    float Drehzahl2=W2impulse*58.59375/1000.0;
    // Drehzahlen und Impulse der letzten Sekunde ausgeben
    Serial.print("Master\t");Serial.print(Drehzahl1,3);Serial.print(" UPM\t");
    Serial.print(W1impulse);
    Serial.print("\tSlave\t");Serial.print(Drehzahl2,3);Serial.print(" UPM\t");
    Serial.print(W2impulse);
    Serial.print("\tDiff: ");Serial.print((Drehzahl2/Drehzahl1-1)*100);
    Serial.println(" %");
  }  
}

P.S.: Wennn Du doch lieber die Logik mit der Anzeigeaktualisierung nach 10000 Impulsen hättest statt nach Zeitablauf, ist das natürlich leicht einzubauen mit einer anderen if-Abfrage in der Loop-Funktion, dann schreibst Du einfach:
if (w1counter>=10000) ...
und führst entsprechend etwas andere Berechnungen durch.

Die Maschinen werden in einem Servicelauf immer auf die 100m/min gefahren da dies.extra für diesen Test hinterlegt ist

volvodani:
Die Maschinen werden in einem Servicelauf immer auf die 100m/min gefahren da dies.extra für diesen Test hinterlegt ist

Anyway, bei einem vernünftig strukturierten Programm mit Trennung von Verarbeitung und Ausgabe ist es natürlich eine Kleinigkeit, die Ausgabe umzustellen, z.B. von "Ausgabe alle 1024 ms" auf "Ausgabe alle 10000 Impulse".

Hier der modifizierte und dabei fast unveränderte Code für Drehzahlausgabe alle 10000 Impulse:

/* Walzendrehzahlen einer Maschine messen,
   die Maschine habe eine Masterwalze und eine Slavewalze, 
   die je 1000 Impulse pro Umdrehung abgeben und mit ca. 500 Umdrehungen pro Minute laufen
   ermittelt werden soll der Drehzahlunterschied in %
   
   Der Sketch erzeugt simulierte Walzenimpulse an Pin-4 und -5.
   Verkabelung zur Simulation: 
   - eine Drahtbrücke zwischen Pin-2 und Pin-4
   - eine Drahtbrücke zwischen Pin-3 und Pin-5
   
   Verkabelung im Betrieb mit Maschine:
   - Impuls der Masterwalze an Pin-2
   - Impuls der Slavewalze an Pin-3
   
   Zielplattform: Arduino UNO mit Interrupt-0 an Pin2 und Interrupt-1 an Pin-3
*/   

// Eingangspins für das Walzensignal
#define Walze1Signal 2
#define Walze2Signal 3

// Pins für den simulierten Signalgeber
#define Walze1Geber 4
#define Walze2Geber 5

// Zähler für die Impulse volatile deklarieren, da in Interrupt verwendet
volatile long w1counter;
volatile long w2counter;

void setup()
{
  Serial.begin(9600);
  pinMode(Walze1Signal,INPUT);
  pinMode(Walze2Signal,INPUT);
  pinMode(Walze1Geber,OUTPUT);
  pinMode(Walze2Geber,OUTPUT);
  attachInterrupt(0,Walze1ISR,RISING);
  attachInterrupt(1,Walze2ISR,RISING);
}

void Walze1ISR()
// Interrupt-Serviceroutine für die Master-Walze
{
  w1counter++;
}

void Walze2ISR()
// Interrupt-Serviceroutine für die Slave-Walze
{
  w2counter++;
}


// Drehzahl festlegen, "Nanosekunden zwischen zwei Impulsen"
// 60000 Nanosekunden entspricht 500 U/min bei 1000 Impulsen pro Umdrehung
// hier für die Simulation vorgegeben: kleiner Drehzahlunterschied
#define w1mus 60002L
// kleinere Zahlen stehen für höhere Drehzahlen, größere Zahlen für nierigere Drehzahlen
#define w2mus 60004L


void impulsGenerator()
{
  static long nano1rest, nano2rest, alteMicros;
  unsigned long neueMicros,nanodiff;
  neueMicros=micros();
  nanodiff=1000*(neueMicros-alteMicros);
  alteMicros=neueMicros;
  nano1rest+=nanodiff;
  nano2rest+=nanodiff;
  if (nano1rest>w1mus)
  {
    digitalWrite(Walze1Geber,!digitalRead(Walze1Geber));
    nano1rest-=w1mus;
  }  
  if (nano2rest>w2mus)
  {
    digitalWrite(Walze2Geber,!digitalRead(Walze2Geber));
    nano2rest-=w2mus;
  }  
}


unsigned long zeit, alteZeit, zeitdifferenz; // Mikrosekunden-Werte
void loop()
{
  // Für eine bessere Simulation: impulsGenerator() auf einem zweiten Arduino laufen lassen
  impulsGenerator(); // Simulation der Walzenimpulse durch die Funktion "impulsGenerator()"
  if (w1counter>=10000) // immer nach 10000 Impulsen / 10 Umdrehungen eine Anzeige
  {
    // Zuerst bei deaktivierten Interrupts die volatile-Variablen umkopieren und zurücksetzen
    noInterrupts(); // Interrupts sperren
    long W1impulse=w1counter;
    w1counter=0;
    long W2impulse=w2counter;
    w2counter=0;
    interrupts(); // Interrupts zulassen
    // Zeitdifferenz seit der letzten Berechnung ermitteln
    zeit=micros(); // Mikrosekundengenauigkeit!
    zeitdifferenz=zeit-alteZeit;
    alteZeit=zeit;
    // Drehzahl pro Minute ermitteln
    float Drehzahl1=60000.0*W1impulse/zeitdifferenz;
    float Drehzahl2=60000.0*W2impulse/zeitdifferenz;
    // Drehzahlen und Impulse der letzten Sekunde ausgeben
    Serial.print("Master\t");Serial.print(Drehzahl1,3);Serial.print(" UPM\t");
    Serial.print(W1impulse);
    Serial.print("\tSlave\t");Serial.print(Drehzahl2,3);Serial.print(" UPM\t");
    Serial.print(W2impulse);
    Serial.print("\tDiff: ");Serial.print((Drehzahl2/Drehzahl1-1)*100,3);
    Serial.println(" %");
  }  
}

Was ich hauptsächlich zeigen wollte:

  1. Interrupt-Behandlungsroutinen müssen kurz sein. Und zwar um so kürzer, je schneller die Interrupts eintreffen. In meinem Beispielcode ist der Interrupt-Code jeweils ein Einzeiler.
  2. Man braucht die Interrupts nicht dauernd zu attachen und detachen. Es reicht, einmal vor jeder Berechnung
  • die Interrupts kurz zu sperren
  • die volatile Zählvariablen in andere Variablen umzukopieren, die von der Interruptroutine nicht verändert werden
  • die volatile Zählvariablen auf 0 zu setzen
  • die Interrupts wieder freizugeben
    So geht kein einziger Interrupt/Impuls bei der Zählung verloren.

Falls während der "Interrupt-Sperrzeit" ein Interrupt eingetreten sein sollte, hat das System diesen Interrupt auf "waiting" gesetzt und führt ihn aus, unmittelbar nach wiedererfolgter Freigabe der Interrupts. Verloren gehen können Interrupts/Impulse bei dieser Art der kurzfristigen Interruptsperrung nur dann, wenn die Sperrung so lange dauert, dass während der Sperrzeit zwei oder mehr identische Interrupts/Impulse eintreten. Denn wenn während der Sperrung der Interrupts beispielsweise zwei Impulse von der Masterwalze kommen, steht der Interrupt bei der Freigabe zwar auf waiting, aber er wird dann nur einmal ausgeführt, obwohl er zweimal auf waiting gesetzt worden war.

Die Simulation mit dem "impulsGenerator();" in der loop-Funktion ist jedenfalls nur ein Notbehelf. Die Simulation der Maschine wird besser, wenn Du den Code auf zwei Arduinos aufteilst: Einer bekommt den "impulsGenerator();" als loopCode und wird an den zweiten Arduino angeschlossen, auf dem nur der Auswerteteil läuft. So können die Interrupts dann wirklich in jeden Programmteil reinhauen.

Jedenfalls zeigt mein Sketch: Der Arduino ist nicht nur schnell genug, um 2 * 500000 Interrupts pro Minute zu verarbeiten, sondern der Arduino kann sogar nebenbei noch als Impulsgenerator zur Erzeugung von 2 * 1000000 Pegelwechseln dienen, ohne dass ihm dabei die Puste ausgeht.

Danke jurs für den Code :smiley:
Den Kram hatte ich schon so ähnlich aufgabaut. Ich war mir nur nicht im klaren das der kleine Atmega das so ohne weiteres Gestemmt kriegt.
Das mit den Interrupts war mir schon so klar ;). Da ich ja schon einige Sachen gemacht habe mit dem Mega.
Ich hatte gedacht mit der Frage an nach dem Intterupt nach 10k Impulsen für mein Programm, das der Thread dann so eine positve entwicklung macht sogar mit fast fertigem Code, überrascht mich sehr. Ich werde die mal mit zwei Arduinos simulieren. Da dieses Messgrät für die Industrie ist muss ich mir sicher sein auf +/- 0,01% zu kommen. Und die 10.000 Impulse haben nur den parktischen grund das 1 Impuls genau für 0,01% stehen.
Danke für die Arbeit. Fortschritt wird dokumentiert.
Gruß
Der Dani

volvodani:
Da dieses Messgrät für die Industrie ist muss ich mir sicher sein auf +/- 0,01% zu kommen. Und die 10.000 Impulse haben nur den parktischen grund das 1 Impuls genau für 0,01% stehen.

Bist Du noch an dem Messgerät für die Walzendrehzahlen dran?

Gerade fällt mir ein, dass ich erst gestern wieder was mit Impulsen per Interrupt gemacht habe, es ging um die Programmierung eines Fahrradtachos:
http://forum.arduino.cc/index.php?topic=172506.msg1289260#msg1289260

Und da es bei der langsamen Impulsfolge eines Fahrrad-Speichenmagneten ganz besonders darauf ankommt, dass man nicht eine Ungenauigkeit von +/- 1 Impuls pro Sekunde reinbekommt, wenn die Anzeige einmal pro Sekunde aktualisiert werden soll, habe ich die Auswertung natürlich so gemacht, dass die Auswertung genauer ist.

Und nun fällt mir auf: Genau so ginge es mit Deinem Messgerät! Die Genauigkeit bei der Erfassung der Slave-Walze von +/- 1 Impuls pro Auswerteperiode, also 2 Impulse pro 10000 Impulse = 2/10000 = 0,02% ist nicht in Stein gemeißelt, sondern es geht genauer.

Man braucht nur wie in dem Fahrradtacho-Sketch zusätzlich zur Anzahl der Impulse innerhalb der Interrupt-Routine die zeitlichen Abstände der Impulse aufaddieren. Natürlich für jede Walze getrennt. Und mit Zeiterfassung in Mikrosekunden statt Millisekunden.

Dann könnte man für die Slave-Walze sehr viel genauer die exakte Drehzahl ermitteln, nämlich aus den erfassten Impulsen der Slave-Walze und der exakt dafür von der Slave-Walze benötigten Zeitdauer.

Genauigkeitsabschätzung: +/- Laufzeit einer Interrupt-Routine +/- 4 Mikrosekunden
Wenn eine Interrupt-Routine ca. 200 Takte läuft, sind das bei 16 MHz Systemtakt
2* (200/16000000 + 4/1000000) = 0,000033 s = 33 Mikrosekunden

Bezogen auf eine Messdauer von je 1,2 s / 10000 Umdrehungen:
0,000033 / 1,2 = 0,0000275 = 0,00275% Drehzahlunterschied

Das ist mehr als sieben mal genauer als die 0,02% Drehzahlunterschied, die nach der von mir bisher geposteten Messmethode entstehen!

Da es Dir ja insbesondere auf Genauigkeit ankommt, würde ich also vorschlagen, in der Interrupt-Routine von "Zählung der Impulse" auf "Zählung von Impulsen UND Zeit" umzustellen. So ähnlich wie in dem Fahrradtacho-Sketch, nur eben für eine größere Anzahl Impulse pro Sekunde. Aber eben so, dass die exakte Drehzahl der Slave-Walze aus den Impulsen der Slave-Walze und der dafür von der Slave-Walze benötigten Zeitdauer errechnet wird, und nicht aus den Impulsen der Slave-Walze und der Zeitdauer, die die Master-Walze für 10000 Umdrehungen benötigt hat.

Ich bin mir ziemlich sicher das die miilis() Funktion im ISR mir dann in die quere kommt.
Gruß
Der Dani

volvodani:
Ich bin mir ziemlich sicher das die miilis() Funktion im ISR mir dann in die quere kommt.

Inwiefern "in die Quere"?

Mein Fahrradtacho-Sketch funktioniert prima damit.
Timer-Abfragen innerhalb von ISR-Routinen funktionieren bestens.

Man darf sich nur nicht darauf verlassen, dass ein Timer innerhalb einer ISR weiterläuft.
Beispiel millis(): millis() liefert innerhalb einer ISR immer denselben Wert zurück und verändert sich nicht. Der Wert entspricht dem Stand des millis-Timers beim Start der Interrupt-Routine.