Go Down

Topic: Arduino Nano SIm800L Modul String setzen und vergleichen. (Read 556 times) previous topic - next topic

GastAnfaenger0815

Danke Serenifly,

war mein Fehler im ursprungscode hatte ich

c = tcSerial.read();

durch

Serial.print(c);

getauscht.

Aber beim schreiben des testscetches nicht mehr daran gedacht.

Wenn ich mein Scetch jetzt auf einem NodeMCU laden möchte,
hatte ich gelesen, dass ich mir eine andere SoftwareSerial Librarie runterladen muss.
Diese hat allerdings den selben Namen wie die originale von Arduino.
Reicht es wenn ich diese nur umbennene oder muss ich da noch andere Sachen beachten?

Hier findet man die besagte SoftwareSerial librarie.

Tommy56

Du hast 2 grundlegende Wege:

1. die alte Lib löschen/verschieben
2. für die Arbeit mit dem ESP zusätzlich eine eigene portable Version der IDE benutzen.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

GastAnfaenger0815

Du hast 2 grundlegende Wege:

1. die alte Lib löschen/verschieben
2. für die Arbeit mit dem ESP zusätzlich eine eigene portable Version der IDE benutzen.

Gruß Tommy
Okay, das mit dem verschieben funktioniert schon mal, dann gucke ich morgen mal dabei eine portable Version zu machen, ist glaube für die Zukunft dann einfacherer. Vielen dank.

noiasca

Weiters könntest du:

3. die Dateien der weitere Lib lokal im Sketch speichern und lokal einbinden
4. die weitere Lib runterladen und einen anderen Namen geben
DE: Wie man Fragen postet:
1. was hat man (Sketch und Hardware)
2. was SOLL es machen
3. was macht es: IST (Fehlverhalten, Fehlermeldungen, Serial.Output ...)
4. Eine Frage stellen bzw. erklären was man erwartet

GastAnfaenger0815

#34
Jul 30, 2019, 11:43 pm Last Edit: Jul 30, 2019, 11:49 pm by GastAnfaenger0815
TEIL 1 von 2.


Vielen dank, mit der portablen Version funktioniert es auch.

Da ich jedoch gerne beim Arduino Nano bleiben würde, hätte ich noch eine Frage.

Ich habe jetzt 2 Sketche, einmal diesen hier:

Code: [Select]

#include <NewPing.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <SoftwareSerial.h>
#define rxPin 9
#define txPin 8
#define ONE_WIRE_BUS
#define TRIG_PIN 3
#define ECHO_PIN 4
#define MAX_DIST 400
SoftwareSerial tcSerial = SoftwareSerial(rxPin, txPin);
OneWire oneWire(9);
DallasTemperature sensors (&oneWire);
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DIST);
uint32_t requestMillis = 0;
bool requestStarted = false;
uint8_t bitResolution = 12;
int16_t ConvWait = 750;
char fuellstand[15] = "\nFuellstand?";
char tempTemp[15] = "\nTemperatur?";
char nummer[20] = "+49xxxxxxxxx";
char inhalt[160] = "";
char smsErhalten[3] = "";
char c;
float platzhalter = 0;
float temp = 0;
float abstand = 0;
int fuesseCount = 0;
int lnCount = 0;
int charCounter = 0;
int count = 0;
//----------------------------------------------------------------------------------------------------------------------------------------------------------
void setup()
{
  pinMode(10, OUTPUT);
  tcSerial.begin(9600);
  Serial.begin(9600);
  while (!Serial) {}
  digitalWrite(10, 0);
  delay(1000);
  digitalWrite(10, 1);
  delay(3000);
  tcSerial.println(F("AT+CMGF=1")); // Setze Textmode auf 1
  delay(1000);  
  tcSerial.println(F("AT+CMGD=1")); // CMGD Löscht nachrichten.
  delay(5000);
  Serial.println(F("Bereit"));
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------
void loop()
{
  abstand = sonar.ping_cm();
  if (!requestStarted)
  {
    sensors.requestTemperatures();
    requestStarted = true;
    requestMillis = millis();
  }
  if (millis() - requestMillis >= ConvWait)
  {
    temp = sensors.getTempCByIndex(0);
    requestStarted = false;  
  }
  LeseNachricht();
  if (strcmp(inhalt, fuellstand) == 0) // Wenn inhalt = char Array fuellstand dann mache:
  {
    platzhalter = abstand*25;
    Serial.println(F("Sende Nachricht mit aktuellen Wert des Fuellstandes."));
    NachrichtenLoeschen();
    NachrichtenLoeschen();
    Serial.println(F("Sende Nachricht..."));
    tcSerial.print(F("AT+CMGS=\"")); // AT-Befehl für Nummer.
    tcSerial.print(nummer); // Gibt Nummer weiter an den AT-Befehl.
    tcSerial.print(F("\"\r")); // Sendet ein Enter.
    delay(1000);
    tcSerial.print(F("Der Fuellstand liegt bei")); // Übergibt zu sendenden Text an das Modul.
    tcSerial.print(platzhalter); // Übergibt den Platzhalter an das Modul.
    tcSerial.print(F("Liter"));
    delay(1000);
    tcSerial.print((char)26); // sendet CTRL+Z
    delay(5000);
  }
  else if (strcmp(inhalt, tempTemp) == 0) // Wenn inhalt = char Array tempTemp dann mache:
  {  
    Serial.println(F("Sende Nachricht mit aktuellen Wert der Temperatur."));
    platzhalter = temp;
    NachrichtenLoeschen();
    NachrichtenLoeschen();
    Serial.println(F("Sende Nachricht..."));
    tcSerial.print(F("AT+CMGS=\"")); // AT-Befehl für Nummer.
    tcSerial.print(nummer); // Gibt Nummer weiter an den AT-Befehl.
    tcSerial.print(F("\"\r")); // Sendet ein Enter.
    delay(1000);
    tcSerial.print(F("Die Temperatur liegt bei:")); // Übergibt zu sendenden Text an das Modul.
    tcSerial.print(platzhalter); // Übergibt den Platzhalter an das Modul.
    tcSerial.print(F("Grad Celsius"));
    delay(1000);
    tcSerial.print((char)26); // sendet CTRL+Z
    delay(5000);
  }
  else if (strcmp(inhalt, smsErhalten) != 0) // Wenn inhalt != smsErhalten dann mache:
  {
    Serial.println(F("Hier ist noch ein Fehler"));
    platzhalter = 0;
    NachrichtenLoeschen();
    NachrichtenLoeschen();
    Serial.println(F("Sende Nachricht..."));
    tcSerial.print(F("AT+CMGS=\"")); // AT-Befehl für Nummer.
    tcSerial.print(nummer); // Gibt Nummer weiter an den AT-Befehl.
    tcSerial.print(F("\"\r")); // Sendet ein Enter.
    delay(1000);
    tcSerial.print(F("Sende Fuellstand? fuer den aktuellen Wert des Fuellstandes, oder Temperatur? fuer den aktuellen Wert der Temperatur.")); // Übergibt zu sendenden Text an das Modul.
    delay(1000);
    tcSerial.print((char)26); // sendet CTRL+Z
    delay(5000);  
  }
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------
void LeseNachricht()
{
  tcSerial.println(F("AT+CMGR=1")); // Lese erste Nachricht im Speicher SM
  delay(750);
  while (count == 0) // Loop bis count nicht mehr gleich 0.
  {
    charCounter = 0;
    fuesseCount = 0;
    lnCount = 0;
    while (tcSerial.available() > 0)// Wenn dort Daten sind dann lese sie.
    {
      c = tcSerial.read();
      if (fuesseCount >= 6) //Zählt bis anzahl der '"' erreicht.
      {
        inhalt[charCounter] = '\0';
        if (c == '\n') lnCount++; // Zählt [\n].
        if (lnCount == 1 && lnCount != 2)
        {
          inhalt[charCounter++] = c; // Schreibt jedes Zeichen einzellnd in das Char Array
        }  
      }
      inhalt[charCounter] = '\0';
      if (c == '"') fuesseCount++;  // Zählt ["]
      Serial.print(c);
      count++; // Erhöhe die Variable count um 1
    }
  }
  Serial.println(inhalt); //
  Serial.println(charCounter);
  Serial.println(lnCount);
  count = 0;
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------
void NachrichtenLoeschen()
{
  tcSerial.println(F("AT+CMGD=1")); // CMGD Löscht nachrichten.
  delay(1000);
}


Da habe ich nach dem kompilieren noch 487 bytes freien dynamischen Speicher. Dafür wird der Teil
void loop relativ lang und meiner Meinung nach unübersichtlich.


GastAnfaenger0815

#35
Jul 30, 2019, 11:48 pm Last Edit: Jul 30, 2019, 11:50 pm by GastAnfaenger0815
TEIL 2 von 2.

Und diesen Sketch:

Code: [Select]

#include <NewPing.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <SoftwareSerial.h>
#define rxPin 9
#define txPin 8
#define ONE_WIRE_BUS
#define TRIG_PIN 3
#define ECHO_PIN 4
#define MAX_DIST 400
SoftwareSerial tcSerial = SoftwareSerial(rxPin, txPin);
OneWire oneWire(9);
DallasTemperature sensors (&oneWire);
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DIST);
uint32_t requestMillis = 0;
bool requestStarted = false;
uint8_t bitResolution = 12;
int16_t ConvWait = 750;
char fuellstand[15] = "\nFuellstand?";
char tempTemp[15] = "\nTemperatur?";
char nummer[20] = "+49xxxxxxxxxxx";
char inhalt[160] = "";
char smsErhalten[3] = "";
char text[160] = "";
char c;
float platzhalter = 0;
float temp = 0;
float abstand = 0;
int fuesseCount = 0;
int lnCount = 0;
int charCounter = 0;
int count = 0;
//----------------------------------------------------------------------------------------------------------------------------------------------------------
void setup()
{
  pinMode(10, OUTPUT);
  tcSerial.begin(9600);
  Serial.begin(9600);
  while (!Serial) {}
  digitalWrite(10, 0);
  delay(1000);
  digitalWrite(10, 1);
  delay(3000);
  tcSerial.println(F("AT+CMGF=1")); // Setze Textmode auf 1
  delay(1000);  
  tcSerial.println(F("AT+CMGD=1")); // CMGD Löscht nachrichten.
  delay(5000);
  Serial.println(F("Bereit"));
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------
void loop()
{
  abstand = sonar.ping_cm();
  if (!requestStarted)
  {
    sensors.requestTemperatures();
    requestStarted = true;
    requestMillis = millis();
  }
  if (millis() - requestMillis >= ConvWait)
  {
    temp = sensors.getTempCByIndex(0);
    requestStarted = false;  
  }
  LeseNachricht();
  if (strcmp(inhalt, fuellstand) == 0) // Wenn inhalt = char Array fuellstand dann mache:
  {
    platzhalter = abstand*25;
    Serial.println(F("Sende Nachricht mit aktuellen Wert des Fuellstandes."));
    NachrichtenLoeschen();
    NachrichtenLoeschen();
    NachrichtSenden ("Der Fuellstand liegt bei");
  }
  else if (strcmp(inhalt, tempTemp) == 0) // Wenn inhalt = char Array tempTemp dann mache:
  {  
    Serial.println(F("Sende Nachricht mit aktuellen Wert der Temperatur."));
    platzhalter = temp;
    NachrichtenLoeschen();
    NachrichtenLoeschen();
    NachrichtSenden ("Die Temperatur liegt bei:");
  }
  else if (strcmp(inhalt, smsErhalten) != 0) // Wenn inhalt != smsErhalten dann mache:
  {
    Serial.println(F("Hier ist noch ein Fehler"));
    platzhalter = 0;
    NachrichtenLoeschen();
    NachrichtenLoeschen();
    NachrichtSenden("Sende Fuellstand? fuer den aktuellen Wert des Fuellstandes, oder Temperatur? fuer den aktuellen Wert der Temperatur.");  
  }
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------
void LeseNachricht()
{
  tcSerial.println(F("AT+CMGR=1")); // Lese erste Nachricht im Speicher SM
  delay(750);
  while (count == 0) // Loop bis count nicht mehr gleich 0.
  {
    charCounter = 0;
    fuesseCount = 0;
    lnCount = 0;
    while (tcSerial.available() > 0)// Wenn dort Daten sind dann lese sie.
    {
      c = tcSerial.read();
      if (fuesseCount >= 6) //Zählt bis anzahl der '"' erreicht.
      {
        inhalt[charCounter] = '\0';
        if (c == '\n') lnCount++; // Zählt [\n].
        if (lnCount == 1 && lnCount != 2)
        {
          inhalt[charCounter++] = c; // Schreibt jedes Zeichen einzellnd in das Char Array
        }  
      }
      inhalt[charCounter] = '\0';
      if (c == '"') fuesseCount++;  // Zählt ["]
      Serial.print(c);
      count++; // Erhöhe die Variable count um 1
    }
  }
  Serial.println(inhalt); //
  Serial.println(charCounter);
  Serial.println(lnCount);
  count = 0;
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------
void NachrichtenLoeschen()
{
  tcSerial.println(F("AT+CMGD=1")); // CMGD Löscht nachrichten.
  delay(1000);
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------
void NachrichtSenden(char text[160])
{
    Serial.println(F("Sende Nachricht..."));
    tcSerial.print(F("AT+CMGS=\"")); // AT-Befehl für Nummer.
    tcSerial.print(nummer); // Gibt Nummer weiter an den AT-Befehl.
    tcSerial.print(F("\"\r")); // Sendet ein Enter.
    delay(1000);
    tcSerial.print(text); // Übergibt zu sendenden Text an das Modul.
    tcSerial.print(platzhalter); // Übergibt den Platzhalter an das Modul.
    delay(1000);
    tcSerial.print((char)26); // sendet CTRL+Z
    delay(5000);
}



Da habe ich nur noch 310 bytes frei für den dynamischen Speicher.
Und hier ist der void loop deutlich kürzer und meiner Meinung nach schöner.
Ist ja auch klar, der größte Teil befindet sich dann in der Methode NachrichtSenden()

Gibt es einfache Möglichkeiten wie z.b. durch (F(....)) das was in den dynamsichen Speicher geschrieben wird in den Programmspeicher abzulegen?

Oder generell noch für einem Anfänger mittel und Wege mehr Speicher zu sparen?
"Anfänger" setze ich mal so, da ich durchaus gewillt bin mich auch mit komplexeren Sachen zu beschäftigen.

Tommy56

z.B. mal mit PROGMEM und strcmp_P beschäftigen und alles was konstant ist auch als const deklarieren.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

Serenifly

Du solltest dir abgewöhnen ständig die Größe von Arrays vorzugeben wenn es gar nicht nötig ist. z.B. bei deinen Text-Konstanten und NachrichtSenden(). Bei Literalen kann der Compiler die Länge selbst ermitteln.
Und bei Funktionen übergibt man char Arrays als Zeiger! Ein Array zerfällt immer zu einem Zeiger auf das erste Element

Die Größe musst du nur bei Puffern angeben wo du nicht weißt wie lange der tatsächliche Inhalt sein wird

Code: [Select]

const char str[] PROGMEM = "PROGMEM String";

void setup()
{
  Serial.begin(9600);

  printText_P(str);
  printText_P(PSTR("PSTR() String"));
  printText_P_Alt(PSTR("PSTR() String Alternative"));

  printText_F(F("F() String"));

  if (strcmp_P("Test String", PSTR("Test String")) == 0)  //1. String im RAM, 2. String mit PSTR() oder PROGMEM im Flash
  {
    Serial.println("gleich");
  }
}

void loop()
{
}

//Text wird komplett Puffer kopiert. Hier kann man evtl. statt dessen einen gemeinsamen globalen Puffer für alles nehmen
void printText_P(const char* str)
{
  char buffer[20];
  strlcpy_P(buffer, str, sizeof(buffer));
  Serial.println(buffer);
}

//Alternative ohne speicherfressenden Puffer. Buchstaben werden Stück für Stück ausgegeben
void printText_P_Alt(const char* str)
{
  char c;
  for (byte i = 0; (c = pgm_read_byte(str + i)) != '\0'; i++)
    Serial.print(c);
  Serial.println();
}

//Verwendet statt dessen das F() Makro der Arduino Software
void printText_F(const __FlashStringHelper* str)
{
  Serial.println(str);
}


const char* kann nicht zwischen einem String im RAM und im Flash unterscheiden. Deshalb hat die Arduino Software noch F() und __FlashStringHelper mit einem speziellen Datentyp. Für print()/println() kann das deshalb die bessere Wahl sein, da man nichts per Hand umkopieren muss

Wenn man andere Dinge tun will braucht man aber PROGMEM/PSTR(). Von allen C String Funktionen gibt es _P Versionen die mit Strings im PROGMEM umgehen können:
https://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html

GastAnfaenger0815

#38
Aug 04, 2019, 06:11 pm Last Edit: Aug 04, 2019, 06:14 pm by GastAnfaenger0815
Vielen Dank für die viele Hilfe bis jetzt.

Der hohe Speicher-verbrauch des dynamischen Speichers lag daran, dass ich in der Software Serial Lib den Buffer von 64 bytes  auf 1024 bytes  erhöht hatte. Das es daran liegen könnte ist mir aber erst aufgefallen, als ich auf einem anderen System die Arduino IDE installiert hatte und mein Code nicht mehr funktionierte, da beim Einlesen einer SMS nur 64 bytes gelesen wurden. Habe den Buffer jetzt erstmal auf 256 bytes  reduziert. Und jetzt noch 1258 bytes frei. Eure vorgeschlagenen Lösungsansätze werde ich mir später angucken. Da das Programmieren mir wohl doch mehr Spaß gemacht hatte als ich zuerst dachte, habe ich mir jetzt ein Programmierer Handbuch bestellt. Bis jetzt hatte ich mich immer nur mit Hardware Sachen herum geschlagen. Ich poste mal ein paar Bilder von meinem Aufbau für die, die es interessiert.








Serenifly

Quote
Das es daran liegen könnte ist mir aber erst aufgefallen, als ich auf einem anderen System die Arduino IDE installiert hatte und mein Code nicht mehr funktionierte, da beim Einlesen einer SMS nur 64 bytes gelesen wurden.
Ich glaube da ist eher das Schuld was du programmiert hat. Die serielle Schnittstelle ist sehr, sehr viel langsamer als der Prozessor. Ein Byte braucht 1 * Baudrate * 10 Sekunden. Selbst bei hohen Baudraten kann man daher den Eingangspuffer schneller auslesen als Daten ankommen.
Du musst nur dein Programm vernünftig schreiben. Vor allem nicht-blockierend, so dass man ständig überprüfen kann ob neue Daten da sind

Also lass den Puffer auf einer normalen Größe. Dann lege dir im eigentlichen Programm einen Puffer an der groß genug für die größte Nachricht ist (muss das wirklich 1kB sein) und kopiere ständig die Daten um

Go Up