logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[C]TWI, SPI - przesyłanie zmiennej float

kirby 13 Maj 2009 18:06 4112 13
REKLAMA
  • #1 6525835
    kirby
    Poziom 10  
    Witam,
    Problem może jest laicki, ale nie mogę sobie z tym poradzić. Mianowicie między dwiema komunikującymi się ze sobą Atmegami8 za pomocą TWI lub SPI chciałbym przesyłać dane zmiennopozycyjne.
    Próbowałem przesyłać zmienną float bezpośrednio wrzucając ją na magistrale, a po stronie odbiorczej zamienić na stringa (funkcja dtostrf()) i wyświetlić na LCD, jednak wyświetlane są same zera (SPI i TWI działają poprawnie). Zmienna typu float jest 32bitowa, jednak myślałem, że osiem najstarszych bitów zostanie przesłanych.
    Nie chciałbym przesyłać zmiennej jako typ string gotowy do wyświetlenia, ponieważ po stronie odbiorczej zmienna ta musi być jeszcze przeliczana w działaniach.
    W jaki sposób można to rozwiązać ?
  • REKLAMA
  • #2 6525869
    zdebel
    Poziom 15  
    Prześlij jako string, odbierz jako string, sscanf'em sobie na floata przekształć do obliczeń?
  • Pomocny post
    #3 6525942
    Freddie Chopin
    Specjalista - Mikrokontrolery
    nie rozumiem na czym problem... przesłać 4 bajty tworzące floata (bajt po bajcie), odebrać 4 bajty i poskładać je w owego floata (bajt po bajcie)...

    wysyłanie:

    
    float data;
    ...
    for(i=0;i<4;i++)
    send(((uint8_t*)&data)[i]);
    


    odbiór:

    
    float data;
    ...
    for(i=0;i<4;i++)
    ((uint8_t*)&data)[i]=receive();
    


    Pomysł użycia do tego stringów jest skrajnie bezsensowny, skoro przesyłanie zachodzić będzie między identycznymi architekturami. Funkcje konwersji float->string i string->float nie są za darmo i zajmują kilkanaście kB kodu.

    4\/3!!
  • REKLAMA
  • #4 6526029
    BoskiDialer
    Poziom 34  
    Freddie Chopin: Masz drobny błąd w kodzie - na wskaźnik rzutujesz nie adres zmiennej "data", tylko jej wartość.

    Ogólnie warto jest posiadać funkcję do wysyłania bloku danych - wystarczy podać wskaźnik oraz długość danych.
  • #6 6529063
    kirby
    Poziom 10  
    Ponieważ w układzie master wyświetlającym na LCD przesyłaną zmienną float mam same zera, chciałbym się upewnić, czy prawidłowo korzystam z funkcji dzielących zmienną do przesłania (na przykładzie TWI).

    Kod slave'a - wysłanie zmiennej float:

    volatile float dana = 1.234;
    
    void TWI_write (volatile uint8_t ilosc)
    {
     
     (...)
    
     for(volatile uint8_t i=0; i<(ilosc-1); i++)     //wysyłanie 3 bajtów oprócz ostatniego z potwierdzeniem ack
      { 
       TWDR = (((volatile uint8_t*)&dana)[i]); 
    
       TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);         
      } 
     
     TWDR = (((volatile uint8_t*)&dana)[ilosc]);    //wyslanie ostatniego (4go) bajtu zmiennej float, bez ack
    
     TWCR = (1<<TWINT) | (1<<TWEN);
     
     (...) 
    } 





    Kod mastera - odbiór zmiennej float:

    float dana;
    
    void TWI_read (uint8_t ilosc)
    { 
     (...)
    
     for(uint8_t j=0; j<(ilosc-1); j++)                         //odbiór pierwszych 3 bajtow i wystawienie ack
     {
    
      TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);	
      
     (((uint8_t*)&dana)[j])= TWDR;
    
     }
     (...)
    
     TWCR = (1<<TWINT) | (1<<TWEN);	                  //odbior ostatniego (4go) bajtu zmiennej float i wystawienie nack
     
    (((uint8_t*)&dana)[ilosc])= TWDR;            
    
     (...)
    }



    W masterze zmienna float jest następnie zamieniana w funkcji dtostrf() na stringa, a zmienna "ilosc", którą przyjmują funkcje - wysyłająca w slave'ie i odbierająca w masterze wynosi 4.

    Czy rozłożenie i złożenie zmiennej float powinno przebiegać poprawnie ?
  • REKLAMA
  • #7 6529083
    BoskiDialer
    Poziom 34  
    Tak rozkładanie będzie przebiegać poprawnie. Powiedz mi tylko, jak TWI ma zdążyć z wysyłaniem danych, jeśli nie masz tam żadnych pętli opóźniających - nie czekasz na przyjście bajtu ani na dokończenie transmisji.
  • #8 6529164
    kirby
    Poziom 10  
    Podałem skrótowy kod jedynie z istotną pętlą rozkładania i składania zmiennej float żeby łatwiej było go przeczytać. Oczekiwania na zakończenie działań oczywiście są:

    Kod mastera:

    void TWI_read (uint8_t ilosc)
    {
    
     for(uint8_t j=0; j<(ilosc-1); j++)
     {
    
      TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);	
      
      while(!(TWCR & (1<<TWINT)));			
      
     (((uint8_t*)&dana)[j])= TWDR;
    
     }
    
     TWCR = (1<<TWINT) | (1<<TWEN);	
     
      while(!(TWCR & (1<<TWINT)));			
    
    (((uint8_t*)&dana)[ilosc])= TWDR;
    }


    Jeżeli rozkładanie i składanie zmiennej float przebiega poprawnie, to nie wiem w takim razie dlaczego wyświetlane są same zera.
  • Pomocny post
    #10 6529205
    BoskiDialer
    Poziom 34  
    Teraz zauważyłem: W kodzie wysyłane są bajty od 0 do "ilosc-2" włącznie, bajt o numerze "ilosc-1" jest pomijany, następny jest bajt o numerze "ilosc" który jest poza zakresem. Podobnie jest przy odbiorze. Napisz sobie funkcję, która przyjmuje 3 parametry: wskaźnik na dane, ilość bajtów oraz czy przy ostatnim bajcie ma być ACK (funkcja odczytu). Wtedy nie powinieneś mieć żadnego problemu z transmisją.
  • REKLAMA
  • Pomocny post
    #12 6529520
    Dr.Vee
    VIP Zasłużony dla elektroda
    Ja z kolei zaproponuję użycie unii - dzięki temu nie są łamane zasady tzw. przesłaniania wskaźników (pointer aliasing).
    void spi_send_float(float f) {
        union {
            float f;
            uint8_t u8[sizeof(float)];
        } temp;
        unsigned i;
    
        temp.f = f;
        for (i = 0; i < sizeof(temp); ++i)
            spi_send(temp.u8[i]);
    }
    Analogicznie wykonywany odbiór.
    Pozdrawiam,
    Dr.Vee
REKLAMA