Hey everyone,
so this is my kind a first bigger project with Arduino. The project is about a Smart library in school, so the basic concept would be that every student has an RFID tag and every book also has an RFID tag. The student first scans his tag on an RFID RC522 reader, after that Arduino sends his tag ID to web server over WiFi using an ESP8266 module and checks if the ID is valid and if it is then the student can scan the book and again same process to validate the book and if everything is correct the information is saved in the database. All the output is shown on an LCD 16x2 screen.
Now the problem is that the code is running normally until some point in time and then it crashes. I can see some weird signs on the LCD and then it freezes. If I run the code only once or twice (borrow and return book) then it works, even though sometimes the RFID scanner doesn't work from the beginning so i have to restart it.
My concern is that maybe Arduino is running out of dynamic memory and that is why it is crashing. I tried to make it smaller as possible, but still same problem. I'm not an expert so I'm seeking help here. I have uploaded the code as an attachment as it is kinda long to post it.
Should I try to optimize the code more or should I move onto Arduino Mega?
Sketch uses 22932 bytes (71%) of program storage space. Maximum is 32256 bytes.
Global variables use 1509 bytes (73%) of dynamic memory, leaving 539 bytes for local variables. Maximum is 2048 bytes.
msimic:
My concern is that maybe Arduino is running out of dynamic memory and that is why it is crashing.
You could well be correct.
msimic:
Should I try to optimize the code more or should I move onto Arduino Mega?
I would optimise first and then switch as a last resort. You can make considerable savings in the code you have. The following points apply:
You are heavily using the String class.
The String class is a nice abstraction and helps avoid a slew of common programming errors. Unfortunately on a memory constrained Arduino it can just cause memory problems - like those you are seeing.
You need to eliminate String and replace it with old-style C-strings, ie. null terminated char arrays. You can use functions like strcmp, strcpy, etc. to manipulate them.
client.println("GET /OpenHouse2019/returnBook.php?studentTag="+studentTag+"&bookTag="+bookTag+" HTTP/1.1");
To avoid the possibility of temporary String objects being created and thus consuming more memory, this is better written as:
Use the F() macro where possible.
Sometimes functions that take C-string arguments allow those arguments to be stored only in PROGMEM. You can simply write the function like Serial.println(F("foo!")) to save some RAM.
Not all functions will accept it though, but you can try it and get a compile time error if it's not going to fly.
client.find("BookFound")
Since some functions won't accept parameters in PROGMEM, you could consider writing a wrapper around them to copy each PROGMEM string on demand into a buffer before it is passed to the function. If your were careful 1 decent sized global buffer might suffice for all of these sorts of function calls, or you could use a locally allocated buffer which will have a little more run time risk. You can copy strings from PROGMEM using the strcpy_P function.
That's possible, I see a lot of String tinkering so yeah, common with that. I would say switching to strings (without capital) would be a good start. And you can also try the F() macro to save more memory although I'm not sure the LiquidCrystal_I2C and WiFi libraries support it.
[edit]arduarn was quicker and way more specific.
And no, I would never switch to a Mega. But you can probably run everything on the ESP itself with ease.
PS
//Buttons
int buttonPin2 = 2;
int buttonPin3 = 3;
int buttonPin4 = 4;
Terrible names. Why bother with names if you don't make them something useful?
Works with the LCD library I am using, would help if I knew the exact one you are using, the LiquidCrystal_I2C.h filename is used in multiple libraries.
arduarn: client.println("GET /OpenHouse2019/returnBook.php?studentTag="+studentTag+"&bookTag="+bookTag+" HTTP/1.1");
To avoid the possibility of temporary String objects being created and thus consuming more memory, this is better written as:
**Use the F() macro where possible.**
Sometimes functions that take C-string arguments allow those arguments to be stored only in PROGMEM. You can simply write the function like Serial.println(F("foo!")) to save some RAM.
Not all functions will accept it though, but you can try it and get a compile time error if it's not going to fly.
Thank you for the suggestion, this has greatly reduced the memory size by almost 30%. Now the program doesn't crash anymore.
david_2018:
It is a little cryptic to implement, but you can change your UpdateScreen() function to use strings stored in progmem:
Works with the LCD library I am using, would help if I knew the exact one you are using, the LiquidCrystal_I2C.h filename is used in multiple libraries.
I tried using it with my LCD and it works without any problems, thank you for suggestion.
But now the ESP8266 can't send information to the web server, it's always giving the same error. Anyone have any idea?
[WiFiEsp] Connecting to xxxxxxx.net
[WiFiEsp] Data packet send error (2)
[WiFiEsp] Failed to write to socket 3
[WiFiEsp] Disconnecting 3
That should be just *print*, not *println*. Could that be the issue?
I was looking almost all day at the code and didn't see it... But yes that was the problem.
After i changed it, it started to communicate with the web server but it was getting always a timeout
[WiFiEsp] Connecting to xxxxxxx.net
[WiFiEsp] >>> TIMEOUT >>>
I fixed it by removing a delay(5000); after the GET request. It worked for some time and then there was another error
[WiFiEsp] Connecting to xxxxxxx.net
[WiFiEsp] No socket available
Fixed by changing the host connection from:
String conn = "Connection: keep-alive";
to:
String conn = "Connection: close";
I guess it was holding too many connections alive at same time.
Now so far everything works, just the RFID scanner sometimes doesn't want to scan but I guess it might be a lose connection (will try to solder it) or maybe just a cheap scanner.