Go Down

Topic: Atmega328P-PU with Arduino UNO Bootloader chrashs (Read 181 times) previous topic - next topic

timofischerprojects

Jan 05, 2020, 08:52 pm Last Edit: Jan 05, 2020, 09:07 pm by timofischerprojects
Hello everybody,

I have a problem with my program for my Atmega328P-PU with Arduino Uno Bootloader. The program seems to crash after 1-3 hours for no reason. Try to observe the error in which I use the serial monitor but after 6 hours I had no result and no errors.

The circuit is about a prototype for a weather probe which should write live data into a database.

Used hardware:
-Atmega328P-PU with Arduino Bootloader
-SIM800L
-18650 Li-Ion battery 3000mAh 3,7V
-MT3608
-TP4056
-5V 2.5W Solar panel

Photo:


The Sketch uses 18418 bytes (57%) of the program memory. The maximum is 32256 bytes.
Global variables use 784 bytes (38%) of dynamic memory, 1264 bytes remain for local variables. The maximum is 2048 bytes.

Error description:
After 1-4 hours no more messages arrive in the database. From time to time records were also sent twice to 5 times and then nothing more. The Sim800L flashes normally, so the http request was completed successfully. If the µC is reset the program starts and everything works. Therefore I assume a program error.

My theory is that the µC crashes because I don't read the serial output and therefore it sends the messages into the empty space. Is that possible?

Thanks a lot for answering :)
Greetings
Timo

blh64

The issue is you are using the 'String' class which will fragment your limited memory and crash the program.  If this is intended for a long running application, learn how to use C strings (nul terminated char arrays) and forget about 'Strings'

timofischerprojects

The issue is you are using the 'String' class which will fragment your limited memory and crash the program.  If this is intended for a long running application, learn how to use C strings (nul terminated char arrays) and forget about 'Strings'
So my problem is that every time I create a new string, the string can change in length which can cause problems in the memory because the place were the string is place in the memory is maybe not the same/there is not enough space in a row.
But if I would call my variable "char Datensatz[150]" instead of "String Datensatz;" there would be a fixed place in memory where the string can be stored and the µC can't get mixed up that easily?

blh64

Sort of.  The String class will allocate memory as needed, but may allocate a completely new buffer and abandon the old one as you add more chars to it.  The abandoned memory never gets reused so eventually, you run out of memory.  There is no garbage collection on an adruino to re-use memory.  The arduino does not get mixed up, it simply tried to get some memory and fails since no more is available.

You can read lots of gory details here

timofischerprojects

#4
Jan 07, 2020, 10:29 am Last Edit: Jan 07, 2020, 10:31 am by timofischerprojects
Hey blh64,

Thanks for your help. The script seems to run stable. The website for reading helps alot. I have now banned almost all strings from my program. Only 4 are left, but they are not changing and are only in a Serial.print command.
Instead of passing the variables in the functions, I now only pass the reference. The memory manager should like that more.
Last but not least, here is my solution for the huge string. Is the solution ok or are there better solutions to feed float and text together?

mitteltemp_XXm are float vars from a DS18B20.

Code: [Select]

  char Datensatz[300] = "";               //Datensatz der gesendet werden soll
  char TempClip[10] = "";
  char batterie_volt[5] = "1111";         //Batterie Spannung
  char batterie_proz[3] = "11";           //Batterie Füllstand
 
  //Fasse Daten zu Datensatz zusammen
  strcat(Datensatz, "AT+HTTPPARA=\"URL\",\"http://google.com/DataLogger.php?SID='");
  strcat(Datensatz, SondenID);
  strcat(Datensatz, "'&T0=");dtostrf(mitteltemp_00m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T1=");dtostrf(mitteltemp_01m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T2=");dtostrf(mitteltemp_02m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T3=");dtostrf(mitteltemp_03m, 5, 2, TempClip);strcat(Datensatz, TempClip);  
  strcat(Datensatz, "&T4=");dtostrf(mitteltemp_04m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T5=");dtostrf(mitteltemp_05m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T6=");dtostrf(mitteltemp_06m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T7=");dtostrf(mitteltemp_07m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T8=");dtostrf(mitteltemp_08m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T9=");dtostrf(mitteltemp_09m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T10=");dtostrf(mitteltemp_10m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&AP=");strcat(Datensatz, batterie_proz);
  strcat(Datensatz, "&AV=");strcat(Datensatz, batterie_volt);
  strcat(Datensatz, "\"");

blh64

Hey blh64,

Thanks for your help. The script seems to run stable. The website for reading helps alot. I have now banned almost all strings from my program. Only 4 are left, but they are not changing and are only in a Serial.print command.
Why would you ever need to use a constang String in a Serial.print() statement?  That function will handle C strings both in RAM and PROGMEM
Code: [Select]

Serial.print("Constant string in memory");
Serial.print( F("Constant string in PROGMEM which uses less RAM"));


Quote
Instead of passing the variables in the functions, I now only pass the reference. The memory manager should like that more.
Last but not least, here is my solution for the huge string. Is the solution ok or are there better solutions to feed float and text together?

mitteltemp_XXm are float vars from a DS18B20.

Code: [Select]

  char Datensatz[300] = "";               //Datensatz der gesendet werden soll
  char TempClip[10] = "";
  char batterie_volt[5] = "1111";         //Batterie Spannung
  char batterie_proz[3] = "11";           //Batterie Füllstand
 
  //Fasse Daten zu Datensatz zusammen
  strcat(Datensatz, "AT+HTTPPARA=\"URL\",\"http://google.com/DataLogger.php?SID='");
  strcat(Datensatz, SondenID);
  strcat(Datensatz, "'&T0=");dtostrf(mitteltemp_00m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T1=");dtostrf(mitteltemp_01m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T2=");dtostrf(mitteltemp_02m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T3=");dtostrf(mitteltemp_03m, 5, 2, TempClip);strcat(Datensatz, TempClip); 
  strcat(Datensatz, "&T4=");dtostrf(mitteltemp_04m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T5=");dtostrf(mitteltemp_05m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T6=");dtostrf(mitteltemp_06m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T7=");dtostrf(mitteltemp_07m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T8=");dtostrf(mitteltemp_08m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T9=");dtostrf(mitteltemp_09m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&T10=");dtostrf(mitteltemp_10m, 5, 2, TempClip);strcat(Datensatz, TempClip);
  strcat(Datensatz, "&AP=");strcat(Datensatz, batterie_proz);
  strcat(Datensatz, "&AV=");strcat(Datensatz, batterie_volt);
  strcat(Datensatz, "\"");


Are you sure there is a need for one huge string.  Many/Most situations can be handles by simply using multiple print statements or whatever to get all the information transferred.

timofischerprojects

#6
Jan 14, 2020, 09:44 am Last Edit: Jan 14, 2020, 09:59 am by timofischerprojects Reason: Add Code
Hello blh64,

The strings have almost always been in the F() function and therefore in the PROGMEM. In the meantime I have simply commented out all Serial.print commands. Since then the program runs stable. For programming work I can activate the serial output at any time again.

In principle you could split the C-String into several small parts, but I use a standardized function for the communication with the Sim800L, which waits for the Sim800L to confirm the command, e.g. with 'OK' etc.

My problem is rather that I can not yet transfer the data encrypted with SSL. As soon as I change the URL index on https:// the transmission does not work anymore. Also the AT+HTTPSSL did not help.

Maybe I should really make a POST instead of a GET. That could possibly help...

Code: [Select]

//SIM800L BEFEHLE
byte Sim800WD1 = 1;
byte Sim800WD5 = 5;

char batterie_proz[4] = "111";          //Batterie Füllstand
char batterie_volt[5] = "1111";         //Batterie Spannung

char Sim800Free[1] = "";
char Sim800CBCa[6] = "CBC: ";

char Sim800AT[3] = "AT";
char Sim800OK[3] = "OK";
char Sim800READY[6] = "READY";

char Sim800ATCPINf[9] = "AT+CPIN?";        //Frage SIM Karte ab

char Sim800ATCGATT0[11] = "AT+CGATT=0";
char Sim800ATCGATT1[11] = "AT+CGATT=1";
char Sim800CGATTf[10] = "AT+CGATT?";
char Sim800CGATTa1[10] = "+CGATT: 1";

char Sim800ATCSCLK0[11] = "AT+CSCLK=0"; //GSM-Modul aufwecken
char Sim800ATCSCLK2[11] = "AT+CSCLK=2"; //GSM-Modul schlafen legen

char Sim800Contype[34] = "AT+SAPBR=3,1,\"Contype\",\"GPRS\"";
char Sim800APN[42] = "AT+SAPBR=3,1,\"APN\",\"internet.eplus.de\"";
char Sim800USER[32] = "AT+SAPBR=3,1,\"USER\",\"eplus\"";
char Sim800PWD[30] = "AT+SAPBR=3,1,\"PWD\",\"gprs\"";

char Sim800ATHTTPREAD[12] = "AT+HTTPREAD";
char Sim800ATHTTPINIT[12] = "AT+HTTPINIT";
char Sim800ATHTTPTERM[12] = "AT+HTTPTERM";
char Sim800ATHTTPSSL1[13] = "AT+HTTPSSL=1";
char Sim800ATHTTPACTION0[16] = "AT+HTTPACTION=0";

char Sim800ATSAPBR01[13] = "AT+SAPBR=0,1";
char Sim800ATSAPBR11[13] = "AT+SAPBR=1,1";
char Sim800ATSAPBR21[13] = "AT+SAPBR=2,1";

void loop() {
[...]
  WaitForSimAnswer(Sim800ATCSCLK0, Sim800OK, Sim800Free, Sim800WD5); //Wake UP
  WaitForSimAnswer(Sim800CGATTf, Sim800CGATTa1,Sim800ATCGATT1, Sim800WD5); //Check
  WaitForSimAnswer(Sim800Contype, Sim800OK, Sim800Free, Sim800WD5); //LogIn
  WaitForSimAnswer(Sim800APN, Sim800OK, Sim800Free, Sim800WD5);
  WaitForSimAnswer(Sim800USER, Sim800OK, Sim800Free, Sim800WD5);
  WaitForSimAnswer(Sim800PWD, Sim800OK, Sim800Free, Sim800WD5); 
  WaitForSimAnswer(Sim800ATSAPBR11, Sim800OK, Sim800Free, Sim800WD5);
  WaitForSimAnswer(Sim800ATSAPBR21, Sim800OK, Sim800Free, Sim800WD5);
  WaitForSimAnswer(Sim800ATHTTPINIT, Sim800OK, Sim800Free, Sim800WD5); //HTTP Initial
  WaitForSimAnswer(Datensatz, Sim800OK, Sim800Free, Sim800WD5); //Send URL to Sim800L
  WaitForSimAnswer(Sim800ATHTTPSSL1, Sim800OK, Sim800Free, Sim800WD5); //Acitvate SSL
  WaitForSimAnswer(Sim800ATHTTPACTION0, Sim800OK, Sim800Free, Sim800WD1); //Do Get-Request
  WaitForSimAnswer(Sim800ATHTTPREAD, Sim800OK, Sim800Free, Sim800WD5); //HTTP Read
  WaitForSimAnswer(Sim800ATHTTPTERM, Sim800OK, Sim800Free, Sim800WD5); //End HTTP
  WaitForSimAnswer(Sim800ATSAPBR01, Sim800OK, Sim800ATCGATT0, Sim800WD5); //END GPRS
  WaitForSimAnswer(Sim800ATCSCLK2, Sim800OK, Sim800Free, Sim800WD5); //Sleep Mode Sim800L
[...]
}

void WaitForSimAnswer(char* Frage, char* Antwort, char* Loesungsbefehl, byte &CounterEnd)
{
  byte Counter = 0;

  flushSerial();
 
  while(1){   
    sim.println(Frage);  //Stelle Frage an das GSM-Modul
    delay(500);
    if (sim.find(Antwort)) //Finde Antwort
    {
      flushSerial();
      break;
    }
    else
    {
      Counter++;
           
      if (Counter >= CounterEnd)
      {
        flushSerial();
        break;
      }
      if(Loesungsbefehl != ""){sim.print(Loesungsbefehl);}
         
      flushSerial();
      delay(500);
    }
  }
}



Greetings

Timo

Go Up