Forum: Mikrocontroller und Digitale Elektronik Arduino - Speicheroptimierung?


von Wolfram F. (mega-hz)


Lesenswert?

Hallo,

für meine Haussteuerung habe ich einen Arduino Uno mit 32 Ein- und 32 
Ausgängen (74HC165 & 74HC595), Ethernet für die Webseite und CAN-Bus mit 
MCP2515 aufgebaut.
Manche haben den IO-Webserver schon aufgerufen,
   http://mega-hz.dnshome.de:85
die IOs funktionieren ja schon, aber ich habe nicht mehr genug Speicher 
frei um die Can-Bus routinen einzubauen.
Da ich eher der Hardworker bin, bitte ich Euch um Hilfe, den Code zu 
optimieren!

hier das Listing:
1
/*--------------------------------------------------------------
2
Arduino HOME-SYS
3
--------------------------------------------------------------*/
4
5
#include <SPI.h>
6
#include <Ethernet.h>
7
#include <SD.h>
8
#include <mcp_can.h>
9
#define REQ_BUF_SZ   60
10
unsigned char len = 0;
11
unsigned char rxBuf[8];
12
#define CAN0_INT 2                              // Set INT to pin 2
13
MCP_CAN CAN0(9);                               // Set CS to pin 9
14
15
// Pin- und Variablen-Definierung des 32 Kanal SHIFT-IN-SHIELDs 
16
17
uint8_t IN_loadPin = 5;         // per Jumper wählbar D2 - D11
18
uint8_t IN_dataPin = 6;         // per Jumper wählbar D2 - D11
19
uint8_t IN_clockPin = 3;         // per Jumper wählbar D2 - D11
20
uint8_t Input[32] = {};
21
uint32_t Inputs = 0;
22
23
// Pin- und Variablen-Definierung des 32 Kanal SHIFT-OUT-SHIELDs 
24
25
uint8_t OUT_latchPin = 8;         // per Jumper wählbar D2 - D11
26
uint8_t OUT_dataPin = 7;          // per Jumper wählbar D2 - D11
27
uint8_t OUT_clockPin = 3;         // per Jumper wählbar D2 - D11
28
uint32_t Outputs = 0;
29
30
// Ethernet Shield benutzt 10,11,12,13! SD-Card CS = 4 !
31
32
// MAC address from Ethernet shield sticker under board
33
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
34
IPAddress ip(192, 168, 2, 231); // IP address, may need to change depending on network
35
EthernetServer server(85);  // create a server at port 80
36
File webFile;               // the web page file on the SD card
37
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
38
char req_index = 0;              // index into HTTP_req buffer
39
unsigned char LED_state[4] = {0}; // stores the states of the LEDs
40
41
void setup()
42
{
43
delay(2000);                        // gib dem Controller Zeit für den Upload
44
45
pinMode(IN_dataPin, INPUT);
46
pinMode(IN_loadPin, OUTPUT);
47
pinMode(IN_clockPin, OUTPUT);
48
pinMode(OUT_latchPin, OUTPUT);
49
pinMode(OUT_clockPin, OUTPUT);
50
pinMode(OUT_dataPin, OUTPUT);
51
52
digitalWrite(IN_dataPin, LOW);      // Pullups abschalten
53
digitalWrite(OUT_clockPin, LOW);
54
digitalWrite(IN_clockPin, LOW);
55
digitalWrite(IN_loadPin, LOW);
56
digitalWrite(OUT_latchPin, LOW);
57
digitalWrite(OUT_dataPin, LOW);
58
59
pinMode(A0,OUTPUT);
60
digitalWrite(A0,LOW);
61
pinMode(A1,OUTPUT);
62
digitalWrite(A1,LOW);
63
64
    int i;
65
    
66
    // disable Ethernet chip
67
    pinMode(10, OUTPUT);
68
    digitalWrite(10, HIGH);
69
    
70
   // initialize SD card
71
    if (!SD.begin(4)) {
72
        digitalWrite(A1,HIGH);
73
    }
74
    // check for web-io.htm file
75
    if (!SD.exists("/WEB-IO.HTM")) {
76
        digitalWrite(A1,HIGH);
77
    }
78
        digitalWrite(A1,LOW);
79
    
80
    Ethernet.begin(mac, ip);  // initialize Ethernet device
81
    server.begin();           // start to listen for clients
82
// ---------------------------------------------------------------------
83
// ZU WENIG SPEICHER für die CAN-BUS Routinen!
84
// ---------------------------------------------------------------------
85
//    CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ);                                
86
//    CAN0.setMode(MCP_NORMAL);   // Change to normal mode to allow messages to be transmitted
87
    pinMode(CAN0_INT, INPUT);                            // Configuring pin for /INT input
88
// ---------------------------------------------------------------------
89
clr_Outputs();
90
}
91
92
void loop()
93
{
94
//    canbus();
95
EthernetClient client = server.available();  // try to get client
96
97
    if (client) {  // got client?
98
        boolean currentLineIsBlank = true;
99
        while (client.connected()) 
100
        {
101
            digitalWrite(A0,HIGH);
102
            if (client.available()) 
103
            {   // client data available to read
104
                char c = client.read(); // read 1 byte (character) from client
105
                // limit the size of the stored received HTTP request
106
                // buffer first part of HTTP request in HTTP_req array (string)
107
                // leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
108
                if (req_index < (REQ_BUF_SZ - 1)) 
109
                {
110
                    HTTP_req[req_index] = c;          // save HTTP request character
111
                    req_index++;
112
                }
113
                // last line of client request is blank and ends with \n
114
                // respond to client only after last line received
115
                if (c == '\n' && currentLineIsBlank) 
116
                {
117
                    // send a standard http response header
118
                    client.println("HTTP/1.1 200 OK");
119
                    // remainder of header follows below, depending on if
120
                    // web page or XML page is requested
121
                    // Ajax request - send XML file
122
                    if (StrContains(HTTP_req, "ajax_inputs")) 
123
                    {
124
                        // send rest of HTTP header
125
                        client.println("Content-Type: text/xml");
126
                        client.println("Connection: keep-alive");
127
                        client.println();
128
                        SetLEDs();
129
                        // send XML file containing input states
130
                        XML_response(client);
131
                    }
132
                    else 
133
                    {  // web page request
134
                        // send rest of HTTP header
135
                        client.println("Content-Type: text/html");
136
                        client.println("Connection: keep-alive");
137
                        client.println();
138
                        // send web page
139
                        webFile = SD.open("/WEB-IO.HTM");        // open web page file
140
                        if (webFile) 
141
                        {
142
                            while(webFile.available()) 
143
                            {
144
                                client.write(webFile.read()); // send web page to client
145
                            }
146
                            webFile.close();
147
                        }
148
                    }
149
                    // display received HTTP request on serial port
150
                    // reset buffer index and all buffer elements to 0
151
                    req_index = 0;
152
                    StrClear(HTTP_req, REQ_BUF_SZ);
153
                    
154
                    break;
155
                }
156
                // every line of text received from the client ends with \r\n
157
                if (c == '\n') {
158
                    // last character on line of received text
159
                    // starting new line with next character read
160
                    currentLineIsBlank = true;
161
                } 
162
                else if (c != '\r') {
163
                    // a text character was received from client
164
                    currentLineIsBlank = false;
165
                }
166
            } // end if (client.available())
167
        } // end while (client.connected())
168
        delay(2);      // give the web browser time to receive the data
169
        client.stop(); // close the connection
170
        digitalWrite(A0,LOW);
171
    } // end if (client)
172
}
173
174
// checks if received HTTP request is switching on/off LEDs
175
// also saves the state of the LEDs
176
void SetLEDs(void)
177
{
178
    char str_on[12] = {0};
179
    char str_off[12] = {0};
180
    unsigned char i;
181
    unsigned int  j;
182
    int LED_num = 0;
183
    
184
    for (i = 0; i < 4; i++) 
185
    {
186
        for (j = 1; j <= 0x80; j <<= 1) 
187
        {
188
            sprintf(str_on,  "LED%d=%d", LED_num, 1);
189
            sprintf(str_off, "LED%d=%d", LED_num, 0);
190
            if (StrContains(HTTP_req, str_on)) 
191
            {
192
                LED_state[i] |= (unsigned char)j;  // save LED state
193
                bitSet(Outputs,LED_num);
194
            }
195
            else if (StrContains(HTTP_req, str_off)) 
196
            {
197
                LED_state[i] &= (unsigned char)(~j);  // save LED state
198
                bitClear(Outputs,LED_num);
199
            }
200
            LED_num++;
201
        }
202
    }
203
                shiftOut32(Outputs);
204
}
205
206
// send the XML file with analog values, switch status
207
//  and LED status
208
void XML_response(EthernetClient cl)
209
{
210
    unsigned char i;
211
    unsigned int  j;
212
    
213
    cl.print("<?xml version = \"1.0\" ?>");
214
    cl.print("<inputs>");
215
    for (i = 0; i < 4; i++) 
216
    {
217
        for (j = 1; j <= 0x80; j <<= 1) 
218
        {
219
            cl.print("<LED>");
220
            if ((unsigned char)LED_state[i] & j) 
221
            {
222
                cl.print("checked");
223
            }
224
            else {
225
                cl.print("unchecked");
226
            }
227
            cl.println("</LED>");
228
        }
229
    }
230
231
 shiftIn32();  
232
233
  for( uint8_t i = 0; i<32; i++ )
234
{
235
            cl.print("<switch>");
236
            if (Input[i])
237
            {
238
                cl.print("checked");
239
            }
240
            else {
241
                cl.print("unchecked");
242
            }
243
            cl.println("</switch>");
244
        }
245
    
246
247
    cl.print("</inputs>");
248
}
249
250
// sets every element of str to 0 (clears array)
251
void StrClear(char *str, char length)
252
{
253
    for (int i = 0; i < length; i++) 
254
    {
255
        str[i] = 0;
256
    }
257
}
258
259
// searches for the string sfind in the string str
260
// returns 1 if string found
261
// returns 0 if string not found
262
char StrContains(char *str, char *sfind)
263
{
264
    char found = 0;
265
    char index = 0;
266
    char len;
267
268
    len = strlen(str);
269
    
270
    if (strlen(sfind) > len) 
271
    {
272
        return 0;
273
    }
274
    while (index < len) 
275
    {
276
        if (str[index] == sfind[found]) 
277
        {
278
            found++;
279
            if (strlen(sfind) == found) 
280
            {
281
                return 1;
282
            }
283
        }
284
        else {
285
            found = 0;
286
        }
287
        index++;
288
    }
289
290
    return 0;
291
}
292
//-----------------------------------------------------------------------------------------------------------------
293
void clr_Outputs() // - Bitmuster Übergabe an Shift-Routine
294
//-----------------------------------------------------------------------------------------------------------------
295
{
296
  Outputs = 0x00000000; // alle Ausgänge aus              
297
  shiftOut32(Outputs);  
298
}
299
//-----------------------------------------------------------------------------------------------------------------
300
// 32 Bit ShiftOut Routine für 4x 74HTC595 - Hauptroutine SHIFT-OUT Shield, kopiere diese in dein Listing!
301
//-----------------------------------------------------------------------------------------------------------------
302
void shiftOut32(uint32_t val)
303
{
304
  byte i;
305
  byte i1;
306
  byte Sbyte;
307
  byte shiftNo;       
308
  digitalWrite(OUT_latchPin, LOW);    // Latch-Output disablen, während übertragen wird
309
        Sbyte = val;
310
        for (i1 = 0; i1 < 4; i1++) 
311
        {
312
          for (i = 0; i < 8; i++)  
313
          {
314
            digitalWrite(OUT_dataPin, !!(Sbyte & (1 << i)));
315
            digitalWrite(OUT_clockPin, HIGH);
316
            digitalWrite(OUT_clockPin, LOW);
317
          }
318
          shiftNo += 8;
319
          Sbyte = val >> shiftNo;
320
        }
321
  digitalWrite(OUT_latchPin, HIGH);    // Latch-Output enablen, nach der Übertragung
322
  digitalWrite(OUT_clockPin, LOW);
323
}
324
//-----------------------------------------------------------------------------------------------------------------
325
// 32 Bit ShiftIn Routine für 4x 74HC165 - Hauptroutine SHIFT-IN Shield, kopiere diese in dein Listing!
326
//-----------------------------------------------------------------------------------------------------------------
327
uint32_t shiftIn32( void )
328
{
329
330
  digitalWrite(IN_loadPin, LOW);
331
  digitalWrite(IN_loadPin, HIGH);
332
  for( uint8_t i = 0; i<32; i++ )
333
  {
334
    Inputs >>= 1;
335
    if( digitalRead(IN_dataPin))
336
      {
337
        Inputs |= 0x80000000;
338
        Input[i] = 1;
339
      }
340
     else
341
      {
342
        Input[i] = 0;
343
      }
344
      
345
    digitalWrite(IN_clockPin, HIGH);
346
    digitalWrite(IN_clockPin, LOW);
347
  }
348
return Inputs;
349
}
350
//-----------------------------------------------------------------------------------------------------------------
351
void canbus()                               // erstmal nur zum testen...
352
{
353
long unsigned int rxId;
354
        digitalWrite(A1,HIGH);
355
356
  // send data:  ID = 0x100, Standard CAN Frame, Data length = 8 bytes, 'data' = array of data bytes to send
357
  int pwm_count = random(255);
358
  byte data[8] = {0x10, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
359
  byte data2[8] = {0x81, pwm_count, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
360
361
  byte sndStat1 = CAN0.sendMsgBuf(0x101, 0, 8, data);
362
  byte sndStat2 = CAN0.sendMsgBuf(0x777, 0, 8, data2);
363
  byte sndStat3 = CAN0.sendMsgBuf(0x100, 0, 8, data2);
364
365
  if(!digitalRead(CAN0_INT))                         // If CAN0_INT pin is low, read receive buffer
366
    {
367
      CAN0.readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
368
    }
369
        digitalWrite(A1,LOW);
370
}
371
//------------------------------------------------ EOF -----------------------------------------------------------------

Ohne die CAN-BUS Routine habe ich diese Meldung:
1
Der Sketch verwendet 25.658 Bytes (79%) des Programmspeicherplatzes.
2
Das Maximum sind 32.256 Bytes.
3
Globale Variablen verwenden 1.395 Bytes (68%) des dynamischen Speichers,
4
653 Bytes für lokale Variablen verbleiben. 
5
Das Maximum sind 2.048 Bytes.

mit CAN BUS sind es nur noch 152 Bytes.

Wo könnte man was optimieren?

Ich bin für Tips sehr dankbar!

Wolfram.

: Bearbeitet durch User
von Εrnst B. (ernst)


Lesenswert?

IIRC braucht die mitgelieferte Standard-SD-Card Library 
unverhältnismäßig viel Flash&Ram.

Da gibt es kleinere, ggfs. unter Verzicht auf exFAT und andere 
Spielereien.

Ansonsten Strings wo möglich in F("...") klammern.

also
 cl.print("checked"); -->  cl.print(F("checked"));

: Bearbeitet durch User
von Wolfram F. (mega-hz)


Lesenswert?

Εrnst B. schrieb:
> Da gibt es kleinere, ggfs. unter Verzicht auf exFAT und andere
> Spielereien.

hast du nen link für eine sparsamere SD Library?
>
> Ansonsten Strings wo möglich in F("...") klammern.
das geht doch aber nur für Strings mit sich nicht ändernden Daten, oder?
(z.B. die MAC-Adresse?)

von Εrnst B. (ernst)


Lesenswert?

Wolfram F. schrieb:
> (z.B. die MAC-Adresse?)
geht für fast alle konstanten Strings, also alles was zwischen 
Gänsefüßchen im Quelltext steht.
als Parameter zu s(n)printf gehts z.B. nicht, da könnte man auf 
snprinf_P und PSTR ausweichen, wenn man auch noch die letzten Bytes 
rausquetschen will.

Wolfram F. schrieb:
> link für eine sparsamere SD Library

Leider nicht, bin länger nicht mehr mit Arduino unterwegs gewesen. 
Sollte sich aber leicht was finden lassen, ggfs. kann man auch per 
#define (-D Compileroption) die mitgeliferte SD-Lib verkleinern.

von Nico W. (nico_w)


Angehängte Dateien:

Lesenswert?

Ggf. noch auf digitalWrite und pinMode verzichten.

Hab jetzt nur mal kurz mit direktem Registerzugriff den Unterschied 
angeguckt. Ein Pin als Output gesetzt und dann in der loop auf LOW.

digitalWrite/PinMode:
Der Sketch verwendet 1.268 Bytes (0%) des Programmspeicherplatzes. Das 
Maximum sind 253.952 Bytes.

direkter Registerzugriff via Makro:
Der Sketch verwendet 660 Bytes (0%) des Programmspeicherplatzes. Das 
Maximum sind 253.952 Bytes.

von Wolfram F. (mega-hz)


Lesenswert?

wow, das sind Unterschiede!
Aber mit direkter Register-Programmierung kenn ich mich leider nicht aus 
:-(

Ich habe aber eben alle print ausgaben mit F() versehen, das brachte 
schonmal 172 Bytes mehr!

Kannst Du mir den Code für die Makros mal schreiben?

von Wolfram F. (mega-hz)


Lesenswert?

konnte nochwas sparen:

// send rest of HTTP header
client.println(F("Content-Type: text/xml"));
client.println(F("Connection: keep-alive"));
client.println();   <-- entfernt und:

// send rest of HTTP header
client.println(F("Content-Type: text/xml"));
client.println(F("Connection: keep-alive\n"));

8 Bytes mehr! (allerdings im Flash, nicht SRAM)

: Bearbeitet durch User
von TestX (Gast)


Lesenswert?

@mega-hz

Schau dir das avr gcc tutorial hier auf der seite an! Dort findest du 
alle infos und weißt danach auch selbst wie es geht.

Wenn du dir die arbeit nicht machen willst ist es sinnvoller sich einen 
größeren arduino zu kaufen und den code dort laufen zu lassen..

von Einer K. (Gast)


Lesenswert?

Wolfram F. schrieb:
> Kannst Du mir den Code für die Makros mal schreiben?

Suche mal nach "digitalfastwrite" oder "arduino fast pin"

von Wolfram F. (mega-hz)


Lesenswert?

die digitalFastWrite Lib hab ich schon öfter benutzt, verbraucht die 
denn weniger?
Mal probieren...

von Wolfram F. (mega-hz)


Lesenswert?

alle pinMode, digitalWrite und digitalRead sind nun durch Fast ersetzt,
ergab 62 Bytes weniger Flashspeicher.

Byte für Byte.... :-)

Habe aber immernoch nur 825 Bytes SRAM frei,
mal sehen ob sich die Can-Routinen jetzt schon mit einbinden lassen...

von Arduinoquäler (Gast)


Lesenswert?

Wolfram F. schrieb:
> Da ich eher der Hardworker bin, bitte ich Euch um Hilfe, den Code zu
> optimieren!

Wenn du unbedingt bei Arduino bleiben willst dann nimm einen
Mega2560 der "pinkompatibel" ist. Kost' ja nix ... und hat
viel mehr Flash und RAM.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

> Speicheroptimierung

Vor Optimierung erfolgt erst mal Profiling um rauszufinden, wo wann 
warum wieviel Speicher verbraucht wird.  Darauf basierend kann dann u.U. 
Optimierung erfolgen.

Als erstes findest du also heraus, selche Komponenten statisch / 
dynamisch Speicher, Stack, Heap, Static Storage etc. benötigen und 
wieviel.

von Wolfram F. (mega-hz)


Lesenswert?

Wolfram F. schrieb:
> mal sehen ob sich die Can-Routinen jetzt schon mit einbinden lassen...

Und was soll ich sagen, die Can-Bus Routinen funktionieren nun!
Auch wenn nur noch 328Bytes frei sind (RAM) läuft der Webserver incl.CAN 
nun!

Erstmal vielen Dank für Eure Tips!

Werde mich nun noch nach einer speichersparenden SD-Lib kümmern.

Da noch ne Frage an die Experten:

Wäre es nicht auch irgendwie möglich, die Webseite anstatt von einer 
SD-Karte direkt von meinem Server zu laden und weiterzusenden?

Also anstatt SD.open / read usw. 192.168.2.223/web-io.htm ?

> Wenn du unbedingt bei Arduino bleiben willst dann nimm einen
> Mega2560 der "pinkompatibel" ist. Kost' ja nix ... und hat
> viel mehr Flash und RAM.

Das es größere Controller gibt, ist mir schon klar, wenn es nicht 
geklappt hätte, wäre das ein Weg.
Arduino ist nur in der Test-/Aufbauphase, da praktisch.
Später kommt auf eine eigene Platine dann auch ein einzelner Controller.

von Arduinoquäler (Gast)


Lesenswert?

Wolfram F. schrieb:
> Später kommt auf eine eigene Platine dann auch ein einzelner Controller.

Und dann hoffentlich auch ohne Arduino IDE ....

von Εrnst B. (ernst)


Lesenswert?

Wolfram F. schrieb:
> SD-Karte direkt von meinem Server zu laden und weiterzusenden?

Umständlich.

Wie groß ist die Webseite denn?
Wenn sie kleiner ist als der Flash-Bedarf der SD-Lib (und die SD nicht 
für andere Sachen auch gebraucht wird) dann lad sie doch aus dem 
AVR-Flash.

Und im HTML kannst du den Webbrowser ja direkt Bilder, JS, CSS usw. von 
deinem Server laden lassen.

von Stefan F. (Gast)


Lesenswert?

"Hilfe mir geht der Speicher aus" hört man auffällig oft von Arduino 
Nutzern.

Ganz ehrlich: Wer so komplexe Programme hinbekommt, der kann das auch 
ohne Arduino Software. Versuch es einfach mal, ist wirklich nicht 
schwer.

von Wolfram F. (mega-hz)


Lesenswert?

das kommt ja auch bald, Visual Studio 2015 ist schon installiert.

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

Stefan U. schrieb:
> "Hilfe mir geht der Speicher aus" hört man auffällig oft von Arduino
> Nutzern.

Wer sich so gar nicht mit Mikrocontrollern befassen will und daher 
copy&paste-Programmierung mit gewaltigem Overhead macht, der muß sich 
eben einen fetteren Chip kaufen.

Was ja auch der Grund ist, wieso das Arduino-Ökosystem in der Industrie 
jedenfalls dort keinen Fuß fassen konnte, wo es um Stückzahlen geht.

von c r (Gast)


Lesenswert?

Nop schrieb:
> Was ja auch der Grund ist, wieso das Arduino-Ökosystem in der Industrie
> jedenfalls dort keinen Fuß fassen konnte, wo es um Stückzahlen geht.

Ich denke der Grund ist eher, dass das nie das Ziel war.

von Stefan F. (Gast)


Lesenswert?

Naja, ich programmiere beruflich hauptsächlich in Java mit zahlreichen 
Frameworks über Framworks. Das ist auch nicht gerade Platzsparend und 
schon gar nicht effizient. Vor 20 Jahren war außerdem Java selbst noch 
fast eine Scriptsprache.

Dennoch hat Java und seine Frameworks einen sicheren Platz im Enterprise 
Umfeld. Da kommt es (wegen der geringen Stückzahl) eher auf niedrige 
Entwicklungskosten an. In so einem Umfeld könnte Arduino durchaus 
punkten. Also ich meine dort, wo man nicht in Massen für jedermann 
produziert, sondern Spezialkonstruktionen für einzelne Anwendungsfälle.

von Nop (Gast)


Lesenswert?

c r schrieb:

> Ich denke der Grund ist eher, dass das nie das Ziel war.

Und wieso kommen dann Leute auf die blödsinnige Idee, bei einem 
Einzelprojekt wie einer DIY-Haussteuerung unbedingt am Controller sparen 
zu wollen? Und bei Webserver, Ehternet, IO, CAN unbedingt 32k ROM und 2k 
RAM verwenden zu wollen? Und das auch noch mit der Arduino-Bloatware?

Also entweder man hat Stückzahlen und will daher den Controller günstig 
halten, dann macht man das nicht mit der Arduino-Software. Oder man hat 
keine Stückzahlen, will die Entwicklung bequem halten und nimmt daher 
die Arduino-Software, dann aber halt auch einen größeren Controller.

Ein Arduino Mega hat statt 2k/32k schonmal 8k/128k, und damit hätte der 
TE seine Probleme nicht.

Die eierlegende Wollmilchsau, also bequeme Programmierung ohne 
Einarbeitung, billigen Controller UND komplexe Anwendung, das geht nicht 
gut. Von diesen drei Parametern sind nur jeweils zwei wählbar.

von Wolfram F. (mega-hz)


Lesenswert?

dieses Projekt ist ja erst so nach und nach entstanden und dafür ist der 
Arduino doch prima! Da ich inzwischen aber noch ein paar Ideen habe, 
plane ich einen Atmega128 zu verwenden, damit habe ich dann auch genug 
Reserve.
Alles was das laufende Programm jetzt macht, ist nahe dem Ziel.
Was noch rein muss, sind diverse Auswertungen des CAN-BUSses und 
Reaktionen auf bestimmte Daten. RTC, sonst ist nix mehr geplant.
Der 128er kommt dann mit allen anderen Teilen und OHNE Arduino 
Bootloader auf eine Platine, die ich noch entwerfe.

Genauso habe ich meine UP-Platinen mit CAN-Bus entwickelt, erst auf dem 
Arduino getestet dann PCB gemacht, ATMEGA8, MCP2515 und Relays drauf, 
fertig!

Ich weiss garnicht, warum von einer bestimmten Personengruppe regelmäßig 
auf die Arduinos geschimpft wird, ist doch ein prima "Baukasten"!

Ich kann mich noch gut an die Zeiten erinnern, wo Computer nur 8Bit 
hatten und man sich qualvoll und unbequem mit LDA #$00 STA $400 
Assembler rumquälen MUSSTE!
Dagegen ist so ein Arduino doch wirklich ein Leckerbissen!

Aber ich denke es sind die gleichen Leute, die auch PCBs, die mit EAGLE 
gemacht wurden, nur belächeln...

Trotzdem bin ich heute einiges weiter gekommen und bedanke mich sehr 
dafür!

: Bearbeitet durch User
von Walter S. (avatar)


Lesenswert?

Wolfram F. schrieb:
> Ich kann mich noch gut an die Zeiten erinnern, wo Computer nur 8Bit
> hatten und man sich qualvoll und unbequem mit LDA #$00 STA $400
> Assembler rumquälen MUSSTE!
> Dagegen ist so ein Arduino doch wirklich ein Leckerbissen!

obwohl er auch nur 8-Bit hat

von Falk B. (falk)


Lesenswert?

@Stefan Us (stefanus)


>"Hilfe mir geht der Speicher aus" hört man auffällig oft von Arduino
>Nutzern.

Dort gibt es halt einen hohen Anteil Anfänger und "mach mal schnell 
Maker" ohne Hintergrundwissen.

>Ganz ehrlich: Wer so komplexe Programme hinbekommt, der kann das auch
>ohne Arduino Software. Versuch es einfach mal, ist wirklich nicht
>schwer.

Unfug! Man erfindet das Rad nicht neu! Die meisten Arduino-Libs sind 
schon voll OK, das kann man mit vernünftigem Aufwand kaum besser machen.
Warst du nicht derjenige, der sich über die lernunwilligen Kinder 
beschwert hat? Bei deiner Sichtweise kein Wunder . . .

von Nop (Gast)


Lesenswert?

Wolfram F. schrieb:

> Ich weiss garnicht, warum von einer bestimmten Personengruppe regelmäßig
> auf die Arduinos geschimpft wird, ist doch ein prima "Baukasten"!

Weil es nunmal kein Wunder ist, daß man dauernd Ressourcenprobleme hat, 
wenn man seinen Controller unbedingt mit einen Lasagnedesaster aus 
Bloatsoftware programmieren will.

Man kann dann einfach einen größeren Controller nehmen und muß halt 
damit leben, daß die Leute, die das kritisieren, denselben Zweck mit 
einem viel kleineren Controller erreichen können. Das ist der Lohn der 
Einarbeitung nach Controller-Datenblatt.

Dies übrigens ohne flächendeckende Assemblerprogrammierung; das wird 
heute nur noch in sehr wenigen Teilen gemacht. Für den Rest nimmt man 
entweder C oder (im Wesentlichen) auf "C mit Klassen" begrenztes C++. 
Dann braucht man ohne die Lasagne-Architektur auch nicht 100 Taktzyklen, 
um einen Pin zu toggeln.

Andererseits gibt's ja sogar Leute, die für ein paar GPIOs unter einem 
Raspi gar nicht erst anfangen. Hat den Vorteil, daß man dann weder 
Assembler noch C noch C++ braucht, sondern das auch mehr oder weniger 
mit Shellscripten hinbekommt. ;-)

von Einer K. (Gast)


Lesenswert?

Nop schrieb:
> Weil es nunmal kein Wunder ist, daß man dauernd Ressourcenprobleme hat,
> wenn man seinen Controller unbedingt mit einen Lasagnedesaster aus
> Bloatsoftware programmieren will.
>
> Man kann dann einfach einen größeren Controller nehmen und muß halt
> damit leben, daß die Leute, die das kritisieren, denselben Zweck mit
> einem viel kleineren Controller erreichen können. Das ist der Lohn der
> Einarbeitung nach Controller-Datenblatt.
>
> Dies übrigens ohne flächendeckende Assemblerprogrammierung; das wird
> heute nur noch in sehr wenigen Teilen gemacht. Für den Rest nimmt man
> entweder C oder (im Wesentlichen) auf "C mit Klassen" begrenztes C++.
> Dann braucht man ohne die Lasagne-Architektur auch nicht 100 Taktzyklen,
> um einen Pin zu toggeln.

Das geht auch alles mit der Arduino IDE...
c++ ist dort Standard
Die Arduino Komfort Funktionen muss man ja nicht verwenden, wenn sie 
stören.
Nix "Bloat", wenn man nicht will.

Deine Argumente sind heiße Luft.

von Nop (Gast)


Lesenswert?

Im Codebeispiel übrigens noch:

- StrContains/StrClear: beide überflüssig.

- Verwendung von sprintf: Völlig unnötig für diesen Anwendungsfall, und 
außerdem mit unnötigem Stackverbrauch. Wäre interessant zu sehen, ob 
sich damit nennenswert Speicher sparen läßt - falls nicht anderswo im 
Framework unter der Haube sowieso noch printfs herumspuken.

Alternative, zumal LED_num offensichtlich nicht größer als 8 werden kann 
(weil j nur für 8 bits in der Schleife durchläuft):
1
#define STR_REQ_LED_LEN 7
2
#define STR_REQ_LED_NUM_POS   3
3
#define STR_REQ_LED_STATE_POS 5
4
void SetLEDs(void)
5
{
6
    char str_req[STR_REQ_LED_LEN];
7
    uint8_t i, j, LED_num = 0;
8
    
9
    
10
    strcpy(str_req, "LEDx=y");
11
    
12
    for (i = 0; i < 4; i++) 
13
    {
14
        for (j = 1; j > 0; j <<= 1) 
15
        {
16
            str_req[STR_REQ_LED_NUM_POS] = ((char) (LED_num)) + '0';
17
            str_req[STR_REQ_LED_STATE_POS] = '1';
18
            if (strstr(HTTP_req, str_req)) 
19
            {
20
                LED_state[i] |= j;  // save LED state
21
                bitSet(Outputs,LED_num);
22
            }
23
            else
24
            {
25
                str_req[STR_REQ_LED_STATE_POS] = '0';
26
                if (strstr(HTTP_req, str_off)) 
27
                {
28
                    LED_state[i] &= (~j);  // save LED state
29
                    bitClear(Outputs,LED_num);
30
                }
31
            }
32
            LED_num++;
33
        }
34
    }
35
    shiftOut32(Outputs);
36
}

Kann ich jetzt nicht testen, aber die Idee ist, sprintf ganz 
rauszukriegen, und das bißchen Stringhandling direkt am String zu 
machen.

von Nop (Gast)


Lesenswert?

Arduino F. schrieb:

> Die Arduino Komfort Funktionen muss man ja nicht verwenden, wenn sie
> stören.

Arduino ist aber gerade wegen des SW-Ökosystems so erfolgreich, also 
wegen des Bloats. Und wie es der Zufall mit der ehißen Luft so will, 
schau mal, was hier im konkreten Fall verwendet wird.

von Einer K. (Gast)


Lesenswert?

Nop schrieb:
> was hier im konkreten Fall verwendet wird.

Wenn Hein Blöd seine Konservendose mit der Axt öffnet, dann kann 
passieren, dass er ein paar Spritzer abbekommt.

Was ist in dem Fall scheiße/fehlerhaft?
(es sind auch Mehrfachnennungen erlaubt)
[ ] Die Axt ist kaputt, und muss durch eine modernere ersetzt werden
[ ] Die Dose entspricht nicht der Dosen Spezifikation

von IDE Löter (Gast)


Lesenswert?

>> Später kommt auf eine eigene Platine dann auch ein einzelner Controller.
>
> Und dann hoffentlich auch ohne Arduino IDE ....

Hab noch keine A.IDE auf einer Platine gesehen!

von Nop (Gast)


Lesenswert?

Arduino F. schrieb:

> Was ist in dem Fall scheiße/fehlerhaft?

Dein Quotemardering.

von Cyblord -. (cyblord)


Lesenswert?

Arduino F. schrieb:
> Deine Argumente sind heiße Luft.

Haha DAS letzte Argumente der ArduinoZombies. Es ist nicht scheiße weil 
man es ja nicht nutzen muss. Sehr gut! So wie der Zucker der den Kaffee 
bitter macht, wenn man ihn nicht rein tut.

Müßig darauf hinzuweisen dass das Problem dann nicht mehr besteht, wenn 
man die problematische Software nicht mehr einsetzt.
Aber "Arduino" ohne dieses ganze BLOAT, ist natürlich kein Arduino mehr, 
sondern eine Platine mit Controller wie tausend andere auch. Darum nutzt 
der TE auch das BLOAT weil er sich nicht damit beschäftigen will, 
sondern er sich für den coolen Frood hält wenn er "server.begin()" in 
die dunkle Nacht ruft, aber keine Taschenlampe hat um zu sehen was da 
eigentlich hinter steckt. DAS wäre bei einer klassischen Lib anders, DIE 
würde aber bisschen Skill erfordern. Will man also nicht.

Und da es natürlich keine guten oder schlechten Entscheidungen gibt, 
sondern nur Konsequenzen, ist die Konsequenz aus deiner 
Arduino-Entscheidung nun eben die dass es nicht funktioniert. 
Glückwunsch. Danke. Weitergehen!

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

Cyblord -. schrieb:
> ist die Konsequenz aus deiner
> Arduino-Entscheidung nun eben die dass es nicht funktioniert.

Mit nem Arduino Mega würde es ja wieder funktionieren, was die 
Speicherproblematik angeht. Nur hat der kein Ethernet; aber der 
verwendete Uno hat das ja auch nicht, von daher bin ich auch ein wenig 
verwundert, wie das überhaupt da reingeht. Es sei denn, es handelt sich 
in Wahrheit um den Arduino Ethernet, der bis eben auf die 
Ethernet-Schnittstelle mit dem Uno identisch ist.

Da es den Mega aber AFAIK nicht in der Ethernet-Ausfürhung gibt, wäre 
das natürlich etwas tricky.

Wenn es eine ganze Haussteuerung ist, wäre es aber sowieso eine 
Alternative, sich die lokalen Knoten aufzubauen ohne Ethernet, sondern 
mit CAN.

Und dann als Zentralserver nen Raspi zu nehmen, der das Monitoring und 
zentrale Koordination übernimmt. Etwa im Winter gucken, wie die 
gemittelte Leistung der kleinen Dach-PV ist, daraus zu folgern, ob Sonne 
scheint oder nicht, und dementsprechend tagsüber die Rolläden hochfahren 
oder runter. Damit könnte man wohl Heizkosten sparen.

Außerdem wäre auch ewig viel Speicher da für Logfiles, was sicherlich 
beim Debuggen und Optimieren hilft. Beispielsweise, wie lange die 
sinnvolle Mittelungszeit der PV sein sollte, um bei "heiter bis wolkig" 
vernünftig zu regeln.

Zudem hätte man dann eine Art von Schichten-Architektur im System, statt 
alles in einem ball of mud zusammenzukleben, was zugegebenermaßen genau 
das ist, wozu Arduino-Sketche ihrem Aufbau nach ohnehin sehr verführen. 
Ist ja OK für schnell-mal-eben-was-prototypen, aber mehr auch nicht.

von Einer K. (Gast)


Lesenswert?

Nop schrieb:
> Mit nem Arduino Mega würde es ja wieder funktionieren, was die
> Speicherproblematik angeht. Nur hat der kein Ethernet; aber der
> verwendete Uno hat das ja auch nicht, von daher bin ich auch ein wenig
> verwundert, wie das überhaupt da reingeht. Es sei denn, es handelt sich
> in Wahrheit um den Arduino Ethernet, der bis eben auf die
> Ethernet-Schnittstelle mit dem Uno identisch ist.
>
> Da es den Mega aber AFAIK nicht in der Ethernet-Ausfürhung gibt, wäre
> das natürlich etwas tricky.

Das Arduino Ethernet Shield passt auf UNO und Mega.

von Wolfram F. (mega-hz)


Lesenswert?

Arduino F. schrieb:
> Das Arduino Ethernet Shield passt auf UNO und Mega

genau so ist es, Uno,Ethernet-Shield,Can-bus,shift-in,shift-out shield.

Nop schrieb:
> Wenn es eine ganze Haussteuerung ist, wäre es aber sowieso eine
> Alternative, sich die lokalen Knoten aufzubauen ohne Ethernet, sondern
> mit CAN.

Und auch dies ist genau das, was der Haufen machen soll!
Die Ehternet Schnittstelle ist nur für die Webseite/Weboberfläche.
Die einzelnen Knoten haben je eine einstellbare CAN-ID und warten auf 
Befehle (PWM oder Relays-Ausgang) und senden bei Bedarf 8 Analog-Werte, 
wobei der erste Wert immer die Betriebsspannung (28V) in 8Bit und der 
2.Wert immer den echten Zustand des Relays zurückliefert. Alle anderen 
Eingänge können analog oder digital sein -> NTC oder auch Tür-Kontakt.

Nop schrieb:
> #define STR_REQ_LED_LEN 7
> #define STR_REQ_LED_NUM_POS   3
> #define STR_REQ_LED_STATE_POS 5
> void SetLEDs(void)
> {
>     char str_req[STR_REQ_LED_LEN];
>     uint8_t i, j, LED_num = 0;
>
>
>     strcpy(str_req, "LEDx=y");
>
>     for (i = 0; i < 4; i++)
>     {
>         for (j = 1; j > 0; j <<= 1)
>         {
>             str_req[STR_REQ_LED_NUM_POS] = ((char) (LED_num)) + '0';
>             str_req[STR_REQ_LED_STATE_POS] = '1';
>             if (strstr(HTTP_req, str_req))
>             {
>                 LED_state[i] |= j;  // save LED state
>                 bitSet(Outputs,LED_num);
>             }
>             else
>             {
>                 str_req[STR_REQ_LED_STATE_POS] = '0';
>>>>>             if (strstr(HTTP_req, str_off)) <<<soll str_req sein!?
>                 {
>                     LED_state[i] &= (~j);  // save LED state
>                     bitClear(Outputs,LED_num);
>                 }
>             }
>             LED_num++;
>         }
>     }
>     shiftOut32(Outputs);
> }

diese Routine bringt zwar 1482 Bytes mehr Flash und 2 Bytes mehr RAM 
funktioniert (abgesehen von dem str_off Fehler) aber nur von Ausgang 0 
bis 9 !

von Nop (Gast)


Lesenswert?

Wolfram F. schrieb:

>> soll str_req sein!?

Jepp, vergessen.

Ich sehe gerade, daß LED_Num in jeder inneren Schleife hochgetickert 
wird, so daß sie LED_Num mit 4mal von der äußeren Schleife und 8mal von 
der inneren bis 31 gehen kann und nicht nur bis 7, wie ich annahm, daher 
der Fehler.

Da in den Requests die LED-Nummer nicht mit führender 0 übergeben wird, 
können die also lauten:

LED1=1 (bzw =0) bis LED31=1 (bzw. 0). Sinnvoll abgetestet mit meinem 
Code werden aber nur die LEDS 0-9.

Mit AVR-GCC müßte auch die Funktion itoa() verfügbar sein und in 
stdlib.h definiert sein. Ist allerdings kein ANSI-C, aber wenn's die 
schon gibt, kann man die vorhandene auch nehmen.

1482 Bytes Flash für das bißchen Recoding ist definitiv ein Knaller, 
damit kriegt man schonmal zumindest Codespace.
1
#define STR_REQ_LED_LEN       8
2
#define STR_REQ_LED_NUM_POS   3
3
4
void SetLEDs(void)
5
{
6
    char str_req[STR_REQ_LED_LEN];
7
    uint8_t i, j, LED_num = 0;
8
    
9
    strcpy(str_req, "LED");
10
11
    for (i = 0; i < 4; i++)
12
    {
13
        for (j = 1; j > 0; j <<= 1) /*after 0x80, uint8 wraps to 0*/
14
        {
15
            /*reset the request string to "LED"*/
16
            str_req[STR_REQ_LED_NUM_POS] = 0;
17
            
18
            /*append LED number 0-31*/
19
            (void) itoa(LED_num, str_req+STR_REQ_LED_NUM_POS, 10);
20
            strcat(str_req, "=1");
21
            
22
            if (strstr(HTTP_req, str_req))
23
            {
24
                LED_state[i] |= j;  // save LED state
25
                bitSet(Outputs,LED_num);
26
            }
27
            else
28
            {
29
                /*change the last character of the req string from '1' to '0'*/
30
                str_req[strlen(str_req)-1] = '0';
31
                
32
                if (strstr(HTTP_req, str_req))
33
                {
34
                    LED_state[i] &= (~j);  // save LED state
35
                    bitClear(Outputs,LED_num);
36
                }
37
            }
38
            LED_num++;
39
        }
40
    }
41
    shiftOut32(Outputs);
42
}

von Nop (Gast)


Lesenswert?

Nop schrieb:

> /*reset the request string to "LED"*/
> str_req[STR_REQ_LED_NUM_POS] = 0;

Öh, das ist auch überflüssig, merke ich gerade.

von Wolfram F. (mega-hz)


Lesenswert?

das funktioniert fast!
Output 31, also der letzte (0-31) lässt sich nicht schalten!
EDIT: lässt sich doch schalten!! Aber irgendwie ist alles etwas 
langsamer jetzt!


und die Speicher Ersparnis ist runter auf +1288 Bytes im Flash.
Ich bräuchte mehr Ram-Speicher.

Anstatt die LED_State[] mit 4x 8Bit Belegung UND der long Variable 
"Outputs" beide zu benutzen, könnte man das nicht auch nur mit der Long 
Outputs machen?

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

Wolfram F. schrieb:
> das funktioniert fast!
> Output 31, also der letzte (0-31) lässt sich nicht schalten!
> EDIT: lässt sich doch schalten!! Aber irgendwie ist alles etwas
> langsamer jetzt!

Ich vermute, itoa() ist für Integer implementiert, also für 
16bit-Variablen. Das ist auf einem 8-bitter umständlich, zumal hier ja 
eigentlich nur 8bit-Ints gebraucht werden. Außerdem ist die Basis auch 
noch variabel. Also wohl mit Modulo und Division und dann auch noch in 
16bit.

Daher könnte man ein LEDtoa() selber implementieren, das sollte auch die 
Flash-Ersparnis wieder raufschrauben.

also itoa(LED_num, str_req+STR_REQ_LED_NUM_POS, 10); ersetzen und den 
Basisparameter (10 für dezimal) dabei rauswerfen. Das Eklige daran ist, 
daß auf dem AVR zwar die nette Funktion div existiert, die einem 
Quotient und Rest einer Division auf einen Schlag liefert, blöderweise 
aber für 16bit-ints.

Also richtig zu Fuß und dann auch ohne Division und Modulo, das müßte 
auch auf einem 8-bitter zügig gehen. 8-bit-Hacking, yeah. :-)
1
/*converts numbers 0-39 to 0 terminated ASCII, no leading zeros*/
2
void LEDtoa(uint8_t val, char *str)
3
{
4
    if (val >= 30)
5
    {
6
        *str++ = '3';
7
        val -= 30;
8
    } else if (val >= 20)
9
    {
10
        *str++ = '2';
11
        val -= 20;
12
    } else /*between 10 and 19*/
13
    {
14
        *str++ = '1';
15
        val -= 10;
16
    }
17
    *str++ = (char) val + '0';
18
    *str = 0; /*string zero termination*/
19
}

> Anstatt die LED_State[] mit 4x 8Bit Belegung UND der long Variable
> "Outputs" beide zu benutzen, könnte man das nicht auch nur mit der Long
> Outputs machen?

Ja, das wäre auch eine Option; soviel Rewrite hatte ich jetzt spontan 
nicht angedacht, um die Funktion "nach außen" hin konstant zu halten.

von Nop (Gast)


Lesenswert?

Korrektur.. hm als Gast kann ich nicht editieren, der else-Zweig für 
10..19 ist bei einer Umstrukturierung fehlerhaft übrig geblieben:
1
/*converts numbers 0-39 to ASCII, no leading zeros*/
2
void LEDtoa(uint8_t val, char *str)
3
{
4
    if (val >= 30)
5
    {
6
        *str++ = '3';
7
        val -= 30;
8
    } else if (val >= 20)
9
    {
10
        *str++ = '2';
11
        val -= 20;
12
    } else if (val >= 10)
13
    {
14
        *str++ = '1';
15
        val -= 10;
16
    }
17
    *str++ = (char) val + '0';
18
    *str = 0; /*string zero termination*/
19
}

von Wolfram F. (mega-hz)


Lesenswert?

ok, DAS funktioniert! hat +58 Bytes Flash und 2 Bytes RAM gebracht.
Vielen Dank dafür!

Mit den Variablen Outputs und Inputs (je long) hätte man eigentlich ja 
alles abgedeckt, eben 32Bits pro.

Dann bräuchte man die Input[8] nicht mehr, wären nochmal 9x8 Bytes...

Was zwar kein Speicherplatz jedoch weniger traffic bringt, wäre ne 
Abfrage, ob sich was geändert hat, Out oder Inputs, wenn nicht, brauchen 
die Ajax Daten auch nicht ständig hin und her geschickt werden.

von PittyJ (Gast)


Lesenswert?

Spätestens in 2 Monaten entstehen weitere Wünsche. Und da wird wieder 
der Platz nicht reichen. Da kann man so lange rumoptimieren wie man 
will, das führt aber nicht weiter.

Also sollte man jetzt schon schauen. ob es eine Architektur mit mehr 
Platz gibt. z.B. Arduino Due mit 500 K Flash und 96 K Ram. Oder man 
teilt das Programm auf mehrere Rechner auf: Arduino zum Steuern, Raspi 
für den Web-Server.

von Wolfram F. (mega-hz)


Lesenswert?

wie ich schon weiter oben erwähnte, soll auf der Platine dann ein 
Atmega128 Platz finden!
Nen PI für die Webseite?
Etwas overkill, oder?
Dann könnte man mit nem PI auch ALLES Steuern... aber wozu?
Ist preislich dann doch schon ein großer Unterschied.

Ziel ist es, daß die Webseite von meinem Server kommt,nicht mehr von der 
SD-Karte.
bin gerade dabei, dies hinzubekommen.... und die Umleitung vom Arduino 
zum Server klappt bereits,

client.println(F("HTTP/1.1 302 Found"));
client.println(F("Location: 
http://192.168.2.222/Arduino/WEB-IO/web-io.htm";));

nur kommen die Ajax Daten nun nicht mehr an.
Wie ich die Verbindung wieder hinbekomme, weiss ich noch nicht.
Jemand ne Idee?

von Εrnst B. (ernst)


Lesenswert?

Wolfram F. schrieb:
> nur kommen die Ajax Daten nun nicht mehr an.

Am einfachsten: Pack auf den AVR eine minimalst-Webseite, darin bindest 
du  Javascript+CSS von deinem Server ein. Im Javascript baust du die 
Webseiten-Elemente/Layout zusammen, und sprichst deine AJAX-Endpoints 
an.

So erfüllst du die "same domain policy" des Webbrowsers, hast aber 
trotzdem 99% der Webseite von einem anderen Server geladen.

von Wolfram F. (mega-hz)


Lesenswert?

ja, aber dann hab ich ja quasi das, wie es jetzt mit sd-karte ist!
Das meiste der Webseite ist ja CSS und JS!
Müsste nicht in der Webseite wieder eine "Verbindung" zum Arduino 
hergestellt werden?

von Εrnst B. (ernst)


Lesenswert?

Wolfram F. schrieb:
> ja, aber dann hab ich ja quasi das, wie es jetzt mit sd-karte ist!
> Das meiste der Webseite ist ja CSS und JS!
> Müsste nicht in der Webseite wieder eine "Verbindung" zum Arduino
> hergestellt werden?

Nein, ja.

Idee ist ein Minimal-HTML-File aus dem Arduino-flash(nicht SD!) 
auszuliefern, und den Rest vom externen Server nachladen zu lassen.

Zusammenführen macht der Webbrowser.

Der AVR muss nicht Reverse-Proxy spielen.

AJAX dann natürlich direkt zwischen Webbrowser und AVR.

von Wolfram F. (mega-hz)


Lesenswert?

und wie macht man das?
Hast Du Vorschläge?

von Εrnst B. (ernst)


Lesenswert?

Wolfram F. schrieb:
> und wie macht man das?
> Hast Du Vorschläge?
1
<html><head><script src='http://andererserver'>

von Joachim B. (jar)


Lesenswert?

Εrnst B. schrieb:
> Ansonsten Strings wo möglich in F("...") klammern.

hmmm wie macht man das bei sprintf?

sprintf(tmp_lcd_str, (F("faehrt %01d.%s")), (1+TRYS-f_cnt), dir_str);

 error: cannot convert 'const __FlashStringHelper*' to 'const char*' for 
argument '2' to 'int sprintf(char*, const char*, ...)'


ich erinnere mich auch an Problemchen mit strncmp_P strcpy_P obwohl 
diese ja genau dafür da sind.

von Wolfram F. (mega-hz)


Lesenswert?

Εrnst B. schrieb:
> <html><head><script src='http://andererserver'>;

das funktioniert so nicht:
1
// web page request
2
// send rest of HTTP header
3
client.println(F("Content-Type: text/html"));
4
client.println(F("Connection: keep-alive\n"));
5
// send web page
6
7
client.println(F("<html><head><script src='http://192.168.2.222/Arduino/WEB-IO/web-io.htm'>"));
8
9
//webFile = SD.open("/WEB-IO2.HTM");        // open web page file

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?


von Einer K. (Gast)


Lesenswert?

Joachim B. schrieb:
> ich erinnere mich auch an Problemchen mit strncmp_P strcpy_P obwohl
> diese ja genau dafür da sind.

AHA, jetzt habe ich erst kapiert, welche Sorgen dich da plagen, oder 
geplagt haben...

Du mischt das Arduino Komfort F() Macro mit den Atmel Lib Funktionen....
Da klemmt es!

So geht das:
1
const char PROGMEM format[] = "Running %08u ms";
2
3
4
char buffer[64];
5
6
void setup() 
7
{ 
8
   Serial.begin(9600);
9
}
10
11
void loop() 
12
{
13
  sprintf_P(buffer,format,millis());
14
  Serial.println(buffer);
15
  delay(997);
16
}

von Εrnst B. (ernst)


Lesenswert?

Wolfram F. schrieb:
> client.println(F("<html><head><script
> src='http://192.168.2.222/Arduino/WEB-IO/web-io.htm'>";));

Als Script natürlich ein Javascript-File, kein HTML-file angeben.

Im Javascript kannst du dann HTML-Fragmente zum Seitenaufbau und auch 
Daten per AJAX von AVR & 192.168.2.222 nachladen.

Sorry, bin davon ausgegangen, dass du zumindest ein paar HTML-Grundlagen 
beherrschst, nachdem oben die Anfrage nach AJAX kam...

Würde dir raten, das mit dem HTML erstmal ohne AVR, also "trocken", zu 
üben.

von Joachim B. (jar)


Lesenswert?

Arduino F. schrieb:
> AHA, jetzt habe ich erst kapiert, welche Sorgen dich da plagen, oder
> geplagt haben...

hat eh nichts gebracht

das F() macro bringt ja viel, aber der Wechsel von sprintf zu sprintf_P 
ist gelinde gesagt sinnlos

vorher sprintf
   text    data     bss     dec     hex
  28670     706     919   30295    7657
Binäre Sketchgröße: 29.376 Bytes


nachher sprintf_P
   text    data     bss     dec     hex
  28718     708     919   30345    7689
Binäre Sketchgröße: 29.376 Bytes

48 Byte im flash verloren und 2 Byte im data verloren, tolle 
Optimierung.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Joachim B. schrieb:
> tolle Optimierung.


sprintf_P
Flash: 3.130 Bytes
Ram: 250 Bytes

sprintf
Flash: 3.128 Bytes
Ram: 266 Bytes

Getestet, mit meinem Programm, von eben....

Das Verlegen des Formatstrings ins Flash gewinnt die volle Stringlänge 
im Ram, und kostet 1 Wort im Flash.

von Wolfram F. (mega-hz)


Lesenswert?

Εrnst B. schrieb:
> Als Script natürlich ein Javascript-File, kein HTML-file angeben.

hast du Dir die Seite eigentlich mal angeschaut?

von Joachim B. (jar)


Lesenswert?

Arduino F. schrieb:
> Das Verlegen des Formatstrings ins Flash gewinnt die volle Stringlänge
> im Ram, und kostet 1 Wort im Flash.

hätte ich auch erwartet

aber der Optimierer -o3 überrascht mich immer wieder, wenn ich denke ich 
schreibe besseren Code kommt hinterher optimiert was längeres raus.

vielleicht konnte er mit sprintf besser optimieren als mit sprintf_P

von Einer K. (Gast)


Lesenswert?

Joachim B. schrieb:
> vielleicht konnte er mit sprintf besser optimieren als mit sprintf_P

Meine Kristallkugel sagt:
Wahrscheinlich pullern bei dem Experiment sowohl sprintf und sprintf_P 
im Code rum. Damit wird wirksam verhindert, dass der Linker eine davon 
rauswirft. Ganz im Gegenteil, er muss beide einbinden.

von Εrnst B. (ernst)


Lesenswert?

Wolfram F. schrieb:
> hast du Dir die Seite eigentlich mal angeschaut?

Ja, die, die du oben gepostet hast:

Wolfram F. schrieb:
1
client.println(F("<html><head><script src='http://192.168.2.222/Arduino/WEB-IO/web-io.htm'>"));

Auf 192.168.2.222 habe ich logischerweise keinen Zugriff.

von Wolfram F. (mega-hz)


Lesenswert?


: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Arduino F. schrieb:
> Meine Kristallkugel sagt:
> Wahrscheinlich pullern bei dem Experiment sowohl sprintf und sprintf_P
> im Code rum.

nur wenn

suche sprintf
ersetze sprintf_P
alle ersetzen

nicht funktioniert

allerdings weiss ich nicht wie die IDE mit dem tmp Speicher umgeht

Die Namen sehen ja gleich aus an den o-files ändert sich evtl. kaum was

ich kann das nur noch mal probieren in dem ich nach ersetzen von sprintf 
jedes File noch mal absuche und dann das Projekt unter neuem Namen 
abspeichere, nur müsste ich dann sicherheitshalbee alle Projektfiles 
umbenennen und auch die #include umbenennen damit nix aus tmp rüber 
streusselt, besser noch das neue auf einen anderen Compi spielen, der 
den Cache tmp leeren.

von Einer K. (Gast)


Lesenswert?

Joachim B. schrieb:
> allerdings weiss ich nicht wie die IDE mit dem tmp Speicher umgeht

Die macht das schon richtig.
Zumindest ist mir da noch nichts gegenteiliges aufgefallen.

von Joachim B. (jar)


Lesenswert?

Wolfram F. schrieb:
> hast du Dir die Seite eigentlich mal angeschaut?

Scherzkeks -> 192.xxx ist eine aus dem internen Netz bei dir da kommt 
keiner von aussen ran!

Nop schrieb:
> Weil es nunmal kein Wunder ist, daß man dauernd Ressourcenprobleme hat,
> wenn man seinen Controller unbedingt mit einen Lasagnedesaster aus
> Bloatsoftware programmieren will.
>
> Man kann dann einfach einen größeren Controller nehmen

mache ich gerne statt nano328p 32k flash, 2k SRAM mighty mini mit 128k 
flash und 16k SRAM und damit doppelt so viel RAM als der olle m2560 und 
auch noch breadboard freundlicher.

Arduinoquäler schrieb:
> Wenn du unbedingt bei Arduino bleiben willst dann nimm einen
> Mega2560 der "pinkompatibel" ist. Kost' ja nix ... und hat
> viel mehr Flash und RAM.

klar s.o. nur ist der mighty mini richtig teuer geworden, den m2560 
bekommt man ja hinterher geworfen.

Stefan U. schrieb:
> "Hilfe mir geht der Speicher aus" hört man auffällig oft von Arduino
> Nutzern.
> Ganz ehrlich: Wer so komplexe Programme hinbekommt, der kann das auch
> ohne Arduino Software.

ist aber bequemer und das kostet halt, allerdings kann man sich auch mal 
hinsetzen und überflüsiges rauswerfen, so habe ich bei meiner 
Rolladensteuerung nach Sonnenstand auf dem Noka Display auch 1,5k flash 
optimieren können, vorher auf dem nano328p 30700 nur noch 20 Byte frei, 
nun nach Aufräumen 1,5k flash freigeschaufelt.

Arduino F. schrieb:
> http://www.atmel.com/webdoc/AVRLibcReferenceManual...

danke hatte ich auch schon gefunden.

: Bearbeitet durch User
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.