Forum: Mikrocontroller und Digitale Elektronik AVR Frequenzmessung, DS18S20


von Luggi F. (luggi_f)


Angehängte Dateien:

Lesenswert?

Hallo!

Seit einigen Jahren lese ich schon hier mit, jetzt mal meine erste 
eigene Frage. Zuerst ein paar Zeilen zum Projekt (Probleme im nächsten 
Absatz): Ich arbeite gerade an einem Stromaggregat (12kW), das aus einem 
alten Dieselmotor und einem neuen Drehstromgenerator entsteht. Die 
Steuerung soll stark automatisiert sein, also mit automatischem 
Start/Stop, Strom-/Spannungs-/Frequenzüberwachung und -nachregelung. 
Dazu sind 3 AVRs verbaut, als Haupt-Controller ein Arduino Mega2560, zum 
Messen ein Atmega8 per TWI eingebunden, zur Gassteuerung mit 
Schrittmotor ein weiterer Atmega8 per UART eingebunden.

So, zum Problem Nr. 1: Der Mess-uC (Mega8) misst mittels Input Capture 
am Timer 1 die "Netz"-Frequenz. Dazu wird die Spannung über einen 
Printtrafo auf 9V RMS heruntergespannt, mit Diode einweg-gleichgerichtet 
und mit Spannungsteiler auf knappe 5V gebracht. Das klappt soweit super 
(Frequenz ändert sich bei Drehzahländerung), aber als Ergebnis bekomme 
ich immer etwa 1Hz zu wenig heraus!! Wenn ich das Teil also an die 
Steckdose hänge, zeigt es ca. 48,9 Hz an und das ist meiner Meinung 
nicht normal, oder? Im Moment zähle ich immer 1 Hz dazu... Auszug aus 
"Netzmessung_TWI.cpp":
1
ISR(TIMER1_CAPT_vect)
2
{
3
  icr_ovf_tmp = icr_ovf;  //Variable temporär laden, da diese sich durch Interrupt ändern kann!
4
  icr_ovf = 0;
5
  icr_new = ICR1;
6
  
7
  icr_diff = (icr_new + (ICR_TOP * icr_ovf_tmp)) - icr_old;  
8
        //Letzte "+0.5" ist nur WORKARAOUND UM PROBLEM!
9
  freq = (0.5*freq) + 0.5*((F_CPU/8.0)/icr_diff)+0.5;  //Prescaler:8 und Verlauf glätten
10
  
11
  icr_old = icr_new;
12
}
13
14
ISR(TIMER1_OVF_vect)
15
{
16
  icr_ovf++; //Zähler erhöhen wenn Overflow Interrupt ausgelöst hat
17
}

Problem 2 ist eher einfacher: Es werden 3 Temperaturen über DS18S20 
Temperatursensoren (1-wire) gemessen. Dazu wird mittels mehreren Timer 
Compares zuerst die Umrechnung in den Sensoren gestartet und danach die 
Temperatur ausgelesen. In der Setup-Funktion wird sicherheitshalber eine 
Umrechnung gestartet, da sonst nur 85°C ausgegeben wird. Allerdings 
funktioniert genau das bei mir nicht. Egal was ich versuche, beim ersten 
Auslesen wird immer 85°C zurückgegeben (ist für mich problematisch). Ich 
habe auch schon versucht, die Timer Compares zu vertauschen, hat aber 
nichts gebracht. Im Moment umgehe ich das Problem, indem ich alle Werte 
vor dem ersten von 85 verschiedenen ignoriere. Auszug aus 
"Aggregat_v2.c":
1
void setup()
2
{
3
 //.......
4
    //Libraries "starten"
5
    lcd.begin(20, 4);   //LCD
6
    sensors_temp.begin();   //Temperatursensoren
7
    sensors_temp.setWaitForConversion(FALSE);   //nicht auf sensoren warten
8
    sensors_temp.requestTemperatures(); //Erste Temperatur Umrechnung starten ("Warmlaufen")
9
 //.......
10
    //Timer3 setup
11
    TCCR3A = 0x00;
12
    TCCR3B = (1<<WGM32) | (1<<CS32) | (1<<CS30);    //CTC Mode, Prescaler 1024
13
    OCR3A = 0xffff;     //ca. alle 4.2s, hier Überlauf
14
    OCR3B = 2*OCR3A/3;    //Auch alle 4.2s, aber versetzt
15
    OCR3C = OCR3A/3;    //Auch alle 4.2s, aber versetzt
16
    TIMSK3 |= (1 << OCIE3A);    //Int A aktivieren
17
    TIMSK3 |= (1 << OCIE3B);    //Int B aktivieren
18
    TIMSK3 |= (1 << OCIE3C);    //Int C aktivieren
19
 //.........
20
}
21
22
ISR (TIMER3_COMPC_vect)
23
{
24
    //HIER WORKAROUND, normal ohne "temp_buf" und "temps_ready"!
25
    int16_t temp_buf;
26
    //Temperaturen über 1wire auslesen
27
    temp_buf = sensors_temp.getTempC(ADDR_TEMP1);    //Motor
28
    if(temp_buf != 85 || temps_ready != 0)
29
    {
30
        stat_temp1 = temp_buf;                             //Motor
31
        stat_temp2 = sensors_temp.getTempC(ADDR_TEMP2);    //Kühler
32
        stat_temp3 = sensors_temp.getTempC(ADDR_TEMP3);    //Generator
33
        temps_ready = 1;
34
    }
35
}
36
37
ISR (TIMER3_COMPB_vect)
38
{
39
40
    sensors_temp.requestTemperatures(); //Temperatur Umrechnung starten
41
42
}
43
44
ISR (TIMER3_COMPA_vect)
45
{
46
    //Tankfüllstand messen
47
    measurement_fuel();
48
49
    //LCD neu initialisieren, falls Spannungsschwankungen auftraten
50
    lcd.begin(20, 4);   //LCD
51
    lcd_write();
52
}

Grüße, Luggi

von Lurchi (Gast)


Lesenswert?

Einen systematischen Fehler, der eine konstant zu große Frequenz gibt 
kann ich in der Frequenzmessung nicht finden. Allerdings ist bei dem 
Programm mit gelegentelichen falschen Werten (ein Overflow zu wenig) zu 
rechnen, weil der Fall von fast gleichzeitigem ICP und Overflow 
interrupt nicht berücksichtigt wird. Sofern man keine sehr hohe 
Auflösung braucht, könnte man ggf. über den divider dafür sorgen, dass 
man keinen Overflow hat.

Systematische Fehler kann man ggf. beim µC takt rein bekommen - der 
interne Takt kann schon mal 1-2 % daneben liegen.
Eventuell könnten auch die anderen Interrupts die Messung der Frequenz 
stören, weil durch eine zu lange ISR ggf. ein Overflow verloren geht. 
Insbesondere so etwas wie die LCD Ausgabe oder das Auslesen von Werten 
über das 1 Wire interface sollte eher nicht in eine ISR Routine. Dies 
sollte aber höchstens zu kurze Zeiten und damit eine zu hohe Frequenz 
verursachen.

von Steffen (Gast)


Lesenswert?

Ludwig F. schrieb:
> Egal was ich versuche, beim ersten
> Auslesen wird immer 85°C zurückgegeben (ist für mich problematisch).

Wenn ich mich recht erinnere ist das normal, die erste Messung verwerfe 
ich auch in dem ich das direkt nach der Initialisierung lese.

von Luggi F. (luggi_f)


Lesenswert?

Danke für die Antworten!

Ein Overflow bei der Frequenzmessung ist recht unwahrscheinlich (erst 
unter 15Hz), aber Danke für den Hinweis auf das unbehandelte Problem!

Mit den anderen Interrupts hat das nichts zu tun, läuft ja auf 2 
verschiedenen uCs (jede angehängte Datei auf einem).

Aber das mit dem CPU-Takt ist wohl der Schlüssel zur Sache, hab keinen 
externen Quarz verwendet und 2% Abweichung trifft die Sache ziemlich 
genau auf den Punkt. Mal sehen, was passiert wenns warm wird...

Zur Temperaturmessung: Ich dachte, die erste Messung muss ich nur 
verwerfen, wenn ich zuvor noch keine Umrechnung angefragt habe? Genau 
das tu ich ja nach der Initialisierung! Eigentlich möchte ich in der 
Initialisierung nicht abwarten bis alle Sensoren fertig gerechnet haben 
und die dann auch noch auslesen.
Bei mir läuft das ja etwa so:

(Speicher im DS12S20 = 85°C)
-> Befehl "Umrechnen!"
....ca.1,4s warten
(Speicher im DS18S20 sollte jetzt Temperatur enthalten)
-> Befehl "Sende Speicher!"
-> empfange trotzdem 85°C ????

Wenn ich jetzt den ersten Befehl "Umrechnen!" nicht habe, ist schon 
klar, dass ich die 85 empfange, aber warum ist das bei mir so??

von Veit D. (devil-elec)


Lesenswert?

Hallo,

85°C Ausgabe ist nicht normal. Das ist eine Art Fehlercode. Ich hoffe 
die DS18S20 sind nicht parasitär versorgt sondern ordentlich mit 5V.

Den 4,7k haste auch richtig drin?

Warum verwendest Du Interrupts für die Temperaturmessung? Die Arduino 
Lib braucht das nicht. Die Wartezeiten von 750ms hälst Du auch ein? Ich 
sehe auch keine Definition der Sensoren auf 9Bit.

Ist das Deine Lib?
http://milesburton.com/Main_Page?title=Dallas_Temperature_Control_Library

Guck Dir nochmal das Bsp. "WaitForConversion 2" an.

: Bearbeitet durch User
von Luggi F. (luggi_f)


Lesenswert?

Hallo!

Veit D. schrieb:
> 85°C Ausgabe ist nicht normal. Das ist eine Art Fehlercode. Ich hoffe
> die DS18S20 sind nicht parasitär versorgt sondern ordentlich mit 5V.
Die 85°C werden genau dann ausgegeben, wenn vorher noch kein Wert vom 
DS18S20 in den Speicher "berechnet" wurde. Die lib gibt als "Fehler" 
-127 zurück.
Ja, Stromversorgung und 4k7 sind da. Die Sensoren funktionieren ja auch!

> Warum verwendest Du Interrupts für die Temperaturmessung? Die Arduino
> Lib braucht das nicht. Die Wartezeiten von 750ms hälst Du auch ein? Ich
> sehe auch keine Definition der Sensoren auf 9Bit.
>
> Ist das Deine Lib?
> http://milesburton.com/Main_Page?title=Dallas_Temperature_Control_Library
>
> Guck Dir nochmal das Bsp. "WaitForConversion 2" an.
Ja, das ist meine Library. Beispiel angeschaut.
Die Sensoren muss man nicht auf 9 Bit einstellen, das ist Standard. 
Genau diese 750ms sind der Knackpunkt. Eigentlich werden meine 3 Timer 
Compares nur versetzt alle 4,2s ausgeführt, somit kommt der erste 
Interrupt erst 1,4s nach der Initialisierung (in der das erste 
"requestTemperatures" steht).
Mit Interrupts läuft das eigentlich nur, um Rechenzeit zu sparen und die 
Temperaturen nicht in jeder Hauptschleife abzufragen. Vielleicht sollte 
ich das tatsächlich ändern und einfach in jeder Schleife 
"isConversionComplete()" fragen und einfach öfter auslesen. Auch wenn 
ich nicht so viele Werte brauche.

von Wolfgang (Gast)


Lesenswert?

Veit D. schrieb:
> Das ist eine Art Fehlercode. Ich hoffe die DS18S20 sind nicht parasitär
> versorgt sondern ordentlich mit 5V.

Warum hoffst du das? Was hast du gegen eine parasitäre Versorgung? 
Kennst du den Chip besser als der Hersteller?

von Michael U. (amiga)


Lesenswert?

Hallo,

ich hätte aus reinem Interesse eine Frage: soviel Aufwand für einen 
Generatur?
Frequenz wäre bei mir ein Vorwiderstand, ein Optokoppler mit 
anti-paraller Diode direkt an einer Phase. Temperatur hätte ich 
vermutlich NTC genommen, der interessante Temperaturbereich ist relativ 
klein, eine Linearisierung kein damit kein wirkliches Problem und 1-2 
Grad Abweichung dürften uninteressant sein. Schrittmotorsteuerung ist 
auch keine Hexerei.
Alles läuft für einen µC doch sehr gemächlich ab, thermische und 
mechanische Trägheit sorgen doch dafür daß man ausreichend Rechenzeit 
hat.
Eigentlich sollte das doch ein einzelner ATMega 328 schon packen?

Oder liege habe ich etwas wesentliches übersehen?

Gruß aus Berlin
Michael

von Veit D. (devil-elec)


Lesenswert?

Hallo,

der Standard 9 Bit kommt laut meines Wissens darauf an wie man die Lib 
verwendet. Eigentlich sollte man das angeben.
1
sensors.begin();
2
// set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
3
sensors.setResolution(sensor1, 9); 
4
sensors.setResolution(sensor2, 9);
5
sensors.setResolution(sensor3, 9);
6
sensors.setWaitForConversion(false);  // makes it async

Die 750ms sind die Mindestwartezeit zwischen Request und auslesen. Nach 
dem auslesen kannst Du sofort wieder einen Request ausgeben.

Wenn ich Dich jetzt richtig verstehe, kommt der Fehler zu stande, weil 
du zu Beginn erst ausliest und dann einen Request schickst. Warum machst 
du das dann? Genau das funktioniert nicht. Spannung einschalten oder 
Reset oder was auch immer, erst Request, warten, auslesen. Die Zeit von 
750ms mußte einfach haben. Anders funktioniert das nicht. Oder Du nimmst 
die DS18B20, die benötigen in 9 Bit nur 95ms.

von Veit D. (devil-elec)


Lesenswert?

Wolfgang schrieb:
> Veit D. schrieb:
>> Das ist eine Art Fehlercode. Ich hoffe die DS18S20 sind nicht parasitär
>> versorgt sondern ordentlich mit 5V.
>
> Warum hoffst du das? Was hast du gegen eine parasitäre Versorgung?
> Kennst du den Chip besser als der Hersteller?

Hallo,

weil viele Problem mit der Spannungsversorgung zusammenhängen. Also wenn 
man nicht unbedingt den einen Draht sparen muß, dann zieht man den mit. 
Ich habe ein Netzwerkkabel verwendet für meine 3 Sensoren und keinerlei 
Probleme.

von Luggi F. (luggi_f)


Lesenswert?

Michael U. schrieb im Beitrag #4276593
> Frequenz wäre bei mir ein Vorwiderstand, ein Optokoppler mit
> anti-paraller Diode direkt an einer Phase.

Da ist es deswegen Trafo und uC, weil der außerdem noch Spannung, Ströme 
und Phasenwinkel berechnen muss. Das Ganze noch über mehrere Perioden 
und schon dauert eine Messung eine knappe Sekunde.

> Temperatur hätte ich
> vermutlich NTC genommen

Naja, Geschmackssache, oder? Die 3 Sensoren liegen doch etwas 3m (kabel) 
entfernt und mehr Aufwand sind die digitalen sensoren ja auch nicht.

> Schrittmotorsteuerung ist
> auch keine Hexerei.

Ok, das hätte man auch integrieren können, war bei mir aber erst 
variante 2, da hats vom platz her so besser gepasst. Und eine 
Treiberplatine brauchts eh, da hab ich halt den mega auch noch 
draufgelötet.

> Alles läuft für einen µC doch sehr gemächlich ab, thermische und
> mechanische Trägheit sorgen doch dafür daß man ausreichend Rechenzeit
> hat.

Naja, es kommen auch einige Kleinigkeiten dazu. Es ist eine 
Fernbedienung per rs232 geplant, andauernd werden alle werte überwacht 
und auch entsprechend am gas nachgeregelt. Außerden bin ich nicht soo 
fit, was optimierung auf rechenzeit angeht...

von Luggi F. (luggi_f)


Lesenswert?

Veit D. schrieb:
> Hallo,
>
> der Standard 9 Bit kommt laut meines Wissens darauf an wie man die Lib
> verwendet. Eigentlich sollte man das angeben.

Also in dem Beispiel auf der Seite der Library (dein Link vorhin) ist 
das auch nicht gemacht mit dem Hinweis, dass 9 bit Standard ist. Ich 
kann das ja mal ins TODO aufnehmen...

> Die 750ms sind die Mindestwartezeit zwischen Request und auslesen. Nach
> dem auslesen kannst Du sofort wieder einen Request ausgeben.
>
> Wenn ich Dich jetzt richtig verstehe, kommt der Fehler zu stande, weil
> du zu Beginn erst ausliest und dann einen Request schickst. Warum machst
> du das dann? Genau das funktioniert nicht. Spannung einschalten oder
> Reset oder was auch immer, erst Request, warten, auslesen. Die Zeit von
> 750ms mußte einfach haben. Anders funktioniert das nicht. Oder Du nimmst
> die DS18B20, die benötigen in 9 Bit nur 95ms.

Nein, ich warte eben vor der Ausführung ca. 1,4 s, da bereits nach dem 
Initialisieren ein request steht und der erste Timer comp. Interrupt 
(mit dem get) nach ca. 1,4s kommt.
Oder verstehe ich bei meinen Timern was falsch, Der läuft doch bei 0 
los, dann kommt nach 1,4s COMPC_vect, dann nach 1,4s COMPB_vect, und 
nach weiteren 1,4s COMPA_vect. Und so weiter. Oder?

von Veit D. (devil-elec)


Lesenswert?

Hallo,

okay, Standard sind wirklich 9 Bit, wenn das reicht muß man nichts extra 
angeben. Sorry.

Bei den Timern ist wirklich was falsch. Wobei ich das mit den Timern für 
Overkill halte. Kannste alles per millis machen.

Du requestest mit Timer 3.B
und liest aus mit Timer 3.C

OCR3B = 2*OCR3A/3;    //Auch alle 4.2s, aber versetzt
OCR3C = OCR3A/3;      //Auch alle 4.2s, aber versetzt

dummerweise löst aber Timer 3.B nach 3.C aus, weil sein Compare Wert 
doppelt so groß.

Außerdem rechnet er möglicherweise zusätzlich falsch. Denn mit 2* 0xFFFF 
haste einen Überlauf drin. Du müßtest erst durch 3 und dann mal 2 
nehmen.

Setz mal für OCR3B und OCR3C feste Werte ein.

Der Befehlskommentar stimmt so auch nicht. "Auch alle 4.2s, aber 
versetzt". Wenn der Compare Wert verschieden ist, ist das Auslösetiming 
auch verschieden.

Sichtbar machen könntest Du den Effekt wenn Du im ISR eine LED toggeln 
läßt.

Edit:

ich habs mal ausgerechnet.

OCR3A = 0xffff;
OCR3B = 2*OCR3A/3;
OCR3C = OCR3A/3;

Dein Timer 3.A löst aller 4,2s aus.
Dein Timer 3.B löst aller 2,8s aus.
Dein Timer 3.C löst aller 1,4s aus.

und damit überschneidet sich auch dein request und read immer wieder 
einmal.

: Bearbeitet durch User
von Luggi F. (luggi_f)


Lesenswert?

Veit D. schrieb:
Hallo!

> Bei den Timern ist wirklich was falsch. Wobei ich das mit den Timern für
> Overkill halte. Kannste alles per millis machen.

Wahrscheinlich werde ich dann wohl das Ganze in die loop() packen und 
nur wenn mein aktueller Wert zu alt ist, einen neuen holen. Trotzdem 
will ich das Problem jetzt lösen, einfach Interessehalber...

> Setz mal für OCR3B und OCR3C feste Werte ein.

Schon probiert, ändert nichts.

> Der Befehlskommentar stimmt so auch nicht. "Auch alle 4.2s, aber
> versetzt". Wenn der Compare Wert verschieden ist, ist das Auslösetiming
> auch verschieden.
> Dein Timer 3.A löst aller 4,2s aus.
> Dein Timer 3.B löst aller 2,8s aus.
> Dein Timer 3.C löst aller 1,4s aus.
>
> und damit überschneidet sich auch dein request und read immer wieder
> einmal.

Das ist meiner Meinung nach falsch. Es gibt ja nur einen Timer3 und der 
resetet immer wenn er den Wert von OCR3A erreicht. Jedes Interrupt 
(COMPA-C) wird also pro Timerdurchlauf genau einmal ausgeführt, nur eben 
versetzt.

Jedenfalls hab ich jetzt mit einer LED bissl rumprobiert und 
festgestellt, dass jeder Interrupt beim PowerOn einmal ausgeführt wird. 
Und wenn ich so nachdenke, hab ich das glaube auch schonmal wo gelesen. 
Ist wohl einfach so. Für den Moment hab ich mein Problem jetzt mit einem 
delay(750) im setup() gelöst.

Danke! Grüße, Luggi

von Wolfgang (Gast)


Lesenswert?

Veit D. schrieb:
> weil viele Problem mit der Spannungsversorgung zusammenhängen. Also wenn
> man nicht unbedingt den einen Draht sparen muß, dann zieht man den mit.

Sorry, aber diese Paranoia verstehe ich nicht. Bei mir laufen die Dinger 
hier als *-Netz mit teilweise 10 Metern Kabeln ohne Probleme.

von Veit D. (devil-elec)


Angehängte Dateien:

Lesenswert?

Hallo,

uhh, habs nachgestellt, tatsächlich, die takten "nur" versetzt. Sorry. 
Kopfkratz.
Aber wie schon erwähnt, hast Du bestimmt Timer.3.B mit Timer.3.C 
vertauscht. Bzw. die Reihenfolge der Compare Werte. Denn 3.B löst nach 
3.C aus. Damit kommt der Request nach dem auslesen. Deshalb bestimmt das 
Problem.

Habe das mit dem Code nachgestellt und aufgezeichnet. Reihenfolge von 
oben nach unten A, B, C direkt nach µC Reset.
1
#define F_CPU 16000000UL
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#define NOP __asm__ __volatile__ ("nop\n\t")
5
6
void set_Timer3(void);  // Funktion deklarieren
7
void set_Timer3()       // 
8
{   
9
  cli();  //stop interrupts
10
11
  // set Timer-1 Register
12
  TCCR3A = 0;      // Reset TCCR3A Register 
13
  TCCR3B = 0;      // Reset TCCR3B Register
14
  TIMSK3 = 0;      // Reset TIMSK3 Register (disable Timer Compare Interrupts)
15
  TCNT3  = 0;      // initialize counter value to 0
16
  
17
  TCCR3A  |= (1 << COM3A0);  // set Toggle OCnA Pin on compare match
18
  TCCR3A  |= (1 << COM3B0);  // set Toggle OCnB Pin on compare match
19
  TCCR3A  |= (1 << COM3C0);  // set Toggle OCnC Pin on compare match
20
  
21
  OCR3A =  399;    // Compare Match Register A
22
  OCR3B =  266;    // Compare Match Register B
23
  OCR3C =  133;    // Compare Match Register C
24
    
25
  //TCCR3B |= (1 << CS11);    // set Prescaler 8
26
  TCCR3B = (1<<WGM32) | (1<<CS31);    //CTC Mode, Prescaler 8
27
  TIMSK3 |= (1 << OCIE3A);  // enable Timer Compare Interrupt  A
28
  TIMSK3 |= (1 << OCIE3B);  // enable Timer Compare Interrupt  B
29
  TIMSK3 |= (1 << OCIE3C);  // enable Timer Compare Interrupt  C
30
  
31
  sei();   //allow interrupts
32
  
33
}  // end Funktion
34
35
ISR(TIMER3_COMPA_vect) {  // Timer 3.A Interrupt 
36
  //
37
}
38
39
ISR(TIMER3_COMPB_vect) {  // Timer 3.B Interrupt 
40
  //
41
}
42
43
ISR(TIMER3_COMPC_vect) {  // Timer 3.C Interrupt 
44
  //
45
}  
46
47
48
int main(void)  {
49
  DDRE = 0xFF;   // alles Ausgänge
50
51
  set_Timer3();
52
  
53
while(1)  {         
54
55
}
56
  
57
}   // Ende main()

von Veit D. (devil-elec)


Lesenswert?

Wolfgang schrieb:
> Veit D. schrieb:
>> weil viele Problem mit der Spannungsversorgung zusammenhängen. Also wenn
>> man nicht unbedingt den einen Draht sparen muß, dann zieht man den mit.
>
> Sorry, aber diese Paranoia verstehe ich nicht. Bei mir laufen die Dinger
> hier als *-Netz mit teilweise 10 Metern Kabeln ohne Probleme.

Hallo,

nutzt du parasitär? Was für Kabel hast du? Geschirmt usw.? Sicherlich 
keine 10m Flachbandleitung.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

bin echt am grübeln warum die nur versetzt und ansonsten im gleichen 
Abstand takten. Könnte mir das mal bitte jemand erklären? Alle 3 haben 
doch unterschiedliche Compare Werte. Damit müßten sie doch alle 
durcheinander takten.

von Luggi F. (luggi_f)


Lesenswert?

Veit D. schrieb:
> Hallo,
>
> bin echt am grübeln warum die nur versetzt und ansonsten im gleichen
> Abstand takten. Könnte mir das mal bitte jemand erklären? Alle 3 haben
> doch unterschiedliche Compare Werte. Damit müßten sie doch alle
> durcheinander takten.
Ich versuchs nochmal... (Dem Problem widme ich mich morgen wieder, danke 
mal für die ganzen Antworten!)

Es läuft ja (physikalisch) ein Timer, der immer von Null bis zum dem 
Wert zählt, der in OCR3A steht. Das ist jetzt praktisch erstmal 
"normale" Clear Timer on Compare Match (CTC) Funktionsweise. Was anderes 
macht der Timer nicht, egal was passiert.
Nun gibt es ja die Compare-Interrupts, die genau dann ausgelöst werden, 
wenn der momentane Wert des Timers mit dem Wert im zugehörigen Compare 
Match Register übereinstimmt. Sprich "ISR_ISR(TIMER3_COMPB_vect)" wird 
genau dann ausgeführt, wenn der Timer den Wert von "OCR3B" hat. Genauso 
läuft das mit "ISR_ISR(TIMER3_COMPA_vect)" und 
"ISR_ISR(TIMER3_COMPC_vect)".
Da der Timer jeden Wert pro Durchlauf genau einmal annimmt (liegt halt 
in der Natur des zählens :-)), wird jede der 3 ISRs pro Timerdurchlauf 
einmal ausgeführt.
In welchem Abstand das passiert, hängt von der Verteilung der 3 Zahlen 
in den OCR3x Registern ab. Bei mir ist das eben genau 1/3, damit wird 
bei mir alle 1,4s eine der 3 Routinen ausgeführt.

Ich hoffe mal, das war hilfreich,
Grüße, Luggi

PS: Wo kommt denn die erste fallende Flanke in deiner Grafik her? Wenn 
da nach der Initialisierung einmal die 3 ISRs ausgeführt werden, liegt 
genau da mein Problem...

: Bearbeitet durch User
von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich glaube ich habs verstanden. Gar nicht so einfach mit dem Timern. 
Danke für die Erklärung.

Diagramm.
Die ersten gemeinsam fallenden Flanken ist der Startschuss der 3 
Timerkanäle. Zur Darstellung lasse ich die Timer Pins direkt toggeln. 
Ich weis nicht ob beim direkten ersten Start schon ein Interrupt 
ausgelöst wird im ISR Handler oder ob ich das nur am Toggle Pin sehe.

Ich dachte bisher Dein Problem liegt eine Flanke weiter. Denn erst kommt 
die steigende Flanke vom lesen (3. Zeile) und danach die steigende 
Flanke (2. Zeile) vom Request. Das meinte ich mit vertauscht. ??? 
Vertausche mal B mit C. Mal sehen was mit dem Sensor passiert.

von Luggi F. (luggi_f)


Lesenswert?

Hätte ich vielleicht schreiben sollen:
Die 3 Interrupt Routinen hab ich in einem Anflug von 
"Ich-weiß-nichtmehr-weiter" schon in allen möglichen Kombinationen 
getauscht... Im Moment ist es die Variante mit der ich am schnellsten 
einen gültigen Wert bekomme.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

gut zu wissen. Wie ich schon anmerkte halte ich von der Timerlösung 
wenig. Dadurch kommste ja in den Schlamassel. Einen einzigen Timer 
kannste meinetwegen verwenden, wenn die Messabstände genau eingehalten 
werden sollen. Dann würde ich mit nur einem Timer den Startschuß mit 
einem Flag geben und den Rest im Hauptprogramm über millis erledigen. 
Also die 750ms Wartezeit.

ISR gibt Request Flag im Hauptprgramm frei, dann über millis 750ms 
warten und auslesen.

Müssen die Messungen so genau sein im Abstand? Warum überhaupt?

von Luggi F. (luggi_f)


Lesenswert?

Hallo,

Also irgendwelche delays kann ich mir garnicht leisten, wenn dann würde 
ich bei jeder Temperaturmessung millis() in eine Variable schreiben und 
dann in jeder loop die Variable mit millis() vergleichen. Und wenn die 
Differenz groß genug ist erst ein "get" machen, dann ein "request" für 
die nächste Messung.

In einem genauen Abstand müssen die Messungen nicht sein, aber z.b. 
während dem Motorstart wird die loop() mal für (bis zu) 1 min garnicht 
ausgeführt. Darum stehen da bei mir nur Taster- und Fehlerbehandlungen 
drin. Die ganze Einleserei läuft nur über (verschieden schnelle) Timer, 
damit ich immer aktuelle Werte in den Variablen habe. Es ist ja doch 
einiges, was das Ding zu erledigen hat (Gesamte Datei in ersten Post!).

Im Moment läuft es ja mit einem 750ms Delay im setup()(direkt nach dem 
ersten request). Eigentlich ist das garnicht sooo schlimm, das kann ich 
auch so lassen.

Grüße, Ludwig

von Veit D. (devil-elec)


Lesenswert?

Hallo,

wenn du damit zufrieden bist, na gut. Belassen wir es dabei.

Nur eine Anmerkung noch zum Sensor. Einen aktuellen Messwert bekommst Du 
nur mittels Request. Wenn Du 10s später ausliest, dann ist die Messung 
schon 10s alt. Oder genauer 10s abzüglich 750ms.

Will damit sagen. Für aktuelle Werte nützt es nichts gleich einen 
Request nach dem read hinterherzuschicken, wenn Du erst Sekunden später 
ausliest. Die 750ms mußte so oder so warten. Ob du in der Zwischenzeit 
was anderes machts ist dir überlassen.

von Luggi F. (luggi_f)


Lesenswert?

Ja, ich werd es wohl dabei belassen. Vielleicht mache ich bei komplett 
fertigem Programm mal einen Thread zur Optimierung auf (Ich merke schon, 
ist wohl nicht besonders schön, meine Methode).
Ja, so superaktuell muss es auch nicht sein, grade bei den Temperaturen. 
Da geht es nur um Lüftersteuerung, Vorglühzeit, etc...

Danke nochmal!

von Veit D. (devil-elec)


Lesenswert?

Hallo,

na wenn es nicht so aktuell sein muß, dann würd es wirklich ganz ohne 
Timer ausreichen alles in der loop zu machen. Ich denke Du hast Dich 
vielleicht etwas in die Timermethode verrannt. Soll ich mal versuchen 
ein Bsp. zu erstellen? In meinem Datalogger messe ich auch Temperaturen 
mit dem DS18S20.
Oder brauchst Du das jetzt nicht, erst später?

Dann könntest Du in der loop ständig neue Temperaturen erfassen. Eben 
aller 750ms im schnellsten Fall und ohne Timer. Wenn ich richtig sehe 
reicht es dir aller 4sec aus.

von Luggi F. (luggi_f)


Angehängte Dateien:

Lesenswert?

Hallo!

Mit "nicht ganz aktuell" meinte ich ein paar Sekunden alte Werte machen 
garnichts aus, aber 2 Minuten alte Werte können im Zweifel schon 
schlecht sein.

Zum Beispiel läuft das Programm zum Motorstart in die Funktion 
engine_control(), glüht je nach Motortemperatur vor, startet den Motor 
und wartet bis zu 1 min (oder nach Einstellung länger) auf eine passende 
Drehzahl und Spannung. Währenddessen sollen aber auch alle Werte 
(einigermaßen, je nach Typ) aktuell sein, da diese teilweise zu 
Kühlersteuerung, Gasregelung,... gebraucht werden.

Ich hänge nochmal mein (aktuelles) ganzes Programm an, falls es dich 
interessiert. Am Können wird es nicht scheitern, das Ganze in die 
Schleife zu schieben, allerdings müsste ich dann auch große Teile des 
Restprogramms ändern.

Grüße, Ludwig

von Veit D. (devil-elec)


Lesenswert?

Hallo,

okay, wenn das so ist. War wohl ein Missverständnis.
Dann sagen wir mal so. Ein Code ist gut wenn er das macht was er soll 
und verständlich ist. Also nach Jahren noch lesbar für einen selbst. 
:-)

von Max B. (theeye)


Lesenswert?

Veit D. schrieb:
> Soll ich mal versuchen ein Bsp. zu erstellen? In meinem Datalogger messe
> ich auch Temperaturen mit dem DS18S20.

Würde mich (und eventuell andere Mitleser) interessieren :-)

Gruß Max

von Veit D. (devil-elec)


Angehängte Dateien:

Lesenswert?

Hallo,

bitte schön.

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.