Hallo zusammen. ich will die Drehzahl mit Hilfe eines Encoders (mit Stirnrad auf der Motorwelle) messen und die Drehzahlwerte über CAN senden. Als Hardware habe ich ein Arduino uno board mit aufgesteckten CAN sgield genommen, weil das gerade verfügbar war. Im Prinzip funktioniert die Messung und das Senden, allerdings gibt es zwei Probleme. 1)Ab und zu scheint die Messung nicht zu funktionieren. Bei einer festen Drehzahl von 500 rpm werden über CAN ab und zu mal falsche Werte übermittelt. Das peaks von etwa 525-535 rpm. Das passiert auch bei anderen Drehzahlen. 2)Bei einer Drehzahl < 60 rpm werden "Phantasiewerte", z.B. 1325, über CAN zurückgemeldet. Diese springen auch ziemlich. Im Code nutze ich den input capture um die Zeitstempel für den Beginn und das Ende einer Umdrehung zu messen (24 Pulse/Umdrehung). Aus der Zeitdifferenz wird dann die Drehzahl berechnet. So der Plan. Hat jemand eine Idee was da schief läuft? Falls es auch andere Verbesserungsvorschläge für die Umsetzung und den Code gibt, wäre ich dankbar, wenn ihr es mich wissen lassen würdet.
:
Verschoben durch Moderator
Hi ich hab mal kurz in den Code geschaut. Ich arbeite zwar nicht mit Arduion, aber mir ist aufgefallen, das Du an der Anzahl der Pulss sowohl im Interrupt als auch im Main Veränderungen (Pulse reset) vornimst. Dies kann dazu führen, das die Interruptroutine mehr pulse zählt als deine 24. Gruß Bernd
ISR(TIMER1_OVF_vect) { } Hier fehlt der entscheidene Inhalt. Laß Timer1 mit voller Geschwindigkeit laufen und beachte die Überläufe. Dann klappt das auch. Code für Arduino: http://mino-elektronik.de/fmeter/fm_software.htm#bsp7
Vielen Dank für die Rückmeldungen. Ich weiß nicht so richtig, was ich in ISR(TIMER1_OVF_vect) machen soll, weil mich die Überläufe doch gar nicht interessieren. Oder sollten sie das? Daher habe ich den ovf interrupt mal komplett ausgeschaltet. Das ändert aber rein gar nichts, immer noch peaks. Aufrund BerndBs Hinweis habe ich den code so geändert, dass nur noch in ISR(TIMER1_CAPT_vect) die Variable verändert wird und nicht zusätzlich noch im Main. Das hat an der Peak Thematik auch nichts geändert. Sollte ich das Ganze vll so aufziehen, dass ich einfach nach einem festen Zeintintervall die bis dahin gezählten Pulse auswerte und mit Bezug auf das Zeitintervall und den Pulsen/Umdrehung die Dehzahl berechne?
M. H. schrieb: > Ich weiß nicht so richtig, was ich in ISR(TIMER1_OVF_vect) machen soll, > weil mich die Überläufe doch gar nicht interessieren. Oder sollten sie > das? Willst Du nicht mal lesen, was ich Dir geschrieben habe?
> if (pulse==PulseProUmdrehung+1)
Da ist es reiner Zufall dass deine while()-Schleife diese Bedingung mal
trifft. Was passiert wenn innerhalb eines Durchlaufs deiner
while()-Schleife die ISR mehrmals zuschlägt?
M. H. schrieb: > 2)Bei einer Drehzahl < 60 rpm werden "Phantasiewerte", z.B. 1325, über > CAN zurückgemeldet. Diese springen auch ziemlich. TCNT1 läuft über. 16 MHz/256/65536 = 0,95 Hz -> 57 rpm
Danke für die Hinweise. Ich versuche mal den code zu verbessern und melde mich wieder
M. H. schrieb: > Im Code nutze ich den input capture um die Zeitstempel für den Beginn > und das Ende einer Umdrehung zu messen (24 Pulse/Umdrehung). Eine Umdrehung hat für mich prinzipiell keinen Anfang und kein Ende. Und warum schaltest du die zu zählende Flanke um? Ich würde immer nur von der selben Flanke zur selben Flanke messen (steigend oder fallend, je nach dem, was definierter ist). Und du musst zur Auswertung nicht 24 Impulse abwarten. Im Prinzip weißt du schon nach der zweiten steigenden Flanke (und bei jeder einzelenen nachfolgenden Flanke) die Drehzahl: die ist 24mal niedriger als die per Capture gemessene Zeit und die daraus berechnete Frequenz. Du musst also einfach immer nur den Zeitpunkt der letzten Flanke vom Zeitpunkt der aktuellen Flanke abziehen und hast damit ein 24stel der Zeit bestimmt, die eine Umdrehung braucht. Dann merkst du dir die aktuelle Zeit für die nächste Berechnung bei der nächsten Flanke. > rpm = 60000 / ((timeStamp2-timeStamp1)*0.016) ; // Prescaler 256 Abgesehen vom relativ nutzlosen Kommentar: lass den zeitaufwändigen Umweg über diese float-Berechnung. Schreib die Zeile besser so:
1 | rpm = 3750000 / (long)(timeStamp2-timeStamp1); // Magic Number 3750000 = 60000/0.016 |
:
Bearbeitet durch Moderator
das liest sich alles ziemlich einleuchtend. Danke für die Hinweise. Die Umschaltung der zählenden Flanke war ein Versuch, da sich nichts geändert hat, habe ich im Code gelassen. Ich habe den Code abgeändert, allerdings komme ich nicht zum richtigen Messwert.
1 | /*--------------------------------------------------------------------------------------------------
|
2 | CAPTURE ISR
|
3 | ---------------------------------------------------------------------------------------------------*/
|
4 | ISR(TIMER1_CAPT_vect) |
5 | {
|
6 | if (pulse == 0) |
7 | {
|
8 | Capt1 = ICR1; |
9 | pulse++; |
10 | }
|
11 | else
|
12 | {
|
13 | Capt2 = ICR1; |
14 | ueberlauf = ueberlauf_count; |
15 | ueberlauf_count=0; |
16 | timeStamp1 = Capt1; |
17 | timeStamp2 = Capt2 + ueberlauf*256; |
18 | zeit_diff = timeStamp2-timeStamp1; |
19 | rpm = 3750000 / (long)(timeStamp2-timeStamp1) * 24; // Magic Number 3750000 = 60000/0.016 |
20 | Capt1 = Capt2; |
21 | }
|
22 | }
|
23 | /*--------------------------------------------------------------------------------------------------
|
24 | OVF ISR
|
25 | ---------------------------------------------------------------------------------------------------*/
|
26 | ISR(TIMER1_OVF_vect) |
27 | {
|
28 | ueberlauf_count++; |
29 | }
|
M. H. schrieb: > Ich habe den Code abgeändert Immer noch recht holprig... Und hier: timeStamp2 = Capt2 + ueberlauf*256; Frage ich mich: ist der Timer 1 nicht ein 16 Bit-Zähler? Dann kommt ein Überlauf erst nach 65536 und nicht schon nach 256... > allerdings komme ich nicht zum richtigen Messwert. Du darfst die rpm auch nicht mit 24 mutliplizieren, denn die Überlaufe an sich kommen ja schon um das 24fache zu oft... Ich würde an deiner Stelle aus dem Capture und dem Überlauf einen 32Bit Wert basteln und damit weiterrechnen:
1 | unsigned long timeStampAkt, timeStampLast, zeit_diff; |
2 | ISR(TIMER1_CAPT_vect) |
3 | {
|
4 | timeStampAkt = (ueberlauf_count<<16) + ICR1; // aus ICP und Überlaufz. einen 32 Bit Zähler basteln |
5 | rpm = 1234567 / (timeStampAkt-timeStampAlt); // Magic Number anpassen... ;-) |
6 | timeStampAlt = timeStampAkt; // fürs nächste Mal merken |
7 | }
|
:
Bearbeitet durch Moderator
Lothar M. schrieb: > rpm = 1234567 / (timeStampAkt-timeStampAlt); // Magic Number > anpassen... ;-) Nein, sondern die Auswertung zum einen nicht in der ISR erledigen und zum anderen mit float rechnen. Lothar M. schrieb: > lass den zeitaufwändigen > Umweg über diese float-Berechnung. Der Zeitaufwand ist minimal und kein Grund auf float zu verzichten. Das muß wohl mal wieder gesagt werden ;-)
m.n. schrieb: > Der Zeitaufwand ist minimal und kein Grund auf float zu verzichten. > Das muß wohl mal wieder gesagt werden ;-) Dann sage ich halt: "nimm einen 32Bit Integer weil der genauer ist!", denn ein 32-Bit-float hat nur 7 signifikante Stellen. Und die Dynamik, die ein float bietet, wird bei der Aufgabe hier nicht benötigt. > Nein, sondern die Auswertung zum einen nicht in der ISR erledigen Wenn die "Auswertung" nur noch die 3 verbliebenen Zeilen ist, dann kann man die auch in der ISR machen. Aber soll jeder nach seiner Fasson selig werden. Über Software streite ich genausowenig wie über Schönheit... ;-)
Lothar M. schrieb: > timeStamp2 = Capt2 + ueberlauf*256; > Frage ich mich: ist der Timer 1 nicht ein 16 Bit-Zähler? Dann kommt ein > Überlauf erst nach 65536 und nicht schon nach 256... Denkfehler, danke für die Aufklärung. Ich habe mit dem Tipp von Ikmiller mal zwei Varianten versucht. 1) Auswertung der Zeit von zwei aufeinander folgenden Pulsen
1 | void StartTimer1(void) |
2 | {
|
3 | TCCR1B|=(1<<CS12); //STARTING TIMER WITH PRESCALER 256 |
4 | }
|
5 | unsigned long timeStampAkt, timeStampLast;//, zeit_diff; |
6 | ISR(TIMER1_CAPT_vect) |
7 | {
|
8 | timeStampAkt = (ueberlauf_count<<16) + ICR1; // aus ICP und Überlaufz. einen 32 Bit Zähler basteln |
9 | rpm = 3750000 / (timeStampAkt-timeStampLast)/24; // Magic Number 3750000 = 60000/0.016 |
10 | timeStampLast = timeStampAkt; // fürs nächste Mal merken |
11 | }
|
12 | ISR(TIMER1_OVF_vect) |
13 | {
|
14 | ueberlauf_count++; // Ueberlaeufe von T1 ergeben obere 16bit der Messzeit |
15 | }
|
2) Auswertung erst, wenn Pulse = 24 (Stirnrad hat 24 Zähne)
1 | void StartTimer1(void) |
2 | {
|
3 | TCCR1B|=(1<<CS12); //STARTING TIMER WITH PRESCALER 256 |
4 | }
|
5 | unsigned long timeStampAkt, timeStampLast;//, zeit_diff; |
6 | ISR(TIMER1_CAPT_vect) |
7 | {
|
8 | if (pulse == 0) |
9 | {
|
10 | timeStampLast = ICR1; |
11 | }
|
12 | pulse++; //INCREMENTING FLAG |
13 | if (pulse == PulseProUmdrehung) |
14 | {
|
15 | timeStampAkt = ICR1; |
16 | timeStampAkt = (ueberlauf_count<<16) + ICR1; // aus ICP und Überlaufz. einen 32 Bit Zähler basteln |
17 | rpm = 3750000 / (timeStampAkt-timeStampLast); // Magic Number 3750000 = 60000/0.016 |
18 | ueberlauf_count=0; |
19 | pulse = 0; |
20 | }
|
21 | }
|
22 | |
23 | ISR(TIMER1_OVF_vect) |
24 | {
|
25 | ueberlauf_count++; // Ueberlaeufe von T1 ergeben obere 16bit der Messzeit |
26 | }
|
Zusätzlich sind die jeweiligen Codevarianten komplett angehängt. Außerdem noch die CAN plots der rpm Werte Bei einer Drehzahl von 647 rpm. Variante 2 läuft stabiler, allerdings springt die Drehzahl gelegntlich auf 671. Ein ähnliches Problem hatte ich beim ursprünglichen code. Bei beiden Varianten springt der rpm Wert regelmäßig auf 0.
Ich habe zwar keine Ahnung, aber: im Beispielcode unter https://rn-wissen.de/wiki/index.php/Timer/Counter_(Avr)#Input_Capture werden das high und low Byte von ICR1 separat ausgelesen und ausgewertet gerade um Overflow-situationen glatt zu bügeln.
Eric B. schrieb: > werden das high und low Byte von ICR1 separat ausgelesen und ausgewertet > gerade um Overflow-situationen glatt zu bügeln. Das separate Auslesen ist nicht der Punkt. Der TO muß erst erkennen, daß ein Überlauf auch dann auftreten kann, wenn die TIMER1_CAPT-ISR gerade aktiv ist. Beispielcode hat er ja genug. Lothar M. schrieb: > Dann sage ich halt: "nimm einen 32Bit Integer weil der genauer ist!", > denn ein 32-Bit-float hat nur 7 signifikante Stellen. Nimm eine Divison x/y. x und y liegen im Bereich 1 - 999. Wo ist denn hier die Integer-Berechnung genauer als die mit float? Einfaches Beispiel: x = 10 und y = 3. int-Ergebnis = 3 float-Ergebnis = 3.333333 > Und die > Dynamik, die ein float bietet, wird bei der Aufgabe hier nicht > benötigt. Da irrst Du. Wenn man nicht aufpaßt und seine Wertebereiche strikt eingrenzt, hat man mit uin32_t Werten schnell Über- oder Unterläufe - selbst, wenn man nur 4-stellige Ergebnisse braucht. Lothar M. schrieb: > Wenn die "Auswertung" nur noch die 3 verbliebenen Zeilen ist, dann kann > man die auch in der ISR machen. Gut, aber zuvor bitte wieder mit sei(); andere ISRs zulassen, damit diese durch größere Ausführungszeiten nicht blockiert werden. Das Gesamtprogramm ist ja noch nicht fertig. Es geht mir nicht um Schönheit sondern um Pferdefüße ;-)
M. H. schrieb: > ich will die Drehzahl mit Hilfe eines Encoders (mit Stirnrad auf der > Motorwelle) messen und die Drehzahlwerte über CAN senden. Das würde ich bleiben lassen, denn jeder Eingriff in die Elektrik führt zum Erlöschen der Betriebserlaubnis! Zudem möchte ich nicht in deiner Haut stecken, wenn du wegen Signalmanipulation einen Unfall auslöst.
Anton schrieb: > Das würde ich bleiben lassen, denn jeder Eingriff in die Elektrik führt > zum Erlöschen der Betriebserlaubnis! Zudem möchte ich nicht in deiner > Haut stecken, wenn du wegen Signalmanipulation einen Unfall auslöst. Den einzigen "Unfall", den ich damit auslösen kann, ist ein falscher Messwert, der niemanden (außer mich) interessiert. Ich will nur die Drehzahl überprüfen und über CAN ausgeben, damit dieser Wert im gleichen CAN plot landet (aus Dokumentationszwecken), wie alle anderen Werte eines Umrichters, der den Motor antreibt.
Eric B. schrieb: > werden das high und low Byte von ICR1 separat ausgelesen und ausgewertet > gerade um Overflow-situationen glatt zu bügeln. Das habe ich auch ausprobiert. sieht schon deutlich besser aus, aber ausreißer sind immer noch drin. (Nicht wundern, Drehzahl wurde ein wenig erhöht)
Eric B. schrieb: > im Beispielcode unter > https://rn-wissen.de/wiki/index.php/Timer/Counter_(Avr)#Input_Capture > werden das high und low Byte von ICR1 separat ausgelesen Das macht der Compiler automatisch richtig. M. H. schrieb: > Variante 2 läuft stabiler Vergiss hier, irgendwelche "stabilere" oder "bessere" Varianten hinzubasteln. Die Aufgabe muss einfach einmal "richtig" gelöst werden. Das geht. So wie es aussieht, sind die Probleme weitestgehend zyklisch und das hat dann mit irgendwelchen Überläufen und Datentransfers zu tun. M. H. schrieb: > Bei beiden Varianten springt der rpm Wert regelmäßig auf 0. Das ist der eigentliche Witz hier: du hast irgendein Semaphorenproblem. Der Zähler verstolpert sich. Das könnte daher kommen, dass der ICP und der Überlauf-Zähler sich irgendwie "verheddern". Und natürlich hast du das noch das übliche Semaphorenproblem, denn du liest hier: message.data[0] = rpm; message.data[1] = (rpm>>8); einen 16 Bit Wert in 2 Schritten aus. Zwischen diesen 2 Schritten kann ein Interrupt kommen und einen neuen Wert in rpm schreiben. Dann geht auf den CAN zur Hälfte der Neue und zur Hälfte der alte Wert. Und wenn der alte Wert rpm = 256 war und der Neue rpm = 255 ist, was geht dann auf den Bus? > Außerdem noch die CAN plots Hast du auch qualifizierte Messgeräte (mehrkanaliges digitales Speicheroszilloskop oder Logicanalyzer) zur Hand? Denn du musst das Problem mal direkter an der Quelle anpacken und z.B. mal das Interrupt-Timing messen, indem du zu Beginn jeder ISR einen Ausgangspin setzt und am Ende wieder zurücksetzt (idealerweise aber nicht mit der schnarchlangsamen Arduino-Funktion, sondern durch direkten Registerzugriff). M. H. schrieb: > Eric B. schrieb: >> werden das high und low Byte von ICR1 separat ausgelesen > Das habe ich auch ausprobiert. > sieht schon deutlich besser aus Vermutlich sieht es deshalb "besser aus", weil du die Frequenz ein wenig hochgedreht hast. Dann ist der Zyklus der Ausreißer logischerweise anders. Mit ein wenig Glück findest du sogar eine Drehzahl, wo gar kein Fehler sichtbar ist. EDIT: m.n. schrieb: > Gut, aber zuvor bitte wieder mit sei(); andere ISRs zulassen, damit > diese durch größere Ausführungszeiten nicht blockiert werden. Das > Gesamtprogramm ist ja noch nicht fertig. Ja, aber dabei aufpassen, damit ein zwischendurch auftretender Timer-Overflow nicht wieder den 16 Bit Zugriff auf ueberlauf_count korrumpiert. > Nimm eine Divison x/y. x und y liegen im Bereich 1 - 999. Wo ist denn > hier die Integer-Berechnung genauer als die mit float? Einfaches > Beispiel: x = 10 und y = 3. > int-Ergebnis = 3 > float-Ergebnis = 3.333333 Ja klar, das ist jetzt aber auch nicht das Problem, das ich meinte. > Wo ist denn hier die Integer-Berechnung genauer als die mit float? Die Mantisse hat nur 24 Bits, also kann sie 0..16777215 darstellen. Das sind effektiv 7 Stellen. Und bei 32 Bit kann ich den Zahlenbereich 0..429497295 abbilden. Das sind gut 2 Dezimalstellen mehr. Also rechne einfach mal 4444444444+1 in 32-Bit-float und in 32-Bit-Integer. Das ist mit "signifikanten Stellen" gemeint. > Nimm eine Divison x/y. x und y liegen im Bereich 1 - 999. Wo ist denn > hier die Integer-Berechnung genauer als die mit float? > Beispiel: x = 10 und y = 3. > int-Ergebnis = 3 > float-Ergebnis = 3.333333 Wenn ich die Nachkommastellen brauche, dann rechne ich einfach rechne also z.B. statt in Volt in µV oder statt in Metern in µm und damit 10000000/3000000 und bekomme 3333333. Und dann denke ich mir den Dezimalpunkt an die passende Stelle und gut ist. Und dann bekomme ich auch noch bei 1000000000/3000000 (entspricht 1000.0/3.0) bis zur letzten "mikro-Nachkommastelle" das richtige Ergebnis. >> Und die Dynamik, die ein float bietet, wird bei der Aufgabe hier nicht >> benötigt. > Da irrst Du Nein, alle Zahlen, die bei der Aufgabe hier zu berechnen sind, passen wunderbar in den Zahlenbereich eines 32 Bit Integers.
:
Bearbeitet durch Moderator
Lothar M. schrieb: > Die Aufgabe muss einfach einmal "richtig" gelöst werden. da bin ich deiner Meinung. Lothar M. schrieb: > Und natürlich hast du das noch das übliche Semaphorenproblem, denn du > liest hier: > message.data[0] = rpm; > message.data[1] = (rpm>>8); > einen 16 Bit Wert in 2 Schritten aus. Zwischen diesen 2 Schritten kann > ein Interrupt kommen und einen neuen Wert in rpm schreiben. Dann geht > auf den CAN zur Hälfte der Neue und zur Hälfte der alte Wert. Und wenn > der alte Wert rpm = 256 war und der Neue rpm = 255 ist, was geht dann > auf den Bus? das Problem habe ich auch schon gesehen. Das müsste aber doch weg sein, wen man die Interrupts vor dem ganzen Sendevorgang ausschalte und danach wieder einschalte, oder nicht? Lothar M. schrieb: > Hast du auch qualifizierte Messgeräte (mehrkanaliges digitales > Speicheroszilloskop oder Logicanalyzer) zur Hand? Denn du musst das > Problem mal direkter an der Quelle anpacken und z.B. mal das > Interrupt-Timing messen Ja, das werde ich machen.
Lothar M. schrieb: > Und natürlich hast du das noch das übliche Semaphorenproblem, denn du > liest hier: > message.data[0] = rpm; > message.data[1] = (rpm>>8); > einen 16 Bit Wert in 2 Schritten aus. Zwischen diesen 2 Schritten kann > ein Interrupt kommen und einen neuen Wert in rpm schreiben. Dann geht > auf den CAN zur Hälfte der Neue und zur Hälfte der alte Wert. Und wenn > der alte Wert rpm = 256 war und der Neue rpm = 255 ist, was geht dann > auf den Bus? Wenn ich den sendevorgang in die ISR verlagere, sehe ich keine Ausreißer mehr im plot. Ich weiß, man sollte möglichst wenig in der ISR tun, aber für meinen Fall ist das doch eigentlich nicht wichtig wie lange die ISR braucht, oder?
1 | ISR(TIMER1_CAPT_vect) // Flanke an ICP pin |
2 | {
|
3 | if (pulse == 0) |
4 | {
|
5 | cap.i8l = ICR1L; // low Byte zuerst, high Byte wird gepuffert |
6 | cap.i8m = ICR1H; |
7 | timestamp = cap.i32; |
8 | }
|
9 | pulse++; //INCREMENTING FLAG |
10 | if (pulse == PulseProUmdrehung) |
11 | {
|
12 | cap.i8l = ICR1L; // low Byte zuerst, high Byte wird gepuffert |
13 | cap.i8m = ICR1H; |
14 | // overflow verpasst, wenn ICR1H klein und wartender Overflow Interrupt
|
15 | if ((cap.i8m < 128) && (TIFR1 & (1<<TOV1))) |
16 | { // wartenden timer overflow Interrupt vorziehen |
17 | ++ueberlauf_count; |
18 | TIFR1 = (1<<TOV1); // timer overflow int. löschen, da schon hier ausgeführt |
19 | }
|
20 | cap.high = ueberlauf_count; // obere 16 Bit aus Software Zähler |
21 | zeitdifferenz = cap.i32 - timestamp; |
22 | rpm = 3750000 / zeitdifferenz; // Magic Number 3750000 = 60000/0.016 |
23 | |
24 | tCAN message; |
25 | message.id = 0x631; //formatted in HEX |
26 | message.header.rtr = 0; |
27 | message.header.length = 2; //formatted in DEC |
28 | message.data[0] = rpm; |
29 | message.data[1] = (rpm>>8); |
30 | mcp2515_bit_modify(CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), 0); |
31 | mcp2515_send_message(&message); |
32 | pulse = 0; |
33 | }
|
34 | }
|
M. H. schrieb: > Wenn ich den sendevorgang in die ISR verlagere, sehe ich keine Ausreißer > mehr im plot. > Ich weiß, man sollte möglichst wenig in der ISR tun, aber für meinen > Fall ist das doch eigentlich nicht wichtig wie lange die ISR braucht, > oder? M. H. schrieb: > wen man die Interrupts vor dem ganzen Sendevorgang ausschalte und danach > wieder einschalte Man soll Interrupts nur ganz kurz sperren. Denn ein Interrupt ist wie der Postbote: der klingelt an der Haustelefonanlage und das Klingeln wird vom Haustelefon gespeichert. Wenn du jetzt zu lange auf dem Klo gesessen hast, ist der Postbote mitsamt dem wichtigen persönlich zu übergebenden Brief schon wieder weg, obwohl der "Interrupt" gespeichert wurde. > wen man die Interrupts vor dem ganzen Sendevorgang ausschalte und danach > wieder einschalte Du musst ja nur diesen Zugriff auf die 16-Bit-Variable (und die Zugriffe auf andere Variablen breiter als 1 char, die in ISR verändert werden) atomar machen. Also reicht es, die Interrupts direkt vorher zu sperren und am Besten sofort danach wieder freizugeben: cli(); message.data[0] = rpm; message.data[1] = (rpm>>8); sei(); M. H. schrieb: > Wenn ich den sendevorgang in die ISR verlagere, sehe ich keine Ausreißer > mehr im plot. Messen, nicht basteln! Mach das mit den Pins in deinen Code und schließ das Oszi an.
Lothar M. schrieb: > Eric B. schrieb: >> im Beispielcode unter >> https://rn-wissen.de/wiki/index.php/Timer/Counter_(Avr)#Input_Capture >> werden das high und low Byte von ICR1 separat ausgelesen > Das macht der Compiler automatisch richtig. Es ging mir nicht so sehr um das Regster auslesen an sich, sondern um diese Auswertung:
1 | // overflow verpasst, wenn ICR1H klein und wartender Overflow Interrupt
|
2 | if ((cap.i8m < 128) && (TIFR1 & (1<<TOV1))) |
3 | { // wartenden timer overflow Interrupt vorziehen |
4 | ++ueberlauf_count; |
5 | TIFR1 = (1<<TOV1); // timer overflow int. löschen, da schon hier ausgeführt |
6 | }
|
Und ich habe nicht umsonst den Ich-habe-keine-Ahnung-Disclaimer hingepackt ;-)
Eric B. schrieb: > sondern um diese Auswertung: An dieser Stelle hast du ggfs. sowieso schon Interrupts verpasst, weil das du ja 24 Pulse abwartest und in der Zwischenzeit das Überlaufflag schon "zweimal" gesetzt wurde. Das Hochzählen des Überlaufzählers gehört direkt in die Overflow-ISR...
Eric B. schrieb: > ++ueberlauf_count; > TIFR1 = (1<<TOV1); // timer overflow int. löschen, da Das ist riskant. Sobald in der ISR zu TOV1 noch mehr ausgeführt wird, gibt es neue Fehler.
Im Moment komme ich nicht dazu, hier weiter zu machen. Ich melde mich wieder.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.