Forum: Mikrocontroller und Digitale Elektronik Speicherverbrauch bei Funktionsaufrufen (Funktion in Funktion)


von Uwe K. (Firma: --) (kullmann)


Lesenswert?

Hallo
Ich habe eine Verständnisfrage zu einem Problem:
Ich habe ein Sketch in der Arduino IDE für ein Nano Board.
Laut Compiler sind noch 700 Bytes frei für Variablen.
Trotzdem spinnt mein Programm nach kurzer Zeit. Die zuletzt angelegten 
Variablen weisen Werte auf, die ich nicht reingeschrieben habe.
Nach viel Recherche habe ich gelesen, das der Stack von "hinten" den 
Speicher verbraucht und wenn nicht genug Speicher vorhaben ist, das dann 
genau dieser Fall wie beschrieben zu sehen ist. Man sieht dann quasi 
irgendwelche Stackdaten in dern Variablen.
Ich habe mein Programm dann extrem vereinfacht was das Problem gelöst 
hatte. Dann habe ich noch mehr Variablen eingespart indem ich Funktionen 
verschachtelt habe:

Vorher:
1
    x = Funktion1;
2
    result = Funktion2(x);
Danach:
1
result = Funktion2(Funktion1);

Das hat aber das Problem erst Recht verschärft wieder vorgeholt!
Nachdem ich dann alle verschachtelten Aufrufe getrennt habe (per 
Temp_int und Temp_Float Variablen), läuft das Programm einwandfrei.

Warum ist das so? Ich rufe doch nicht mehr Funktionen auf als vorher und 
ich habe Arbeitsspeicher eingespart! Oder ist das ein Mangel im 
Compilercode?

LG
Uwe

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Uwe K. schrieb:
> Nach viel Recherche habe ich gelesen, das der Stack von "hinten" den
> Speicher verbraucht
Nur, wenn man einen Programmfehler hat. Meist ist es einfach ein simpler 
amoklaufender Pointer, der solche Effekte hervorruft.

: Bearbeitet durch Moderator
von EAF (Gast)


Lesenswert?

Uwe K. schrieb:
> Warum ist das so? Ich rufe doch nicht mehr Funktionen auf als vorher und
> ich habe Arbeitsspeicher eingespart! Oder ist das ein Mangel im
> Compilercode?

Der Stapel wird beim verlassen der Funktion wieder frei.
Rufst du Funktionen nacheinander auf, wird auch nacheinander belegt und 
frei gemacht.
Wenn du Funktionen schachtest dann stapeln sich eben bei jedem Aufruf 
mehr Daten auf dem Stapel. Das ist sein Job.

Prominentes Beispiel: Rekursion!

von Eine Frage (Gast)


Lesenswert?

x = Funktion1;
result = Funktion2(Funktion1);

statt

x = Funktion1();
result = Funktion2(Funktion1());

Sind die () nur beim Copy&Paste in dieses Forum verloren gegangen?

> Wenn du Funktionen schachtest dann stapeln sich eben bei jedem Aufruf
> mehr Daten auf dem Stapel.

Hast du das im Assemblercode kontrolliert? Funktion1 hat gar keine 
Parameter.  Und der Stack zum sichern der Register wird vor dem return 
zurück gesetzt. Und warum sollte der Compiler die Parameter für 
Funktion1 erst nach Ausführung von Funktion2 anräumen?

von MaWin (Gast)


Lesenswert?

Lothar M. schrieb:
> Uwe K. schrieb:
>> Nach viel Recherche habe ich gelesen, das der Stack von "hinten" den
>> Speicher verbraucht
> Nur, wenn man einen Programmfehler hat.

Die Moderation war auch mal besser.
Das ist natürlich Unsinn. Mit Fehlern hat das nichts zu tun.

von MaWin (Gast)


Lesenswert?

Uwe K. schrieb:
> Warum ist das so?

Das können wir nicht wissen, ohne deinen Code zu sehen.

von EAF (Gast)


Lesenswert?

Eine Frage schrieb:
> Hast du das im Assemblercode kontrolliert?

Brauche ich nicht.
Das weiß ich, dass das so ist!
So funktionieren Funktionen, wenn sie geschachtelt aufgerufen werden 
werden, in C und C++.

Von irgendwelchem Opimizer/Inline Gefummel mal abgesehen.

von EAF (Gast)


Lesenswert?

EAF schrieb:
> Das weiß ich, dass das so ist!
Warte....
Ich ziehe provisorisch zurück.

von Rolf M. (rmagnus)


Lesenswert?

Uwe K. schrieb:
> Warum ist das so? Ich rufe doch nicht mehr Funktionen auf als vorher und
> ich habe Arbeitsspeicher eingespart!

Wie kommst du darauf, dass du was gespart hättest? Der Unterschied ist 
nur, dass der von Funktion1 zurückgegebene Wert keinen Namen hat. 
Gespeichert werden muss er aber trotzdem.

von Eine Frage (Gast)


Lesenswert?

> Gespeichert werden muss er aber trotzdem.

Wenn wir nur wüssten, ob x eine lokale Variable ist. Zumindest 
theoretisch wäre möglich, aus einem anderen Grund kommt das selbe 
heraus. Der Compiler merkt, x wird nicht gebraucht benutzt in beiden 
Fällen nur Register und Stack.

Zur ursprünglichen Frage. Wieso bist du dir sicher, der neue Fehler ist 
auch wieder ein Stackoverflow? Nicht zufällig irgend ein anderer Fehler.

von A. S. (Gast)


Lesenswert?

Uwe K. schrieb:
> Das hat aber das Problem erst Recht verschärft wieder vorgeholt!

Das kannst Du nur wissen, wenn Du den Stackverbrauch prüfst (wie viel 
Reserve Du hast).

Sobald der Stack zu groß wird (und Du ein Problem hast), ist alles 
Verhalten nur noch Glücksache.

von Rolf M. (rmagnus)


Lesenswert?

Eine Frage schrieb:
>> Gespeichert werden muss er aber trotzdem.
>
> Wenn wir nur wüssten, ob x eine lokale Variable ist.

Davon war ich jetzt ausgegangen. Eine globale Variable verwendet 
hoffentlich keiner nur zur Zwischenspeicherung eines Funktionsergebnis 
zur Übergabe an eine andere Funktion.

> Der Compiler merkt, x wird nicht gebraucht benutzt in beiden Fällen nur
> Register und Stack.

Um den Stack geht es doch gerade.

von (prx) A. K. (prx)


Lesenswert?

Bei AVRs werden Parameter meist in Registern übergeben, nicht auf dem 
Stack. Erst wenn mächtig viele zusammenkommen, kommt der Stack ins 
Spiel. Und selbst dann kann es sein, dass der Compiler eine 
verschachtelte Schreibweise der Aufrufe "entschachtelt". Bei einem 
simplen Test rief avr-gcc beispielsweise mit Optimierung verschachtelt 
auf, ohne nicht.

: Bearbeitet durch User
von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Uwe K. schrieb:

> Nach viel Recherche habe ich gelesen, das der Stack von "hinten" den
> Speicher verbraucht und wenn nicht genug Speicher vorhaben ist, das dann
> genau dieser Fall wie beschrieben zu sehen ist. Man sieht dann quasi
> irgendwelche Stackdaten in dern Variablen.

Ja, wenn Du z.B. den Stack an das Ende des RAMs legst, und der von Dir 
für den Stack vorgesehene Bereich nicht ausreicht, dann wächst der Stack 
in die Bereiche, die entweder für den heap oder die statischen Variablen 
vorgesehen sind.

Leider sind die meisten Linker Skripte so aufgebaut. Wenn Du den Stack 
an den Anfang des RAMs legst, dann würde ein Überlauf des Stacks in der 
Regel dazu führen, dass die CPU versucht in Bereiche zu schreiben, die 
oftmals nicht beschreibbar sind (hängt natürlich hochgradig vom 
Controller ab) und lösen dann ggf. eine Schutzverletzung aus (hängt 
natürlich von der verwendeten Architektur ab).

> Warum ist das so? Ich rufe doch nicht mehr Funktionen auf als vorher und
> ich habe Arbeitsspeicher eingespart! Oder ist das ein Mangel im
> Compilercode?

Dazu müsstest Du Dir mal den generierten assembler Code angucken. Wenn 
Du Deinem Compiler auf volle Optimierung eingestellt hast, würde ich 
keinen Unterschied erwarten.

Was Du auch noch mal machen kannst, ist in Deinem Linker-Script zu 
gucken, ob und wieviel RAM für den Heap reserviert ist und ob Du das so 
brauchst.

von (prx) A. K. (prx)


Lesenswert?

Torsten R. schrieb:
> Leider sind die meisten Linker Skripte so aufgebaut. Wenn Du den Stack
> an den Anfang des RAMs legst, dann würde ein Überlauf des Stacks in der
> Regel dazu führen, dass die CPU versucht in Bereiche zu schreiben, die
> oftmals nicht beschreibbar sind

Das wäre bei AVRs keine sonderlich gute Idee, denn da liegen die 
I/O-Register. Ein Stacküberlauf könnte dann sehr interessante Ergebnisse 
zeigen.

Der Stack dürfte bei AVRs immer am Ende des RAMs liegen, denn darauf 
initialisiert sich bei allen nicht uralten Typen der Stackpointer.

von (prx) A. K. (prx)


Lesenswert?

Torsten R. schrieb:
> Was Du auch noch mal machen kannst, ist in Deinem Linker-Script zu
> gucken, ob und wieviel RAM für den Heap reserviert ist und ob Du das so
> brauchst.

Ich habe das so in Erinnerung, dass Stack und Heap gegeneinander laufen, 
ohne spezielle Grenze dazwischen, also auch ohne eigens für den Heap 
andressierten Adressraum.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

(prx) A. K. schrieb:
> Das wäre bei AVRs keine sonderlich gute Idee, denn da liegen die
> I/O-Register. Ein Stacküberlauf könnte dann sehr interessante Ergebnisse
> zeigen.

Dann könnte man da ggf. an ein paar Pins eine Logik anschalten, die 
direkt mit dem Reset-Pin verbunden ist ;-)

von Peter D. (peda)


Lesenswert?

(prx) A. K. schrieb:
> Das wäre bei AVRs keine sonderlich gute Idee, denn da liegen die
> I/O-Register. Ein Stacküberlauf könnte dann sehr interessante Ergebnisse
> zeigen.

Es passiert einfach nichts (NOP).

Die klassik AVRs erlaubten wohl noch alle Speicheroperationen auch auf 
IO und Registerbereich.
Bei den ATtiny/Mega sind Stackoperation (push, pop, call, ret) nur auf 
den SRAM möglich, also nicht auf MMIO.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Peter D. schrieb:
> Es passiert einfach nichts (NOP).
>
> Die klassik AVRs erlaubten wohl noch alle Speicheroperationen auch auf
> IO und Registerbereich.
> Bei den ATtiny/Mega sind Stackoperation (push, pop, call, ret) nur auf
> den SRAM möglich, also nicht auf MMIO.

Dann könnte es evtl. auffallen, wenn die Rücksprungadresse vom Stack 
geholt wird?

von (prx) A. K. (prx)


Lesenswert?

Peter D. schrieb:
> Bei den ATtiny/Mega sind Stackoperation (push, pop, call, ret) nur auf
> den SRAM möglich, also nicht auf MMIO.

Dummerweise liegen bei AVR-GCC auf dem Stack nicht nur die 
Return-Adressen, sondern auch die lokalen Daten. Und die werden ganz 
normal geschrieben.

von Oliver S. (oliverso)


Lesenswert?

(prx) A. K. schrieb:
> Ich habe das so in Erinnerung, dass Stack und Heap gegeneinander laufen,
> ohne spezielle Grenze dazwischen, also auch ohne eigens für den Heap
> andressierten Adressraum.

Der AVR kennt von sich aus nur seinen (Hardware-)Stack, aber keinen 
heap. Der heap existiert nur auf Softwareebene durch die Implementierung 
von malloc und free, oder was auch immer die verwendete 
Programmierumgebung dafür nutzt.

Die Default-Implementierung in der avrlibc hängt zwar den heap hinter 
das bss-Segment, das kann man aber beliebig selber umschreiben, wenn man 
will.

Oliver

von Uwe K. (Firma: --) (kullmann)


Lesenswert?

Hallo an Alle,

Das sind ja VIELE Infos!!
Also Assembler würde ich vermutlich noch lesen können, komplett 
verstehen, naja...
Ich nutze aktuell sogar nur die Arduino IDE, Ich sehe zwar das sie den 
GCC Compiler aufruft mit jede Menge Parameter, aber was die genau alle 
sagen, bin halt kein Experte.

Anbei mal den kompletten Sourecode, damit Ihr wisst was ich da gebaut 
habe. Das Programm unten läuft nun stabil, ist aber nicht hübsch.
Ich habe statt der Klasse für ein Expotentialfilter die Codezeilen 
direkt reingeschrieben, Programmspeicher verschwendet, aber die Nutzen 
der klasse führte direkt zu Weihnachtsbaumergebnissen in den Registern.
Die unnützen Tmp_int und Tmp_Float Konstrukte lassen es stabil laufen. 
Verschachelet ich auch nur zwei oder drei Aufrufe wie beschrieben, 
tauchen komische Zahlen auf in den Modbusregistern.
Das ich alles seriell runter geschrieben habe ist auch nicht meine Art. 
Ich hatte mal für alles Funktionen geschrieben. Aber aufgrund des Fehler 
wollte ich jegliche selbstgebaute Funktion vermeiden (zugegeben, es war 
eine Verzweifelungstat)
1
/*
2
 *
3
 * 
4
  Modbus RTU Server Solarheizungsansteuerung 
5
6
  ACHTUNG: Library ArduinoModbus wurde aus dem Github Repo gezogen, um int poll() zu benutzen!!
7
  Version ist weiterhin 1.0.6...
8
  
9
  Dieser Sketch erlaubt einen Modbuszugriff auf die Solarsteurungskomponenten
10
  Circuit:
11
  Arduino NANO
12
  9600Bd
13
  AVR ISP- Old Bootloader
14
  
15
                Nano Layout
16
            #--------------------------#
17
            1   TXD             Vin       Netzteil 6V
18
            0   RXD             GND       GND
19
                Res             Res
20
                GND             5V        5V Platine
21
  Ppe IST   2   D2              ADC7
22
            3   D3              ADC6
23
  DE RS485  4   D4              ADC5  19  Licht
24
  Ppe Soll  5   D5              ADC4  18  Temp4
25
            6   D6              ADC3  17  Temp3
26
            7   D7              ADC2  16  Temp2
27
  3Wege     8   D8              ADC1  15  Temp1
28
  Ppe       9   D9              ADC0  14  Temp0
29
            10  D10             AREF
30
            11  D11             3V3
31
            12  D12             PB5   13
32
            #--------------------------#
33
Modbus Register Settings (Arduino Start 30000, PC= 30001=
34
30000 Temp1 (Factor 10)
35
30001 Temp2
36
30002 Temp3
37
30003 Temp4
38
30004 Temp5                         oder bei V3: Fuellstand
39
30005 Licht                         (nur in V3)
40
30006 3Wegeventil, 0 = Off, 1 = ON  (nur in V2)
41
30007 Pumpe (0=off, 1=ON            (nur in V2)
42
30008 Pumpe Istwert in Watt         (nur in V2)
43
30009 Pumpe Sollwert (0-100%)       (nur in V2)
44
45
Onewire
46
Pin Func  Sensore
47
14  A0    Temp Placa Vorlauf
48
15  A1    Temp Place Rücklauf
49
16  A2    Temp Placa Fläche oder Aussen
50
17  A3    Temp Speicher
51
18  A4    Temp Fussboden
52
19  A5    Temp 6 Reserve
53
54
 */
55
//---------------------------------------------------------------------------------
56
// Verschiedene Versionen Kompilieren!!
57
// V2 = 5x Temp, 1xLicht, 2 Relais, PWM SIgnale, Modbusadr 4
58
// V3 = 2xTemp, 1xLicht, 1xFüllstand, Modbusadr 5
59
// V4 = 2xTemp, Modbusadr 6
60
#define FirmwareVersion2
61
//---------------------------------------------------------------------------------
62
63
64
 
65
//---------------------------------------------------------------------------------
66
//RS485 Library
67
#include <ArduinoRS485.h> // ArduinoModbus depends on the ArduinoRS485 library
68
#include <ArduinoModbus.h>
69
//ONEWIRE
70
#include <OneWire.h>
71
#include <DallasTemperature.h>
72
//#include "filter.h"
73
74
//---------------------------------------------------------------------------------
75
//Global Const und Vars
76
#define IO_Wegeventil 8
77
#define IO_Pumpe  9
78
#define IO_D5 5
79
#ifdef FirmwareVersion2
80
#define IO_Licht 19
81
#endif
82
#ifdef FirmwareVersion3
83
#define IO_Licht 17
84
#define IO_Fuellstand 16
85
#endif
86
#define IO_D2 2
87
88
89
90
//Modbus
91
#define numCoils 0
92
#define numDiscreteInputs 0
93
#define numHoldingRegisters 10
94
#define numInputRegisters 0
95
#ifdef FirmwareVersion2
96
 #define Modbusadress 4
97
#endif
98
#ifdef FirmwareVersion3
99
 #define Modbusadress 5
100
#endif
101
#ifdef FirmwareVersion4
102
 #define Modbusadress 6
103
#endif
104
105
//Dallas TempSensoren
106
OneWire ds18x201(14);
107
OneWire ds18x202(15);
108
#ifdef FirmwareVersion2
109
 OneWire ds18x203(16);
110
 OneWire ds18x204(17);
111
 OneWire ds18x205(18);
112
#endif
113
114
#define oneWireCount 5
115
DallasTemperature sensor[oneWireCount];
116
117
//Check if Master still connected
118
unsigned long period = 60000;
119
unsigned long time_now = 0;
120
121
unsigned int pwmsoll = 0;
122
unsigned long PpeHightime = 0;
123
unsigned long PpeLowtime = 0;
124
int TmpInt = 0;
125
float TmpFloat = 0.0;
126
float T1_Current = 0;
127
float T2_Current = 0;
128
float T3_Current = 0;
129
float T4_Current = 0;
130
float T5_Current = 0;
131
float TLicht_Current = 0;
132
float TFuell_Current =0;
133
134
//---------------------------------------------------------------------------------
135
void setup() {
136
  //Serial.begin(9600);
137
  //while (!Serial);
138
#ifdef FirmwareVersion2
139
  pinMode(IO_Wegeventil, OUTPUT); //Relais für Pumpe EIN
140
  pinMode(IO_Pumpe, OUTPUT); //Relais für 3Wegeventil
141
  digitalWrite(IO_Wegeventil,1); // Relais abschalten
142
  digitalWrite(IO_Pumpe,1);
143
  pinMode(IO_Licht,INPUT); //Lichtsensor A6  
144
#endif
145
#ifdef FirmwareVersion3
146
  pinMode(IO_Licht,INPUT); //Lichtsensor A6 
147
  pinMode(IO_Fuellstand,INPUT); //Lichtsensor A6 
148
   
149
#endif
150
  pinMode(LED_BUILTIN, OUTPUT);
151
  analogReference(DEFAULT);
152
153
  digitalWrite(LED_BUILTIN,HIGH);
154
  //Die RX,TX und Richtungspins setzen
155
  RS485.setPins(0,1,4);
156
  
157
  // start the Modbus RTU server, with (slave) id 
158
  if (!ModbusRTUServer.begin(Modbusadress, 9600)) {
159
    while (1);
160
  }
161
  ModbusRTUServer.configureHoldingRegisters(30000, numHoldingRegisters);
162
 
163
  //Onewire SETUP
164
  // Start up the library on all defined bus-wires
165
  DeviceAddress deviceAddress;
166
  sensor[0].setOneWire(&ds18x201);
167
  sensor[0].begin();
168
  if (sensor[0].getAddress(deviceAddress, 0)){
169
    sensor[0].setResolution(deviceAddress, 9);
170
    sensor[0].setWaitForConversion(false);
171
  }
172
  sensor[1].setOneWire(&ds18x202);
173
  sensor[1].begin();
174
  if (sensor[1].getAddress(deviceAddress, 0)){
175
    sensor[1].setResolution(deviceAddress, 9);
176
    sensor[1].setWaitForConversion(false);
177
  }
178
#ifdef FirmwareVersion2
179
  sensor[2].setOneWire(&ds18x203);
180
  sensor[2].begin();
181
  if (sensor[2].getAddress(deviceAddress, 0)){
182
    sensor[2].setResolution(deviceAddress, 9);
183
    sensor[2].setWaitForConversion(false);
184
  }
185
  sensor[3].setOneWire(&ds18x204);
186
  sensor[3].begin();
187
  if (sensor[3].getAddress(deviceAddress, 0)){
188
    sensor[3].setResolution(deviceAddress, 9);
189
    sensor[3].setWaitForConversion(false);
190
  }
191
  sensor[4].setOneWire(&ds18x205);
192
  sensor[4].begin();
193
  if (sensor[4].getAddress(deviceAddress, 0)) {
194
    sensor[4].setResolution(deviceAddress, 9);
195
    sensor[4].setWaitForConversion(false);
196
  }
197
#endif
198
  
199
  ModbusRTUServer.holdingRegisterWrite(30000,0);
200
  ModbusRTUServer.holdingRegisterWrite(30001,0);
201
  ModbusRTUServer.holdingRegisterWrite(30002,0);
202
  ModbusRTUServer.holdingRegisterWrite(30003,0);
203
  ModbusRTUServer.holdingRegisterWrite(30004,0);
204
  ModbusRTUServer.holdingRegisterWrite(30005,0);
205
  ModbusRTUServer.holdingRegisterWrite(30006,0);
206
  ModbusRTUServer.holdingRegisterWrite(30007,0);
207
  ModbusRTUServer.holdingRegisterWrite(30008,0);
208
  ModbusRTUServer.holdingRegisterWrite(30009,0);
209
  digitalWrite(LED_BUILTIN,LOW);
210
}
211
212
//---------------------------------------------------------------------------------
213
214
//---------------------------------------------------------------------------------
215
void loop() {
216
  // Sicherheitslogik: Fällt der master aus, dann eigensicherer Zustand   
217
    if (ModbusRTUServer.poll() ==1 ){
218
        time_now = millis();
219
    } else {
220
        if((unsigned long)(millis() - time_now) > period){
221
          ModbusRTUServer.holdingRegisterWrite(30009,0);
222
          ModbusRTUServer.holdingRegisterWrite(30008,0);
223
          ModbusRTUServer.holdingRegisterWrite(30007,0); 
224
          ModbusRTUServer.holdingRegisterWrite(30006,0); 
225
        }
226
    }
227
228
  //5 Temperaturen einlesen
229
    if (sensor[0].getDS18Count() >0) {
230
      sensor[0].requestTemperatures();
231
    }
232
    if (sensor[1].getDS18Count() >0) {
233
      sensor[1].requestTemperatures();
234
    } 
235
#ifdef FirmwareVersion2
236
    if (sensor[2].getDS18Count() >0) {
237
      sensor[2].requestTemperatures();
238
    } 
239
    if (sensor[3].getDS18Count() >0) {
240
      sensor[3].requestTemperatures();
241
    }
242
    if (sensor[4].getDS18Count() >0) {
243
      sensor[4].requestTemperatures();
244
    }
245
#endif 
246
    delay(200); 
247
    if (sensor[0].getDS18Count() >0) {
248
      TmpFloat = sensor[0].getTempCByIndex(0);
249
      T1_Current = (0.1 * TmpFloat) + (0.9) * T1_Current;
250
      TmpInt = int(T1_Current*10);
251
      ModbusRTUServer.holdingRegisterWrite(30000,TmpInt);
252
    }
253
    if (sensor[1].getDS18Count() >0) {
254
      TmpFloat = sensor[1].getTempCByIndex(0);
255
      T2_Current = (0.1 * TmpFloat) + (0.9 * T2_Current);
256
      TmpInt = int(T2_Current*10 );
257
      ModbusRTUServer.holdingRegisterWrite(30001,TmpInt);
258
259
    } 
260
#ifdef FirmwareVersion2
261
    if (sensor[2].getDS18Count() >0) {
262
      TmpFloat = sensor[2].getTempCByIndex(0);    
263
      T3_Current = (0.1 * TmpFloat) + (0.9 * T3_Current);
264
      TmpInt = int(T3_Current*10 );
265
      ModbusRTUServer.holdingRegisterWrite(30002,TmpInt);
266
    }
267
    if (sensor[3].getDS18Count() >0) {
268
      TmpFloat = sensor[3].getTempCByIndex(0);    
269
      T4_Current = (0.1 * TmpFloat) + (0.9 * T4_Current);
270
      TmpInt = int(T4_Current*10 );
271
      ModbusRTUServer.holdingRegisterWrite(30003,TmpInt );
272
    }
273
    if (sensor[4].getDS18Count() >0) {
274
      TmpFloat = sensor[4].getTempCByIndex(0);    
275
      T5_Current = (0.1 * TmpFloat) + (0.9 * T5_Current);
276
      TmpInt = int(T5_Current*10 );
277
      ModbusRTUServer.holdingRegisterWrite(30004,TmpInt );
278
    }
279
#endif
280
281
  //Pumpe Sollwert setzen
282
#ifdef FirmwareVersion2
283
    pwmsoll = ModbusRTUServer.holdingRegisterRead(30009);
284
    if (ModbusRTUServer.holdingRegisterRead(30007) == 1){
285
        digitalWrite(IO_Pumpe,0);    
286
      if (pwmsoll <=100) {
287
        TmpInt = int(2.55*(100-pwmsoll));
288
        analogWrite(IO_D5,TmpInt);
289
      }//if pwm  
290
    } else {
291
        analogWrite(IO_D5,0);
292
        digitalWrite(IO_Pumpe,1);
293
        //ModbusRTUServer.holdingRegisterWrite(30009,0);     
294
    }
295
#endif
296
#ifdef FirmwareVersion2
297
  //Istwert der Pumpe auslesen
298
    PpeHightime = pulseIn(IO_D2, HIGH, 60000);   //Pin, High oder LOW messen, Timeout in µs
299
    PpeLowtime  = pulseIn(IO_D2, LOW, 60000);   //Pin, High oder LOW messen, Timeout in µs
300
    //pulsein liefert 0 wenn kein Signal gemessen wurde, sonst µs Dauer
301
    if (PpeHightime+PpeLowtime > 0){
302
      //d% der Pumpe berechnen d%= 100* (t/T) t=hightime, T=75Hz(ca.13ms)
303
      //Bsp: 50% -> 75Hz=13300µs  PpeHightime = 6650µs, PpeLowTime= 6650µs,
304
      //6650*100 / 6650+6650 = 50
305
      TmpInt = (PpeHightime *100)/(PpeHightime+PpeLowtime);
306
      ModbusRTUServer.holdingRegisterWrite(30008,TmpInt);
307
    } else {
308
      //Keine Rückmeldung der ppe, Wert ist 0
309
      ModbusRTUServer.holdingRegisterWrite(30008,0);
310
    }
311
#endif
312
#ifdef FirmwareVersion2
313
  //3Wegeventil EIN/AUS
314
    if (ModbusRTUServer.holdingRegisterRead(30006) == 1){
315
        digitalWrite(IO_Wegeventil,0);    
316
    } else {
317
        digitalWrite(IO_Wegeventil,1);    
318
    }
319
#endif
320
321
#if defined(FirmwareVersion2) || defined(FirmwareVersion3)
322
  //Lichtsonsor abfragen
323
      TmpInt = analogRead(IO_Licht);
324
      TLicht_Current = (0.1 * TmpInt) + (0.9 * TLicht_Current);
325
      TmpInt = int(TLicht_Current );
326
      ModbusRTUServer.holdingRegisterWrite(30005,TmpInt);
327
#endif
328
329
#ifdef FirmwareVersion3
330
  //Füllstand abfragen
331
      TmpInt = analogRead(IO_Fuellstand);
332
      TFuell_Current = (0.1 * TmpInt) + (0.9 * TFuell_Current);
333
      TmpInt = int(TFuell_Current );      
334
      ModbusRTUServer.holdingRegisterWrite(30004,TmpInt);
335
#endif
336
337
}//Loop
338
//END END END

von EAF (Gast)


Lesenswert?

Du weißt, dass du alle Sensoren auf ein Kable legen kannst?
Du weißt, das man Arrays mit schleifen durchlaufen kann?

Tipp: range based for loop

von Markus F. (mfro)


Lesenswert?

Wenn Du uns dein Programm erst zeigst, wenn's funktioniert, nachdem Du 
es flachgeklopft hast, kann kein Mensch sagen, warum's strukturiert 
nicht funktioniert.
Kann man damit den Fred als geschlossen betrachten?

von Dietrich L. (dietrichl)


Lesenswert?

Uwe K. schrieb:
> Anbei mal den kompletten Sourecode

Beachte bitte:
"Wichtige Regeln - erst lesen, dann posten!"
...
"Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang"

von Uwe K. (Firma: --) (kullmann)


Lesenswert?

Markus F. schrieb:
> Wenn Du uns dein Programm erst zeigst, wenn's funktioniert, nachdem Du
> es flachgeklopft hast, kann kein Mensch sagen, warum's strukturiert
> nicht funktioniert.
> Kann man damit den Fred als geschlossen betrachten?

Nun, ich wollte zeigen das ich darin keine Pointer wie auch immer 
Akrobatik betrieben habe.
Wie EAF schon schrieb, ja das weiß ich. Hatte ich in Funktionen, die 
dann das Problem ausgelöst hatten.
Nun ohne es nun zu 100% zu wissen, ich nehme an das durch die 
Funktion(Function()) der Fehler entstanden ist, weil mir der Stack 
entgegen kam, Ein Aufruf mehr in dieser Form führt auch zu mehr Chaos in 
den Variablen, das konnte ich feststellen.

Also Schliessen wir den Fred

von EAF (Gast)


Lesenswert?

Uwe K. schrieb:
> Wie EAF schon schrieb, ja das weiß ich.

Wenn du das weißt, dann sage mir doch warum du dein wertvolles Flash für 
6 Onwire/Dallas Instanzen verplemperst, wenn doch eine reichen würde?

von EAF (Gast)


Lesenswert?

EAF schrieb:
> Flash
RAM

von Uwe K. (Firma: --) (kullmann)


Lesenswert?

EAF schrieb:
> Uwe K. schrieb:
>> Wie EAF schon schrieb, ja das weiß ich.
>
> Wenn du das weißt, dann sage mir doch warum du dein wertvolles Flash für
> 6 Onwire/Dallas Instanzen verplemperst, wenn doch eine reichen würde?

Weil ich 6 getrennte Eingänge nutze, damit ich mir um die Chipaddresse 
keine Gedanken machen muss

von EAF (Gast)


Lesenswert?

Uwe K. schrieb:
> damit ich mir um die Chipaddresse
> keine Gedanken machen muss

Klingt mir jetzt nicht allzu logisch.
Aber was solls, des Menschen und sein Himmelreich....

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.