Forum: Mikrocontroller und Digitale Elektronik Größe einer char wird überschritten?


von Peter H. (borntopizza)


Lesenswert?

Moin Moin,

Ich stehe hier vor einem kleinen Problem.

Ich habe hier 2 Atmegas 328 die über 2 Enc28j60 mit dem Netzwerk 
verbunden sind.
Der eine Misst die Temperatur und gibt dann, wenn ein bestimmter 
Sollwert erreicht ist auf seiner Website "Status1" bzw. "Status0" aus, 
der 2. Atmega schaltet dann ein Relais. Das ganze funktioniert so weit 
auch ganz gut. Nur möchte ich noch 2 weitere Buttons einfügen, die GPIO 
Pins am Server High bzw. Low schalten.
Das überschreitet aber anscheinend die Größe der const char "reply" des 
Clients.
Bis 3 Buttons geht es gerade so noch, darüber werden die Daten zwar 
empfangen, aber das Relais wird nicht mehr geschalten.

Ich habe versucht den Text auch schon maximal zu kürzen, für einen 4. 
Button reicht es nicht :-(

Gibt es eine möglichkeit die Buttons oder die "Homepage" noch weiter zu 
kürzen, damit der Inhalt der char nicht "überschritten" wird?

Danke und Viele Grüße

Peter
1
static word homePage() {
2
  bfill = ether.tcpOffset();
3
  bfill.emit_p(PSTR(
4
    "HTTP/1.0 200 OK\r\n"
5
    "Content-Type: text/html\r\n"
6
    "Pragma: no-cache\r\n"
7
    "\r\n"
8
    "<meta http-equiv='refresh' content='1'/>"
9
    "<title>SH</title>"
10
    "<h1>Ti $D</h1>"
11
    "<h1>Ts $D</h1>"
12
    "<h1>Status$D</h1>"
13
    "<input type=submit value='+' style=width:90px;height:45px onClick=location.href'/?1'>"
14
    "<input type=submit value='-' style=width:90px;height:45px onClick=location.href'/?2'>"
15
    "<input type=submit value='R' style=width:90px;height:45px onClick=location.href'/?3'>"
16
    ),
17
      t, Tsoll, Status);
18
  return bfill.position();
19
}

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Das sind ungefähr 420 Zeichen zuzüglich die beiden Werte für $D.

Der Mikrocontroller hat insgesamt 2kB RAM. Da kann es durchaus sein, 
dass die Grösse deines Pufferspeichers schon überschritten hast. In 
diesem Fall wirst du deine Sendung wohl in mehrere Pakete aufteilen 
müssen, das ist ja auch der Haupt-Zweck von TCP (verglichen mit UDP).

Wie gross ist denn der Puffer?

von Peter H. (borntopizza)


Lesenswert?

Danke für die Antwort, meinst Du das hier:
1
byte Ethernet::buffer[700];

von Stefan F. (Gast)


Lesenswert?

Peter H. schrieb:
> Danke für die Antwort, meinst Du das hier:
> byte Ethernet::buffer[700];

Sieht danach aus. Genaueres kann ich Dir dazu auch nicht sagen, weil ich 
deine Software nicht kenne.

Bedenke, dass in die 700 Bytes auch noch der Ethernet Header rein muss.

von Peter H. (borntopizza)


Lesenswert?

Hmm ok.

Ich habe auch mal versucht die Zahl nach oben zu setzen, auf 1000, 
leider noch ohne Erfolg.

Das komische ist ja eigentlich, dass der Teil "Status1" bzw. "Stauts0" 
immernoch beim Client ankommt. Das kann ich im Seriellen Monitor sehen. 
Nur ab einem bestimmten Teil wird der Rest abgeschnitten und die "Reply" 
irgendiwie nicht mehr durchsucht und somit auch kein "Stauts1" bzw. 
"Status0" gefunden.

Der Server:
1
#include <EtherCard.h>
2
#include "DHT.h"
3
#include <EEPROM.h>
4
5
#define DHTPIN 4
6
#define DHTTYPE DHT11
7
DHT dht(DHTPIN, DHTTYPE);
8
unsigned long previousMillis = 0;
9
int Tsoll;
10
int t;
11
float Tmp;
12
byte value;
13
int Status;
14
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x38,0x31 };
15
static byte myip[] = { 192,168,10,199 };
16
17
18
byte Ethernet::buffer[1000];
19
BufferFiller bfill;
20
21
void setup (){ 
22
  // Change 'SS' to your Slave Select pin, if you arn't using the default pin
23
  if (ether.begin(sizeof Ethernet::buffer, mymac, 8) == 0)
24
    Serial.println(F("Failed to access Ethernet controller"));
25
  ether.staticSetup(myip);
26
  dht.begin();
27
  pinMode(5,OUTPUT);
28
  pinMode(6,OUTPUT);
29
  pinMode(7,OUTPUT);
30
  value = EEPROM.read(1);
31
  Tsoll = value;
32
  
33
}
34
35
static word homePage() {
36
  bfill = ether.tcpOffset();
37
  bfill.emit_p(PSTR(
38
    "HTTP/1.0 200 OK\r\n"
39
    "Content-Type: text/html\r\n"
40
    "Pragma: no-cache\r\n"
41
    "\r\n"
42
    "<meta http-equiv='refresh' content='1'/>"
43
    "<title>SH</title>"
44
    "<h1>Ti $D</h1>"
45
    "<h1>Ts $D</h1>"
46
    "<h1>Status$D</h1>"
47
    "<input type=submit value='+' style=width:90px;height:45px onClick=location.href'/?1'>"
48
    "<input type=submit value='-' style=width:90px;height:45px onClick=location.href'/?2'>"
49
    "<input type=submit value='R' style=width:90px;height:45px onClick=location.href'/?3'>"
50
    "<input type=submit value='H' style=width:90px;height:45px onClick=location.href'/?5'>"
51
    ),
52
      t, Tsoll, Status);
53
  return bfill.position();
54
}
55
56
void loop () {
57
    word len = ether.packetReceive();
58
    word pos = ether.packetLoop(len);
59
    unsigned long currentMillis = millis();
60
    if (currentMillis - previousMillis >= 3000) {
61
    previousMillis = currentMillis;
62
    Tmp = dht.readTemperature();
63
    value = EEPROM.read(1);
64
    }
65
    t = Tmp;
66
67
    if (Tsoll-2>=t){Status=1;}
68
    if (Tsoll-2<=t){Status=0;} 
69
70
71
    // IF LED10=ON turn it ON
72
    if(strstr((char *)Ethernet::buffer + pos, "GET /?1") != 0) {
73
    Tsoll++;
74
    EEPROM.write(1, Tsoll);
75
    };
76
77
    // IF LED10=OFF turn it OFF
78
    if(strstr((char *)Ethernet::buffer + pos, "GET /?2") != 0) {
79
    Tsoll--;
80
    EEPROM.write(1, Tsoll);
81
    };
82
    
83
    // IF LED10=ON turn it ON
84
    if(strstr((char *)Ethernet::buffer + pos, "GET /?3") != 0) {
85
    digitalWrite(6, LOW);
86
    digitalWrite(7, LOW);
87
    digitalWrite(5, HIGH);
88
    };
89
    // IF LED10=ON turn it ON
90
    if(strstr((char *)Ethernet::buffer + pos, "GET /?4") != 0) {
91
    digitalWrite(5, LOW);
92
    digitalWrite(7, LOW);
93
    digitalWrite(6, HIGH);
94
    };
95
    // IF LED10=ON turn it ON
96
    if(strstr((char *)Ethernet::buffer + pos, "GET /?5") != 0) {
97
    digitalWrite(5, LOW);
98
    digitalWrite(6, LOW);
99
    digitalWrite(7, HIGH);
100
    };
101
102
    if (pos)  // check if valid tcp data is received
103
    ether.httpServerReply(homePage()); // send web page data
104
}

Der Client:
1
// IoT by using module in client mode to send and receive data to your website.
2
3
// Simple demo for feeding some random data to Pachube.
4
// 2011-07-08 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
5
6
// Handle returning code and reset ethernet module if needed
7
// 2013-10-22 hneiraf@gmail.com
8
9
// Modifing so that it works on my setup for www.thingspeak.com.
10
// Arduino pro-mini 5V/16MHz, ETH modul on SPI with CS on pin 10.
11
// Also added a few changes found on various forums. Do not know what the 
12
// res variable is for, tweaked it so it works faster for my application
13
// 2015-11-09 dani.lomajhenic@gmail.com
14
15
#include <EtherCard.h>
16
17
// change these settings to match your own setup
18
//#define FEED "000"
19
#define APIKEY "beef1337beef1337" // put your key here
20
#define ethCSpin 8 // put your CS/SS pin here.
21
22
// ethernet interface mac address, must be unique on the LAN
23
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x37 };
24
const char website[] PROGMEM = "192.168.10.199";  //Change to your domain name 
25
byte Ethernet::buffer[1000];
26
uint32_t timer;
27
Stash stash;
28
byte session;
29
String d1;
30
//timing variable
31
int res = 100; // was 0
32
int analog=0;
33
unsigned long previousMillis = 0;
34
35
void(* resetFunc) (void) = 0;
36
37
void setup () {
38
  pinMode(3,INPUT_PULLUP);
39
  pinMode(7,OUTPUT);
40
  pinMode(4,OUTPUT);
41
  Serial.begin(9600);
42
  Serial.println("\n[ThingSpeak example]");
43
44
  //Initialize Ethernet
45
  initialize_ethernet();
46
47
    #if 1
48
49
  // if website is a string containing an IP address instead of a domain name,
50
  // then use it directly. Note: the string can not be in PROGMEM.
51
  char websiteIP[] = "http://192.168.10.199/";
52
  ether.parseIp(ether.hisip, websiteIP);
53
#else
54
  // or provide a numeric IP address instead of a string
55
  byte hisip[] = {192.168.10.199};
56
  ether.copyIp(ether.hisip, hisip);
57
#endif
58
59
  ether.printIp("SRV: ", ether.hisip);
60
61
62
}
63
64
65
void loop () { 
66
  //if correct answer is not received then re-initialize ethernet module
67
  if (res > 220){
68
    initialize_ethernet(); 
69
  }
70
  
71
  res = res + 1;
72
  
73
  ether.packetLoop(ether.packetReceive());
74
  
75
  //200 res = 30 seconds (150ms each res)
76
  if (res == 200) {
77
78
    analog = analogRead(A0);
79
    if(digitalRead(3)) {d1 = "OFF";} else {d1 = "ON";}  
80
81
    // generate 3 values as payload - by using a separate stash,
82
    // we can determine the size of the generated message ahead of time
83
    
84
    byte sd = stash.create();
85
86
    stash.print("field1=");
87
    stash.print(highByte(analog));
88
    stash.print("&field2=");
89
    stash.print(lowByte(analog));
90
    stash.print("&field3=");
91
    stash.print(d1);
92
    
93
    stash.save();
94
95
    // generate the header with payload - note that the stash size is used,
96
    // and that a "stash descriptor" is passed in as argument using "$H"
97
    Stash::prepare(PSTR("POST /a21.php HTTP/1.1" "\r\n"
98
      "Host: $F" "\r\n"
99
      "Connection: close" "\r\n"
100
      "X-THINGSPEAKAPIKEY: $F" "\r\n"
101
      "Content-Type: application/x-www-form-urlencoded" "\r\n"
102
      "Content-Length: $D" "\r\n"
103
      "\r\n"
104
      "$H"),
105
      website, PSTR(APIKEY), stash.size(), sd);
106
107
    // send the packet - this also releases all stash buffers once done
108
    session = ether.tcpSend(); 
109
110
  }
111
  
112
   const char* reply = ether.tcpReply(session);
113
   
114
   if (reply != 0) {
115
     res = 0;
116
     Serial.println(F(" >>>REPLY recieved...."));
117
     Serial.println(reply);
118
      if(find(reply,"Status1")){digitalWrite(7, HIGH);digitalWrite(4, HIGH);delay(300);Serial.println("4+7HIGH");}
119
      if(find(reply,"Status0")){digitalWrite(7, LOW);digitalWrite(4, LOW);delay(300);}
120
      previousMillis = millis();
121
   }
122
   else {
123
      if (millis() - previousMillis > 50000) {
124
      previousMillis = millis();
125
      digitalWrite(7, LOW);digitalWrite(4, LOW);
126
      initialize_ethernet();
127
      resetFunc();
128
      }
129
   }
130
   delay(150);
131
}
132
133
boolean find(String string, String value){
134
  if(string.indexOf(value)>=0)
135
    return true;
136
  return false;
137
}
138
139
void initialize_ethernet(void){  
140
  for(;;){ // keep trying until you succeed 
141
142
    if (ether.begin(sizeof Ethernet::buffer, mymac, ethCSpin) == 0){ 
143
      Serial.println( "Failed to access Ethernet controller");
144
      digitalWrite(7, LOW);digitalWrite(4, LOW);
145
      
146
      continue;
147
    }
148
    
149
    if (!ether.dhcpSetup()){
150
      Serial.println("DHCP failed");
151
      digitalWrite(7, LOW);digitalWrite(4, LOW);
152
      continue;
153
    }
154
155
    ether.printIp("IP:  ", ether.myip);
156
    ether.printIp("GW:  ", ether.gwip);  
157
    ether.printIp("DNS: ", ether.dnsip);  
158
159
    if (!ether.dnsLookup(website))
160
      Serial.println("DNS failed");
161
      digitalWrite(7, LOW);digitalWrite(4, LOW);
162
163
    ether.printIp("SRV: ", ether.hisip);
164
    
165
166
    //reset init value
167
    res = 180;
168
    break;
169
  }
170
}

von PittyJ (Gast)


Lesenswert?

Manchmal muss man eben eine Nummer größer benutzen.
Gerade im Low-End Arm Bereich gibt es Prozessoren mit mehr Ram, die 
nicht viel teurer sind.
ST-Development Boards gibt es bereits ab 10 Euro.
Ein ESP32 hat 512 KByte Ram, Wlan und kostet auch nur 10 Euro. Das 
bringt vielleicht mehr, als eine verkrüppelte Webseite, weil man nur 
2KByte Ram auf dem Atmel hat.

von Peter H. (borntopizza)


Lesenswert?

Liegt das wirklich am Ram?

Ich konnte den Buffer bis auf 1300 erhöhen, aber das Relais mag immer 
noch nicht anziehen. Die Antwort kommt "Status1" oder "Status0" kommt ja 
auch an.

von Stefan F. (Gast)


Lesenswert?

Da muss sicher mehr angepasst werden, als diese eine Zahl. Ausserdem 
bekommst du einen Stack-Überlauf (Absturz) wenn du den Puffer zu gross 
machst.

Selbst wenn du den Puffer jetzt grösser machst, wirst du bald wieder an 
seine Grenzen stossen. Mehr als 1,4kB ist über gewöhnliche Internet 
Anschlüsse sowieso nicht möglich.

Finde einen Weg, mit dem Puffer aufzukommen - also deine HTML Dokumente 
in mehreren Stücken zu senden.

von Paul (Gast)


Lesenswert?

Moin, moin,

die 700 Byte waren ja gar nicht mal so schlecht.

Ich würde mir als erstes mit Wireshark ansehen, was hin und her gesendet 
wird.

Viele Grüße
Paul

von Hau Wech (Gast)


Lesenswert?

Mehrere Pakete :

if ( bfill.emit_p(PSTR( "Etwas Text" )) ) {
      bfill.emit_p(PSTR( "Mehr Text" )) ) ;
} else {
bfill.emit_p(PSTR( "Fehlercode 1" )) ) ;
return -1;
}


Ich bin leider nur "Hacker" , kein Programmierer ..

von Peter H. (borntopizza)


Lesenswert?

Hau Wech schrieb:
> Mehrere Pakete :
>
> if ( bfill.emit_p(PSTR( "Etwas Text" )) ) {
>       bfill.emit_p(PSTR( "Mehr Text" )) ) ;
> } else {
> bfill.emit_p(PSTR( "Fehlercode 1" )) ) ;
> return -1;
> }
>
>
> Ich bin leider nur "Hacker" , kein Programmierer ..


Hmm irgendwie mag er nicht...

Egal wie ichs drehe, ich bekomms nicht hin, immer wieder andere 
Fehlermeldungen...

von Stefan F. (Gast)


Lesenswert?

Solange du die Fehlermeldungen nicht zitierst und nicht deinen gesamten 
Quelltext zeigst, können wir Dir kaum helfen. Dann müssen wir genau so 
blöd herum raten, wie du.

von Peter H. (borntopizza)


Lesenswert?

1
static word homePage() {
2
    bfill = ether.tcpOffset();
3
 if (bfill.emit_p(PSTR(
4
    "HTTP/1.0 200 OK\r\n"
5
    "Content-Type: text/html\r\n"
6
    "Pragma: no-cache\r\n"
7
    "\r\n"
8
    "<meta http-equiv='refresh' content='1'/>"
9
    "<title>SH</title>"
10
    "<h1>Ti $D</h1>"
11
    "<h1>Ts $D</h1>"
12
    "<h1>Status$D</h1>"
13
    "<input type=submit value='+' style=width:90px;height:45px onClick=location.href'/?1'>"
14
    "<input type=submit value='-' style=width:90px;height:45px onClick=location.href'/?2'>"
15
    "<input type=submit value='S' style=width:90px;height:45px onClick=location.href'/?4'>"
16
    ),
17
    t, Tsoll, Status)
18
    )
19
  {bfill.emit_p(PSTR("<input type=submit value='S' style=width:90px;height:45px onClick=location.href'/?5'>"));} 
20
  else {bfill.emit_p(PSTR("Fehlercode 1"));
21
  return -1;}    
22
  return bfill.position();
23
}

Fehlermeldung:
could not convert 'bfill.BufferFiller::emit_p(({...}), t, Tsoll, 
Status)' from 'void' to 'bool'
Zeile ist: "t, Tsoll, Status)"

Das komische ist ja, dass ich die Website viel größer machen kann. Am PC 
wird das auch so dargestellt, nur der 2. Atmega hat Probleme das 
auszuwerten oder so.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Wenn du die Definition von emit_p() suchst, wirst du feststellen, dass 
dessen Rückgabewert void ist.
Dein Programm erwartet allerdings bool.

Der fatale Fehler ist damit berechtigt.

von Stefan F. (Gast)


Lesenswert?

Du fragst mit if() das Ergebnis von bfill.emit_p() ab, aber diese 
Funktion liefert gar kein Ergebnis!

Bist du sicher, dass du sie einfach so mehrmals hintereinander aufrufen 
kannst, ohne zu warten, bis der buffer gesendet wurde?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter H. schrieb:
> could not convert 'bfill.BufferFiller::emit_p(({...}), t, Tsoll,
> Status)' from 'void' to 'bool'

Offenbar ist die Funktion emit_p() vom Typ void, gibt also keinen Wert 
zurück. Du fragst aber mit "if" den Rückgabewert der Funktion ab.

Was hat das jetzt mit der Größe des RAMs zu tun? Richtig, gar nichts.

von Stefan F. (Gast)


Lesenswert?

>  Am PC wird das auch so dargestellt, nur der 2. Atmega hat
> Probleme das auszuwerten oder so.

Was wertet der 2. Atmega denn aus? Noch hast du uns gar nicht erklärt, 
wie deine Schaltung aussieht und welche Kommunikationsbeziehungen 
bestehen. Zudem fehlen immer noch Schaltplan und Quelltext.

Wer Hilfe erbittet, muss die dazu nötigen Infos bereit stellen. Sonst 
wird das nichts.

von Peter H. (borntopizza)


Angehängte Dateien:

Lesenswert?

Also die Seite aktualisiert sich ja von selbst, 1 mal die Sekunde.

Dann funktioniert ja die ganze Idee vom "Hacker" nicht...

Quelltext müsste oben sein, einmal vom server, und einmal vom Client.

: Bearbeitet durch User
von Peter H. (borntopizza)


Lesenswert?

Also ich denke immernoch dass das an der char "reply" am Empfänger 
liegt. Weil am PC lässt sich die seite ja darstellen und alle GPIO Pins 
am Server lassen sich ja schalten, Temperatur wird auch dargestellt.

Müsste man dann die Website am Client auf "2 mal einlesen"?

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Die Meldung ist eine des Compilers, sie stammt nicht aus dem 
Protokollstack.

von Stefan F. (Gast)


Lesenswert?

Waren Abblock-Kondensatoren gerade Mangelware?
An die Reset Pins gehören auch Kondensatoren.
Aref gehört nicht mit VCC kurzgeschlossen. Lies die entsprechenden 
Hinweise im Datenblatt!

Was funktioniert jetzt nicht, die Darstellung der Webseite im Browser 
oder das Schalten des Relais im Empfänger? Wie kommunizieren die beiden 
Mikrocontroller miteinander?

Inwiefern weicht die fehlerhafte Kommunikation vom Soll ab? Oder ist die 
Kommunikation gar nicht gestört sondern es scheitert an etwas anderem?

Hast du eine Möglichkeit, Debug Meldungen auszugeben? Wenn nicht, dann 
solltest du das bei beiden Mikrocontrollern schleunigst hinzufügen. Und 
lerne, mit Wireshark umzugehen.

Wir sehen uns dann wieder, wenn du die Fehlerursache mit diesen Mitteln 
eingekreist hast. Bis dahin empfehle ich hier eine Sendepause für alle, 
denn wilde Vermutungen enden erfahrungsgemäss in wüsten Beschimpfungen.

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.