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.

[ATMega8][c] - problem z tablicą uzupełnianą w przerwaniu

Citek 02 Wrz 2009 20:22 2680 21
  • #1 02 Wrz 2009 20:22
    Citek
    Poziom 22  

    Witam.
    Buduje dialer GSM, który będzie porównywał dzwoniący nr i jeżeli będzie prawidłowy to będzie sterował jednym z wyjść uP. Niestety trafiłem na problem z porównaniem tablicy poprzez polecenie strncmp, ponieważ dostaję warninga.
    Oto opis z AVRStudio:
    ../C35i_RC1.c:121: warning: passing argument 1 of 'strcmp' discards qualifiers from pointer target type

    Chciałem też wyłączać przerwanie w przerwaniu, czy tak można robić. Pytam się dlatego, bo nie chciało mi to za bardzo działać.

    Oto mój kod:

    Code:

    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <string.h>
    #include <stdlib.h>  // itoa, atoi
    #include <util/delay.h>
    #include <hd44780_at8.c>
    #include <string.h>
    #include <avr/io.h>                 // dostęp do rejestrów
    #include <inttypes.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>

    #define FOSC 4000000
    #define BAUD 19200
    #define MYUBRR FOSC/16/BAUD-1

    unsigned char wys;

    volatile int odbior=0;
    volatile int licz=0;
    volatile char bufor[100]="Test\0";
    //char bufor1[10]="S\0";


    void usart_init(unsigned int ubrr)
    {
       UBRRH = (unsigned char)(ubrr>>8);
       UBRRL = (unsigned char)ubrr;
       UCSRB = (1<<RXCIE)|(1<<TXEN)|(1<<RXEN);
       //UCSRB = (1<<RXEN)|(1<<TXEN);
       UCSRC = (1<<URSEL)|(0<<USBS)|(3<<UCSZ0);
    }

    void nadaj_znak(unsigned char data)
    {
       while(!(UCSRA&(1<<UDRE)));
       UDR=data;
    }

    unsigned char odbierz_znak(void)
    {
       while(!(UCSRA & (1<<RXC)) );
       return UDR;
    }

    void wyslij_slowo(char *dana)
    {
       int dlugosc_slowa, k =0 ;
       dlugosc_slowa = strlen(dana);
       for(k = 0; k<dlugosc_slowa; k++)
        {
             nadaj_znak(dana[k]);
        }
    }

    SIGNAL(SIG_UART_RECV)
    {
       //cli(); - tu próbowałem wyłączyć przerwanie
       //_delay_ms(100);
       LCD_WriteText("1");
       do
       {
          wys=odbierz_znak();
       }
       while ((wys==0x0A)||(wys==0x0D));




       
       licz=-1;

       while ((wys!=0x0A)&&(wys!=0x0D))
       {
          licz++;
          bufor[licz]=wys;
          LCD_WriteData(wys);
          wys=odbierz_znak();
       }
       wys=odbierz_znak(); //odebranie ostatniego 0x0A
       //cli(); - i tu także niestety nic to nie dało
       odbior=1;      
    }

    int main(void)
    {

       LCD_Initalize();
       LCD_Clear();
       LCD_WriteText("LCD@TEST");
       _delay_ms(100);
       usart_init(MYUBRR);
       _delay_ms(1000); //dłuższe opóźnienie, aby uruchomił się UART
        wyslij_slowo("ATE0"); //wyłączenie ECHA
        nadaj_znak(0x0D);
       _delay_ms(100);
       wyslij_slowo("ATD+48500600700;");  //dzwonienie
       nadaj_znak(0x0D);
       _delay_ms(2000);
       wyslij_slowo("ATH");   //rozłączenie
       nadaj_znak(0x0D);
       _delay_ms(100);
       LCD_WriteText("Wysłano numer");
       _delay_ms(1000);
       LCD_Clear();
       LCD_WriteText("Odbieram znaki");
       LCD_Clear();
       wys=odbierz_znak();
       wys=odbierz_znak();
       wys=odbierz_znak();
       sei();
       _delay_ms(1000);

       while(1)
       {   
          LCD_WriteText("*");
          _delay_ms(5500);

          if (odbior==1)
          {
             for (int k=0;k<licz+1;k++)
             {
             LCD_WriteData(bufor[k]);
             }
             if (strncmp (bufor, "RING", 4) == 0)
             {
                LCD_WriteText("OKI?");
             }
             
             odbior=0;
             //cli(); - tu jak wyłączałem przerwanie to działało
          }
       }
    }

    0 21
  • #2 02 Wrz 2009 21:06
    GrEG0
    Poziom 14  

    Za bardzo się nie przyglądałem programowi, ale pierwsze co mi się w oczy rzuciło, to że w przerwaniu USART_RECV używasz procedury odbierz_znak(). To jest nie potrzebne, bo jak masz załączone przerwanie USART_RECV to w UDR będzie dostępny odebrany znak. Twoja dodatkowa procedura wprowadza tylko zamieszanie.

    Usuń także obsługę LCD z przerwania (niepotrzebne blokowanie przerwania) - wstaw ją do pętli głównej.

    0
  • #3 02 Wrz 2009 21:29
    Demoman
    Poziom 17  

    AtMegi podczas wejścia do przerwania automatycznie blokują inne...

    Co do strncmp() to nie bardzo wiem... ale bufor 100 znaków to chyba za dużo na te zastosowanie ;)

    0
  • #4 02 Wrz 2009 21:46
    wojtekkk09
    Poziom 15  

    Witam!

    Aby pozbyć się warningu, musisz rzutować zmienną.
    Zmień linijkę:

    Code:

    if (strncmp (bufor, "RING", 4) == 0)


    na

    Code:

    if (strncmp ((const char*)bufor, "RING", 4) == 0)


    I będzie OK.

    Pozdrawiam
    Wojt

    0
  • #5 02 Wrz 2009 23:49
    Citek
    Poziom 22  

    Tak jak myślałem, że będzie trzeba jakiś wskaźnik zastosować, niestety jakoś tych wskaźników nie mogę zbytnio pojąć, chociaż mam nadzieje że z czasem...

    Dodano po 7 [minuty]:

    Demoman napisał:
    AtMegi podczas wejścia do przerwania automatycznie blokują inne...

    Co do strncmp() to nie bardzo wiem... ale bufor 100 znaków to chyba za dużo na te zastosowanie ;)

    Mi chodzi o wyłączenie przerwania od RX UARTa, gdy będę w pętli i żeby było dalej ciągle wyłączona. Dopiero później w głównej funkcji MAIN gdzieś bym sobie włączał.
    Potrzebuję to do tego, bo zależnie od ustawionych parametrów telefonu mogę otrzymywać kilka "komunikatów", np wpisując do telefonu AT+CLIP=1, przy dzwonieniu będę otrzymywał komunikat a chciałbym go podzielić:
    0x10 0x13 RING 0x10 0x13 - i tu chciałbym właśnie dzielić wiadomość na części
    0x10 0x13 +CLIP: blebleble 0x10 0x13 - druga część wiadomości.
    Wtedy mógłbym moim zdaniem lepiej analizować co przyszło.

    A jeżeli chodzi o bufor to tylko na razie testowo tak zarzuciłem liczbą, żeby przypadkiem nie brakło mi gdzieś znaków.

    0
  • #6 02 Wrz 2009 23:56
    GrEG0
    Poziom 14  

    Odbiór znaków zostaw w przerwaniu, a analizę tego co przyszło zrób poza przerwaniem.
    Tak bedzie najprościej i będzie bez problemów działać.

    Oczywiście możesz też analizować to co przyszło w przerwaniu. Jeżeli 0x10, 0x13 są znakami początku/końca danych to łatwo z tego wyciągnąć dane, które się pomiędzy tymi znakami znajdują. A do tego nie trzeba wogóle wyłączać przerwania.

    0
  • #7 03 Wrz 2009 10:02
    Citek
    Poziom 22  

    GrEG0 napisał:
    Odbiór znaków zostaw w przerwaniu, a analizę tego co przyszło zrób poza przerwaniem.
    Tak bedzie najprościej i będzie bez problemów działać.


    Właśnie chyba tak robię...

    GrEG0 napisał:
    Oczywiście możesz też analizować to co przyszło w przerwaniu. Jeżeli 0x10, 0x13 są znakami początku/końca danych to łatwo z tego wyciągnąć dane, które się pomiędzy tymi znakami znajdują. A do tego nie trzeba wogóle wyłączać przerwania.


    W moim przypadku w przerwaniu od razu odrzucam znaki 0x10 0x13, może to i teraz mój błąd, będę musiał to przemyśleć.

    0
  • #8 03 Wrz 2009 12:38
    GrEG0
    Poziom 14  

    W przerwaniu możesz odrazu odrzucać te dwa znaki. Problemem jest u ciebie, ta ki się wydaje, że ty wyłączasz przewanie i wrzucasz procedure odbioru do środka. Jak znajdę wieczorem trochę czasu to postaram się krótki przykład wrzucić.

    0
  • #9 03 Wrz 2009 19:35
    Citek
    Poziom 22  

    GrEG0 napisał:
    W przerwaniu możesz odrazu odrzucać te dwa znaki

    No i tak robię poprzez pierwszą pętlę do-while, odrzucam pierwsze "znaki specjalne", a poprzez pętle while odrzucam znaki końcowe.

    Dodano po 22 [minuty]:

    Wykombinowałem jeszcze coś takiego wg. waszych wskazówek

    Na razie tylko kod przerwania UART:
    Code:
    {
    
       //LCD_WriteText("1");
       UDR;
       if ((UDR!=0x0A)&&(UDR!=0x0D))
       {
          licz++;
             bufor[licz]=wys;
          LCD_WriteData(UDR); //jako pogląd czy dobrze odbiera
       }
       odbior=1;      
    }


    oraz częściowo Główny program:
    Code:
    int main(void)
    
    {
       LCD_Initalize();
            <...> //wyciąłem na razie ten początkowy kod, aby zyskać na przejrzystości
            <...>
       licz=-1;
       sei();

       while(1)
       {   
          if (odbior==1)
          {
             for (int k=0;k<licz+1;k++) //w celu sprawdzenia czy dobrze zapisalo do buforu
             {
             LCD_WriteData(bufor[k]);
             }

    TUTAJ JESZCZE TRZEBA DOPISAĆ PRZESZUKIWANIE BUFORA

             */if (strncmp ((const char*)bufor, "RING", 4) == 0)
             {
                LCD_WriteText("OKI?");
             }*/
             licz=-1;
             odbior=0;
          }
       }
    }

    Tak jak w opisie muszę stworzyć jeszcze przeszukiwanie tablicy, zastanawiam się jak to zrobić czy poprzez pętlę while czy może jakiś for z if-em.
    Zastanawiałem się nad takim czymś:
    Chcę znaleźć w uzupełnionej tablicy wyraz RING, a więc muszę znaleźć od litery R
    Szukanie jej bym zaczął chyba poprzez pętlę FOR w której byłby IF z funkcją strcmp.
    Na szybko pseudokod:
    For (j=0, j<licz+1,j++)
    {
    if (bufor[j]==R)
    {
    if (strncmp ((const char*)bufor, "RING", 4) == 0)
    {
    LCD_WriteText("OKI?");
    }*/
    }
    }
    Jak myślicie zda to egzamin?
    Zastanawia mnie jeszcze jedno czy przypadkiem nie wyłączyć przerwania jak wejdę do tej pętli if(odbior==1).

    PS. Taki OT. Jak w postach robić tabulatory?

    0
  • Pomocny post
    #10 03 Wrz 2009 20:20
    GrEG0
    Poziom 14  

    W przerwaniu nie powinno być funkcji obsługi LCD. Obsługę LCD daj do pętli głównej, bo inaczej będziesz miał problemy z przerwaniem.

    Jeżeli masz w buforze więcej rozkazów niż tylko RING, to strcmp ci nic nie da, bo funkcja ta porównuje dwa łańcuchy. Ale jeżeli w buforze bedzie zawsze tylko jeden rozkaz to możesz tak zrobić i wtedy nie potrzeba nawet pętli "if". Wystarczy samo strcmp.
    Nie zapomnij też bufora zakończyć znakiem "\0" (koniec łańcucha).

    Jeżeli natomiast w buforze będziesz miał więcej rozkazów to możesz użyć funkcji "strstr" do wyszukiwania odpowiedniego łańcucha w buforze.

    0
  • #11 03 Wrz 2009 20:52
    Citek
    Poziom 22  

    Dzięki GrEG0 za podpowiedź. Zaraz przeanalizuję dokładnie to co napisałeś.
    Jeżeli chodzi o te LCD, to wrzuciłem to tylko na chwilę, żeby zobaczyć czy dobrze odczytuje znak, oczywiście w finalnej wersji na pewno to usunę.
    W między czasie zacząłem robić coś takiego:

    Code:

    while(1)
       {   
          if (odbior==1)
          {
             for (int k=0;k<licz+1;k++)
             {
                LCD_WriteData(bufor[k]);
             }

             
             for (int j=0;j<licz+1;j++)
             {
                if (bufor[j]=='R')
                {
                   if (strncmp ((const char*)bufor[j], "RING", 4) == 0)
                   {
                   LCD_WriteText("OKI?");
                   }
                }
             }
             licz=-1;
             odbior=0;
          }
       }


    Dodano po 1 [minuty]:

    Tylko znowu dostaję warninga przy strncmp. O to jego treść:
    ../C35i_przerwanie.c:118: warning: cast to pointer from integer of different size
    Zaraz poczytam o tym strstr i zobaczę czy coś z tym wykombinuję.

    Dodano po 12 [minuty]:

    Dobra poczytałem i chyba nawet się przyda. Zastanawiam się co się stanie jeżeli będę przeszukiwał tablicę i znajdą się tam dwa razy ten sam znaków, czyli np. szukam te RING a w tablicy mam coś takiego:
    "HELLO RING coscoscos RING GOODBYE" to na który RING dostanę wskaźnik, na pierwszy wyraz czy na drugi, czy może się funkcja strstr wyłoży w co wątpię (obstawiam na logikę, że wskaże mi pierwszy RING).
    Ogólnie dzięki temu teraz będzie mi o wiele łatwiej ponieważ, głównym założeniem było sprawdzenie dzwoniącego nr i jeżeli jest taki sam jak zapisany w pamięci to załączenie np. przekaźnika.

    Dodano po 11 [minuty]:

    A mam takie pytanie, czy istnieje taka możliwość, że:
    dostaję naraz "garść" danych np. 20 na UART, oczywiście załącza się przerwanie, odbiera znak i wychodzi z niego, no i właśnie tu się zastanawiam...
    czy może się zdarzyć taka sytuacja, że jakimś cudem że program będzie wykonywał się z pętli głównej, czyli odbieram 1-wszy, 2-gi, 3-ci znak, wszystko jest ok, ale przed odbiorem 4 program wchodzi mi już do pętli if, zaczyna dalej wszystko poprawnie działać, po np. 10 znaku następuje podobna sytuacja, czyli program wraca do pętli if i wykonuje już for, wraca znowu do przerwania itd.
    Czy może się coś takiego zdarzyć, wydaje mi się że nie ale wolę się upewnić.

    0
  • Pomocny post
    #12 03 Wrz 2009 21:29
    GrEG0
    Poziom 14  

    strstr poda ci wskaźnik na pierwszą pozycję RING. Jeżeli chcesz dalej przeszukiwć to robisz buffor+offset i daje szukasz. Jak znajdziesz to znowu zwiększasz offset.

    Np:
    char *s;
    char offset;
    offset=0;
    s = strstr(bufor+offset, szukany_łańcuch);
    pozycja=s-bufor;

    offset=pozycja;
    s = strstr(bufor+offset, szukany_łańcuch);
    pozycja=s-bufor;

    itd :)

    Dodano po 5 [minuty]:

    Cytat:

    A mam takie pytanie, czy istnieje taka możliwość, że:
    dostaję naraz "garść" danych np. 20 na UART, oczywiście załącza się przerwanie, odbiera znak i wychodzi z niego, no i właśnie tu się zastanawiam...
    czy może się zdarzyć taka sytuacja, że jakimś cudem że program będzie wykonywał się z pętli głównej, czyli odbieram 1-wszy, 2-gi, 3-ci znak, wszystko jest ok, ale przed odbiorem 4 program wchodzi mi już do pętli if, zaczyna dalej wszystko poprawnie działać, po np. 10 znaku następuje podobna sytuacja, czyli program wraca do pętli if i wykonuje już for, wraca znowu do przerwania itd.
    Czy może się coś takiego zdarzyć, wydaje mi się że nie ale wolę się upewnić.


    Oczywiście że może się tak zdarzyć, że program główny zostanie przerwany przez przerwanie :) Ale to chyba nie problem, bo wtedy nie tracisz odbieranych znaków. Zresztą taka jest zasada, że przerwanie przerywa program główny :)

    0
  • #13 03 Wrz 2009 23:29
    Citek
    Poziom 22  

    GrEG0 napisał:
    Oczywiście że może się tak zdarzyć, że program główny zostanie przerwany przez przerwanie :) Ale to chyba nie problem, bo wtedy nie tracisz odbieranych znaków. Zresztą taka jest zasada, że przerwanie przerywa program główny :)

    Może do końca się nie zrozumieliśmy chodzi mi o te, że zaczynam odbierać znaki poprzez przerwanie, czyli wszystko jak na razie jest ok. Odbieram 1, 2, 3 itd., po odebraniu każdego znaku "procesor" wychodzi z przerwania i od razu wraca, aby odebrać następny.
    Nastaje właśnie pesymistyczny przypadek, że jakimś cudem procesor zaczyny wykonywać pętlę główną, chociaż ma jeszcze do odebrania n-znaków, lecz po chwili wraca z powrotem do przerwania. Czy może zajść taki przypadek? Niby procesor jest nieomylny (prawie...), ale nie ma rzeczy idealnych.

    0
  • #14 03 Wrz 2009 23:56
    GrEG0
    Poziom 14  

    Przerwanie zostanie wykonane tylko wtedy gdy nadejdzie nowy znak. W innym przypadku będzie się wykonywał program główny. Jeżeli został odebrany znak to procesor wchodzi w przerwanie, gdzie następuje odczyt UDR i wpisanie go do twojego bufora.

    [kod]
    SIGNAL(SIG_UART_RECV)
    {
    bufor = UDR; // odczyt znaku
    }
    [/kod]

    Następnie procesor wychodzi z obsługi przerwania i już nie wraca do niego. Ponowne wejście w przerwanie nastąpi dopiero, gdy zostanie odebrany kolejny znak. I tak w kółko :)

    Jeżeli kolejne dane zostają bardzo szybko przesyłane i procesor nie będzie miał czasu by wykonywać pętlę główną (w co wątpię, bo przesyłanie po RS232 aż takie szybkie nie jest), to musisz wtedy blokować odbiór danych na pewien czas.

    0
  • Pomocny post
    #15 04 Wrz 2009 00:44
    Dr.Vee
    VIP Zasłużony dla elektroda

    Wystarczy policzyć. 19200 bps = 1920 znaków na sekundę, czyli znak co ~0,5 ms. Przy taktowaniu 4MHz masz +/- 2080 cykli procesora pomiędzy przerwaniami od UARTa, czyli duuużo czasu na wykonywanie instrukcji w pętli głównej.

    Na Twoim miejscu skupiłbym się na przetwarzaniu tekstu np. linia po linii - przerwanie wypełnia bufor, a po wykryciu sekwencji CR LF sygnalizuje, że jest do przetworzenia nowa linia. Możesz użyć dwóch buforów - jeden zapisuje przerwanie, drugi przetwarza pętla główna.

    Np.:

    Code:

    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <stdint.h>
    #include <stdbool.h>

    enum { BUFFER_SIZE = 20 };

    /* receiver buffers */
    static char buffers[2][BUFFER_SIZE];

    static volatile char* write_ptr = buffers[0];
    static volatile uint8_t buf_no = 0;
    static volatile bool isr_saw_cr = false;
    static volatile bool isr_read_line = false;

    ISR(USART_RXC_vect)
    {
        char data = UDR;

        *write_ptr = data;
        write_ptr += 1;

        if ( ( data == 0x0d ) && isr_saw_cr )
        {
            /* found end of the line */
            isr_read_line = true;
            *write_ptr = '\0';

            /* switch buffers - or maybe do so outside of interrupt? */
            buf_no = (buf_no + 1) % 2;
            write_ptr = buffers[buf_no];
        }

        isr_saw_cr = ( data == 0x0a );
    }

    int main(void)
    {
        /* init uart & ISR */
        /* ... */

        for (;;)
        {
            /* set sleep mode idle */
            /* sleep & wait for interrupt*/

            /* we woke up due to interrupt */
            if ( isr_read_line )
            {
                const char* read_ptr;
                uint8_t read_buf_no;

                /* protect buf_no from concurrent update */
                cli();
                read_buf_no = (buf_no + 1) % 2;
                isr_read_line = false;
                sei();
                read_ptr = buffers[read_buf_no];

                /* process data from read_ptr buffer */
            }
        }
    }


    Można dodać sprawdzanie przepełnienia bufora itp. Bardziej skomplikowany byłby bufor cykliczny, ale wtedy nie mógłbyś użyć funkcji bibliotecznych z biblioteki standardowej.

    Pozdrawiam,
    Dr.Vee

    0
  • #16 17 Wrz 2009 13:40
    Citek
    Poziom 22  

    Dobra jak na razie wszystko działa tylko napotkałem problem z identyfikacja (w sumie to i tak na razie jest mi nie potrzebne i w głównym projekcie nie będę z tego korzystał, bo nie będę mocował tam LCD, ale chciałbym się dowiedzieć na przyszłość czemu coś mi nie działa).

    Oto kod z najważniejszymi rzeczami:

    Code:

    #define ILEnr 5

    volatile int odbior=0;
    volatile int licz=0;
    volatile char bufor[30]="TEST\0";
    volatile int isr_cr;

    char nr[ILEnr][13]={
       {"+4850100000\0"},      //mój numer
       {"+4850100001\0"},      //Orange Free
       {"+4850100002\0"},      //tata
       {"+4850100003\0"},      //mama
       {"+48xxxxxxxxx\0"},      //wolne miejsce
    };

    SIGNAL(SIG_UART_RECV)
    {
       //LCD_WriteText("1");
       char data = UDR;
       //UDR;

       if ((data!=0x0A)&&(data!=0x0D))
       {
          licz++;
             bufor[licz]=data;
          //LCD_WriteText("1");
          //LCD_WriteData(UDR); //jako pogląd czy dobrze odbiera
       }

       if ((data==0x0D)&& isr_cr) //znalezienie końca linii
       {
       odbior=1;
       licz++;
       bufor[licz]='\0';
       }
       isr_cr = ((data) == 0x0A); //zanzaczenie, że odebrano znak 0x0A
       
    }

    int main(void)
    {
       while(1)
       {   
          if (odbior==1)
          {         
             for (int j=0;j<ILEnr;j++)
             {
                char *s;
                s = strstr((const char*)bufor, nr[j]);
                if (s!=NULL)
                {
                   LCD_WriteData(j+48);
                   break;

                }
                
             }
             licz=-1;
             odbior=0;
          }
       }
    }


    Tak z grubsza to wygląda. Teraz o co to dokładnie mi chodzi. Chodzi o to że chciałbym, aby na wyświetlaczu wyświetliło mi się 0 jeżeli dzwonię z nr0, 1 jeżeli z nr1 itd.
    Niby wszystko działa, jest identyfikacja, ale potem robią się schody.
    Wytłumaczę to na przykładzie co jest nie tak, a więc:
    dzwonię z nr0 dostaję 0 na wys(oczywiście co jakiś czas się powtarza, bo co jakiś czas telefon przy połączeniu wysyła komendę CLIP), dzwonie drugi raz z nr 0 i znowu 0, czyli jak na razie jest ok, ale jak później zacznę dzwonić z nr1 to otrzymuję na początku 0 a po przyjściu kolejnego CLIPa dopiero 1. Tak samo dzieje się jak zacznę po zresetowaniu procka dzwonić od nr1 do nr0.
    Czemu tak się dzieje? Co może być problemem, czyżby ten break czy może coś innego?

    0
  • #17 17 Wrz 2009 23:12
    Dr.Vee
    VIP Zasłużony dla elektroda

    Masz szczęście, że to w ogóle działa :)
    Po przetworzeniu bufora powinieneś ustawiać licz na zero. Oczywiście liczysz na to, że nowe dane z telefonu nie nadpiszą bufora zanim go nie przetworzysz...

    Edit: ortografia

    Pozdrawiam,
    Dr.Vee

    0
  • #18 18 Wrz 2009 10:57
    Citek
    Poziom 22  

    Tak liczę na to, że nie będą przychodzić tak szybko dane i zdążę przetworzyć to co przyszło (w sumie gdy ktoś dzwoni nic praktycznie innego nie może się pokazać nie liczyć chyba tylko sms'a), jedyne co to mogłem, ale nawet powinienem dodać jeszcze wyłączanie i włączanie przerwania w pętli if (odbior==1).
    A jeżeli chodzi o ten licz to wydaje mi się, że powinno być tak jak jest czyli -1, ponieważ po wejściu do przerwania i odebrania jakiegoś znaku chcę go zapisać na zerowowym miejscu w tablicy a w kodzie najpierw mam zwiększenie licznika a dopiero zapis do tablicy, w sumie chyba można by zrobić na odwrót, ale jak na razie to działa to nie ruszam.

    Dodano po 1 [minuty]:

    Wracając do mego poprzedniego zapytania czemu tak się dzieje, że jak zadzwonię z nr0 to dostaje zera a jak później zadzwonię z nr 1 to dostaje najpierw 0 a potem dopiero 1?

    0
  • Pomocny post
    #19 19 Wrz 2009 12:18
    BoskiDialer
    Poziom 34  

    Problemem jest to, że nie rozróżniasz CR (0x0D) od LF (0x0A). Odpowiedź domyślam się że będzie zakończona przez CRLF podczas gdy Twój kod reaguje na LFCR.
    Aby kod w aktualnej postaci w ogóle działał, koniecznym jest założenie, że po odpowiedzi mogą pojawić się CR LF CR LF (pojawia się LF CR) - w przeciwnym przypadku odpowiedź będzie doklejana do końca buforu, 0x0D (CR) zostanie zignorowane (isr_cr jest równe 0), 0x0A (LF) spowoduje ustawienie isr_cr, ale następny zwykły bajt wyzeruje isr_cr a więc nic nie spowodowało by zwrócenia buforu.
    Tak więc może pojawić się sekwencja CR LF CR LF. Jeśli odpowiedź jest wysyłana jako CR LF jakis_numer CR LF, to opisana sytuacja będzie miała miejsce - numer zostanie zapisany do buforu, CR zignorowane, LF spowoduje ustawienie isr_cr. Pierwsze CR z odpowiedzi następnego numeru spowoduje opróżnienie wcześniejszej zachowanej wartości stąd pojawia się najpierw numer wcześniejszy, potem ten właściwy.

    Dodano po 12 [minuty]:

    Czytając Twój post z "Sro, 02 Wrz 2009 23:49:49" schemat powstawania błędu się zgadza - chociaż mieszasz zapis dziesiątkowy z szesnastkowym (0x10 0x13) to i tak masz te bajty w złej kolejności oraz pojawia się ta sekwencja na początku więc ciąg z jednej odpowiedzi zostanie przekazany do main dopiero przy następnej odpowiedzi która może pojawić się dopiero przy następnym numerze.

    0
  • #20 19 Wrz 2009 20:18
    Citek
    Poziom 22  

    Będę musiał jeszcze raz zobaczyć jakie znaki i w jakiej kolejności przychodzą. Możliwe, że masz rację, bo później pisząc program nie chciało mi się jeszcze sprawdzać co i jak.

    0
  • #21 19 Wrz 2009 20:57
    michalko12
    Specjalista - Mikrokontrolery

    Citek napisał:

    Niby wszystko działa, jest identyfikacja, ale potem robią się schody.
    Wytłumaczę to na przykładzie co jest nie tak, a więc:
    dzwonię z nr0 dostaję 0 na wys(oczywiście co jakiś czas się powtarza, bo co jakiś czas telefon przy połączeniu wysyła komendę CLIP), dzwonie drugi raz z nr 0 i znowu 0, czyli jak na razie jest ok, ale jak później zacznę dzwonić z nr1 to otrzymuję na początku 0 a po przyjściu kolejnego CLIPa dopiero 1. Tak samo dzieje się jak zacznę po zresetowaniu procka dzwonić od nr1 do nr0.
    Czemu tak się dzieje? Co może być problemem, czyżby ten break czy może coś innego?


    Sprawdź to:
    (Nie testowane)


    Code:
    #define ILEnr 5
    

    volatile int odbior=0;
    volatile int licz=0;
    volatile char bufor[30]="TEST\0";

    char nr[ILEnr][13]={
       {"+4850100000\0"},      //mój numer
       {"+4850100001\0"},      //Orange Free
       {"+4850100002\0"},      //tata
       {"+4850100003\0"},      //mama
       {"+48xxxxxxxxx\0"},      //wolne miejsce
    };

    SIGNAL(SIG_UART_RECV)
    {
       char data = UDR;
       
       if(data != '\n')         // wyrzucamy znaki LF
       {
          if(data == '\r')      // reagujemy na CR
          {
             if(licz)         // sprawdzamy czy były odebrane inne znaki
             {
                bufor[licz] = '\0';   // były inne znaki wiec konczymy linie znakiem konca linii
                odbior=1;         // info odebrania całego stringu
                licz=0;         // zarowanie indeksu bufora
             }
          }
          else
          {
             bufor[licz++]=data;   // zapisujemy znak do bufora i zwiekszamy indeks
          }
        }
    }

    int main(void)
    {
       while(1)
       {   
          if (odbior==1)
          {         
             for (int j=0;j<ILEnr;j++)
             {
                char *s;
                s = strstr((const char*)bufor, nr[j]);
                if (s!=NULL)
                   LCD_WriteData(j+48);
                else
                   LCD_WriteData('-');
             }
             odbior=0;
          }
       }
    }

    0
  • #22 03 Paź 2009 20:03
    Citek
    Poziom 22  

    Ok, wszystko działa, @BoskiDialer miał rację pokręciłem kolejność LR i CR.
    Prawidłowo powinno być:

    Code:
    0D 0A KOMENDA 0D 0A

    0