Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[atmega64][moduł GSM] Odebranie, dekodowanie oraz odesłanie SMS zwrotnego

bercik11palcow 06 Lip 2014 15:24 3834 36
  • #1 06 Lip 2014 15:24
    bercik11palcow
    Poziom 18  

    Witam,
    Chcę zrobić następującą rzecz: Wysyłam do modułu GSM wiadomość o treści "pozycja", i chcę aby odesłał mi wiadomość z aktualną pozycją (z modułu GPS, ale to już mam obsłużone). Na razie chcę żeby mi tę pozycję wysłał na terminal. Format ramki jaki GSM wyświetla w terminalu po odebraniu SMS'a, wygląda następująco:

    Code:
     +CMT: "48663256495", ,"2014/07/06 15:19:28+08"
    
    pozycja


    Oto mój kod w c++:
    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Niestety po wysłaniu SMS, nic się nie pokazuje w terminalu.

    0 29
  • #2 06 Lip 2014 17:46
    zumek
    Poziom 39  

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Spójrz na tę pętlę i wyobraź sobie, że cała wiadomość odczytana z modułu GSM, składa się z np. 80 znaków :idea:

    0
  • #3 06 Lip 2014 21:58
    bercik11palcow
    Poziom 18  

    ok, mogę zmniejszyć bufor lub dopisać linijkę:

    Code:
    //jesli napotkasz 'a'(ostania literke wyrazu pozycja)
    
    if (bufor_GSM[i] == 'a'{
                   break;
                }


    ale to nic nie daje :/

    0
  • #4 06 Lip 2014 22:17
    BlueDraco
    Specjalista - Mikrokontrolery

    I nie da. Modem może wysyłać dowolne komunikaty w dowolnych okolicznościach. Musisz cyklicznie odpytywać modem o SMSy (AT+CMGL="ALL"), odczytywać je pleceniem AT+CMGR i konieczenie kasować AT+CMGD. Nie możesz czekiwać koonkretenj odpowiedzi od modemu - raczej analizuj wszytsko, co z niego przychodzi, rozpoznawaj odpowiedź na CMGL i "rozbieraj" wiadomość.

    0
  • #5 07 Lip 2014 14:03
    bercik11palcow
    Poziom 18  

    Czyli muszę zrobić coś takiego(na razie szkic), tak?:

    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    0
  • #6 07 Lip 2014 16:38
    BlueDraco
    Specjalista - Mikrokontrolery

    Nie, bo po wysłaniu dowolnego polecenia możesz spodziewać się z modemu komunikatu, który nie jest odpowiedzią na to polecenie. Musisz też zachować odstępy czasowe pomiędzy poleceniami.

    Ja robię to tak, że jeden automat zajmuje się nadawaniem poleceń do modemu, a niezależny od niego parser odpowiedzi, również zrobiony jako automat, zajmuje się wyłącznie obróbką odpowiedzi, w tym wykrywaniem treści SMS i ich interpretacją.

    0
  • #7 07 Lip 2014 16:46
    bercik11palcow
    Poziom 18  

    W takim razie nie rozumiem jak mam to zrobić. Co i jak nadawać i skąd wiedzieć co i czy w ogóle coś nadchodzi z modemu?

    0
  • #8 07 Lip 2014 17:47
    BlueDraco
    Specjalista - Mikrokontrolery

    Kiedy coś nadchodzi z modemu - UART zgłasza przerwanie odbioru znaku. Parsować odpowiedzi modemu możesz np. w procedurze obsługi tego przerwania.

    Co i kiedy nadawać? To, co potrzebujesz nadać (np. AT+CMGL), po upłynięciu określonego czasu lub po wystąpieniu jakiegoś zdarzenia, którego znacznik ustawi parser odpowiedzi modemu. Takim pożytecznym znacznikiem jest np. znacznik odbioru "OK".

    0
  • #9 07 Lip 2014 18:29
    atom1477
    Poziom 43  

    Ja to robię tak samo jak BlueDraco, czyli za pomocą dwóch niezależnych automatów.

    Tutaj dla ułatwienia masz jak to wygląda u mnie:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #10 23 Lip 2014 10:30
    bercik11palcow
    Poziom 18  

    hmm, no już mniej więcej rozumiem o co chodzi. Tylko ja nie mam funkcji porownaj_tekst więc zastosowałem funkcję memcmp i zrzutowałem RX_Buffer na (const void*)
    Do testów wysyłam do modemu AT i sprawdza czy tylko odebrał OK, jeśli jest to OK, to wysyłam tekst Działa. Tylko jest problem, bo nie wysyła mi całego tekstu "działa!", tylko "dzi". Oto mój kod:

    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    0
  • #11 23 Lip 2014 16:15
    nsvinc
    Poziom 35  

    "Czekanie na enter" nie jest najszczęsliwszym rozwiązaniem. Standard hayesa definiuje 3 standardowe wzorce odpowiedzi:

    1) [cr][lf][wyrazenie][cr][lf]
    2) [cr][lf][wyrazenie]=[wartosc](,[wartosc],[wartosc],...)[cr][lf]OK[cr][lf]
    3) [cr][lf][wyrazenie]=[wartosc](,[wartosc],[wartosc],...)[cr][lf][plaintext][cr][lf]OK[cr][lf]

    W przypadku URC:
    1) [cr][lf][wyrazenie[cr][lf]
    2) [cr][lf][wyrazenie]=[wartosc](,[wartosc],[wartosc],...)[cr][lf]
    3) [cr][lf][wyrazenie]=[wartosc](,[wartosc],[wartosc],...)[cr][lf][plaintext][cr][lf]

    Roznica miedzy URC a responsem, to ten wlasnie OK, ktory idzie w responsie, a w URC juz nie. Sam response moze byc rowniez 'zaskakujacy', czyli zamiast tresciwej odpowiedzi dostajemy chamski ERROR. I na to trzeba się przygotować, np. próbując ręcznie zarejestrować modem w roamingowej sieci, albo wykonać attach GPRS jak nie ma zasiegu GPRS ;] Magiczny ERROR może przyjść zawsze...

    Pod kategorię 1 podpadają wyrazenia typu OK, ERROR
    Pod kategorię 2 podpadają wyrazenia z parametrem, typu +CGATT=1
    Pod kategorię 3 podpadają wyrażenia transportujące plaintext, np. SMSy (niezaleznie od tego, czy PDU, czy ASCII), jak +CBM=[costam],[costam],...[cr][lf]ToJestTekstBroadcastMessage[cr][lf]

    Co do dwóch niezależnych automatów - zgodzę się, i chyba nie ma innej sensownej drogi na około. Jednak do parsera bym sie przyczepił ;] Ja robię to tak:
    - mam tablice kojarzącą wyrazenie z handlerem

    Kod: C
    Zaloguj się, aby zobaczyć kod


    Nastepnie tablica:
    Kod: C
    Zaloguj się, aby zobaczyć kod

    Parser jest 3etapowy:
    1) wycinanie danych z fifo do liniowego bufora miedzy dwoma [cr][lf]
    2) po otrzymaniu tego drugiego [cr][lf] odpala sie preparser ktory za pomoca xorowania całych 32bitowych slow (taki moj patent :)) porownuje ciagi znakow i szuka handlera w exprTable
    3) nastepnie odpala się handler podajac mu jako argument index w fifo bezposrednio za znakiem '=' (o ile on istnieje).

    Zrobiłem tak, gdyż w moim przypadku aplikacja wymaga w miarę płynnej konwersacji z modemem i faktyczną reakcję na to, co on odpowiada. Np. URC na utrate połączenia GPRS powoduje lawinowe wstrzymanie 2 wątków, a trzeci (supervisor modemu) najpierw robi deattach GPRS, potem pyta o zasięg, obecność karty SIM, itp itd, i w zaleznosci od odpowiedzi na te pytania podejmuje odpowiednie akcje; czyli jak wystąpił zonk karty SIM, to modem dostaje cykl zasilania, i wykonuje się jego rozbiegówka.
    Dlatego mam parser który interpretuje argumenty response'a osobno - zamiast czekać na "+CPIN=READY", a jak przyjdzie coś innego niż "READY" to zonk, i nie wiemy co to jest; to dynamicznie rozpatruję to, co zwraca CPIN...

    BTW, bazując na URC +CMT mozna bez odpytywania w kółko, odbierać esemesy prost po UARTcie - wystarczy ustawić:
    Kod: C
    Zaloguj się, aby zobaczyć kod

    0
  • #12 24 Lip 2014 16:11
    bercik11palcow
    Poziom 18  

    Witam, uporałem się z poprzednim problemem lecz napotkałem kolejny. Zrobiłem na razie coś takiego. Wysyłam do modemu komende do odczytania wiadomości nr8. Jeśli nie ma tej wiadomości to na terminal ma mi wysłać tekst Brak SMS, a jeśli jest i zawarta w niej tresc zawiera słowo "pozycja", to ma mi wyslac komunikat "odebrano SMS". Jest to na razie faza testów. Problem polega na tym, że nie wysyła mi ciągle wiadomości "brak sms" lub "odebrano SMS" tylko wyśle kilka razy i stoi w miejscu. Czemu tak się dzieje?

    Oto kod:

    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    0
  • #13 25 Lip 2014 18:28
    BlueDraco
    Specjalista - Mikrokontrolery

    Wysyłasz po kolei dwa polecenie nie czekając na echo, ani na odpowiedź modemu. Większość modemów tego nie lubi. Zrób np. sekundę przerwy pomiędzy poleceniami.

    Dostałeś kilka dobrych rad i jakoś nie widać, żebyś je zastosował.

    0
  • #14 27 Lip 2014 22:01
    nsvinc
    Poziom 35  

    Niektóre po prostu 'nie lubią', inne dostają kociokwiku i wpadają w nieustalone stany (vide pierwsze wersje znienawidzonego SIM900). Zasadą jest, że na każdy rozkaz jest zawsze odpowiedź - chociażby głupi OK czy ERROR - ale zawsze jest.
    Brak odpowiedzi z modemu przez okreslony czas od momentu wyslania rozkazu (czas okresla producent i datasheety lepszych modemów podają timeouty, do gorszych - trzeba sobie te timeouty zgadnąć) to jest krytyczny fail modemu i trzeba sprzedać mu reset i 'przewinąć' kod który go obsługuje.
    Nie wolno wysłać następnego rozkazu dopóki nie przyjdzie odpowiedź na poprzedni - taka jest specyfika AT hayesa. W niektorych pierwszych dokumentacjach protokołu zdarzało się stwierdzenie, że wysłanie dwóch rozkazów pod rząd może skonczyć się 'undefined behavior' ;]
    Np. LEONy Ublox'a od softu 7 inteligentnie ignorują cokolwiek, co sie wysle między konczącą crlf'ką rozkazu, a kończącą crlf'ką odpowiedzi. Wczesniejszy soft niestety zachowywał się różnie w pewnych konkretnych przypadkach...

    0
  • #15 28 Lip 2014 18:55
    bercik11palcow
    Poziom 18  

    hmm, mam pytanko. Chciałem wysłać do modemu TYLKO RAZ komendę np AT, czyli przed while(1) wstawiłem po prostu wyslij_slowo_UART1("AT\x0D"); i zamiast wyswietlic mi na konsoli:
    AT
    OK, to wyświetla mi PU. Jak wrzucę to do while'a to normalnie wysyła. Czemu tak się dzieje?

    0
  • #16 28 Lip 2014 20:20
    BlueDraco
    Specjalista - Mikrokontrolery

    Po jakim czasie od włączenia modemu wysyłasz to polecenie? Jaki czas uruchamiania modemu od włączenia podaje jego producent? Jaki masz odstęp czasowy pomiędzy tym poleceniem i następnym?

    Bez kodu raczej Ci nie pomożemy.

    0
  • #17 28 Lip 2014 20:30
    bercik11palcow
    Poziom 18  

    1. Polecenie to wysyłam po jakimkolwiek czasie(bo pierw uruchamiam modem, jak już dioda sygnalizująca miga w taki sposób że wiem że modem jest gotowy do pracy, to podłączam programator, a tym samym uruchamiam program w AVR). Ale próbowałem i po kilku min i nic. A jak pisałem, jak wrzuce to do while'a to jest OK.
    2. Odstęp czasowy między tymi poleceniami, próbowałem 1s i 2s i nic.

    0
  • #18 28 Lip 2014 20:49
    witoldwitoldowicz
    Poziom 28  

    Moze masz jakies buforowanie i dopiero po przepelnieniu wysyla.

    0
  • #19 28 Lip 2014 21:00
    bercik11palcow
    Poziom 18  

    no raczej nie, main wyglada tak:

    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    Jak wrzucę wyslij_slowo.... do while'a to działa, tylko że wysyła w nieskończoność, a ja chce wysłać to raz.

    0
  • #20 28 Lip 2014 21:15
    BlueDraco
    Specjalista - Mikrokontrolery

    A przerwania kiedy odblokowujesz?

    Nie pokazałeś całego kodu.

    0
  • #21 28 Lip 2014 21:52
    bercik11palcow
    Poziom 18  

    no ale teraz chcę po prostu wysłać coś RAZ do modemu, bez żadnych przerwań i dekodowania smsów...

    0
  • #22 28 Lip 2014 22:33
    nsvinc
    Poziom 35  

    1) Machanie PWRKEY (lub jego odpowiednikiem)
    2) Zasilanie modemu
    3) External reset modemu

    Jeśli modem masz domyślnie zasilany cały czas, nie masz podłączonego resetu modemu do procka, a tylko i wylacznie masz kontrole poprzez pin PWRKEY, to masz problem, i cięzko będzie ci wykonywać sekwencje restartu modemu jak on złapie zgon.

    Generalnie wygląda to tak:
    a) reset=0, brak zasilania, pwrkey=hiz, jesli idziesz z kroku m) to idz do a0) else idz do b)
    a0) delay ~1000ms
    b) podac zasilanie
    c) delay ~100ms
    d) reset=1
    e) delay ~1500ms
    f) "AT", ma wrócić OK w ciagu 1000ms (raczej standard); jeśli nie ma odpowiedzi to:
    g) pwrkey=0
    h) delay ~800ms
    i) pwrkey=hiz
    j) delay ~1500ms
    k) idz do kroku f), jesli modem odpowiada to jest gotowy na przyjmowanie rozkazow, jesli nie, ponów 3 razy krok f) ("AT" - timeout 1000ms - "AT" - timeout 1000ms - "AT" - timeout 1000ms) jeśli odpowiedzi wciąż brak, to idz do a)

    0
  • #23 30 Lip 2014 16:49
    bercik11palcow
    Poziom 18  

    Witam,
    Kombinuję i kombinuję i nic mi nie wychodzi. Próbowałem zrobić coś takiego jak napisał nsvinc, lecz jeśli tylko podłączę pin POWERKEY do któregoś z portów uP(nawet przy odłączonym zasilaniu uP), to modem od razu się włącza, tak jak by na wszystkich pinach domyślnie było GND(a nie jest bo sprawdzałem miernikiem).
    Chciałem zrobić coś takiego, że, jeśli wiadomość nr9 zawiera słowo Pozycja, to wyślij SMS'a o treści "sms2". Lecz modem mi nic nie wysyła. Natomiast jeśli zamiast procedury wysłania sms'a wstawię tam np linijkę wyslij_slowo_UART("odebranoSMS");, to wysyła mi po drugim UART normalnie do konsoli ten tekst. Czemu nie chce to działać z tym SMS'em?
    Druga sprawa, to w poniższym kodzie, jak dam delay'a pomiędzy pierwszymi dwoma komendami w while(1), to nic nie wysyła, nawet po tym drugim UART'cie. Jak zakomentuję tego delay'a to normalnie wysyła do PC tekst na terminal. A z SMS nie działa ani z delay ani bez niego.

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Numer tel, tam gdzie są xxx wpisuję normalnie swój.
    A procedura wyslania sms jest na pewno dobra, bo jak wkleję przed while'a
    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    to wysyłą normalnie SMS'a

    0
  • #24 30 Lip 2014 17:09
    BlueDraco
    Specjalista - Mikrokontrolery

    Nadal ignorujesz wszelkie rady dot. współpracy z modemem. Czy poczekałeś na "OK" po AT+CMGR?

    W Twoim programie aż się roi od błędów algorytmicznych, więc dla mnie byłoby bardzo dziwne, gdyby zadziałał.
    Np. skąd pomysł, że SMS będzie miał zawsze numer 9?

    Zadziwia mnie też to:
    if (Response[Response_RD & 0x0F] == Response_OK)
    Ciekawe, ile błędów jest w tej linijce - stawiam, że min. 2.

    Niezasilany mikrokontroler ma wyjścia zwarte do masy przez diody technologiczne, więc włączanie modemu przez niezasilany uC jest całkiem normalne. TO uC powinien być zasilony jako pierwszy lub równocześnie z modemem.

    0
  • #25 30 Lip 2014 17:52
    atom1477
    Poziom 43  

    BlueDraco napisał:
    Zadziwia mnie też to:
    if (Response[Response_RD & 0x0F] == Response_OK)
    Ciekawe, ile błędów jest w tej linijce - stawiam, że min. 2.

    Ja nie widzę żadnego. Mógł byś powiedzieć jakie to błędy?

    0
  • #26 30 Lip 2014 18:01
    nsvinc
    Poziom 35  

    >bercik

    Przestań gwałcić modem, tylko zacznij z nim współpracować - to nie modem nie chce współpracować z tobą, tylko na odwrót ;] Gwałcąc modem nie dojdziesz do sukcesu ;]

    Zdradź nam w koncu czy potrafisz kluczować zasilaniem modemu? Lub jego resetem?...
    Ciekawe też, że owiałeś misterną tajemnicą sam modem - w tym wątku ani razu nie padło pytanie o model (lol), a sam go nie podałeś (wiekszy lol...)

    Zacznij się ściśle sugerować tym co ci próbujemy wytłumaczyć, i będziesz w stanie opanować modem. Po twojemu niestety nie działa, i nie będzie - z prostej przyczyny - nie tak to się robi.

    Dodano po 4 [minuty]:

    >atom1477

    Ja tam tez nie widzę błędu jako takiego; w ISRrze jest "tokenizer" ktory wypluwa do fifo Response jakiś token. I to jest raczej dopuszczalne... Ale to nie zmienia faktu, że ten kod nadaje się na śmietnik, a dodatkowo ma zerowe reusability (a to juz jest mistrzostwo) :D

    0
  • #27 30 Lip 2014 19:30
    bercik11palcow
    Poziom 18  

    ok, Modem to MG2639 od ZTE.
    Oto co zrobiłem teraz:

    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    I teraz modem nie chce się w ogóle włączyć, tzn tak jak by zaczynał się włączać, dioda mignie szybko z 3 razy (a powinna przez ok 7s), i się resetuje.

    0
  • #28 30 Lip 2014 19:46
    nsvinc
    Poziom 35  

    Nadal - po podniesieniu resetu musisz poczekać conajmniej sekundę i [b]sprawdzić czy modem wstał, wysyłając mu AT.
    Jeśli nie, dopiero wtedy macac PWRKEY.

    Przestań na siłę wciskać ten AT+CMGF=1 tylko napisz porządną rozbiegówkę, tak, jak napisałem w #22. To az takie trudne?
    Wez ten tokenizer, dostaw mu obsługę OK. Zanim wyślesz cokolwiek innego do modemu, wysyłaj mu AT, i ma odpowiedzieć OK! Nie zadne CMGF czy inne konfigi.

    Zanim podniesiesz reset modemu, musisz mieć zainicjalizowany UART, gotowy do odbioru danych. Niektóre modemy wysyłają powitanie jak wstaną, same z siebie.

    I po wysłaniu czegokolwiek nie ma być zaden delay, tylko masz czekać na odpowiedź. Któryś raz z kolei ktoś ci mówi że masz czekać na odpowiedź i dopiero jeśli ją dostaniesz to kontynuować. Nie delay. Nie cudawianki. Nie szklana kula która zgadnie czy modem dostał/zrozumiał/wykonał rozkaz. Musisz interpretować to co zwraca modem. Nie ma drogi naokoło, zrozum to w końcu.

    Jak byś sie czuł, gdyby ktoś wydawał ci rozkazy z losową prędkością w losowych momentach, kompletnie olewając to co odpowiadasz i czy odpowiadasz w ogóle; dodatkowo przerywał ci nowym rozkazem gdy jeszcze zastanawiasz sie nad wykonaniem poprzedniego?
    To własnie robisz w ten biedny modem - on juz pewnie ma traumę ;]

    0
  • #29 03 Sie 2014 12:04
    bercik11palcow
    Poziom 18  

    To że modem nie wstanie po samym resecie jest więcej niż pewne. Wykombinowalem coś takiego:

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    lecz nie wiem czy dobrze zrobiłem to odbieranie OK od modemu po podaniu mu AT. No bo nie wiem jak odebrać coś inaczej od modemu jak nie przez przerwanie? I jak to jest dobrze, to jak wyjść z warunku if i iść dalej do następnej linijki kodu jak będzie spełniony, i co napisać w else żeby wrócił do linijki z włączeniem modemu

    edit:
    druga sprawa, to uruchomienie modemu. Jak zrobię tak:
    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    to modem się normalnie włącza.
    Ale jak odkomentuję linijkę //wyslij_slowo_UART1("AT\x0D");, to modem nie chce się uruchomić. Dioda mignie raz czy dwa i się jak by resetuje.

    0
  • #30 03 Sie 2014 19:50
    nsvinc
    Poziom 35  

    W #9 atom1477 podał ci gotowy kod który możesz z powodzeniem użyć. Skoro już tu go wkleił, to go skopiuj do siebie... a przerabiać będziesz jak ogarniesz temat ;]

    Jeśli masz możliwość fizycznego podglądu TXa modemu lub uzywasz debuggera, sprawdź co wysyła modem jak się włącza.

    bercik11palcow napisał:
    To że modem nie wstanie po samym resecie jest więcej niż pewne.

    Wcale nie jest pewne. uBlox wstaje po resecie, Telit wstaje po resecie... Ale zakładam, że sprawdziłeś fizycznie, że po podniesieniu resetu modem nie dał znaku życia przez conajmniej 10 sekund.

    bercik11palców napisał:
    Ale jak odkomentuję linijkę //wyslij_slowo_UART1("AT\x0D");, to modem nie chce się uruchomić. Dioda mignie raz czy dwa i się jak by resetuje.

    Sprawdź więc, co dokładnie robi modem po wysłaniu mu tego AT. Może coś odpowiada?...

    Dodano po 9 [minuty]:

    BTW, widzę ze do modemu gadasz z jakiegos AVRa. Proszę powiedz że nie zasilasz procesora z 5V lub masz jakis level shift na liniach miedzy prockiem a modemem...

    Dodano po 23 [minuty]:

    Przejrzałem dokumentację, i powiem ci w tajemnicy ;] wybrałeś chyba najgorszy modem do nauki jaki istnieje. Tragiczny ciezko zrozumiały datasheet, i jeszcze tragiczniejszy opis komend AT. Nawet nigdzie o URC nie wspomnieli... Nigdzie nie ma defaultów, brak opisu co modem robi po resecie, brak ogolnie to wszystkiego, co by ci sie przydało na początki przygody z modemami. Dodatkowo uzywany tam język tylko pozornie przypomina angielski :D Więc większość musisz rozkminiać sam, co z doswiadczeniem takim, jakie masz, dostarczy ci dobrej zabawy ;]
    Nawet dla mnie (a mam doswiadczenie, przerobiłem już Telita, uBloxa, SIM900 i bardzo dawno temu też jakiś grat od ZTE) dokumentacja to bajzel i modem musiałbym 'rozkminiać'. Czyli do resetu i PWRKEY podlaczyc tactswitch'e, UART modemu puścić przez przejściówkę UART<->USB, i próbować ogarniać modem 'z palca', przez terminal (typu Realterm)...

    0