Forum: Mikrocontroller und Digitale Elektronik max. Input Frequenz ATMEGA328


von Philipp G. (geiserp01)


Lesenswert?

Ich möchte mit dem Atmega328 die Frequenz (resp. RPM) eines +5V Rechteck 
Signals (50/50) messen.

Der folgende Code soll mir RPM zurückgeben:
1
//loop
2
long lRPM
3
lRPM = 272727 / pulseIn(5, LOW); // 500000 * 60 / 11

Meine Frage: Da das Rechnen an sich auch CPU Zeit beansprucht, 
funktioniert das so bis zu 165kHz? Hat da jemand Erfahrungswerte?

: Bearbeitet durch User
von Sebastian R. (sebastian_r569)


Lesenswert?

Sowas macht man eigentlich per Input Capture mit einem Timer.

Man lässt einen Timer durch sein Takt-Signal hochzählen und schaut sich 
dann zyklisch (zweiter Timer als Tor) den Zählwert an und setzt die 
Zähltregister wieder auf null.

Das ganze klappt dann nahezu vollständig in Hardware und geht bis ein 
paar Megahertz (Je nach Torzeit), ohne die Firmware zu blockieren.

von K. S. (the_yrr)


Lesenswert?

Philipp G. schrieb:
> Da das Rechnen an sich auch CPU Zeit beansprucht,
> funktioniert das so bis zu 165kHz? Hat da jemand Erfahrungswerte?

- welche Taktrate hat der?
- was ist PulseIn()? Arduino funktion? sonst poste den Code
- was macht der restliche Code?
- musst du durchgängig messen oder reicht einmal messen, dann Code zur 
Anzeige u.s.w., dann wieder messen?

bei 16MHz Takt hast du 100 Zyklen für 160kHz, das sollte machbar sein in 
C, allerdings nicht viel mehr außenrum und bei Arduino könnte der 
overhead schon etwass viel werden. Timer zur Zeitmessung (Timerwert alt 
- neu + Anzahl der Overflows => Zeit) und Pin Change Interrupt schaffen 
das locker.

von Falk B. (falk)


Lesenswert?

Philipp G. schrieb:
> Ich möchte mit dem Atmega328 die Frequenz (resp. RPM) eines +5V Rechteck
> Signals (50/50) messen.

RPM = revolutions per minute

Das kann selbst beim schnellsten Motor kaum über ein paar kHz gehen, 
also langsam für einen Mikrocontroller.

> Der folgende Code soll mir RPM zurückgeben:
> //loop
> long lRPM
> lRPM = 272727 / pulseIn(5, LOW); // 500000 * 60 / 11
>
> Meine Frage: Da das Rechnen an sich auch CPU Zeit beansprucht,
> funktioniert das so bis zu 165kHz? Hat da jemand Erfahrungswerte?

Du willst mal sicher NICHT mit 165kHz eine Drehzahl berechnen, sondern 
eher ein paar Mal pro Sekunde bis zu 165kHz messen und dann umrechnen. 
Wobei 165 kHz nur von einem hochauflösenden Encoder kommen können, nicht 
als einfaches Drehzahlsignal von einem Motor, denn der hätte dann 9,9 
Millionen Umdrehung/min ;-)

Und wenn gleich deine Arduino-Methode PulseIn() irgendwas ausspucken 
wird, so ist die Drehzahlmessung über nur einen Puls eher ungenau. 
Sinnvollerweise mißt man deutlich mehr Pulse über einen längeren 
Zeitraum.

von Adam P. (adamap)


Lesenswert?

Man kann es ja mal theoretisch betrachten:

T = 1 / 165000 = 6µs

Wenn du dein ATmega328 mit 20Mhz betreibst, dann dauert ein Takt 50ns.

Somit ergeben sich max. 120 Takte, bzw. 120 ASM-Anweisungen (wenn es 
Anweisungen sind die nur 1 Takt benötigen).

von K. S. (the_yrr)


Lesenswert?

Sebastian R. schrieb:
> Man lässt einen Timer durch sein Takt-Signal hochzählen und schaut sich
> dann zyklisch (zweiter Timer als Tor) den Zählwert an und setzt die
> Zähltregister wieder auf null.

Philipp G. schrieb:
> Der folgende Code soll mir RPM zurückgeben:

der Vorschlag ist auch gut, aber bei sehr niedrigen RPM muss man dann in 
der Software glitches ausschließen, wenn die Zeit zwischen Pulsen zu 
groß wird im Verhältnis zur Torzeit, sonst schwankt der Ausgang trotz 
konstanter RPM.

von Sebastian R. (sebastian_r569)


Lesenswert?

K. S. schrieb:
> der Vorschlag ist auch gut, aber bei sehr niedrigen RPM muss man dann in
> der Software glitches ausschließen, wenn die Zeit zwischen Pulsen zu
> groß wird im Verhältnis zur Torzeit, sonst schwankt der Ausgang trotz
> konstanter RPM.

Man muss die Torzeit so wählen, dass der Timer weder überläuft, noch 
dass er nur ein paar Werte weit zählt.

Je weiter der Timer in einer Torzeit bei gegebener Drehzahl kommt, desto 
genauer ist das Ergebnis und desto geringer ist der Jitter.

Wenn man dann noch die Möglichkeit hat, ein bisschen zu filtern, sollte 
das schon gut gehen.

von Philipp G. (geiserp01)


Angehängte Dateien:

Lesenswert?

K. S. schrieb:
> welche Taktrate hat der?

16MMhz

K. S. schrieb:
> - was ist PulseIn()? Arduino funktion? sonst poste den Code

Ja, misst die Zeit von Low bis wieder ein High anliegt.

K. S. schrieb:
> - was macht der restliche Code?

auf einem LCD die Zahl ausgeben. Plus den Höchstwert jeweils in eine 
Variable schreiben.

K. S. schrieb:
> - musst du durchgängig messen oder reicht einmal messen, dann Code zur
> Anzeige

Nein, durchgängig messen, immer.

Falk B. schrieb:
> RPM = revolutions per minute
>
> Das kann selbst beim schnellsten Motor kaum über ein paar kHz gehen,
> also langsam für einen Mikrocontroller.

Hm, wie so oft liegt das Problem zwischen den Ohren, hast wieder mal 
Recht @FAlk :)

Dann muss ich tiefer ausholen.

Es handelt sich um einen Speed Sensor für einen Turbo. Der ist bei 
165'000 Umin im Surge Limit, also praktisch gesehen möchte ich messen 
bis 200'000 Umin.

Das Datenblatt gibt es hierzu ab Seite 12:

https://www.garrettmotion.com/wp-content/uploads/2018/06/781328_Speed_Sensor_Kit_Installation_Instructions-1.pdf

Also:

Der Sensor misst die vorbeikommenden Blätter, ein Blatt - ein Impuls. 
Mein Turbo hat 11. Der Sensor gibt jedes achte Blatt als Ausgangfrequenz 
zurück. Das geht hieraus hervor:
1
Sensor Signal: the speed sensor will output a square-wave signal at 1/8 the input
2
frequency(originally intended for 8-blade wheel). The input frequency is simply one pulse
3
per blade, as the blades pass by the sensor. The sensor therefore measures the following
4
input frequency (in rpm):
5
Equation 1
6
where N is the number of blades, and RPM is the turbo speed.
7
Therefore, your data logger needs to convert the speed sensor signal based on
8
equation 1.
9
For example, with a 12-bladed wheel,
10
Example
11
Therefore the logger would need to multiply the sensor signal by 40 in order to record true
12
turbo RPM (for a 12-bladed wheel).

Das habe ich überlesen, ergo bedeutet das für meinen Code:
1
//loop
2
long lRPM
3
//lRPM = 60 * 8 / 11 * 500000 / pulseIn(5, LOW);
4
//lRPM = 43.63 * 500000 / pulseIn(5, LOW);
5
lRPM = 21815000/ pulseIn(5, LOW);

Stimmt die Rechung? Könnt ihr mich folgen?


ergo, das sind rund ~5Khz, nix von 165.

edit: Damit es dann so aussieht, wie deren Rundinstrument (Bild im 
Anhang) messen wir bis 180'000 mit einem Teiler von 1000:
1
lRPM = 21815 / pulseIn(5, LOW);
2
LCD.print (lRPM + " x1000 RPM")

: Bearbeitet durch User
von Thomas W. (diddl)


Lesenswert?

Philipp G. schrieb:
> funktioniert das so bis zu 165kHz? Hat da jemand Erfahrungswerte?

Es funktioniert gerade noch so bei einem 328 mit 16MHz getaktet in C 
geschrieben.

Allerdings muss getrickst werden.
Während der Messung keine Interrupts.
Wenn Arduino verwendet wird, dann nur mit direkten Port Zugriff.
Oder alternativ diese Fast IO Lib.


Hab was ähnliches gemacht.
Einen Floppy Controller mit einem Arduino Nano.
Da kommen so alle 4µs ein Datenbit ...

: Bearbeitet durch User
Beitrag #5722931 wurde vom Autor gelöscht.
von Falk B. (falk)


Lesenswert?

Philipp G. schrieb:
>> - was ist PulseIn()? Arduino funktion? sonst poste den Code
>
> Ja, misst die Zeit von Low bis wieder ein High anliegt.

Das wäre aber ein PulsBREITENmessung und keine Frequenzmessung. Und 
genau das macht die Funktion auch und ist damit für deine Anwendung 
unbrauchbar.

https://www.arduino.cc/reference/en/language/functions/advanced-io/pulsein/

> auf einem LCD die Zahl ausgeben. Plus den Höchstwert jeweils in eine
> Variable schreiben.

Trivial, trotzdem kann man da viel Unsinn machen.

> Es handelt sich um einen Speed Sensor für einen Turbo. Der ist bei
> 165'000 Umin im Surge Limit, also praktisch gesehen möchte ich messen
> bis 200'000 Umin.

Schöner Staubsauger ;-)

> Der Sensor misst die vorbeikommenden Blätter, ein Blatt - ein Impuls.
> Mein Turbo hat 11. Der Sensor gibt jedes achte Blatt als Ausgangfrequenz
> zurück.

Also ist die echte Drehzahl

RPM = Pulsfrequenz [Hz] * 8 / 11 * 60

> Das habe ich überlesen, ergo bedeutet das für meinen Code:
>
> //loop
> long lRPM
> //lRPM = 60 * 8 / 11 * 500000 / pulseIn(5, LOW);
> //lRPM = 43.63 * 500000 / pulseIn(5, LOW);
> lRPM = 21815000/ pulseIn(5, LOW);
>
> Stimmt die Rechung? Könnt ihr mich folgen?

Wo kommt die 500000 her?

> ergo, das sind rund ~5Khz, nix von 165.

Immer noch falsch. Deine max. 200.000 U/min = 3,3kHz
Der Sensor gibt aber nur 1/8 davon aus, also 416Hz. Laaaaaangsaaaam ;-)

> edit: Damit es dann so aussieht, wie deren Rundinstrument (Bild im
> Anhang) messen wir bis 180'000 mit einem Teiler von 1000:
> lRPM = 21815 / pulseIn(5, LOW);
> LCD.print (lRPM + " x1000 RPM")

Naja, bei den Drehzahlen und der Tatsache, daß die praktisch nie auf 
Null absinkt, mißt man sinnvollerweise eine volle Periode, das ist genau 
genug. Dazu reicht ein passend konfigurierter externer Interrupt, der 
auf die fallende oder steigende Flanke reagiert, aber nicht auf beide. 
Dann noch einen Timer passend eingestellt und die Differenz gebildet, 
fettig. Dann kann man auch problemlos das Anzeigeinstrument mit 100Hz 
oder mehr Updaterate betreiben und eine analoge, dynamische Anzeige 
nachbauen.

Wenn man also ~420 Hz (2,3ms) mit 1% Auflösung messen will (mehr braucht 
kein Mensch für sowas), braucht man ca. 42kHz Timerfrequenz. Sagen wir 
62,5kHz und gut. Also den Prescaler von Timer 1 auf /256 konfigurieren 
und messen, der mißt dann eine Differenz ~143 Takte bei Maximaldrehzahl. 
Die messbare Minimaldrehzahl liegt um Faktor 458 tiefer bei ca. 0,2% 
bzw. 430U/min, darunter kann man so direkt nicht messen, weil es dann 
zum Zählerüberlauf bei der Differenzbildung von Timer 1 kommt (16 Bit). 
Sollte reichen, muss man aber ggf. per Software abfangen, sonst zeigt 
euer Instrument ggf. Unsinn an, wenn der Kreisel steht.

von m.n. (Gast)


Lesenswert?

Weder Revolution, noch Resolution, noch Absolution:
RPM = rotations per minute bzw.
UPM = Umdrehungen pro Minute

Für ATmega328 oder Arduino Uno gibt es fertigen Code: 
http://mino-elektronik.de/fmeter/fm_software.htm#bsp7 Automatische 
Bereichswahl von 16 mHz - 250 kHz mit höchster Auflösung ist inklusiv.
Der keramische Resonator des Arduino hat aber eine sehr bescheidene 
Stabilität, weshalb die Taktfrequenz unbedingt mit einem Quarz oder TCXO 
erzeugt werden sollte.

Das Maximum mit AVR bei 20 MHz Takt liegt bei 1 MHz mit input-capture: 
http://mino-elektronik.de/fmeter/fmeter.htm
Bascom mit Assembler Unterstützung ist auch nicht schlecht!

von Wolfgang (Gast)


Lesenswert?

Thomas W. schrieb:
> Philipp G. schrieb:
>> funktioniert das so bis zu 165kHz? Hat da jemand Erfahrungswerte?
>
> Es funktioniert gerade noch so bei einem 328 mit 16MHz getaktet in C
> geschrieben.
>
> Allerdings muss getrickst werden.

Der einfachste Tick ist, das Zählen der eingebauten Hardware im 
ATmega328 zu überlassen. Wozu soll der sich damit per Software 
rumplagen. Währenddessen kann er sich genauso gut mit anderen Dingen 
beschäftigen.

von Wolfgang (Gast)


Lesenswert?

m.n. schrieb:
> Bereichswahl von 16 mHz - 250 kHz mit höchster Auflösung ist inklusiv.
> Der keramische Resonator des Arduino hat aber eine sehr bescheidene
> Stabilität, weshalb die Taktfrequenz unbedingt mit einem Quarz oder TCXO
> erzeugt werden sollte.

Der CPU-Takt muss nicht genauer sein, als die erforderliche Genauigkeit 
der Drehzahlmessung.

von Philipp G. (geiserp01)


Lesenswert?

Falk B. schrieb:
> Also ist die echte Drehzahl
>
> RPM = Pulsfrequenz [Hz] * 8 / 11 * 60

Genau.

Falk B. schrieb:
> Immer noch falsch. Deine max. 200.000 U/min = 3,3kHz
> Der Sensor gibt aber nur 1/8 davon aus, also 416Hz. Laaaaaangsaaaam

Hm, hat was, ja.

Falk B. schrieb:
> Wo kommt die 500000 her?

1'000'000 us / 2, weil die Zeit gemessen wird, bis von low wieder ein 
high einliegt, und nicht die volle Periode.

Falk B. schrieb:
> Wenn man also ~420 Hz (2,3ms) mit 1% Auflösung messen will (mehr braucht
> kein Mensch für sowas), braucht man ca. 42kHz Timerfrequenz. Sagen wir
> 62,5kHz und gut. Also den Prescaler von Timer 1 auf /256 konfigurieren
> und messen, der mißt dann eine Differenz ~143 Takte bei Maximaldrehzahl.

Meinst Du das so:
1
  // method 2
2
  Serial.println(getFrequency(3));
3
}
4
5
long getFrequency(int pin) {
6
  #define SAMPLES 256
7
  long freq = 0;
8
  for(unsigned int j=0; j<SAMPLES; j++) freq+= 500000/pulseIn(pin, HIGH, 250000);
9
  return freq / SAMPLES;
10
}

Da ist halt immer noch die PulseIn Funktion drin, mangels Wissen wie man 
es besser machen könnte :(

m.n. schrieb:
> gibt es fertigen Code:
> http://mino-elektronik.de/fmeter/fm_software.htm#bsp7 Automatische
> Bereichswahl von 16 mHz - 250 kHz mit höchster Auflösung

dank dir, schaue ich mir morgen mal an.

Wolfgang schrieb:
> Der einfachste Tick ist, das Zählen der eingebauten Hardware im
> ATmega328 zu überlassen. Wozu soll der sich damit per Software
> rumplagen. Währenddessen

Damit bin ich überfordert.

von m.n. (Gast)


Lesenswert?

Wolfgang schrieb:
> Der CPU-Takt muss nicht genauer sein, als die erforderliche Genauigkeit
> der Drehzahlmessung.

Im Prinzip richtig, aber: Wenn man sechs Stellen anzeigt, sollten diese 
auch aussagefähig sein. Man kann zwar die letzten drei Stellen 
ausblenden, nur warum? Mit einem Quarz für 20 cent hat man neben der 
Auflösung auch volle Genauigkeit. Dafür nimmt man doch einen µC.
Sonst täte es ja auch ein Frequenz/Spannungs-Wandler mit angeschlossenem 
Multimeter: http://mino-elektronik.de/fmeter/fm_software.htm#bsp11

Philipp G. schrieb:
> Wolfgang schrieb:
>> Der einfachste Tick ist, das Zählen der eingebauten Hardware im
>> ATmega328 zu überlassen. Wozu soll der sich damit per Software
>> rumplagen. Währenddessen
>
> Damit bin ich überfordert.

Nicht nur Du ;-)

von Wolfgang (Gast)


Lesenswert?

m.n. schrieb:
> Im Prinzip richtig, aber: Wenn man sechs Stellen anzeigt, sollten diese
> auch aussagefähig sein.

Manchmal nimmt man auch eine Anzeige mit vielen Stellen, um einfach nur 
die Messbereichsumschaltung zu sparen und beim Ablesen nicht dauernd das 
Dezimaltrennzeichen suchen zu müssen.

von m.n. (Gast)


Lesenswert?

Wolfgang schrieb:
> Manchmal nimmt man auch eine Anzeige mit vielen Stellen, um einfach nur
> die Messbereichsumschaltung zu sparen und beim Ablesen nicht dauernd das
> Dezimaltrennzeichen suchen zu müssen.

Womöglich noch ohne Vornullenunterdrückung? Das erinnert mich an die 
70er Jahre. Da hatten alle Frequenzzähler acht Stellen (ICM7216) ;-)
Stand der Technik ist automatische Bereichswahl - seit Jahrzehnten.

von c-hater (Gast)


Lesenswert?

Philipp G. schrieb:

> Wolfgang schrieb:
>> Der einfachste Tick ist, das Zählen der eingebauten Hardware im
>> ATmega328 zu überlassen. Wozu soll der sich damit per Software
>> rumplagen. Währenddessen
>
> Damit bin ich überfordert.

Wo ist das Problem? Im Kern musst du nur ein Byte Konfiguration in ein 
dämliches Timer-Register schreiben, um den Timer dazu zu bringen, halt 
Impulse "von aussen" zu zählen statt der des Systemtaktes.

Natürlich brauchst du einen weiteren, vom Systemtakt angetriebenen Timer 
als Referenz, denn Messen heißt vergleichen.

Hast du die beiden Timer konfiguriert, laufen die einfach von alleine 
und tun ihren Job ohne dass dein Programm weiter mit ihnen interagieren 
muss.

Das muss bloß noch die beiden Timerregister zu zwei Zeitpunkten auslesen 
und die vier ausgelesenen Werte mit ein wenig Sechstklässlermathematik 
miteinander verrechnen und das Ergebnis zur Anzeige bringen.

Wenn man's richtig gut machen will, kann man auch noch die 
systematischen Fehler der Ausleseroutine korrigieren und das 
Messintervall dynamisch anpassen, wobei letzteres bei der Anwendung für 
einen Turbolader eher nicht nötig sein dürfte. Das kann man wohl einfach 
durch die Rückgabe einer schlichten 0 bei Unterschreitung eines 
Grenzwertes ersetzen, da kein Schwein sich dafür interessiert, ob der 
Lader eventuell im An- oder Auslaufen schon/noch mit 1000, 500 oder 
100rpm läuft. Das ist im Sinne der Messaufgabe alles praktisch mit 0 
gleichzusetzen.

von Philipp G. (geiserp01)


Lesenswert?

Meint ihr das mit dem Interupt so:
1
// Definition of interrupt names
2
#include < avr/io.h >
3
// ISR interrupt service routine
4
#include < avr/interrupt.h >
5
6
7
// LED connected to digital pin 13
8
int ledPin = 13;
9
// This is the INT0 Pin of the ATMega8
10
int sensePin = 2;
11
// We need to declare the data exchange
12
// variable to be volatile - the value is
13
// read from memory.
14
volatile int value = 0;
15
16
// Install the interrupt routine.
17
ISR(INT0_vect) {
18
  // check the value again - since it takes some time to
19
  // activate the interrupt routine, we get a clear signal.
20
  value = digitalRead(sensePin);
21
}
22
23
24
void setup() {
25
  Serial.begin(9600);
26
  Serial.println("Initializing ihandler");
27
  // sets the digital pin as output
28
  pinMode(ledPin, OUTPUT);
29
  // read from the sense pin
30
  pinMode(sensePin, INPUT);
31
  Serial.println("Processing initialization");
32
  // Global Enable INT0 interrupt
33
  GICR |= ( 1 < < INT0);
34
  // Signal change triggers interrupt
35
  MCUCR |= ( 1 << ISC00);
36
  MCUCR |= ( 0 << ISC01);
37
  Serial.println("Finished initialization");
38
}
39
40
void loop() {
41
  if (value) {
42
    //to do
43
}

Im main loop dann einen Timer bauen, der alle n ms die Takte zählt?

von m.n. (Gast)


Lesenswert?

c-hater schrieb:
> Natürlich brauchst du einen weiteren, vom Systemtakt angetriebenen Timer
> als Referenz, denn Messen heißt vergleichen.
>
> Hast du die beiden Timer konfiguriert, laufen die einfach von alleine
> und tun ihren Job ohne dass dein Programm weiter mit ihnen interagieren
> muss.
>
> Das muss bloß noch die beiden Timerregister zu zwei Zeitpunkten auslesen
> und die vier ausgelesenen Werte mit ein wenig Sechstklässlermathematik
> miteinander verrechnen und das Ergebnis zur Anzeige bringen.
>
> Wenn man's richtig gut machen will,

dann muß man diese beiden Timer synchronisieren. Und dafür bietet der 
AVR nichts an. Folglich können Überläufe des Ereigniszählers falsch 
zugeordnet werden.
Richtig gut geht anders!

von Wolfgang (Gast)


Lesenswert?

m.n. schrieb:
> Stand der Technik ist automatische Bereichswahl - seit Jahrzehnten.

Quatsch. Stand der Technik ist, das man die automatische Bereichswahl 
abschalten kann, wenn man es satt hat, nicht nur die Zahlen ablesen zu 
müssen, sondern auch noch immer nach dem aktuellen Messbereich gucken zu 
müssen.

von c-hater (Gast)


Lesenswert?

m.n. schrieb:

> dann muß man diese beiden Timer synchronisieren.

???

Das Messprinzip beruht gerade darauf, dass sie nicht synchron sind, 
einer läuft nämlich mit Systemtakt, der andere mit der zu messenden 
Frequenz.

Aus diesem Prinzip ergibt sich schon zwingend, dass sie unmöglich 
synchron sein können.

Tatsächlich ist das aber nur die halbe Wahrheit, denn in gewissem Umfang 
sind sie doch synchron, der externe Takt über den Tn-Eingang wird 
nämlich synchronisiert, bevor er tatsächlich an den Timer gelangt. Das 
leistet die Hardware des AVR (ist auch so dokumentiert).

Und damit sind beide Timer sozusagen "benutzungstechnisch" natürlich in 
einer Taktdomäne, weswegen eine deterministische Auswertung kein Problem 
darstellt. Man muss halt nur korrekt programmieren können...

Der Nachteil der Synchronisierung mit dem Systemtakt ist eine gewisse 
Unsicherheit der Messung, die man einfach dadurch unwichtig macht, dass 
man das Messintervall groß genug wählt, deutlich größer als vier 
Systemtakte, denn das ist der maximal durch die Synchronisierung 
erzeugte Messfehler.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

m.n. schrieb:
> dann muß man diese beiden Timer synchronisieren.

Nö, wieso denn? Timer 1 zählt die T1 Pulse, Timer 0 liefert einen z.B. 
Tickertakt (1 Sekunde, 1/10tel Sekunde oder wasauchimmer).
Der Timeroverflow des externen Counters (Timer 1)ist für 24-bit Werte 
reserviert und die Timer0 ISR ist der Ticker, in der Timer 1 gelesen und 
zurückgesetzt wird. Und man hat Pulse/Tickerzeit - Fertig. Timer1 ISR 
kann man sich sparen, wenn die 64k Pulse/Tickerzeit reichen.

: Bearbeitet durch User
von abc.def (Gast)


Lesenswert?

>> dann muß man diese beiden Timer synchronisieren.

ich denke, da ist was anderes gemeint.
Der gute alte Frequenzzähler hatte die Torzeit. Hardwaremäßig wurden die 
Impulse während dieser Zeit gezählt. Vor ein paar Jahren habe ich einen 
Zähler für das 40m Band auf dem m8 programmiert. Das einzige saubere 
war, die Torzeit (weiß nicht mehr, welcher T0,1,2) an den Reset des 
(externen) Vorteilers zu geben, damit ich das Pulspaket genau der 
Torzeit zählen kann. Wenn man denn einen Vorteiler oder ein anderes 
externes Gatter hat. Hat man das nicht, muß man zu Anfang oder Ende der 
Torzeit einen Timer-Interrupt bekommen und damit den Impuls-Zähler 
auslesen. Dabei ist es die Hoffnung (mehr nicht), daß von diesem 
Timer-Interrupt bis zum Register lesen die Software immer gleich lang 
ist sonst ist die Torzeit unterschiedlich. Fehler, und keiner hat's 
gemerkt. Für 3 Stellen reicht es auch so.
Bin ich noch up-to-date mit der Info, daß das Gate des Zählers 
hardwareseitig fehlt, oder gibt es was Neues?

von Falk B. (falk)


Lesenswert?

m.n. schrieb:
> Weder Revolution, noch Resolution, noch Absolution:
> RPM = rotations per minute bzw.
> UPM = Umdrehungen pro Minute

Sagt wer?

https://dict.leo.org/englisch-deutsch/drehzahl

von Falk B. (falk)


Lesenswert?

Philipp G. schrieb:

>> Immer noch falsch. Deine max. 200.000 U/min = 3,3kHz
>> Der Sensor gibt aber nur 1/8 davon aus, also 416Hz. Laaaaaangsaaaam
>
> Hm, hat was, ja.

Ja, da hab ich aber den Faktor 11 vergessen. Ist aber nicht tragisch, 
11*420Hz sind auch nur 4,6kHz, da muss man halt den Prescaler auf 64 
verringern, dann paßt es wieder.

> 1'000'000 us / 2, weil die Zeit gemessen wird, bis von low wieder ein
> high einliegt, und nicht die volle Periode.

Funktioniert so nicht wirklich gut. Du willst die PERIODENDAUER messen, 
als von HIGH-LOW zu HIGH-LOW Flanke! Nicht die LOW oder HIGH Zeiten! Ok, 
du kannst Glück haben, weil der Sensor intern durch 8 teilt, da kommen 
IMMER exakt 50% Tastverhältnis raus und es funktioniert.

> Meinst Du das so:
>   // method 2
>   Serial.println(getFrequency(3));
> }
>
> long getFrequency(int pin) {
>   #define SAMPLES 256
>   long freq = 0;
>   for(unsigned int j=0; j<SAMPLES; j++) freq+= 500000/pulseIn(pin, HIGH,
> 250000);
>   return freq / SAMPLES;
> }

Nö, das ist wieder halbgarer Arduino-Murks.

> Da ist halt immer noch die PulseIn Funktion drin, mangels Wissen wie man
> es besser machen könnte :(

Sagte ich bereits, mit einer ISR, welche auf die Flanke eine externen 
Interrupts reagiert.

> Damit bin ich überfordert.

Tja, dann mußt du entweder,

- es lernen
- jemanden finden der dir beim Lernen hilft
- jemanden finden, der dir das Programm schreibt
- es vergessen

Wähle.

von Falk B. (falk)


Lesenswert?

Philipp G. schrieb:
> Meint ihr das mit dem Interupt so:

Nein, aber der Anfang ist schon mal OK.

von Falk B. (falk)


Lesenswert?

Eher so.
1
/*
2
3
RPM counter for turbo fan
4
5
*/
6
7
// Definition of interrupt names
8
9
// LED connected to digital pin 13
10
int ledPin = 13;
11
// This is the INT0 Pin of the ATMega8
12
int sensePin = 2;
13
// We need to declare the data exchange
14
// variable to be volatile - the value is
15
// read from memory.
16
volatile uint16_t period = 0;
17
18
// Install the interrupt routine.
19
ISR(INT0_vect) {
20
    static uint16_t time_last;
21
    uint16_t time_now; 
22
23
    time_now = TCNT1;
24
    period = time_now-time_last;
25
    time_last = time_now;
26
}
27
28
// atomic read access
29
30
uint16_t get_period(void) {
31
    uint16_t tmp;
32
33
    cli();
34
    tmp = period;
35
    sei();
36
    return tmp;
37
}
38
39
void setup() {
40
  Serial.begin(9600);
41
  Serial.println("Initializing ihandler");
42
  // sets the digital pin as output
43
  pinMode(ledPin, OUTPUT);
44
  // read from the sense pin
45
  pinMode(sensePin, INPUT);
46
  Serial.println("Processing initialization");
47
  // Global Enable INT0 interrupt on rising edge
48
  EICRA = (1<<ISC10) | (1<<ISC00);
49
  EIMSK |= (1<<INT0);
50
  // init timer 1, mode 0, prescaler 64, 250kHz timer clock
51
  TCCR1A = 0;
52
  TCCR1B = (1<<CS11) | (1<<CS10);
53
  Serial.println("Finished initialization");
54
}
55
56
void loop() {
57
  uint16_t rpm_1k;
58
 
59
  // rpm [RPM] = 1/period[s]/11*60*8              // basic formula
60
  // rpm [RPM] = 1/(period[cnt]*4us)/11*60*8      // basic formula using counter result and counter clock
61
  // rpm [1000RPM] = 250e3/period[cnts]/11*60*8/1000  // result in units of 1000 RPMs
62
  // rpm [1000RPM] = 10909 / period [cnts]
63
  rpm_1k = 10909 / get_period(); // atomic read access!!!
64
  // do something with rpm
65
}

>Im main loop dann einen Timer bauen, der alle n ms die Takte zählt?

NEIN!!!! Mach es gescheit und nicht Arduino-Murks-Style!

: Bearbeitet durch User
von Heinz (Gast)


Lesenswert?

Unter
http://interface.khm.de/index.php/lab/interfaces-advanced/arduino-frequency-counter-library/
gibt es eine Library mit der es möglich sein soll Frequenzen bis zu 1/4 
der Prozessortaktfrequenz zu messen.
Ich hatte die selbst mal mit einem Arduino UNO im Einsatz und bei 3MHz 
Messsignal war noch nicht Schluss.

Gruß
Heinz

von Philipp G. (geiserp01)


Lesenswert?

Falk B. schrieb:
>> Hm, hat was, ja.
>
> Ja, da hab ich aber den Faktor 11 vergessen.

Ja, wäre schon übel gewesen mich grad zweimal zu verrechnen.

Falk B. schrieb:
> /*
> RPM counter for turbo fan
> */

Das ist ein Kompressor, kein CPU Lüfter. :)

Aber Danke Dir Falk!!!! Scheint zu gehen. Nächste Herausforderung ist 
nun, die Luftmasse (nicht Luftmenge!) zu berechnen. Aber das muss ich 
erstmal aufbereiten und hier vorstellen.

Wie funktioniert eigentlich dieser Sensor? Ist das nur ein kapazitiver 
Näherungssensor oder etwas Spezielles drin? Nur der Sensor kostet gut 
400USD.

: Bearbeitet durch User
von Philipp G. (geiserp01)


Lesenswert?

Nächste Frage, die Ausgabge der korrigierten RPM in Bezug auf Luftmasse. 
Wie kann ich die Formel vereinfachen? Hatte in Mathe einen Fensterplatz 
:)
1
void loop() {
2
  uint16_t rpm_1k;
3
  int rpm_1k_corr = 0; // corrected turbo speed
4
  int TempInF = 0; // inlet temp in Fahreinheit
5
  int TinC = 0; // inlet temp in Celcius
6
7
  // do something with rpm
8
  
9
  // calc corrected rpm
10
  // sq (root(rpm_1k) / (Tin(F) + 460) / 545)
11
  
12
  // convert Temp in from celsicus to fahreinheit
13
  if (TinC < 0)
14
  { // no need to convert minus degrees
15
      TinC = 0;
16
  }
17
  TempinF = (TinC * 1.8) + 32 // works only for pos. degrees
18
 
19
  // calc corrected rpm
20
  uint16_t rpm_1k_corr = sqrt(rpm1k / (TempinF + 460) / 545);
21
22
}

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Philipp G. schrieb:
> Nächste Frage, die Ausgabge der korrigierten RPM in Bezug auf Luftmasse.
> Wie kann ich die Formel vereinfachen? Hatte in Mathe einen Fensterplatz
> :)

Was willst du da groß vereinfachen? Und was ist bei dir sq()?
Die Wurzel oder das Quadrat?
Außerdem hast du einen Unterschied zwischen dein Formel im Kommentar und 
im echten Code? Welche stimmt nun?

von Cyblord -. (cyblord)


Lesenswert?

Falk B. schrieb:
> Außerdem hast du einen Unterschied zwischen dein Formel im Kommentar und
> im echten Code? Welche stimmt nun?

Das ist einer der Gründe warum man Kommentare in Quellcodes meiden 
sollte wie der Teufel das Weihwasser.

von Philipp G. (geiserp01)


Angehängte Dateien:

Lesenswert?

Die Wurzel stimmt natürlich, anbei (Beilage) noch die OEM Formel dazu.

Dann hiesse der Code:
1
void loop() {
2
  uint16_t rpm_1k;
3
  int rpm_1k_corr = 0; // corrected turbo speed
4
  int TempInF = 0; // inlet temp in Fahreinheit
5
  int TinC = 0; // inlet temp in Celcius
6
7
  // calc corrected rpm  
8
  // convert Temp in from celsicus to fahreinheit
9
  if (TinC < 0)
10
  { // no need to convert minus degrees
11
      TinC = 0;
12
  }
13
  TempinF = (TinC * 1.8) + 32 // works only for pos. degrees
14
 
15
  // calc corrected rpm
16
  uint16_t rpm_1k_corr = rpm1k / (sq(TempinF + 460) / 545));
17
}

Ist Wurzel ziehen sehr rechenintenstiv? Wäre noch was zu vereinfachen, 
eher nicht, oder?

Könnte man nicht die Faktorisierung + 460 / 545 direkt auf Celsius 
ummünzen? Wie gesagt, bin eine komplette doofnuss in Mathe.

edit: Notiz an mich selber, doch, es muss einfacher gehen. Weil 545 - 
460 sind umgerechnet 30°C, was Garrett mit atmospheric conditions wohl 
meint. Dann könnte ich dieser Faktor schon auf C anpassen und mir die 
Fahreinheit Konvertierung sparen.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Philipp G. schrieb:

> Die Wurzel stimmt natürlich, anbei (Beilage) noch die OEM Formel dazu.
>
> Dann hiesse der Code:
> void loop() {
>   uint16_t rpm_1k;
>   int rpm_1k_corr = 0; // corrected turbo speed
>   int TempInF = 0; // inlet temp in Fahreinheit
>   int TinC = 0; // inlet temp in Celcius
>
>   // calc corrected rpm
>   // convert Temp in from celsicus to fahreinheit
>   if (TinC < 0)
>   { // no need to convert minus degrees
>       TinC = 0;
>   }
>   TempinF = (TinC * 1.8) + 32 // works only for pos. degrees

Das ist Unsinn, man kann auch negative Celsiustemperaturen in Fahrenheit 
umrechnen, sogar mit der gleichen Formel!

https://de.wikipedia.org/wiki/Grad_Fahrenheit#Umrechnung

>   // calc corrected rpm
>   uint16_t rpm_1k_corr = rpm1k / (sq(TempinF + 460) / 545));

Was ist dieses sq() Funktion? Die normale Wurzel heißt sqrt (Square 
root, Quadratwurzel)

sq() bedeutet square, das ist das QUADRAT!!! Somit ist sie hier FALSCH!

RTFM!

https://www.arduino.cc/reference/en/language/functions/math/sq/

> Ist Wurzel ziehen sehr rechenintenstiv?

Jain, kann schon einige Dutzend Takte brauchen. Für dein 
Ansteuerfrequenz von vielleicht 100 Hz ist das unkritisch.

> Wäre noch was zu vereinfachen,
> eher nicht, oder?

Oder.

> Könnte man nicht die Faktorisierung + 460 / 545 direkt auf Celsius
> ummünzen? Wie gesagt, bin eine komplette doofnuss in Mathe.

Warum? Das bissel Subtrahieren und Dividieren macht der Arduino im 
Schlaf.

> edit: Notiz an mich selber, doch, es muss einfacher gehen. Weil 545 -
> 460 sind umgerechnet 30°C, was Garrett mit atmospheric conditions wohl
> meint. Dann könnte ich dieser Faktor schon auf C anpassen und mir die
> Fahreinheit Konvertierung sparen.

Alles nebensächlich.

von Philipp G. (geiserp01)


Lesenswert?

Wir waren doch gestern uns bezüglich der Ansteuerfrequenz einig:

Falk B. schrieb:
> Ja, da hab ich aber den Faktor 11 vergessen. Ist aber nicht tragisch,
> 11*420Hz sind auch nur 4,6kHz, da muss man halt den Prescaler auf 64
> verringern, dann paßt es wieder

>Jain, kann schon einige Dutzend Takte brauchen. Für dein
>Ansteuerfrequenz von vielleicht 100 Hz ist das unkritisch.
>
~4.5khz

Falk B. schrieb:
> Das ist Unsinn, man kann auch negative Celsiustemperaturen in Fahrenheit
> umrechnen, sogar mit der gleichen Formel!

Ich muss gleich mal schauen woher ist das hab mit den Minus 
Temperaturen.

Falk B. schrieb:
> Was ist dieses sq() Funktion? Die normale Wurzel heißt sqrt (Square
> root, Quadratwurzel)

Hab es genau andersrum erwartet. Hast Recht.

Falk B. schrieb:
> Jain, kann schon einige Dutzend Takte brauchen. Für dein
> Ansteuerfrequenz von vielleicht 100 Hz ist das unkritisch.

Technische Verständnisfrage. Wenn der jetzt für die Wurzel länger zum 
Rechnen braucht, und von 'oben' kommt ein Interrupt rein, was macht dann 
der uC? Springt der zurück oder was?

Darf man Dir eigentlich auch eine PN schreiben?

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Philipp G. schrieb:
> Wir waren doch gestern uns bezüglich der Ansteuerfrequenz einig:

Schon, aber du redest von einer anderen Sache.

> Falk B. schrieb:
>> Ja, da hab ich aber den Faktor 11 vergessen. Ist aber nicht tragisch,
>> 11*420Hz sind auch nur 4,6kHz, da muss man halt den Prescaler auf 64
>> verringern, dann paßt es wieder
>
>>Jain, kann schon einige Dutzend Takte brauchen. Für dein
>>Ansteuerfrequenz von vielleicht 100 Hz ist das unkritisch.
>>
> ~4.5khz

Alles richtig, aber am Problem vorbei. Die 4,5kHz sind die maximale 
EINGANGSfrequenz am Arduino, welche vom Drehzahlsensor kommt.

Die 100 Hz von denen ich rede, ist die UPDATE-Frequenz für deine 
Drehzahlanzeige. D.h. die Umrechnung von Periode in RPM und den ganze 
Rest erfolgt nur mit 100 Hz, auch denn der Interrupt im Hintergrund mit 
bis zu 4,5kHz arbeitet. Wie wird deine Anzeige denn angesteuert?

> Falk B. schrieb:
>> Was ist dieses sq() Funktion? Die normale Wurzel heißt sqrt (Square
>> root, Quadratwurzel)
>
> Hab es genau andersrum erwartet. Hast Recht.

Erwartet? Schon mal was von RTFM gehört? Nein, das ist kein Oldiesender 
;-)

> Technische Verständnisfrage. Wenn der jetzt für die Wurzel länger zum
> Rechnen braucht, und von 'oben' kommt ein Interrupt rein, was macht dann
> der uC? Springt der zurück oder was?

Wohin denn zurück? Weißt du überhaupt, wie ein Interrupt 
funktioniert?
Deine Umrechnung von period in RPM etc. läuft im Hauptprogramm in einer 
Endlosschleife, sinnvollerweise noch etwas gedrosselt, damit die CPU 
nicht mit Maximalgeschwindigkeit da immer wieder durchrennt (das tut der 
zwar nicht weh, ist aber sinnlos und in bestimmten Konstellationen 
kontraproduktiv). Das Hauptprogramm kann jederzeit von einem Interrupt 
unterbrochen werden. Davon merkt es gar nichts und es wird auch nicht 
gestört, außer daß die Ausführung natürlich etwas länger dauert. Selbst 
wenn die Wurzelberechung ein paar Dutzend mal durch einen Interrupt 
unterbrochen werden sollte, so what!

> Darf man Dir eigentlich auch eine PN schreiben?

Darf man.

von Philipp G. (geiserp01)


Lesenswert?

Falk B. schrieb:
>> Darf man Dir eigentlich auch eine PN schreiben?
>
> Darf man.

Alles klar danke Dir Falk, ich baue das jetzt erstmal auf.

Bezüglich der PN, den letzten fanboy den ich angeschrieben habe meinte 
in einem lapidaren Ein, nein Halbzeiler dass keine Unterstützung per Pn 
möglich ist ;)

von Philipp G. (geiserp01)


Lesenswert?

update:

Mit einer EINGANGSFREQUENZ und serial.println funktioniert es bis 20kHz 
gut. Das habe ich eben mit dem Frequenzgenerator getestet.

von m.n. (Gast)


Lesenswert?

Philipp G. schrieb:
> Mit einer EINGANGSFREQUENZ und serial.println funktioniert es bis 20kHz

Und was ist mit Deiner eingangs formulierten Forderung von 165 kHz?
Die sind es ja nun bei weitem nicht.

von Philipp G. (geiserp01)


Lesenswert?

m.n. schrieb:
>> Mit einer EINGANGSFREQUENZ und serial.println funktioniert es bis 20kHz
>
> Und was ist mit Deiner eingangs formulierten Forderung von 165 kHz?
> Die sind es ja nun bei weitem nicht.

Ja, Gott sei Dank lag ich da weit daneben. Die Frequenz am Eingang wird 
max. bei 5kHz liegen.

von Dieter F. (Gast)


Lesenswert?

Cyblord -. schrieb:
> Das ist einer der Gründe warum man Kommentare in Quellcodes meiden
> sollte wie der Teufel das Weihwasser.

Der andere, wahre Grund ist "Arbeitsplatzsicherung" :-)

von Cyblord -. (cyblord)


Lesenswert?

Dieter F. schrieb:
> Cyblord -. schrieb:
>> Das ist einer der Gründe warum man Kommentare in Quellcodes meiden
>> sollte wie der Teufel das Weihwasser.
>
> Der andere, wahre Grund ist "Arbeitsplatzsicherung" :-)

Das ist natürlich eine Möglichkeit ;-)

Nein, der wirklich wahre Grund ist, dass jeder Kommentar dein Versagen 
dokumentiert, deine Intention an dieser Stelle verständlich in Code 
auszudrücken. Jeder Kommentar ist ein Eingeständnis des Scheiterns und 
sollte den bitteren Geschmack der Niederlage auf deiner Zunge 
hinterlassen.

von Philipp G. (geiserp01)


Lesenswert?

Lasst euch bloss nicht stören jungs.

von Falk B. (falk)


Lesenswert?

Cyblord -. schrieb:
> Falk B. schrieb:
>> Außerdem hast du einen Unterschied zwischen dein Formel im Kommentar und
>> im echten Code? Welche stimmt nun?
>
> Das ist einer der Gründe warum man Kommentare in Quellcodes meiden
> sollte wie der Teufel das Weihwasser.

Diese Aussage ist so allgemein Unsinn. Man muss REDUNDANTE, und sich 
damit tendentiell inkonsistente oder gar widersprüchliche Kommentare 
vermeiden. Wenn eine Variable einen passenden Namen hat, ist sie 
selbsterklärend und muss nicht kommentiert werden, dito bei Funktionen.

Strukturierte Programmierung auf Mikrocontrollern

von Falk B. (falk)


Lesenswert?

Cyblord -. schrieb:
> Nein, der wirklich wahre Grund ist, dass jeder Kommentar dein Versagen
> dokumentiert, deine Intention an dieser Stelle verständlich in Code
> auszudrücken. Jeder Kommentar ist ein Eingeständnis des Scheiterns und
> sollte den bitteren Geschmack der Niederlage auf deiner Zunge
> hinterlassen.

Unfug^3.

"Je genialer die Idee, um so nötiger der Kommentar."

Wenn gleich die Masse an Code sicher nicht genial ist sondern 
bestenfalls gut bis OK.

von Cyblord -. (cyblord)


Lesenswert?

Falk B. schrieb:
> Diese Aussage ist so allgemein Unsinn. Man muss REDUNDANTE, und sich
> damit tendentiell inkonsistente oder gar widersprüchliche Kommentare
> vermeiden.

Kommentare sind zu vermeiden u.a. weil sie schnell veralten. Sie werden 
nicht mit refaktoriert. Sie werden beim Kompilieren nicht überprüft. Sie 
stehen evt. ewig lange da und sind schon lange überholt. In praktisch 
jedem Projekt finden sich solche Leichen.

"Je genialer die Idee, um so nötiger der Kommentar."

Die Idee spielt keine Rolle, es kommt darauf an wie du dich in Code 
ausdrücken kannst. Dann ist es egal ob dein Code genial ist oder nicht.
Die Idee dahinter sollte man mit einem Blick auf den Code sehen. DANN 
erst kann man beurteilen ob die Idee jetzt OK oder Genial ist.

Der Kommentar ist eben nur die Krücke, weil du dich nicht in Code 
verständlich ausdrücken kannst, sondern wohl nur in Prosa. Vielleicht 
musst du das einfach üben anstatt die Prosa zu verteidigen.

Warum denkst du (als PROGRAMMIERER), Prosa sei grundsätzlich besser 
verständlich als der Code selbst? Das ist eine absurde These.

Wenn ich mich in Deutsch besser ausdrücken kann, als in Suaheli, liegt 
es dann an der Sprache oder an meinen Fähigkeiten?

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Cyblord -. schrieb:
> Falk B. schrieb:
>> Diese Aussage ist so allgemein Unsinn. Man muss REDUNDANTE, und sich
>> damit tendentiell inkonsistente oder gar widersprüchliche Kommentare
>> vermeiden.
>
> Kommentare sind zu vermeiden u.a. weil sie schnell veralten.

Kann sein, ist aber nicht algemeingültig. Aber OK, es stimmt schon, Code 
und Kommentar können auseinanderdriften, beides sychron zu halten ist 
ebenso aufwändig und unter Softwerkern unbeliebt wie echte Doku 
schreiben 8-0

> Sie werden
> nicht mit refaktoriert. Sie werden beim Kompilieren nicht überprüft.

Muss man auch nicht. Ein Kommentar ist ein Kommentar.

> Sie
> stehen evt. ewig lange da und sind schon lange überholt. In praktisch
> jedem Projekt finden sich solche Leichen.

Mag sein, ist aber kein zwingender Grund gegen Kommentare.

> "Je genialer die Idee, um so nötiger der Kommentar."
>
> Die Idee spielt keine Rolle, es kommt darauf an wie du dich in Code
> ausdrücken kannst. Dann ist es egal ob dein Code genial ist oder nicht.
> Die Idee dahinter sollte man mit einem Blick auf den Code sehen.

Nö, das geht schlicht nicht, zumindest nicht bei anspruchsvollerer und 
umfangreicher Software. Denn im Code steht bestenfalls WIE es gemacht 
wird, aber nie WARUM!!!

"Zusammenhänge dokumentieren. Die erschliessen sich nicht aus den paar 
Zeilen Code, auf die man gerade schaut!

Kommentare sollen die 'Warum'-Frage beantworten und nicht die 
'Wie'-Frage! Wie etwas gemacht wird, steht im Code. Aber dort steht 
nicht warum es gemacht wird."

Und nur weil viele Leute zu faul und disziplinlos sind, bei größeren 
Änderungen auch den Kommentar mitzuziehen, ist das kein ultimatives 
Argument gegen SINNVOLLE Kommentare!

von Philipp G. (geiserp01)


Lesenswert?

Falk B. schrieb:
> Nö, das geht schlicht nicht, zumindest nicht bei anspruchsvollerer und
> umfangreicher Software. Denn im Code steht bestenfalls WIE es gemacht
> wird, aber nie WARUM!!!

Genau das ist der Punkt. Schaut euch selber Codes an die ihr selber vor 
Jahren programmiert habt, sind alle les- und nachvollziehbar, aber WARUM 
macht er das? Ist doch gar nicht nötig. Dann reisst man alles 
auseinander im Sinne von ist nicht nötig und zwei Tage später folgt erst 
die Erkenntnis, warum es eben doch nötig war.

So geht es mir jedesmal (Ich rede jetzt nicht von uC Programmen sondern 
auf PC/.net/java/shell/etc).

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

Philipp G. schrieb:
> Genau das ist der Punkt. Schau euch selber Codes an die ihr vor Jahren
> programmiert habt, sind alle les- und nachvollziehbar, aber WARUM macht
> er das? Ist doch gar nicht nötig. Dann reisst man alles auseinander im
> Sinne von ist nicht nötig und zwei Tage später folgt erst die
> Erkenntnis, warum es eben doch nötig war.

Das liegt dann leider an deinem Code und nicht an der grunsätzlichen 
Ausdrucksschwäche von Quellcode.

Es reicht natürlich nicht, nur keine Kommentare zu schreiben. In erster 
Linie musst du den Code so schreiben, dass du keine Kommentare brauchst.

: Bearbeitet durch User
von Philipp G. (geiserp01)


Lesenswert?

Cyblord -. schrieb:
> Das liegt dann leider an deinem Code und nicht an der grunsätzlichen
> Ausdrucksschwäche von Quellcode.

Gutes Beispiel steht weiter oben. Warum teilt der durch 8 und 
multipliziert dann mal 11? na? Warum? Der Sensor gibt doch doch 1/8tel 
der Drehzahl raus.

Weil eben nirgendwo steht, dass der Turbo nun mal 11 Schaufeln hat. Das 
ist hier und jetzt jedem klar, nur nicht unbedingt in 5 Jahren.

Philipp G. schrieb:
> Gutes Beispiel steht weiter oben. Warum teilt der durch 8 und
> multipliziert dann mal 11? na? Warum? Der Sensor gibt doch doch 1/8tel
> der Drehzahl raus.
>
> Weil eben nirgendwo steht, dass der Turbo nun mal 11 Schaufeln hat. Das
> ist hier und jetzt jedem klar, nur nicht unbedingt in 5 Jahren.

Das ist Quatsch Cylord, reden wir mal von grösseren Software Projekten 
mit x Mitarbeitern und n Mitarbeiter. Du brauchst dazu eine lückenlose 
Doku, auch wenn das nur Kommentare sind.

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

Philipp G. schrieb:
> Cyblord -. schrieb:
>> Das liegt dann leider an deinem Code und nicht an der grunsätzlichen
>> Ausdrucksschwäche von Quellcode.
>
> Gutes Beispiel steht weiter oben. Warum teilt der durch 8 und
> multipliziert dann mal 11? na? Warum? Der Sensor gibt doch doch 1/8tel
> der Drehzahl raus.
>
> Weil eben nirgendwo steht, dass der Turbo nun mal 11 Schaufeln hat. Das
> ist hier und jetzt jedem klar, nur nicht unbedingt in 5 Jahren.

Und du bist der Meinung das könnte man nicht so hinschreiben dass man 
ohne Kommentar weiß was gemacht wird, und warum?

Nur weil ein C-Vollnoob (sorry) da oben irgendwas hinkritzelt, ist das 
jetzt der Beweis für die Notwendigkeit von Kommentaren?

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Cyblord -. schrieb:
> Philipp G. schrieb:
>> Cyblord -. schrieb:
>>> Das liegt dann leider an deinem Code und nicht an der grunsätzlichen
>>> Ausdrucksschwäche von Quellcode.
>>
>> Gutes Beispiel steht weiter oben. Warum teilt der durch 8 und
>> multipliziert dann mal 11? na? Warum? Der Sensor gibt doch doch 1/8tel
>> der Drehzahl raus.
>>
>> Weil eben nirgendwo steht, dass der Turbo nun mal 11 Schaufeln hat. Das
>> ist hier und jetzt jedem klar, nur nicht unbedingt in 5 Jahren.
>
> Und du bist der Meinung das könnte man nicht so hinschreiben dass man
> ohne Kommentar weiß was gemacht wird, und warum?

Na dann zeigt doch einfach mal, wie du das ohne Kommentare 
selbsterklärend aufschreiben würdest.

von Philipp G. (geiserp01)


Lesenswert?

Cyblord -. schrieb:
> Und du bist der Meinung das könnte man nicht so hinschreiben dass man
> ohne Kommentar weiß was gemacht wird, und warum?
>
> Nur weil ein C-Vollnoob da oben irgendwas hinkritzelt, ist das jetzt der
> Beweis für die Notwendigkeit von Kommentaren?

Was hast Du dagegen? Die werden nicht kompiliert, die brauchen keinen 
nennenswerten Platz, also schreiben wir doch Sensor Typ und Turbo 
einfach zu.

Das ist Quatsch Cylord, reden wir mal von grösseren Software Projekten
mit x Mitarbeitern und n Klassen. Du brauchst dazu eine lückenlose
Doku, auch wenn das nur Kommentare sind.

von Cyblord -. (cyblord)


Lesenswert?

Falk B. schrieb:
> Na dann zeigt doch einfach mal, wie du das ohne Kommentare
> selbsterklärend aufschreiben würdest.

Also bitte. Aber das ist doch eher trivial.

Ein Anfang wäre, das ganze in eine sinnige Funktion zu packen, z.B 
calculateRPM(). Mit passenden Parametern natürlich.
Das bringt erstmal dass, das ich um das Programm zu lesen und verstehen 
zu können, was passiert, die Formel gar nicht sehen muss. Die 
interessiert mich dafür nämlich gar nicht.

Dann in dieser Funktion NATÜRLICH errstmal die Konstanten benamen. Und 
die Variablen ebenfalls sinnvoller benamen.

Mehr braucht man ja gar nicht für eine popelige Funktion die eine 
Drehzahl berechnet.

> Was hast Du dagegen?

Habe ich schon ausgeführt.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Philipp G. schrieb:

> Was hast Du dagegen? Die werden nicht kompiliert, die brauchen keinen
> nennenswerten Platz, also schreiben wir doch Sensor Typ und Turbo
> einfach zu.
>
> Das ist Quatsch Cylord, reden wir mal von grösseren Software Projekten
> mit x Mitarbeitern und n Klassen. Du brauchst dazu eine lückenlose
> Doku, auch wenn das nur Kommentare sind.

Es gibt sogar Software wie doxygen, die aus Kommentaren eine schön 
lesbare, strukturierte Doku macht. Und der Kommentar im Quelltext ist 
DEUTLICH näher am realen Code und kann auch deutlich einfacher synchron 
gehalten werden als ein "weit entferntes" Word-Dokument.

von Philipp G. (geiserp01)


Lesenswert?

Ich denke Cylord meint in unserem Beispiel sowas hier:
1
// no comments at all from now on;)
2
cont int iTurboCompressorWheelBlades = 11;
3
cont int iSensorOutFreqDivider = 8;

Das mag für obigen Code besser ausehen, ja. Aber nicht für grössere 
Software Projekte. Da kommt man um Kommentare nicht umhin. Weil es für 
andere nachvollziehbar sein muss. Schon mal nur für ein Code Review, 
Security Audits, etc.

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

Philipp G. schrieb:

>
1
> // no comments at all from now on;)
2
> cont int iTurboCompressorWheelBlades = 11;
3
> cont int iSensorOutFreqDivider = 8;
4
>
>
> Das mag für obigen Code besser ausehen, ja.

Und warum hast du das dann nicht gleich so gemacht? Faul beim Coden, 
aber dann fleißig beim Kommentieren? Bist du Programmierer oder 
Schriftsteller?

Und es sieht nicht besser aus, es erklärt sich bereits selbst. Es gibt 
nicht um Ästhetik.
Und irgendwelche magic numbers sollten sowieso nirgendwo auftauchen.

> Aber nicht für grössere Software Projekte.

Ach in größere Softwareprojekte klatscht man unlesbaren Code und 
kommentiert dann aber um so mehr?
Komisch, bei meinen größeren Projekten bisher ging das alles sehr gut.

GERADE bei komplexer Software braucht man sauberen Code. Beim 100 Zeilen 
Tool ist im Zweifel alles egal.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Falk B. schrieb:

> "Je genialer die Idee, um so nötiger der Kommentar."

Es passiert wirklich selten, dass wir einer Meinung sind, aber hier sind 
wir uns einig.

Ein Kommentar ist genau dann nötig und wünschenswert, wenn er das 
Konzept des Codes dokumentiert oder ein spezielles, aus irgendwelchen 
Gründen trickreich gelöstes Detail (vom Würgaround um fremde Fehler 
[eigene behebt man natürlich] bis hin zu einer ungewöhnlichen 
Optimierung, die im allgemeinen Fall nur Schaden anrichten würde, aber 
im speziellen Fall den Unterschied zwischen "geht" und "geht nicht" 
ausmacht).

Ein Kommentar ist unnötig, wenn er nur in Prosa das wiedergibt, was 
links von ihm selber im Quelltext sowieso zu lesen ist. Wenn es denn zu 
lesen ist. Einige C/C++-Klartext-Verschlüssler finden es ja toll, wenn 
möglichst niemand versteht, was sie da hingeschrieben haben. Gerade die 
neigen allerdings dann auch eher nicht dazu, irgendwelche Kommentare 
hinzuzufügen.

Cyblord scheint mir ein recht sicherer Kandidat für diesen Schlag 
Programmierer zu sein...

von Dieter F. (Gast)


Lesenswert?

Cyblord -. schrieb:
> Der Kommentar ist eben nur die Krücke, weil du dich nicht in Code
> verständlich ausdrücken kannst, sondern wohl nur in Prosa. Vielleicht
> musst du das einfach üben anstatt die Prosa zu verteidigen.
>
> Warum denkst du (als PROGRAMMIERER), Prosa sei grundsätzlich besser
> verständlich als der Code selbst? Das ist eine absurde These.

Mal im Ernst: Nein.

Ein Kommentar soll nicht erklären, was getan wird (das genau tut der 
Code) sondern, warum es getan wird.

von Philipp G. (geiserp01)


Lesenswert?

doch weil
1
  rpm_1k = 10909 / get_period(); // atomic read access!!!

nicht klar ist, aus was sich obiger faktor zusammensetzt.

WIE rechnet er das ist klar, aber warum mit diesem Faktor?

Grad in diesem Moment, wo du das liest weißt du es auch nicht. Du weißt 
das erst, nachdem du nach oben scrollst und die Kommentare liest.

Klar was ich meine?

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

c-hater schrieb:
> Einige C/C++-Klartext-Verschlüssler finden es ja toll, wenn
> möglichst niemand versteht, was sie da hingeschrieben haben. Gerade die
> neigen allerdings dann auch eher nicht dazu, irgendwelche Kommentare
> hinzuzufügen.
>
> Cyblord scheint mir ein recht sicherer Kandidat für diesen Schlag
> Programmierer zu sein...

Sorry, ich propagiere hier gerade das exakte GEGENTEIL. Nämlich Code so 
zu schreiben dass er von vorn herein verständlich ist. Warum wird mir 
hier dann jetzt sowas unterstellt?

von Cyblord -. (cyblord)


Lesenswert?

Philipp G. schrieb:
> doch weil

Lerne mal zitieren. Niemand weiß auf was sich das beziehen soll.

von Cyblord -. (cyblord)


Lesenswert?

Dieter F. schrieb:
> Ein Kommentar soll nicht erklären, was getan wird (das genau tut der
> Code) sondern, warum es getan wird.

Warum erklärst du es nicht in Code? Warum beim coden irgendwas 
hinschludern um es dann durch einen Kommentar erklären zu müssen?

von c-hater (Gast)


Lesenswert?

Cyblord -. schrieb:

> Sorry, ich propagiere hier gerade das exakte GEGENTEIL. Nämlich Code so
> zu schreiben dass er von vorn herein verständlich ist. Warum wird mir
> hier dann jetzt sowas unterstellt?

Weil du Kommentare als generell unnütz dargestellt hast. Und weil genau 
das absolut typisches Verhalten gerade dieser Klartextverschlüssler ist. 
Ich bin seit 35 Jahren im Geschäft, ich kenne diese Typen nur zu gut...

von Dieter F. (Gast)


Lesenswert?

Cyblord -. schrieb:
> Warum erklärst du es nicht in Code?

Erkläre mal in Code, warum Du 0,175647 vom Sensor-Wert abziehst.

von Cyblord -. (cyblord)


Lesenswert?

Dieter F. schrieb:
> Cyblord -. schrieb:
>> Warum erklärst du es nicht in Code?
>
> Erkläre mal in Code, <b>warum</b> Du 0,175647 vom Sensor-Wert abziehst.

Das kommt darauf an warum du es tust.
Vielleicht wird es klar, wenn du  0,175647 erst mal ordentlich benennst?

z.B.
1
const double CALIBRATION_OFFSET=0.175647;
2
3
sensor_value-=CALIBRATION_OFFSET;

Ist doch völlig klar jetzt oder?

: Bearbeitet durch User
von Dieter F. (Gast)


Lesenswert?

Cyblord -. schrieb:
> Vielleicht wird es klar, wenn du  0,175647 erst mal ordentlich benennst?

Nö - dann schreibst Du vielleicht " - KorrekturFaktor"" aber kein Mensch 
weiß, welchen "KorrekturFaktor" und warum genau Du meinst.

von Dieter F. (Gast)


Lesenswert?

Cyblord -. schrieb:
> Ist doch völlig klar jetzt oder?

Nö - warum?

Zum Bleistift: "Korrekturfaktor ist erforderlich weil der Mond die Sonne 
verdeckt"

von Cyblord -. (cyblord)


Lesenswert?

Dieter F. schrieb:
> Cyblord -. schrieb:
>> Ist doch völlig klar jetzt oder?
>
> Nö - warum?

Du wenn ich mit bockigen Kindern diskutieren will brauch ich nicht hier 
her kommen. Entweder du diskutierst ordentlich oder wir lassen es. ja?

: Bearbeitet durch User
von Dieter F. (Gast)


Lesenswert?


von Cyblord -. (cyblord)


Lesenswert?

Dieter F. schrieb:
> Cyblord -. schrieb:
>> ja
>
> Ja

Sag gleich wenn du nur pöbeln willst. Dann verschwende ich meine Zeit 
nicht an dich.

von Dieter F. (Gast)


Lesenswert?

Cyblord -. schrieb:
> CALIBRATION_OFFSET=0.175647;

Damit kann doch kein Mensch etwas anfangen, wenn er nicht im Thema ist - 
oder?

Vergiss es - bleib in Deiner Welt. Wir werden uns (beruflich) sowieso 
nie begegnen :-)

von Cyblord -. (cyblord)


Lesenswert?

Dieter F. schrieb:
> Cyblord -. schrieb:
>> CALIBRATION_OFFSET=0.175647;
>
> Damit kann doch kein Mensch etwas anfangen, wenn er nicht im Thema ist -
> oder?

Sorry. Ich denke wir sind fertig hier.

von Dieter F. (Gast)


Lesenswert?

Cyblord -. schrieb:
> Sorry. Ich denke wir sind fertig hier.

Full ack :-) - wie immer

Da fällt mir direkt der blöde Hierarchie-Spruch "Information ist eine 
Hol-Schuld" ein ...

von Philipp G. (geiserp01)


Lesenswert?

Philipp G. schrieb:
> doch weil   rpm_1k = 10909 / get_period(); // atomic read
> access!!!
>
> nicht klar ist, aus was sich obiger faktor zusammensetzt.
>
> WIE rechnet er das ist klar, aber warum mit diesem Faktor?
>
> Grad in diesem Moment, wo du das liest weißt du es auch nicht. Du weißt
> das erst, nachdem du nach oben scrollst und die Kommentare liest.
>
> Klar was ich meine?

du hast meine Frage nicht beantwortet cylord

von Cyblord -. (cyblord)


Lesenswert?

Philipp G. schrieb:
> Philipp G. schrieb:
>> doch weil   rpm_1k = 10909 / get_period(); // atomic read
>> access!!!
>>
>> nicht klar ist, aus was sich obiger faktor zusammensetzt.
>>
>> WIE rechnet er das ist klar, aber warum mit diesem Faktor?
>>
>> Grad in diesem Moment, wo du das liest weißt du es auch nicht. Du weißt
>> das erst, nachdem du nach oben scrollst und die Kommentare liest.

Jetzt mal langsam. Erst mal gehört das ordentlich in eine Funktion 
gekapselt.
z.B.
1
int calculateRPM(int period);

Dann wird beim ersten lesen klar was hier gemacht wird. Das WARUM ist 
hier automatisch drin. Wobei der Funktionsname noch enthalten sollte von 
WAS hier genau die RPM gemessen wird. Außer die Funktion ist generisch. 
Dann sollte das in der aufrufenden Funktion aber stehen.

Wir abstrahieren hier also erst mal über die Details WIE GENAU von der 
Periode (evt. besser benamen!) die RPM berechnet werden.
Das ist nämlich für einen Betrachter erst mal völlig irrelevant für das 
Verständnis des Codes.

Nun innerhalb der Funktion calculateRPM kann man alle Konstanten 
sinnvoll benennen. Mehr macht dann aber auch keinen Sinn mehr. Man muss 
dabei nicht überdrehen.
Berechnet diese Funktion tatsächlich eine bestimmte Formel, und ist man 
der Meinung das kann man einfach partout nicht schön darstellen, dann 
kann natürlich ein Kommentar hergenommen werden. Das ist ja keine 
Religion.

Wie ich Eingangs bereits andeutete, Kommentare lassen sich manchmal 
nicht vermeiden. Wichtig ist das entsprechende "Mindset" dass es immer 
besser wäre, ohne Kommentar auszukommen.

: Bearbeitet durch User
von Philipp G. (geiserp01)


Lesenswert?

Dieter F. schrieb:
>> CALIBRATION_OFFSET=0.175647;
>
> Damit kann doch kein Mensch etwas anfangen, wenn er nicht im Thema ist -
> oder?

Wenn ich Jahre später die Hardware oder sonstwas anpassen muss, muss ich 
wissen wie sich der Korrektur Faktor zusammensetzt. Ein Kommentar wäre 
hilfreich.
1
rpm_1k = 10909 / get_period(); // atomic read
2
>> access!!!

Nochmal, obiger Faktor setzt sich wie folgt zusammen:
1
  // rpm [RPM] = 1/period[s]/11*60*8              // basic formula
2
  // rpm [RPM] = 1/(period[cnt]*4us)/11*60*8      // basic formula using counter result and counter clock
3
  // rpm [1000RPM] = 250e3/period[cnts]/11*60*8/1000  // result in units of 1000 RPMs
4
  // rpm [1000RPM] = 10909 / period [cnts]
5
  rpm_1k = 10909 / get_period(); // atomic read access!!!

Erst nachdem ich die Kommentare weggelassen habe, war unklar was mit 
10909 gemeint ist. Merkst Du was?

Cyblord -. schrieb:
> Wir abstrahieren hier also erst mal über die Details WIE GENAU von der
> Periode (evt. besser benamen!) die RPM berechnet werden.

Gut. Dann würdest Du das also so machen?
1
rpm_1k = 1/ get_period() / 11 * 60 * 8;

Dann rechne ich doch lieber mit dem Faktor und schreibe die 
Zusammensetzung als Kommentar dazu. Klar was ich meine?

: Bearbeitet durch User
von Dieter F. (Gast)


Lesenswert?

Philipp G. schrieb:
> Merkst Du was?

Meinst Du mich? Dann lies den Thread bitte nochmal richtig.

von Philipp G. (geiserp01)


Lesenswert?

Dieter F. schrieb:
> Philipp G. schrieb:
>> Merkst Du was?
>
> Meinst Du mich? Dann lies den Thread bitte nochmal richtig.

Nein, ich meine den Cylord, nicht Dich ;) Ich bin der TO, ich kenne den 
Thread daher bestens.

von Cyblord -. (cyblord)


Lesenswert?

Philipp G. schrieb:
> Wenn ich Jahre später die Hardware oder sonstwas anpassen muss, muss ich
> wissen wie sich der Korrektur Faktor zusammensetzt. Ein Kommentar wäre
> hilfreich.

In diesem völlig frei erfundenen Beispiel wäre der Korrekturfactor eben 
eine Konstante aus dem Datenblatt. Kein Ergebniss einer Berechnung.

Es kommt schon auf den Kontext an um zu entscheiden wie man am besten an 
die Sache ran geht.


> Gut. Dann würdest Du das also so machen?
>
1
> rpm_1k = 1/ get_period() / 11 * 60 * 8;
2
>

Ne würde ich nicht.
Was ist 11, 60 und 8?

Kurz: Benenne die Konstanten sinnvoll und packe die Berechnung in eine 
ebenfalls sinvoll benannte Funktion. Damit hast du mindestens 99% 
Dokumentiert. Falls dann WIRKLICH noch Bedarf für die 1% ist reden wir 
weiter.

> Dann rechne ich doch lieber mit dem Faktor
Bringt welchen Vorteil? Einfach eine Zahl im Code (Magic Number) sollte 
man vermeiden.

> und schreibe die
> Zusammensetzung als Kommentar dazu.
Hat keinen Vorteil. Aber z.B. den Nachteil dass eine Änderung der Formel 
auch mal ohne Änderung des Kommentars erfolgen kann, wobei der Kommentar 
dann irreführend wird.
Nutzt du den Code gleichzeitig zur Dokumentation, ist diese immer up to 
date.

> Klar was ich meine?
Klar. Halte ich nur für die falsche Lösung.

: Bearbeitet durch User
von Philipp G. (geiserp01)


Lesenswert?

Cyblord -. schrieb:
>> Dann rechne ich doch lieber mit dem Faktor
> Bringt welchen Vorteil? Einfach eine Zahl im Code (Magic Number) sollte
> man vermeiden.

Weil der dann jede x us dasselbe rechnet, was man sich durch die 
Faktorisierung sparen könnte und stattdessen einen Kommentar dazu 
schreibt, wie sich die magic number zusammensetzt, anstatt:

magic = sq(rpm / 60 * 33 / 6.4223 * (200080 - 200203) + 11 - 3);

Mit diesen Zahlen kann ich genauso wenig anfangen. Wenn ich raten 
müsste, könnte ich höchstens mir vorstellen dass die 60 was mit Sekunden 
oder Minuten zu tun haben könnte, der Rest ist Glaskugel.

Wenn ich dich richtig verstanden habe, möchtest du stattdessen

rpm_1k =  iFullSecond / get_period() / iCompressorWheelBlades * 
iSecondsperMinute * iFreqDividerSensor;

sehen.

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

Philipp G. schrieb:
> Wenn ich dich richtig verstanden habe, möchtest du stattdessen
>
> rpm_1k =  iFullSecond / get_period() / iCompressorWheelBlades *
> iSecondsperMinute * iFreqDividerSensor;

Damit wären zumindest die Bestandteile der Formel ohne jeden Kommentar 
dokumentiert.

Zusätzlich kannst du die Konstanten auch noch komfortabel anpassen, 
falls nötig. Ohne dir jedes mal zu überlegen welche Zahl jetzt was genau 
bedeutet hat.

Wenn das ganze jetzt in der Funktion calculateCompressorRPM() steckt, 
dann weiß ich doch sofort was hier passiert. Beim überfliegen. Wobei mir 
da die konkrete Formel erst mal egal ist, aber auch wenn ich dann auf 
die Formel schauen möchte, sehe ich sofort was ungefähr gerechnet wird.

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Philipp G. schrieb:
> Mit diesen Zahlen kann ich genauso wenig anfangen. Wenn ich raten
> müsste, könnte ich höchstens mir vorstellen dass die 60 was mit Sekunden
> oder Minuten zu tun haben könnte, der Rest ist Glaskugel.
>
> Wenn ich dich richtig verstanden habe, möchtest du stattdessen
>
> rpm_1k =  iFullSecond / get_period() / iCompressorWheelBlades *
> iSecondsperMinute * iFreqDividerSensor;
>
> sehen.

na dann könnte man ja auch den pre rechnen lassen
1
#define SCHAUFEL_UPM_KONST (11 * 60 * 8)
2
rpm_1k = SCHAUFEL_UPM_KONST / get_period(); // atomic read access!!!
Beitrag "Re: rechnet der preprocessor in C gcc (AVR) multiplikation aus?"

und hier macht es sogar der gcc
1
const uint16_t schaufel_upm_const = 11 * 60 * 8;
2
rpm_1k = schaufel_upm_const / get_period(); // atomic read access!!!

: Bearbeitet durch User
von Philipp G. (geiserp01)


Angehängte Dateien:

Lesenswert?

Falk mein Guter, irgendwo haben wir uns verrechnet.

Es funktioniert nicht. Aufbau:

Input_freq_generated: 1kHz
Input_freq_measured: 1kHz
Display: 87k (87'000 U/min)


Nach meiner Rechnung sollte es grad die Hälfte sein:

RPM = 480 * (Freq_OUT[Hz] / compressorwheelcount

RPM = 480 * (1000 / 11)

RPM = 43'636 was falsch ist.

* 2 multipliziert stimmt es aber genau. Was habe ich falsch gemacht? Wir 
messen ja die volle Periodendauer, ich komme grad nicht dahinter.

Anbei nochmal der Code:
1
// Definition of interrupt names
2
3
// LED connected to digital pin 13
4
int ledPin = 13;
5
// This is the INT0 Pin of the ATMega8
6
int sensePin = 2;
7
// We need to declare the data exchange
8
// variable to be volatile - the value is
9
// read from memory.
10
volatile uint16_t period = 0;
11
12
// Install the interrupt routine.
13
ISR(INT0_vect) {
14
    static uint16_t time_last;
15
    uint16_t time_now; 
16
17
    time_now = TCNT1;
18
    period = time_now-time_last;
19
    time_last = time_now;
20
}
21
22
// atomic read access
23
24
uint16_t get_period(void) {
25
    uint16_t tmp;
26
27
    cli();
28
    tmp = period;
29
    sei();
30
    return tmp;
31
}
32
33
void setup() {
34
  Serial.begin(9600);
35
  Serial.println("Initializing ihandler");
36
  // sets the digital pin as output
37
  pinMode(ledPin, OUTPUT);
38
  // read from the sense pin
39
  pinMode(sensePin, INPUT);
40
  Serial.println("Processing initialization");
41
  // Global Enable INT0 interrupt on rising edge
42
  EICRA = (1<<ISC10) | (1<<ISC00);
43
  EIMSK |= (1<<INT0);
44
  // init timer 1, mode 0, prescaler 64, 250kHz timer clock
45
  TCCR1A = 0;
46
  TCCR1B = (1<<CS11) | (1<<CS10);
47
  Serial.println("Finished initialization");
48
}
49
50
void loop() {
51
  uint16_t rpm_1k;
52
 
53
  // rpm [RPM] = 1/period[s]/11*60*8              // basic formula
54
  // rpm [RPM] = 1/(period[cnt]*4us)/11*60*8      // basic formula using counter result and counter clock
55
  // rpm [1000RPM] = 250e3/period[cnts]/11*60*8/1000  // result in units of 1000 RPMs
56
  // rpm [1000RPM] = 10909 / period [cnts]
57
  rpm_1k = 10909 / get_period(); // atomic read access!!!
58
  // do something with rpm
59
}

: Bearbeitet durch User
von Philipp G. (geiserp01)


Angehängte Dateien:

Lesenswert?

Es gibt News. Der obige Code funktioniert nicht mit dem Sensor, wohl 
aber mit dem FG (Bilder siehe ein Post vorher).

Das Tastverhältnis ist jenseits von 50/50, der Impuls ist zu schmal, so 
meine Vermutung. Was eigentlich keine Rolle spielen sollte wenn der die 
gesamte Periodendauer messen sollte.

Aber von vorne:

Erstmal habe ich versucht, einen geeigneten Testaufbau zu machen um dem 
Sensor Signale zu entlocken.

Erster Versuch:

Eine gedruckte Platte mit 4 Gewindestäbe drin. Interessant hierbei war, 
dass der Dremel massive Störungen verursacht, Kollektorfeuer oder die 
PWM Ansteuerung. fail01.

Zweiter Versuch:

Gedrehte und gefräste Platte mit 11 'Schaufeln'. Keine Wirkung, lag aber 
evtl. auch daran, dass die Drehbank nicht schneller als 1300U/min dreht. 
fail02.

Dritter Versuch:

Einen echten Turbo aus dem Lager genommen und den Sensor behelfsmässig 
am Eingang angeschlossen, da dieser Turbo von Haus aus keine Aufnahme 
für den Speedsensor hat. Funktioniert auf dem DSO perfekt.

Leider nicht mit dem Code: Der gibt nur 0 oder 30 aus, und das 
unabhängig der Drehzahl vom Turbo. -> result01.jpg

Auf dem DSO, max 120Hz:
https://www.youtube.com/watch?v=_UvA7HQ0pzg

Auf dem DSO, max 189Hz:
https://www.youtube.com/watch?v=Rcma4bJRmx4

-> Die Impulsbreite ist immer 120us lang.

[Hinweis zu den Videos: Mir ist während der Aufnahme versehentlich die 
Masseklemme abgerutscht, daher das Rauschen]

Ich fand hier sprechender, Videos zu machen als Bilder. Mehr Speed 
wollte ich dem Turbo ohne die Öldruckversorgung nicht zumuten.

Evtl. hat jemand von euch eine Idee.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Mein Fehler

Das hier stimmt NICHT!
1
  // Global Enable INT0 interrupt on rising edge
2
  EICRA = (1<<ISC10) | (1<<ISC00);

eher so!
1
  // Global Enable INT0 interrupt on rising edge
2
  EICRA = (1<<ISC01) | (1<<ISC00);

Durch den Fehler wurde INT0 auf "any edge" konfiguriert und dadurch mißt 
dein Interrupt immer den Abstand zwischen aufeinanderfolgenden Flanken 
und NICHT von steigender zu steigender! Damit ist die gemessene Frequenz 
in deinem Test doppelt so hoch wie real.

von Philipp G. (geiserp01)


Lesenswert?

Falk B. schrieb:
> Durch den Fehler wurde INT0 auf "any edge" konfiguriert und dadurch mißt
> dein Interrupt immer den Abstand zwischen aufeinanderfolgenden Flanken
> und NICHT von steigender zu steigender! Damit ist die gemessene Frequenz
> in deinem Test doppelt so hoch wie real.

Dank Dir Falk.

Das erklärt jetzt auch das Verhalten im vorher beschriebenen Post?

von Falk B. (falk)


Lesenswert?

Philipp G. schrieb:
> Dank Dir Falk.
>
> Das erklärt jetzt auch das Verhalten im vorher beschriebenen Post?

Ja klar. Nimm mal die noch nicht korrigierte Software und stell mal 25% 
Tastverhältnis am Funktionsgenerator ein. Dann pendelt deine Anzeige 
auch zwischen dem vierfachen und 1,5 fachen Wert.

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
Noch kein Account? Hier anmelden.