Stránka 2 z 2

Re: porovnání obsahu řetězce po seriové lince

Napsal: 24 úno 2019, 15:17
od RobertN
Omlouvám, se, co jsem samostudiem nepochopil, na to se zde snažím zeptat. Myslel jsem, že toto fórum je právě od toho.
Chyba je asi tedy jinde, než jsem myslel já, ptám se tedy co je chybné na mém postupu, ke kterému jsem došel a kde dělám chybu.

V GSM modulu je nějaký buffer
V Arduinu je také nějaký buffer
- standardní velikost je 64 "znaků"
- nevím, kolik je to u arduina Mini Pro

Pokud něco posílám do GSM, naplní se buffer v GSM mým příkazem a GSM si to postupně vyčte, až má čas.
Když něco pošle GSM, naplní se buffer v Arduinu a já jej musím vyčíst.
Když jej nevyčtu, tak přepisuje staré znaky novými.

Můj program je nastaven takto:

Vyčisti (příchozí) buffer v arduinu, který může obsahovat kromě odpovědí na mé příkazy, různé servisní info z GSM modulu (přišla SMS, hovor, nízké napětí...)

Kód: Vybrat vše

 while (komunikaceSIM800L.available() > 0) {
    s = komunikaceSIM800L.read();
     }
Když jsem dal jen jednu smyčku while, stávalo se mi, že tam ještě něco zůstalo.

Přidal jsem tam delay(50) aby se vyčítal pomaleji - nevím, zda to pomáhá
Přidal jsem tam mezi smyčky delay(100) aby se mohl dotéct další text - nevím, zda to pomáhá
a zopakoval jsem to 3x

Kód: Vybrat vše

while (komunikaceSIM800L.available() > 0) {
    s = komunikaceSIM800L.read();
    delay(50); // aby se stihl buffer vymazat
  }
delay(100);
  
  while (komunikaceSIM800L.available() > 0) {
    s = komunikaceSIM800L.read();
  delay(50);   // aby se stihl buffer vymazat
  }
delay(100);

while (komunikaceSIM800L.available() > 0) {
    s = komunikaceSIM800L.read();
    
  }
Nyní jsem měl za to, že je příchozí buffer čistý.

Pošlu dotaz na SMS a jak jsem vyčetl v jiných programech, čekám delay(100) než odpoví GSM modul

Kód: Vybrat vše

komunikaceSIM800L.println("AT+CMGR=1");
    delay(100);

Když jsem nedal delay(100), následující smyčka bývala prázdná, protože odpověd ještě nepřišla, tak program pak "utekl" dál, aniž by výsledek vyhodnotil.

Pak chci vyčíst odpověd, protože se mi stávalo (nevím proč), že mi to načetlo jen první část, opět jsem přidal delay(50), aby to vyčítalo pomaleji a proces 2x zopakoval. Nevím, zda je to obojí potřeba. Ale odpověď již pak byla v řetezci celá.

Kód: Vybrat vše

while (komunikaceSIM800L.available() > 0) {
    s = komunikaceSIM800L.read();
    odpsms = odpsms + s;
  delay(50);
  }
 
  delay(100);

while (komunikaceSIM800L.available() > 0) {
    s = komunikaceSIM800L.read();
    odpsms = odpsms + s;
  delay(50);
  }
Pak jsem už jen odpověd převedl na porovnatelný řetezec pomocí funkce strstr a vyhodnotil

Kód: Vybrat vše

char odpsmsprevod[odpsms.length() + 1];
  odpsms.toCharArray(odpsmsprevod, odpsms.length() + 1);


  
  if ((strstr(odpsmsprevod, "+420xxxxxxxxx") != NULL) && (strstr(odpsmsprevod, "ZAPNI") != NULL)) {
    // Serial.println("ssssssss - splněna podmínka 737 a ZAPNI");
    digitalWrite(LED2, HIGH);
    delay(1000);
    akce = 1;
  }

No a zde je problém,v arduino MEGA to funguje, ale v MINI PRO to podmínku že obsahuje "+420xxxxxxxxx" registruje, ale text samotné SMS, tedy část "ZAPNI" už ne.

Protože se mi tam nevejde kvůli velikosti paměti knihovna SoftwareSerial.h, nemůžu sledovat výstupy na monitoru, tak je sleduji jen dle signalizačních ledek...

Re: porovnání obsahu řetězce po seriové lince

Napsal: 24 úno 2019, 16:56
od jankop
Respektuji, že sis dal práci to teď popsat co nejpodrobněji. Pokusím se odpovědět co budu vědět.
I Arduino Mini Pro má seriový buffer defaultně velký 64 byte.
Přidáváním

Kód: Vybrat vše

 delay(50); // aby se stihl buffer vymazat
do smyčky čtení zpomalíš pouze čtení z bufferu a tím urychlíš jeho přetečení.
Problém je filozofie celého tvého programu. Už skutečnost, že čistíš buffer ,ani nevíš od čeho, je špatně.
Měl bys vyjít ze znalosti komunikace s tím modulem. Jednotlivé zprávy jsou nejspíš nějak oddělitelné, třeba znakem konec řádku.
Ve smyčce loop() bys měl číst seriový port neustále, nejlépe všechny znaky, které jsou při daném průchodu smyčkou v bufferu. Tvoje tvrzení, že cyklus while() musíš opakovat třikrát, než je buffer prázdný, je mylné. Prostě než jsi začal data zpracovávat, tak tam přišlo něco dalšího.
A co se týká odeslání znaků, tam předpokládám, že jejich přijetí modul nějak potvrdí. A to musíš využít pro další větvení programu.
V prvé řadě bych začal tím přidáním Softwareserial do programu. Zkusil jsem to u té tvé poslední verze a nenarazil jsem na problém

Re: porovnání obsahu řetězce po seriové lince

Napsal: 24 úno 2019, 18:14
od jankop
Čím vlastně ten modul napájíš? Používáš převodník logických úrovní?

Re: porovnání obsahu řetězce po seriové lince

Napsal: 24 úno 2019, 23:46
od gilhad
Pokud chces cekat na nacteni celeho retezce, tak je asi nejlepsi na nej skutecne pockat, nikoli cekat nejakou dobu. IMHO (ale muzu se mylit, protoze ten modul nemam a nikdy jsem nemel) by ti mel posilat odpovedi po seriove lince, ukoncene vzdy koncem radku.

Coz by asi stalo za to odzkouset tak, ze by ses pripojil seriovou linkou primo na ten modul, rucne mu zadal nejake prikazy a sledoval, co z nej leze za odpovedi. Ale typicky ty AT prikazy se odesilaji jako radek a odpovedi take prichazeji jako radky.

Takze tvuj kod by spis mel vypadat nejak takto (idea):

Kód: Vybrat vše

odpsms=""; // zaciname s prazdnou promennou - asi, nespis, ale podminkou to neni, proste budeme pridavat na konec ...
int zelena=13; // zelena dioda, OUTPUT - kdyz cteme, tak sviti, kdyz neni co cist, nesviti - normalne jen kratce problikne, ze byla prijata nejaka data


// ------
bool konec=false;  // konec radku jeste nenastal

unsigned long zacatekMillis =  millis();  // cas, kdy zaciname cist
const long timeoutMillis = 5000;  // timeout, jak dlouho jsme ochotni cekat na odpoved modulu, nez usoudime, ze chcipnul a neodpovi
bool timeout=false;  // nastal timeout?

while ( ! ( konec || timeout) ) { // dokud nenacteme konec radku a aspon obcas nejaka data prichazi
  while (komunikaceSIM800L.available() > 0) { // je-li neco ke cteni v prijimacim bufferu
       s = komunikaceSIM800L.read();  // tak precti znak
       digitalWrite(zelena,HIGH);  // rozsvit zelenou diodu, ze jsi prijal znak 
       zacatekMillis =  millis(); // modul s nama komunikuje, pocitame timeout znovu od ted
       konec= ( (s=='\n') || (s=='\r'));  // porovnej znak s koncem radku - bud je to '\n' nebo '\r', nebo oba v nejakem poradi (v takovem pripade pristi radek bude prazdny)
       if (konec) break; // vyskoc ze smycky a mas cely radek
       odpsms = odpsms + s;  // jinak to pridej do sve promenne a cekej na dalsi znak
       };
   // ted jsou dve moznosti 
   // (konec==true) tedy jsi nacetl konec radku a velky while skonci a mas cely radek v promenne 
   // (konec == false) nebo jsi ho nenacetl, takze jsi nekde vprostred, jen jsi vyprazdnil prijimaci buffer a musis cekat na nacteni zbytku, dalsi pruchod velkym while
   
   // jeste se podivame, zda nenastal timeout, zda s nama modul vubec komunikuje
   unsigned long currentMillis = millis();
  if (currentMillis - zacatekMillis >= timeoutMillis) { // sakra, nastal timeout
     timeout=true;
     };
  digitalWrite(zelena,LOW); // mame prazdny buffer, nebo konec radku
}; // tady konci velky while, ze ktereho se dostanes jen kdyz skonci radek a mas ho cely nacteny (nebo to vytimeoutovalo)

if (konec) {
  // tady nejak zpracujes tu odpoved a pokud je spravna, tak neco udelas, 
  // pokud je spatna, tak analyzujes chybu a bud 
  //   -- vysles dalsi prikaz modulu, nebo,
  //   -- pokud je to jen nejake potvrzeni jako "OK - prijal jsem prikaz a pracuju" tak nactes dalsi radek v dalsim pruchodu
  //   -- pokud je radek prazdny, nactes dalsi v dalsim pruchodu
} else if (timeout) { 
  // tady zacnes cervene blikat, ze ti modul neodpovida a mas nacteny nanejvys jen kus radku
} else {  
  // sem se nemame jak dostat, 
  // protoze bud jsme precetli konec radku (a pak nemuze byt timeout, neb se pri cteni nastavil novy zacatek)
  // nebo nastal timeout
  // takze sem propadneme jen kdyz smycka skoncila nejak jeste jinak
};


Mozna by jeste stalo za to hlidat, zda necteme prilis mnoho znaku (treba se modul zasekl a posila dokola jeden znak), nebo nam nedochazi volna pamet (cteme moc velky radek a ty objekty String zase tak moc pamet nesetri) a v takovem pripade smycku ukoncit taky, tak by nastal ten "nemozny pripad"

Re: porovnání obsahu řetězce po seriové lince

Napsal: 26 úno 2019, 14:53
od RobertN
Děkuji jankop za určení směru a gilhad za další typy. U toho modulu je právě ta věc, že posílá někdy info i sám od sebe. Nízké napětí, doručená sms atd... Vím, že napájení u tohoto modulu je taky náročné, takže provedu ještě i tady úpravy.
Nicméně jsem konečně zprovoznil softwareserial, protože jsem moula a nevšiml jsem si, že mám v jednom místě dlouhý komentář, který mi zaplňoval tu paměť. Takže už to jede a zkusím to odladit a upravit dle vašich doporučení. Určitě sem dám pak zprávu.
Ještě jednou díky!

Re: porovnání obsahu řetězce po seriové lince

Napsal: 26 úno 2019, 17:45
od gilhad
Pokud modul posila neco sam od sebe, pak je asi nejjednodussi pred vlastni komunikaci precist si cely buffer, nez zacnes vubec vysilat

Kód: Vybrat vše

while (komunikaceSIM800L.available() > 0) { // je-li neco ke cteni v prijimacim bufferu
  komunikaceSIM800L.read();  // tak precti znak a proste ho ignoruj
}; // ted je buffer (na chvilku, snad) prazdny, muzeme zacit vysilat
// stejne mezi tim muze prijit konec nejakych zvastu, takze musime byt pri prijmu zpracovat i nesmyslne zpravy (v tomto pripade rozeznat jako nesmyslne a proste zahodit)

Re: porovnání obsahu řetězce po seriové lince

Napsal: 26 úno 2019, 18:09
od jankop
Ten modul neznám a studovat ho zatím nechci, ale například podstatná část odpovědí končí OK. A myslím si, že nějaký znak NewLine či něco podobného tam bude na konci každé zprávy-odpovědi. Na testování a zobrazování komunikace je opravdu výborný program - terminál Hercules. Snadno s ním jdou zobrazit i netisknutelné znaky. Samotný Sériový monitor v Arduino IDE je velmi slabý prostředek. Jen je potřeba si při práci uvědomit, že když se připojím na sériovou linku Arduina programem terminál, tak před nahrávání musím terminál včas odpojit, jinak se budu divit, proč mi nejde nahrát program.