Stránka 1 z 2
porovnání obsahu řetězce po seriové lince
Napsal: 10 úno 2019, 10:55
od RobertN
Dobrý den,
konunikuji přes seriovou linku s GSM SIM800C modulem. Chci ověřit, že v odpovědi z modulu je obsažen určitý text. Nyní to dělám pomocí substring, ale tam se může stát, že odpověď bude mít nějaký znak na víc nebo na míň a už je to nespolehlivé.
Zde je kod.
Kód: Vybrat vše
.
.
.
// vyčisti buffer
while (komunikaceSIM800L.available() > 0) {
s = komunikaceSIM800L.read();
}
// Je modul registrován
komunikaceSIM800L.println("AT+CREG?");
delay(100);
while (komunikaceSIM800L.available() > 0) {
s = komunikaceSIM800L.read();
odpoved = odpoved+s;
}
if (odpoved.substring(18,21) == "0,1") {
digitalWrite(LED,HIGH);
}
else
{
digitalWrite(LED,LOW);
}
odpoved = "";
.
.
.
Chtěj jsem to udělat pomocí funkce strstr takto:
Kód: Vybrat vše
if(strstr(odpoved, "0,1") != NULL)
{
digitalWrite(LED,HIGH);
}
else
{
digitalWrite(LED,LOW);
}
Ale při kompilaci mi to hlásí
"cannot convert 'String' to 'const char*' for argument '1' to 'char* strstr(const char*, const char*)' "
Nevím, jak to převést a přiznám se, že ani nemůžu nikde najít co znamená to char s hvězdičkou...
Děkuji
Re: porovnání obsahu řetězce po seriové lince
Napsal: 10 úno 2019, 12:53
od RomanB
Předpokládám, že kod je z
https://www.arduinotech.cz/inpage/jak-j ... ky-smskou/ a tam postupně načítá a pak porovnává to co potřebuješ pomocí
Kód: Vybrat vše
if (SIM800.available() != 0) {
// if there are data in the UART input buffer, reads it and checks for the asnwer
response[x] = SIM800.read();
x++;
// check if the desired answer is in the response of the module
if (strstr(response, expected_answer) != NULL)
{
answer = 1;
}
}
Taky by jsi mohl definovat "odpoved" takto
a ne jenom
Re: porovnání obsahu řetězce po seriové lince
Napsal: 10 úno 2019, 15:56
od pavel1tu
SMS je vždy stejně dlouhá ... jen ji musíš řádně zpracovat - jako v tom příkladu
já jedu řádek po řádku a zkoumám jen první znaky
po dotazu na SMS "AT+CMGR=1"
hledám řádek s "OK" - to znamená že není žádná SMS v paměti
nebo "+CMGR:" - to už je první řádek SMS, pak porovnám (na tom samém řádku) že je opravdu ješte nepřečtená "REC UNREAD" - vše za tím ignoruji tam je jen číslo odesílatele (to neporovnávám, ale v příští verzi už budu) a časová značka odeslání asi
a na dalším řádku už je jen čistý text SMS, který zpracuji
pak okamžitě SMS mažu
nevidím v tom problém
Re: porovnání obsahu řetězce po seriové lince
Napsal: 10 úno 2019, 17:01
od gilhad
Myslim, ze autor deklaraci promenne odpoved neuvedl a ma ji nekde v tech třech tečkách, co zastupují začátek včetně setupu.
Nicméně překladač je toho mínění, že ta proměnná je typu String (a autor se k ni taky tak chova, odpoved = odpoved+s; ) a funkce strstr vyžaduje ukazatele na řetězece (char *) jako parametry, nikoli nějaké objekty (String).
Pokud pouze změní deklaraci proměnné, tak mu to zase neprojde, bude muset změnit i její používání (například naplňování jednotlivými znaky) - stejně jako v tom linkovaném příkladu.
char * je ukazatel na znak (char), ten znak může být prvkem pole znaků (char[]) a pak se dá považovat i za ukazatel na začátek nějakého řetězce, dle konvence ukončeného znakem 0x00 (znak s kódem nula, také lze v řetězci zapsat jako '\0', resp. "text\0").
Co znamená char *a případně char b[100] a další podobné hrátky se znaky a řetězci lze najít v každé učebnici jazyka C - nenech se mýlit tím, že u Arduina se místo programu říká sketch a tvrdí že programují v jazyku Wiring - ve skutečnosti jde o knihovnu funkcí (digitalRead, digitalWrite ...) a objektů (Serial, Wire ...) pro C++ a programuje se v C++ (ořezaném o mnohé standardní věci, protože malé Arduino nepojme bez následků velké standardní knihovny a tak nějak v základu postrádá věci jako standardní vstup, výstup a error, nebo práci se soubory)
Nicméně pokud chceš to Arduino používat i pro větší projekty, než jen blikání LEDkou, tak vřele doporučuji se na to C/C++ podívat - a časem tě možná zaujme i assembler, až se dostaneš do úzkých kvůli velikosti paměti a omezení výkonu - který Wiring omezuje ještě víc a přístup "nemusím ničemu rozumět, prostě zkopíruju něco z netu a případně tam přidám ještě pár delay() navíc, stejně o nic nejde" v komunitě obvyklý to ještě umozní)
(Jo, digitalRead() je fajn, že to pochopí každý, ale trvá "strašně dlouho" - 41 cyklů než vůbec začne číst ten pin a pak ještě nějaké další, než vrátí hodnotu. Samotné přečtení toho pinu trvá jednu jedinou instrukci ( navíc můžeš jednou jedinou instrukcí načíst i víc pinů vedle sebe ) - takže pokud potřebuješ něco opravdu rychle, tak Arduino přístup "nebojte se, nemusíte tomu moc rozumět" brzy přestane stačit, protože cena za něj je řádově nižší výkon, než ten HW dovoluje)
Re: porovnání obsahu řetězce po seriové lince
Napsal: 13 úno 2019, 19:43
od RobertN
Dobrý večer všem. Pro sepsání kódu jsem se různě inspiroval. Není to celé, jen výtah toho, co jsem chtěl řešit.
Proměnou odpoved jsem měl definovanou jako String.
Chtěl jsem zkusit hledat shodu v celém řetězci, který mi odpoví seriová linka obecně, nejen z GSM modulu. To po znacích mi funguje také a děkuji za inspiraci.
Děkuji
gilhad za vysvětlení, že
char * je ukazatel (pointer). Když jsem totiž zadal "char *" do Google tak mi to bralo, že hvězdička je zástupný znak a nic jsem nemohl dohledat
Po zadání "ukazatel c++" jsem už našel spoustu článků, ze kterých jsem to pochopil. K Assembleru sice už ve svém věku nedojdu, ale rozhodně jsem se zase mohl posunout někam dál.
Řešení mého problému jsem ale nakonec nalezl v příkazu
"toCharArray" . Níže je již upravený kód, opět je to jen výřez, ale myslím, že to hlavní tam je.
Ještě jednou všem moc díky!
Kód: Vybrat vše
#define komunikaceSIM800L Serial1
#define LED 40
char s;
String odpoved;
.
.
.
{
// vyčisti buffer
while (komunikaceSIM800L.available() > 0) {
s = komunikaceSIM800L.read();
}
komunikaceSIM800L.println("AT+CREG?");
delay(100);
while (komunikaceSIM800L.available() > 0) {
s = komunikaceSIM800L.read();
odpoved = odpoved+s;
}
char odpovedprevod[odpoved.length()+1];
odpoved.toCharArray(odpovedprevod,odpoved.length()+1);
if(strstr(odpovedprevod, "+CREG: 0,1") != NULL)
{
digitalWrite(LED,HIGH);
Serial.println("===== ANO - JE REGISTROVAN =================");
}
else
{
digitalWrite(LED,LOW);
Serial.println(" XXXX NE - NENI REGISTROVAN XXXXX");
}
odpoved = "";
Re: porovnání obsahu řetězce po seriové lince
Napsal: 22 úno 2019, 17:42
od RobertN
Tak teď jsem ještě narazil na jednu věc. Vše mi funguje na arduinu MEGA 256, dal jsem to ted na
MINI PRO a nenačte mi to asi celou SMS.
Výpis sms vypadá obecně nějak takto:
+CMGR: "REC UNREAD","+420xxxxxxxxx","","19/02/02,16:52:00+08"
Text zpravy
Nevím, kolik ji načte, protože komunukuji přes Serial s modulem GSM, takže si ji nemůžu vypsat na monitor, ale když porovnámám řetězec pomocí signalizace LED, tak třeba číslo mi to ještě načte, ale text sms už ne.
Kód je
Kód: Vybrat vše
.
int akce = 10;
char s;
String odpsms;
.
.
.
// vyčisti buffer
while (komunikaceSIM800L.available() > 0) {
s = komunikaceSIM800L.read();
delay(50); // aby se stihl buffer vymazat
}
// pro jistotu ještě jendou
while (komunikaceSIM800L.available() > 0) {
s = komunikaceSIM800L.read();
delay(50); // aby se stihl buffer vymazat
}
delay(100);
// pro jistotu ještě potřetí
while (komunikaceSIM800L.available() > 0) {
s = komunikaceSIM800L.read();
delay(50); // aby se stihl buffer vymazat
}
// přečti SMS
komunikaceSIM800L.println("AT+CMGR=1");
delay(100);
// načti odpověď
while (komunikaceSIM800L.available() > 0) {
s = komunikaceSIM800L.read();
odpsms = odpsms + s;
delay(100);
}
delay(100);
// pokud ještě něco bylo načítej dál (toto je možná zbytečné, ale i u MEGY mi to někdy načetlo jen půl odpovědi)
while (komunikaceSIM800L.available() > 0) {
s = komunikaceSIM800L.read();
odpsms = odpsms + s;
delay(100);
}
delay(100);
char odpsmsprevod[odpsms.length() + 1];
odpsms.toCharArray(odpsmsprevod, odpsms.length() + 1);
if ((strstr(odpsmsprevod, "+420xxxxxxxxxx") != NULL) && (strstr(odpsmsprevod, "ZAPNI") != NULL)) {
// Sssssssss - splněna podmínka odesláno z čísla xxx a text je ZAPNI
digitalWrite(LED2, HIGH);
delay(1000);
akce = 1;
}
.... následuje zpracování proměnné akce, která něco provede
Není to velikostí bufferu? A dá se to nějak vyřešit?
Re: porovnání obsahu řetězce po seriové lince
Napsal: 23 úno 2019, 11:49
od jankop
Standardně je velikost sériového bufferu nastavena tuším na 64byte. Dá se snadno zvětšit. Stačí v Arduino IDE najít soubor USBAPI.h a v něm to přepsat. Dokonce je možné vytvořit konfiguraci, že ti IDE nabídne jestli chceš pro danou desku kompilovat s takovou nebo jinou velikostí cache. Sám jsem se s potřebou zvětšit input serial buffer setkal jenom jednou, když jsem potřeboval ukládat příchozí data přímo do EEPROM. Do ní je zápis relativně pomalý a proto mi buffer přetékal. Ale v tvém případě už při zběžném pohledu na program jsem dospěl k závěru, že děláš naprosté maximum proto, aby ti buffer přetekl co nejdříve. Tak neví proč ho chceš zvětšovat.
Kód: Vybrat vše
// načti odpověď
while (komunikaceSIM800L.available() > 0) {
s = komunikaceSIM800L.read();
odpsms = odpsms + s;
delay(100);
}
delay(100);
Tady v této smyčce ti načtení deseti znaků trvá vteřinu! A pokud máš nastavenu komunikační rychlost 9600kb, tak to je cca 1000 příchozích znaků za vteřinu. To prostě musí přetéct.
Proč máš, kam se jen podívám delay() ? Tím dosáhneš pouze toho, že se procesor zastaví a buffer se mezi tím přeplňuje. Když program rozumně upravíš, tak žádně zvětšení bufferu nebude na těch pár byte SMS třeba.
Když něco ladím, obvykle se bez pomocných výstupů na serial monitor neobejdu. Jen bych ti chtěl připomenout, že pokud máš volné na Arduino Pro Mini dva piny, tak můžeš GSM modul připojit na tyto piny jako Software.serial() a dál po Tx0 a Rx0 komunikovat s IDE.
Re: porovnání obsahu řetězce po seriové lince
Napsal: 23 úno 2019, 15:55
od RobertN
Asi je potřeba zmínit, že mám MINI PRO
ATMEGA168 5V, 16 MHZ ...to asi omezuje ten buffer také.
Co se týká
DELAY je to už jen výsledek laborování. Když jsem jej nedal po odeslání AT dotazu, tak často arduino uteklo pryč dříve, než přišla odpověď.
U mazání buferu jsem to zase musel dát, protože tam byl nějaký text, první smyčka jej vyčetla, ale doteklo tam něco nového a tak jsem ho vyčítal ještě další smyčkou. Nakonec jsem došel až k tomuto stádiu, kdy by měl být opravdu prázdný.
Kód: Vybrat vše
// vyčisti buffer
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();
delay(100); // aby se stihl buffer vymazat
}
Software.serial bych taky rád, ale když tam přidám knihovnu, tak mi to píše, že mám překročenou dynamickou paměť...
Zkusil jsem upravit ten
USBAPI.h, ale stále mi to registruje jen číslo ze SMS, ale na text ze SMS už to nereaguje.
Re: porovnání obsahu řetězce po seriové lince
Napsal: 23 úno 2019, 16:16
od RobertN
Toto je poslední verze celého programu. Na MEGA funguje správně.
Kód: Vybrat vše
#include <EEPROM.h> // knihovna pro zapis do pameti eeprom
#define komunikaceSIM800L Serial // serialurčuje o jaké piny se jedná - u MINI 0 a 1 , serial1 určuje o jaké piny se jedná - u mega je to 19(RX) , 18(TX)
#define LED 4
#define LED2 5
#define LED3 6 //Červená
int akce = 10;
char s;
// char odpsmsprevod[128];
String odpoved;
String odpsms;
void setup() {
// když se použije u příkazu AT+CLTS=1;&W tak je to uloženo nastálo - ale jde to jen u některých příkazů
// Serial.begin(9600);
// Serial.println("............ startuji a čekám 20 vteřin................ ");
delay(20000); // čekej 20 vteřin, aby se nastartoval modul
komunikaceSIM800L.begin(4800);
komunikaceSIM800L.println("AT+CNMI=0,0");
// uz vyuzijeme znalosti z SRAM - nevytvarime promennou
// Serial.print("velikost EEPROM je: ");
// Serial.println(EEPROM.length()); // zobrazime velikost EEPROM
// Serial.println("----------------- TEST DIOD ------------------");
digitalWrite(LED, HIGH);
digitalWrite(LED2, LOW);
digitalWrite(LED3, LOW);
delay(500);
digitalWrite(LED, LOW);
digitalWrite(LED2, HIGH);
digitalWrite(LED3, HIGH);
delay(500);
digitalWrite(LED, HIGH);
digitalWrite(LED2, LOW);
digitalWrite(LED3, LOW);
delay(500);
digitalWrite(LED, LOW);
digitalWrite(LED2, HIGH);
digitalWrite(LED3, HIGH);
delay(1000);
digitalWrite(LED, LOW);
digitalWrite(LED2, LOW);
digitalWrite(LED3, LOW);
// načti hodnotu z paměti EEPROM - pamatuje si ji i po vypnutí - Jednorázově při startu
if (EEPROM.read(2) == 1)
{
digitalWrite(LED2, HIGH);
}
if (EEPROM.read(2) == 0)
{
digitalWrite(LED2, LOW);
}
//delay(3000);
}
//-----------------------------------------------------------------------------------
void loop() {
// digitalWrite(LED3, HIGH); // rozsviď Červenou, že frčíme
komunikaceSIM800L.println("AT+CMGF=1"); // nastav sms na ASCII - kdyby to vypadlo
komunikaceSIM800L.println("AT+CNMI=0,0"); // at nepíše že přišla sms
delay(100);
// vyčisti buffer
while (komunikaceSIM800L.available() > 0) {
s = komunikaceSIM800L.read();
delay(50); // aby se stihl buffer vymazat
}
// je modul registrován?
// Serial.println("Je registrován? ");
komunikaceSIM800L.println("AT+CREG?");
delay(100);
// načti odpověď
while (komunikaceSIM800L.available() > 0) {
s = komunikaceSIM800L.read();
odpoved = odpoved + s;
delay(100);
}
char odpovedprevod[odpoved.length() + 1];
odpoved.toCharArray(odpovedprevod, odpoved.length() + 1);
// Serial.println("PREVOD REGISTRACE ZNI:");
// Serial.println(odpovedprevod);
if (strstr(odpovedprevod, "+CREG: 0,1") != NULL)
//if (strstr.substring(18,21) == "0,1")
{
// Serial.println("===== ANO - JE REGISTROVAN =================");
digitalWrite(LED, HIGH);
}
else
{
digitalWrite(LED, LOW);
// Serial.println(" XXXX NE - NENI REGISTROVAN XXXXX");
}
delay (2000);
odpoved = "";
//ssssssssssssssssssssssssssssssssssssssssssssssssss---------------------------------------------------------
digitalWrite(LED3, HIGH); // rozsviď Červenou, že frčíme
// Serial.println("===== čistím buffer =================");
// vyčisti buffer
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();
delay(100); // aby se stihl buffer vymazat
}
// přečti SMS
komunikaceSIM800L.println("AT+CMGR=1");
delay(100);
// načti odpověď
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);
}
char odpsmsprevod[odpsms.length() + 1];
odpsms.toCharArray(odpsmsprevod, odpsms.length() + 1);
// Serial.println("PREVOD SMS ZNI:");
// Serial.println(odpsmsprevod);
// Serial.println("AKCE MA CISLO:");
// Serial.println(akce);
if ((strstr(odpsmsprevod, "+420xxxxxxxxxx") != NULL) && (strstr(odpsmsprevod, "ZAPNI") != NULL)) {
// Serial.println("ssssssss - splněna podmínka 737 a ZAPNI");
digitalWrite(LED2, HIGH);
delay(1000);
akce = 1;
}
if (strstr(odpsmsprevod, "+420xxxxxxxxxx") != NULL && strstr(odpsmsprevod, "VYPNI") != NULL) {
// Serial.println("ssssssss - splněna podmínka 737 a VYPNI");
akce = 2;
}
if (strstr(odpsmsprevod, "+420xxxxxxxxxx") != NULL && strstr(odpsmsprevod, "STAVMODULU") != NULL) {
// Serial.println("ssssssss - splněna podmínka 737 a STAVMODULU");
akce = 3;
}
// Serial.println("úkol přidělen");
if (strstr(odpsmsprevod, "+CMGR:") != NULL)
{ // Serial.println("byla načtena nějaká SMS, takže je vyhodnocena a tak ji mažu");
komunikaceSIM800L.println("AT+CMGD=1");
delay(500);
// zablikej že smaže SMS
digitalWrite(LED3, HIGH);
delay(500);
digitalWrite(LED3, LOW);
delay(500);
digitalWrite(LED3, HIGH);
delay(500);
digitalWrite(LED3, LOW);
delay(500);
digitalWrite(LED3, HIGH);
delay(500);
digitalWrite(LED3, LOW);
delay(500);
digitalWrite(LED3, HIGH);
delay(500);
digitalWrite(LED3, LOW);
delay(500);
digitalWrite(LED3, HIGH);
}
else
{// Serial.println("SMS NESMAZANA");
// zablikej Bílou že NEMAŽE SMS
digitalWrite(LED, HIGH);
delay(500);
digitalWrite(LED, LOW);
delay(500);
digitalWrite(LED, HIGH);
delay(500);
digitalWrite(LED, LOW);
delay(500);
digitalWrite(LED, HIGH);
delay(500);
digitalWrite(LED, LOW);
delay(500);
digitalWrite(LED, HIGH);
delay(500);
digitalWrite(LED, LOW);
delay(500);
digitalWrite(LED, HIGH);
}
// úkol přidělen nebo chybný příkaz nebo odesílatel - SMAŽ SMS ======
// Serial.println("A po podmínkách má AKCE CISLO:");
// Serial.println(akce);
switch (akce) {
case 1:
// Serial.println("VYKONAVAM podminka 1");
// zapiš do EEPROM 1
EEPROM.update(2, 1);
// Serial.println("===== ZAPNUTO =================");
// prozvon
// Serial.println("Volam si");
komunikaceSIM800L.println("ATD00420xxxxxxxx;");
delay (7000);
// Serial.println("zaves hovor");
komunikaceSIM800L.println("ATH");
break;
case 2:
// Serial.println("VYKONAVAM podminka 2");
//zapiš do EEPROM 0
EEPROM.update(2, 0);
// Serial.println("===== VYPNUTO =================");
// prozvon
// Serial.println("Volam si...");
komunikaceSIM800L.println("ATD00420xxxxxxxxxx;");
delay (7000);
// Serial.println("zavěs ");
komunikaceSIM800L.println("ATH");
delay (1000);
break;
case 3:
// Serial.println("VYKONAVAM podminka 3");
// pokud SMS obsahuje STAV pošli SMS
if (EEPROM.read(2) == 1)
{
// Serial.println("VYKONAVAM podminka 3 - EEPROM = 1");
delay(500);
// pošli sms zapnuto
komunikaceSIM800L.println("AT+CMGS=\"00420xxxxxxxxx\"");
delay (500);
komunikaceSIM800L.println("Testovaci modul - ZAPNUTO");
delay (500);
// Zakonceni zpravy
komunikaceSIM800L.write(char(26));
delay (1000);
}
if (EEPROM.read(2) == 0)
{
// Serial.println("VYKONAVAM podminka 3 - EEPROM = 0");
delay(500);
// pošli sms vypnuto
komunikaceSIM800L.println("AT+CMGS=\"00420xxxxxxxxx\"");
delay (500);
komunikaceSIM800L.println("Testovaci modul - VYPNUTO");
delay (500);
// Zakonceni zpravy
komunikaceSIM800L.write(char(26));
delay (1000);
}
break;
}
// Serial.println("JE PO CASE UZ NIC NEVYKONAVAM");
akce = 10;
odpsms = "";
// sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
// načti hodnotu z paměti EEPROM - pamatuje si ji i po vypnutí
// Serial.println("===== načti hodnotu z EPROM =================");
if (EEPROM.read(2) == 1)
{
// Serial.println("===== EPROM JE 1 - zapni LED 2=================");
digitalWrite(LED2, HIGH);
}
if (EEPROM.read(2) == 0)
{
// Serial.println("===== EPROM JE 0 - vypni LED 2=================");
digitalWrite(LED2, LOW);
}
digitalWrite(LED3, LOW); // zhasni před čekačkou
digitalWrite(LED, LOW);
// Serial.println("===== ČEKám 20 vteřin =================");
delay(20000);
}
Re: porovnání obsahu řetězce po seriové lince
Napsal: 23 úno 2019, 16:45
od jankop
Tvoji poslední verzi programu už studovat nebudu. Zjevně jsi vůbec nepochopil, co ti říkám. A arduino nikam neutíká. To jen ty netušíš, že existuje třeba funkce Serial.flush(). Funkce delay() je prostě tvoje zkáza, tím to jenom všechno przníš.
Ať se ti daří.