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.

[AVR, C] Łączenie dwóch zmiennych char w jedną int.

Adix3 22 Kwi 2016 20:22 1626 25
  • #1 22 Kwi 2016 20:22
    Adix3
    Poziom 13  

    Witam.
    Mam problem. Przez interfejs I2C (TWI) odczytuję dane z czujnika BH1750. Czujnik wysyła mi wartość 16-bitową, podzieloną na 2 bajty (8 bitów). Zapisuję więc odebrane dane do dwóch zmiennych char i teraz pasowałoby z tych dwóch zmiennych zrobić jakoś jedną typu int. Nie mam pomysłu jak to połączyć...

    0 25
  • #2 22 Kwi 2016 20:27
    ZeeWolf
    Poziom 27  

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #3 22 Kwi 2016 20:30
    Samuraj
    Poziom 35  

    Już chyba prędzej tak

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #4 22 Kwi 2016 20:31
    Krashan7
    Poziom 17  

    To by zadziałało dobrze ze zmiennymi bez znaku (unsigned). Chyba że w kompilatorze dla AVR jest to domyślnie. Bo jeżeli nie, to w przypadku gdy najstarszy bit zmiennej 'b' będzie ustawiony, efekt może być inny od zamierzonego. Ewentualnie dać logiczne OR (operator '|') zamiast dodawania.

    0
  • Pomocny post
    #5 22 Kwi 2016 20:39
    grko
    Poziom 33  

    Albo po prostu użyć typów z nagłówka stdint, które są standardem już od 17 lat.

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #6 22 Kwi 2016 21:13
    Adix3
    Poziom 13  

    Dziękuję. W sumie to aż się dziwię, że na to nie wpadłem.

    Przy okazji aby nie zakładać nowego wątku chciałbym zapytać o jeszcze jedną sprawę.
    Teraz próbuję na wyświetlaczu LCD wyświetlić zawartość inta. Do celów testowych wpisuję ręcznie do zmiennej int jakąś wartość - podczas pisania programu. Np.

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Tutaj na wyświetlaczu pojawia się "5535". Problem jest gdy wpiszę większą wartość, np. 60000. Wtedy dostaję na wyświetlaczu "-5536". Co ja robię źle?

    0
  • #7 22 Kwi 2016 21:15
    2675900
    Użytkownik usunął konto  
  • #8 22 Kwi 2016 21:18
    grko
    Poziom 33  

    @Adix3
    Funkcja itoa pobiera jako pierwszy argument int. Na AVR int ma 2 bajty więc jego zakres to: -2^15; 2^15 - 1.
    Zmienna A jest niejawnie rzutowana na int a 60000 to -5536 w kodzie U2.

    Cytat:

    doskladnie albo musi jawnie zrzutować typ na unsigned (uint8_tt)a << 8


    Jak już coś to to trzeba rzutować zmienną b a nie a.

    0
  • Pomocny post
    #9 22 Kwi 2016 21:19
    Krashan7
    Poziom 17  

    Adix3 napisał:
    Tutaj na wyświetlaczu pojawia się "5535". Problem jest gdy wpiszę większą wartość, np. 60000. Wtedy dostaję na wyświetlaczu "-5536". Co ja robię źle?
    Funkcja itoa() oczekuje parametru typu int, a więc ze znakiem. Jeżeli podasz 60000, to szesnastkowo jest to $EA60. Najstarszy bit jest więc jedynką, co itoa() zinterpretuje jako liczbę ujemną. Uzyj funkcji utoa(), która bierze inta bez znaku.

    0
  • #10 22 Kwi 2016 22:10
    2675900
    Użytkownik usunął konto  
  • #11 22 Kwi 2016 22:13
    grko
    Poziom 33  

    @Piotrus_999

    Jeżeli już jak bardzo chcesz podążać za standardem to przesunięcie w prawo jest zależne od implementacji a nie w lewo.

    0
  • #12 22 Kwi 2016 22:14
    Krashan7
    Poziom 17  

    Piotrus_999 napisał:
    Przesunięcie ze znakiem tez wg standardu jest zależne od implementacji
    Przesunięcie w prawo, owszem. Przesunięcie w lewo – nie.

    0
  • #13 22 Kwi 2016 22:19
    Adix3
    Poziom 13  

    Dziękuję za dotychczasową pomoc :)
    Mam jednak już teraz ostatnią prośbę. Próbuję zastosować to wszystko do wyliczania i prezentowania na LCD wartości pomiaru z czujnika BH1750. Chodzi tutaj o pomiar światła i wynik w luxach.

    Według noty
    [AVR, C] Łączenie dwóch zmiennych char w jedną int.

    mam taki oto kod:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    No i jest znowu problem. Według noty przy tych wartościach powinienem otrzymać 28067. Tymczasem pierwszy wyniki na LCD (przed obróbką) wynosi 33680 - czyli tutaj poprawnie. Ale po wymnożeniu tego przez 10 i podzieleniu przez 12 otrzymuję 60834.
    Czy może ktoś jeszcze pomóc mi w tej kwestii?

    0
  • #14 22 Kwi 2016 22:22
    2675900
    Użytkownik usunął konto  
  • #15 22 Kwi 2016 22:26
    Krashan7
    Poziom 17  

    utoa() pracuje z liczbami 16-bitowymi. 'odczytane' jest liczbą 32-bitową, więc trzeba użyć ultoa().

    0
  • #16 22 Kwi 2016 22:44
    2675900
    Użytkownik usunął konto  
  • #17 22 Kwi 2016 22:49
    Adix3
    Poziom 13  

    Krashan7 napisał:
    utoa() pracuje z liczbami 16-bitowymi. 'odczytane' jest liczbą 32-bitową, więc trzeba użyć ultoa().


    Próbowałem przez ultoa, ale wtedy jest jeszcze gorzej bo końcowa wartość wynosi 357887394. I właśnie męczę się z tym prawie od godziny na różne sposoby i nic...

    Używam 32-bitowej zmiennej bo muszę mnożyć przez 10, więc wyszedłbym poza zakres. Tymczasem funkcja utoa działa prawidłowo do czasu gdy nie wykonuję mnożenia i dzielenia tej wartości.

    0
  • #18 22 Kwi 2016 22:54
    2675900
    Użytkownik usunął konto  
  • #19 22 Kwi 2016 23:04
    Adix3
    Poziom 13  

    Piotrus_999 napisał:

    Jestes pewien ze liczba ta (32 bitowa) to 33680 czy to to co pozostało w wywołaniu utoa (tym pierwszym). Zamien tamto utoa na ultoa i zobacz co naprawde masz w tej zmiennej.


    No faktycznie gdy przy pierwszym wyświetleniu zamienię funkcję utoa na ultoa to mam zupełnie co innego, a mianowicie: 4294935440. Kurde, myślałem, że to będzie coś prostego...

    0
  • Pomocny post
    #20 22 Kwi 2016 23:10
    2675900
    Użytkownik usunął konto  
  • #21 22 Kwi 2016 23:23
    Adix3
    Poziom 13  

    Pod tym [...] praktycznie na obecną chwilę nic się nie kryje. Tzn. tam jest kod odpowiedzialny za komunikację TWI, ale na czas zmagań z tym wymnażaniem i dzieleniem jest w całości zakometowany. Mogę ten kod nawet wywalić a i tak jest to samo - już próbowałem.

    Obecnie mój cały kod wygląda tak:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    I nadal wyświetla mi się wartość: 4294935440, szesnastkowo ffff8390.

    ====================
    Ok, widzę chyba gdzie problem. Szesnastkowo na początku mam FFFF a powinno być raczej 0000.

    0
  • Pomocny post
    #22 22 Kwi 2016 23:29
    grko
    Poziom 33  

    Masz błąd w tej linii:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Dodaj rzutowanie.
    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • Pomocny post
    #23 22 Kwi 2016 23:33
    Krashan7
    Poziom 17  

    Adix3 napisał:
    I nadal wyświetla mi się wartość: 4294935440, szesnastkowo ffff8390.
    Z tego by wynikało, że w wyrażeniu
    Kod: c
    Zaloguj się, aby zobaczyć kod
    dochodzi do niezłego bałaganu. To wygląda jakby prawa strona wyrażenia była liczona na 16 bitach i potem rozszerzona do 32 bitów jako liczba ze znakiem (!). Dla mnie to co najmniej dziwne zachowanie kompilatora, ale wobec tego zaatakowałbym takim kodem:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #24 22 Kwi 2016 23:38
    Adix3
    Poziom 13  

    Działa. Dziękuję bardzo!
    Cóż może po prostu Atmel Studio 7 tak ma ;D

    Raz jeszcze bardzo dziękuję za pomoc :)

    0
  • #25 23 Kwi 2016 00:05
    grko
    Poziom 33  

    To jeszcze postaram się wjaśnić. Wyrażenie:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Jest int ponieważ dochodzi do promocji typów. Czyli w naszym przypadku (2 bajtowy int na AVR): -31856 (0x8390).Konwersja do uint32 nastąpi przez dodanie 0xFFFFFFFF + 1 do -31856. W ten nieszczęśliwy sposób w Twojej zmiennej znalazło się FFFF8390. Jeżeli zamiast uint32_t użyłbyś uint16_t to konwersja byłaby prawidłowa: 31856 + 0xFFFF + 1 = 0x8390 = 33680

    0
  • #26 23 Kwi 2016 08:12
    2675900
    Użytkownik usunął konto