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.

UART+strcmp(): Program reaguje na znaki ale na ciąg znaków już nie...

Jakub17 04 Mar 2017 16:54 1416 37
  • #1 04 Mar 2017 16:54
    Jakub17
    Poziom 6  

    Witam

    Chcę przesłać przez terminal realterm ciąg znaków "1234" a następnie wywołać akcję w postaci zapalenia diody. Niestety gdzieś po drodze pojawia się problem.
    Procesor ATmega32

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Znaki do pętli while(1) docierają bo choćby po wysłaniu 1234 gdy w pętli obecny jest taki kod:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    to inna dioda się zapala.

    0 29
  • #2 04 Mar 2017 17:25
    2675900
    Użytkownik usunął konto  
  • #3 04 Mar 2017 18:25
    Jakub17
    Poziom 6  

    Wyznacza zakres znaków ASCII. Funkcja uart_getc() zwraca znak char, jeżeli będzię on należał do wyznaczonego przedziału, a każdy znak z ciągu "1234" należy, to zostanie on zapisany do tablicy.
    No i w sumie mogłem napisać (uart_getc()>='0' && uart_getc()<='9'). Chyba że zamiast znaku wpisać jego kod, ale wydawało mi się że jest to tożsame z napisanie znaku char.

    Dodano po 12 [minuty]:

    Czy coś odróżnia 0 od '\0'? Wiem że ukośnikami przedstawia się sekwencje sterujące.

    0
  • #4 04 Mar 2017 18:41
    2675900
    Użytkownik usunął konto  
  • #5 04 Mar 2017 18:56
    Jakub17
    Poziom 6  

    W jednej linijce kodu nie ma za wiele informacji. Błędu nie widzę, więc może założenia są kompletnie nie takie. Możesz coś więcej powiedzieć? Gdybym przyjął mniej rozbudowany warunek np. uart_getc == '1' to by zadziałało a z innymi operatorami już nie chce działać?

    0
  • Pomocny post
    #6 04 Mar 2017 18:58
    michalko12
    Specjalista - Mikrokontrolery

    Jakub17 napisał:
    uart_getc()


    Pobierz znak do zmiennej lokalnej i dopiero na takiej kopii działaj.
    Kod jest niekompletny i nie widzę nigdzie reinicjalizacji zmiennej licznik_bitow_rx.

    0
  • Pomocny post
    #7 04 Mar 2017 19:54
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Jakub17 napisał:
         if(uart_getc()>'0' && uart_getc()<'9') {
         kod[licznik_bitow_rx] = uart_getc();

    W pierwszej części warunku odbierasz pierwszy znak i sprawdzasz czy jest większy niż '0'. W drugiej części warunku odbierasz kolejny znak i sprawdzasz czy jest mniejszy niż '9'. Jeśli obydwa warunki są spełnione (czyli odebrałeś dwa znaki, z których pierwszy jest większy niż '0', a drugi mniejszy niż '9'), to wtedy odbierasz trzeci znak i zapisujesz go do tablicy.

    Myślę że raczej nie o to Ci chodziło...

    0
  • #8 04 Mar 2017 20:40
    Jakub17
    Poziom 6  

    Cały kod teraz wygląda tak:
    Niestety nadal nie jest tak jak powinno a mianowicie po zapaleniu diody na sekundę zeruję zawartość tablicy i gdy ponownie wysyłam poprzez Realterm "1234" dioda po raz drugi nie chce się zapalić.

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • Pomocny post
    #9 04 Mar 2017 20:49
    tmf
    Moderator Mikrokontrolery Projektowanie

    Wpisujesz NUL na początku łańcucha, ale kolejne znaki są zapisywane dalej, aż przekroczą indeks tablicy, bo nie zerujesz licznik_bitow_rx.

    0
  • Pomocny post
    #10 04 Mar 2017 20:50
    michalko12
    Specjalista - Mikrokontrolery

    Już Ci pisałem, że nie zerujesz zmiennej licznik_bitow_rx.

    0
  • Pomocny post
    #11 04 Mar 2017 21:06
    2675900
    Użytkownik usunął konto  
  • Pomocny post
    #13 04 Mar 2017 21:30
    tmf
    Moderator Mikrokontrolery Projektowanie

    Pozwoliłem sobie odblokować temat, bo kolega @Piotrus_999 częściowo ma rację. Masz jeszcze błąd polegający na tym, że getc jest nieblokujące i nie odróżniasz rzeczywistego końca łańcucha od braku odebranego znaku. Specyficzny sposób w jaki napisałeś swoją funkcję powoduje, że pozornie to działa. Ale zadziała także z łańcuchem np. 1\02\034 i innymi w których znaki przedzielane są \0. Skoro getc zwraca znaki ASCII to pusty bufor możesz sygnalizować np. przez -1 (255) lub dodać wcześniej funkcję sprawdzającą czy istotnie coś w buforze jest do odebrania.

    0
  • #14 04 Mar 2017 21:36
    2675900
    Użytkownik usunął konto  
  • #15 05 Mar 2017 13:33
    Jakub17
    Poziom 6  

    Jeśli dobrze zrozumiałem to chodzi dokładnie o ten fragment?

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Tzn. że gdy bufor jest pusty funkcja zwraca 0 i to 0 jest interpretowanej jako '\0' dodawane po każdym znaku, czy zupełnie losowo, zależnie od szybkości zapełnienia bufora?

    Czyli w efekcie mam cos takiego ze odbieram znak np. '2' później zmienna znak zawiera '\0' w wyniku pustego bufora i to '\0' nie należy do przedziału if(znak>='1' && znak<='9'), zatem przechodzimy do else i na wyjściu mam coś takiego: 2\0\0?

    Czyli błąd ten moge naprawić w ten sposób:
    Kod: c
    Zaloguj się, aby zobaczyć kod
    Ale co oznacza to -1? Czytałem że jest zwracone w wyniku błędnego rezultatu funkcji? Jaki jest efekt tego -1?

    Dodano po 5 [minuty]:

    Piotrus_999 napisał:
    Tak że do trzeciego odczytu nie dojdzie nigdy, a wszystkie pojawiające sie w buforze znaki będą kanibalizowane przez tę bzdurną linijkę.

    Dlaczego nie dojdzię do kolejnego odczytu? Na końcu odebranego pojedynczego znaku będzie '\0', wiec warunek continue zostanie spełniony ale porownanie strcmp będzie fałszywe więc pętla rozpocznie się od początku i pewnie wtedy już dotrze kolejny znak z bufora

    0
  • #16 05 Mar 2017 13:53
    2675900
    Użytkownik usunął konto  
  • #17 05 Mar 2017 13:55
    tmf
    Moderator Mikrokontrolery Projektowanie

    @Jakub17 Jest dokladnie tak jak myślisz. Zaproponowałem -1 (czyli dla uint8_t wartość 255) dlatego, że w ciągu normalnych znaków ASCII ona nie występuje. Dzięki temu można odróżnić brak znaku w buforze. Jeśli 255 (-1) może być poprawnym znakiem przesyłanego łańcucha to trzeba dodać funkcję sprawdzającą czy w buforze jest znak i wywoływać getc wyłącznie, gdy znak w buforze się znajduje.

    0
  • #18 05 Mar 2017 14:31
    Jakub17
    Poziom 6  

    Piotrus_999 napisał:


    W if-ie masz 2 odczyty.


    Dlaczego dwa odczyty skoro obie składowe warunku if dotyczą tej samej zmiennej znak, czyli tej samej jej zawartości.
    Licznik poprawilem juz wczesniej zerujac go w if(strcmp...) tylko nie zaktualizowałem kodu. Fakt adekwatniej byłoby jezeli licznik dotyczyłby bajtow, bo to one są przesyłane.

    Piotrus_999 napisał:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Czyli to działa tak, że CharReady() pozwala się wykonać funkcji GetChar() tylko jeżeli w buforze są znaki gotowe do wysłania, jeżeli indeksy Head i Tail są równe to co zostaje zwrócone? -1?

    A ta zmienna pomocnicza?

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #19 05 Mar 2017 14:34
    2675900
    Użytkownik usunął konto  
  • #20 05 Mar 2017 14:39
    Jakub17
    Poziom 6  

    Pytanie dotyczyło tego czy nie musze zapisać gdzieś do zmiennej pomocniczej to co zwraca CharReady zanim użyje tego w GetChar. Poprzednio gdy przekazywałem bezpośrednio do warunku if uart_getc() to nie działało, dopiero uprzednie zapisanie do zmiennej znak pomogło

    0
  • #21 05 Mar 2017 14:46
    2675900
    Użytkownik usunął konto  
  • #23 11 Mar 2017 09:59
    2675900
    Użytkownik usunął konto  
  • #24 15 Mar 2017 19:17
    Jakub17
    Poziom 6  

    Piotrus_999 napisał:
    Znowu ta sama odpowiedź co powyżej. Programująć (a nawet ucząc sie programowania) usisz takie rzeczy ogarniać bez pytania, albo umieć przeanalizować, lub przedebugować i zobaczyć jak jest, bo inaczej polegniesz przy czymkolwiek bardziej skomplikowanym.


    No ale przecież to działa tzn. moja modyfikacja Twojego kodu

    0
  • #25 15 Mar 2017 22:58
    nsvinc
    Poziom 35  

    Oczywiście, że "może być" ;] Kod czasami zadziała jak trzeba, a czasami... radośnie zgubisz znak. A innymi czasami, bedzie sie zdawać ze znaki są, mimo tego ze ich nie ma, wtedy dopiero będzie uczta dla kodu ktory te znaki konsumuje ;]

    ->Piotrus_999
    jest dużo gorzej, niż pisales na poczatku. To, który getc() w warunku ifa wykona sie pierwszy, nie jest narzucone przez zaden standard...

    0
  • #26 15 Mar 2017 23:26
    Freddie Chopin
    Specjalista - Mikrokontrolery

    nsvinc napisał:
    ->Piotrus_999
    jest dużo gorzej, niż pisales na poczatku. To, który getc() w warunku ifa wykona sie pierwszy, nie jest narzucone przez zaden standard...

    http://en.cppreference.com/w/c/language/operator_precedence
    Dla operatorów && i || mamy "z lewej do prawej".

    0
  • #27 16 Mar 2017 00:05
    2675900
    Użytkownik usunął konto  
  • #28 16 Mar 2017 00:57
    nsvinc
    Poziom 35  

    Zgadza się, trafiłem jednak kiedyś na informację, że kompilator niekoniecznie musi się tego trzymać, tak jak w przykładzie

    Kod: C
    Zaloguj się, aby zobaczyć kod

    kompilator potrafi byc na tyle inteligentny, aby sprawdzic najpierw latwo dostępne 'b' zamiast bawic sie z f(). Jeśli f() ma efekty uboczne, może zacząć sie cyrk.
    Cóż, tylko przestrzegam, aby pewnych praktyk, dla dobra własnego, nie stosować :)

    Dodano po 2 [minuty]:

    Piotrus_999 to prowokacja jakaś?...:D Ja pisać umiem ;] a za "wybitnego specjaliste" się raczej nie uważam ;]

    Dodano po 21 [minuty]:

    1. jesli getc()=='a' drugi getc() sie nie wykona
    2. jesli getc()!='a' drugi getc() sie nie wykona

    0
  • #29 16 Mar 2017 08:15
    Freddie Chopin
    Specjalista - Mikrokontrolery

    nsvinc napisał:
    Zgadza się, trafiłem jednak kiedyś na informację, że kompilator niekoniecznie musi się tego trzymać, tak jak w przykładzie
    Kod: C
    Zaloguj się, aby zobaczyć kod

    kompilator potrafi byc na tyle inteligentny, aby sprawdzic najpierw latwo dostępne 'b' zamiast bawic sie z f(). Jeśli f() ma efekty uboczne, może zacząć sie cyrk.
    Cóż, tylko przestrzegam, aby pewnych praktyk, dla dobra własnego, nie stosować :)

    Wg info które znalazłem, kompilator taki nie spełnia założeń standardu, które mówią że w przypadku && ma byś wykonane od lewej do prawej.

    http://stackoverflow.com/a/38770652/157344

    Cytat:
    6.5.13.4 Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation; there is a sequence point after the evaluation of the first operand. If the first operand compares equal to 0, the second operand is not evaluated.

    ...

    6.5.14.4 Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation; there is a sequence point after the evaluation of the first operand. If the first operand compares unequal to 0, the second operand is not evaluated.

    0
  • #30 16 Mar 2017 08:23
    BlueDraco
    Specjalista - Mikrokontrolery

    Standard C narzuca ewaluację "zwarciową", więc, jak napisał Freddie, kompilator ma psi obowiązek liczyć wyrażenie logiczne od lewej do prawej i ani odrobiny dłużej, niż do wyznaczenia wartości. Dlatego np. przy odliczaniu czasu w przerwaniu timera piszemy często:
    if (timer && --timer == 0)

    0