• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed EEPROM, float i unie

Object Storage Arubacloud
0 głosów
965 wizyt
pytanie zadane 14 lutego 2017 w Mikrokontrolery przez BanditPlayGame Użytkownik (680 p.)
zamknięte 30 czerwca 2017 przez BanditPlayGame
#include <EEPROM.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(3, 4, 5, 6, 7, 8);

float zl;
    float t;
    int z;
    int to;




  


void setup() {

  union txd
  {
    float t;
    int to;
    float zl;
    int z;
  }convert;  
  





  
  Serial.begin(9600);
  lcd.setCursor(0,0);
  pinMode(12, INPUT);

 for(int q=2; q==2;)
  {
    lcd.print("Czas min: ");
    lcd.print(t);
    delay(60000);
    lcd.clear();
    t++;
    if(digitalRead(12)== HIGH)
    {
      q=1; 
    }
   }
  t=t/60;
  zl=t*0,1;
  zl=t*0,60;
  convert.t = t;
  convert.zl = zl;
  EEPROM.write(0, highByte(convert.to));
}

void loop() {
   
 }

Nie jest to jakiś skomplikowany kod, ale mam problem z zapisaniem danych w pamięci EEPROM. To co zrobiłem do tej pory. Mam książkę w której nie jest napisane za wiele na ten temat. Nie wiem jak to zapisywanie działa. Wiem jak działa zapisywanie int`a. Prosił bym o jakieś wytłumaczenie tego. Zwłaszcza tego convert. A i na początku gdzieś tam ma być wczytywanie z EEPROM (A co się stanie jak nic nie będzie w pamięci EEPROM a my ją wczytamy ;) ) .

komentarz zamknięcia: Wszystko działa i dziękuje draghan za tak obszerną odpowiedź :)

2 odpowiedzi

+1 głos
odpowiedź 15 lutego 2017 przez draghan VIP (106,230 p.)
edycja 15 lutego 2017 przez draghan
 
Najlepsza

Metoda EEPROM::write() potrafi zapisać jedynie liczby prostej reprezentacji, typu int. Stąd nie można bezpośrednio zapisać w EEPROM liczby zmiennoprzecinkowej.

Jednak liczba zmiennoprzecinkowa charakteryzuje się swoim formatem, który w ostateczności i tak należy zapisać jako ciąg zer i jedynek... dokładnie tak, jak liczbę każdego innego typu. Żeby tego dokonać, trzeba dostać się do jej reprezentacji binarnej, czyli tego, jak jest ona zapisana w pamięci.

W języku C/C++ można tego dokonać bezpośrednio na przynajmniej dwa sposoby. Posłużyć się wskaźnikami i pewną nieskomplikowaną manipulacją w ich interpretacji, albo użyć unii*.

Żeby móc w ogóle próbować przedstawić typ float za pomocą typu int, musimy mieć pewność, że mają taką samą liczbę bitów. Zakładam, że autor unii zdawał sobie z tego sprawę i wziął pod uwagę możliwości docelowej platformy.

Kod konwertujący zapis bitowy liczby typu float do reprezentacji jako liczba całkowita z wykorzystaniem wskaźnika:

int float_to_int(float f)
{
    /* Nie jestem pewny czy kompilator w Arduino IDE wspiera C++11.
       Jeśli nie - wypadałoby zamiast static_assert użyć warunku,
       działającego w czasie wykonania... lub nie sprawdzać poprawności.
    */
    static_assert(sizeof(float) == sizeof(int));

    float *p_f;
    int *p_i;
    int result;

    p_f = &f;
    p_i = reinterpret_cast<int*>( p_f );
    result = *p_i;
    return  result;
}

float int_to_float(int i)
{
    static_assert(sizeof(float) == sizeof(int));

    float *p_f;
    int *p_i;
    float result;

    p_i = &i;
    p_f = reinterpret_cast<float*>( p_i );
    result = *p_f;
    return  result;
}

Ciała funkcji są tak rozwleczone dla łatwiejszego zrozumienia.


Można to samo zrobić nieco inaczej - za pomocą unii.* Unia to struktura danych, która w danym czasie ma dostępną tylko jedną swoją składową, zaś jej rozmiar jest równy rozmiarowi jej największego elementu składowego. Reasumując - wszystkie dane przechowuje w jednym miejscu w pamięci. Jak wrzucimy do unii jedną składową, pozostałe stają się niepoprawne, unia je nadpisze.

W tym przypadku rozmiar unii txd powinien wynosić tyle samo, co rozmiar typu int oraz tyle samo, co rozmiar typu float. Zapisując do unii liczbę float, unia przechowuje tę liczbę jako float (jak można się było spodziewać). Jeśli jednak sięgniemy po składową int, to "unia zajrzy" w swoje jedyne dostępne miejsce w pamięci i wyjmie stamtąd to, co było przed chwilą wrzucone jako float. Z tym, że każemy jej wyjąć int, więc zobaczymy dokładnie to samo, co z pomocą przedstawionych przeze mnie wyżej funkcji konwersji. Mam nadzieję, że opisałem to dość zrozumiale.*

Nie wiem natomiast, dlaczego przesyła się do funkcji write() highByte() - to pewnie jest związane z fizyczną reprezentacją danej pamięci EEPROM.

A co się stanie jak nic nie będzie w pamięci EEPROM a my ją wczytamy ;)

EEPROM jest to pamięć stała - więc odczytamy coś, co już tam wcześniej ktoś zapisał. Albo zera. Albo śmieci. :)

* - jak słusznie zauważył adrian17, w C++ zaglądanie do "nieaktywnej" składowej unii jest zachowaniem nielegalnym, wedle dokumentacji to jest UB i nie powinno się tego robić

komentarz 15 lutego 2017 przez Eryk Andrzejewski Mędrzec (164,260 p.)
Za taką odpowiedź musi być plus! Wszystko pięknie i obszernie wytłumaczone, aż się chce czytać :)
1
komentarz 15 lutego 2017 przez adrian17 Ekspert (344,860 p.)

Tylko, że... znacząco przekombinowana. Wystarczy:

EEPROM.put(adres, obiekt_dowolnego_typu);

A to:

 Jeśli jednak sięgniemy po składową int, to "unia zajrzy" w swoje jedyne dostępne miejsce w pamięci i wyjmie stamtąd to, co było przed chwilą wrzucone jako float

jest nielegalne w C++ie.

komentarz 15 lutego 2017 przez BanditPlayGame Użytkownik (680 p.)

Żeby móc w ogóle próbować przedstawić typ float za pomocą typu int, musimy mieć pewność, że mają taką samą liczbę bitów.

To znaczy co? Nie rozumiem. Jak zrobić żeby liczba zmiennoprzecinkowa miała tyle samo bitów co int ? 

 

komentarz 15 lutego 2017 przez BanditPlayGame Użytkownik (680 p.)

Tylko, że... znacząco przekombinowana. Wystarczy:

EEPROM.put(adres, obiekt_dowolnego_typu);

A jak potem to wyciągnąć?

komentarz 15 lutego 2017 przez draghan VIP (106,230 p.)

Jak zrobić żeby liczba zmiennoprzecinkowa miała tyle samo bitów co int ? 

Nijak. To czy będzie miała tyle bitów czy nie, zależy od kompilatora.

Okej a jak to potem wyciągnąć z EEPROM

Proponowałbym skorzystać z rozwiązania, które podsunął adrian17 - wykorzystać meotdy EEPROM::put() i EEPROM::get(). Unikniesz w ten sposób potrzeby konwersji.

komentarz 15 lutego 2017 przez BanditPlayGame Użytkownik (680 p.)
A ten adres to jaki bo na przykład int potrzebował dwóch czy to trzeba uwzględnić (jeżeli tak to ile zajmuje float).
komentarz 15 lutego 2017 przez draghan VIP (106,230 p.)
Zmienna typu float zajmuje dokładnie sizeof(float).

BTW. Zapomniałem napisać. Dzięki bardzo za zwrócenie uwagi, adrian17. :)
komentarz 15 lutego 2017 przez BanditPlayGame Użytkownik (680 p.)
#include <EEPROM.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(2,3,4,5,6,7);

int q=1;
float zl;
float t;
float zlw;
float tw;


void setup() {
  EEPROM.get(0, zlw);
  EEPROM.get(sizeof(float), tw);
  Serial.begin(9600);
  lcd.begin(16,2);
  
  lcd.print("Zl: ");
  lcd.print(zlw);
  lcd.setCursor(0,1);
  lcd.print("Min: ");
  lcd.print(tw);
  delay(2000);

  
  lcd.clear(); 
  lcd.setCursor(0,0);
  pinMode(10, INPUT);

 
}

void loop() {
    lcd.print("Czas min: ");
    lcd.print(t);
    delay(60000);
    lcd.clear();
    t=t+1;
    
   if(digitalRead(10)== HIGH)
  {
  t=t/60;
  zl=t*0,1;
  zl=t*0,60;
  tw=tw+t;
  zlw=zl+zlw;
  EEPROM.put(0, zlw);
  EEPROM.put(sizeof(float), tw);
    }
    }
 

Jestem chyba idiotą ale dalej mi nie działa zapis i odczyt :(

0 głosów
odpowiedź 15 lutego 2017 przez mokrowski Mędrzec (155,460 p.)

Może warto przeczytać dokumentację...

EEPROM.put

Podobne pytania

0 głosów
1 odpowiedź 380 wizyt
pytanie zadane 21 stycznia 2019 w C i C++ przez krzycholl18 Nowicjusz (220 p.)
0 głosów
1 odpowiedź 2,575 wizyt
+1 głos
3 odpowiedzi 207 wizyt

92,551 zapytań

141,399 odpowiedzi

319,529 komentarzy

61,937 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...