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

Atmega8A - [C/Eclipse] Zapis i odczyt zmiennych z EEPROM

iwi1 13 Lis 2013 00:53 3312 11
  • #1 12946163
    iwi1
    Poziom 17  
    Witajcie.
    Napisałem programik zliczający energię w kWh.
    Super działa do czasu wyłaczenia z prądu - wtedy się resetuje i od nowa prawidłowo nalicza.
    Są wbudowane funkcje w eeprom.h które próbuję zmusić do działania i nic z tego nie wychodzi - ciągle kompilator wywala błędy.
    Zapisywanie do EEprom chcę zrobić funkcją eeprom_write_float
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    i w kompilatorze otrzymuje taki błąd: ../main.c:387:5: warning: passing argument 1 of '__eewr_float_m8' makes pointer from integer without a cast [enabled by default]
    zmienna

    Odczytywanie pamięci eeprom mam taką funkcją zrobione, ale nie wiem czy działa bo ciągle nie mogę nic zapisać
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #2 12946167
    mickpr
    Poziom 39  
    iwi1 napisał:
    passing argument 1 of '__eewr_float_m8' makes pointer from integer without a cast
    Pierwszy parametr powinien być wskaźnikiem do zmiennej (możesz podać &uiAddress).
  • #3 12946211
    iwi1
    Poziom 17  
    Nie bardzo rozumiem.
    na pierwszym miejscu mamy zadeklarować gdzie ma być zapisana czyli adres, a na drugim zmienna.
    zmienna w RAM to kWh_stan
    zmienna do eeprom to kWh_stan_ee - ewentualnie jak to się nie pomiesza to może być jedna zmienna kWh_stan do eeproma i do Ramu.

    uiAddress jest zadeklarowana na samym poczatku jako float
    uint16_t uiAddress = 0 ;
    i nie ma znaczenia czy podam zero na końcu czy 1 czy inną liczbę - ciągle się nie kompiluje

    czy może ktoś poać jakiś przykład zapisania zmiennej np kWh_stan do pamięci eeprom
    a jeszcze dokładniej

    1. uC uruchamiamy.
    2. odczytujemy zmienną kWh_stan - jeśli nie istnieje w eepromie to dajemy jej wartość 0
    3. Po wykonaniu warunku IF (jeżeli inna zmienna (Ws_stan) osiągnie wartość 1 kWh=3600000Ws) zwiększamy tą zmienną o 1 i zapisujemy kWh_stan do eeprom już z nową wartością w tym samym adresie.
    W którym adresie ją zapiszemy - jest mi obojętne.
    Wielkość może być uint16_t - nie musi być float.
    Ja już się poddaje - niby takie proste, a nie do końca proste.
  • #4 12946229
    Konto nie istnieje
    Poziom 1  
  • #5 12946364
    mickpr
    Poziom 39  
    iwi1 napisał:
    Nie bardzo rozumiem. na pierwszym miejscu mamy zadeklarować gdzie ma być zapisana czyli adres, a na drugim zmienna.
    Zacznij od pokazania nam definicji/deklaracji funkcji eeprom_write_float.
    Bez tego - to sobie tylko gdybamy.
  • #6 12946582
    inmo
    Poziom 10  
    Dzięki koledzy. Wygląda na to że już będzie działało, ale jeszcze chciałbym uściślić parę wątpliwości
    Cytat:
    To w końcu float, czy uint16_t? To są różne rzeczy.

    jest mi obojętne czy to będzie float czy integer byleby działało. Ogólnie będą liczby całkowite więc wystarczy uint16_t, ale próbowałem już różnych sposobów.
    Nie działała funkcja eeprom_write_byte bo tam było w deklaracji uint8_t a ja cały czas dawałem uint16_t dlatego przeszedłem na float.

    Cytat:
    float* uiAddress = 0;

    po takiej zmianie ładnie się kompiluje, ale albo nie zapisuje, albo nie odczytuje bo po resecie jest zero w dalszym ciągu.
    Jeszcze raz spróbuję przejrzeć cały kod co może być nie tak.

    Czy jest znaczenie między takim zapisem - zamieniam na uint16_t oczywiście?
    uint16_t kWh_stan_ee; a
    uint16_t EEMEM kWh_stan_ee;

    bo wyczytałem że EEMEM to jakieś makro zapisujące do eeprom.
    Ale potem inni piszą, że skoro używa się funkcji eeprom_write_ to nie potrzeba tego makra EEMEM, a to makro służy tylko do wygenerowania pliku, który potem można ręcznie wgrać do eeproma. Jak to jest naprawdę?

    jeszcze takie pytanie. Jak zapisuje cały czas ten sam blok pamięci to korzystać z funkcji write czy update? Jest jakaś różnica?
    przecież jak w komórce 0 siedzi np 0xFF to robiąc write zapisuje w tym miejscu wartość np 0XEE. Zapisując ponownie znowu zamienia z 0xEE na 0xDD itd.
    czym się różnią te funkcje między sobą.

    i czy w uiAddress podajemy dziesiętnie czy szesnastkowo adres pamięci?
    i ewentualnie bo człowiek się gubi w tym. Atmega8A ma 512 bajtów pamięci. Czyli 4096 bitów Czyli zapisując to szesnastkowo to 0x000 do 0xFFF.
    Czyli zapisując zmienną uint16_t zapisuje ją w 16 bitach - czyli ustawiając uint16_t na 0 (0x000) to pierwsze szesnaście bitów jest zajęte i teraz jak będę adresował inną zmienną to muszę pamiętać o tym?
    Ewentualnie nie podając żadnego adresu przy deklarowaniu uiAddress to czy kompilator sam sobie rozmieści zmienną gdzie chce?.


    w pliku eeprom.h jest taki zapis
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #7 12946718
    tmf
    VIP Zasłużony dla elektroda
    Ja na twoim miejscu zacząłbym od nauki podstaw C, a potem ogarnięcia tego języka na AVR. To po pierwsze, a po kolejne:
    - do zliczania nie używaj float, wbrew pozorom to nie jest obojętne, czy będzie float, czy int. Poczytaj o tym jak float jest reprezentowany w pamięci, bo możesz się zdziwić, kiedy np. x+1 będzie ciągle równe x.
    - EEMEM nic nie zapisuje do EEPROM, to kwantyfikator określający lokalizację zmiennej w przestrzeni adresowej procesora (wymagany ze względu na różne przestrzenie w AVR). Musisz go określić dla zmiennej, która ma być w EEPROM.
    - zapis float* uiAddress = 0; powoduje utworzenie wskaźnika na float, który wskazuje na zmienną tego typu umieszczoną w pamięci pod adresem 0. Ponieważ pod tym adresem znajdują się rejestry R0-R3 AVR, odwołanie się do tego adresu jest błędem. Jeśli używasz wskaźnika, to przed użyciem musi on wskazywać na poprawny adres, zamiast tego prościej użyć operatora & z nazwą zmiennej w EEPROM.
    - makra write od update różnią się tym, że to drugie zanim coś zapisze najpierw sprawdza czy znajdująca się w EEPROM wartość nie jest czasem równa nowozapisywanej i jeśli tak to odstępuje od zapisu. Przede wszystkim ma to za zadanie wydłużyć żywotność EEPROM przez eliminację niepotrzebnych zapisów. Swoją drogą, to też musisz przemyśleć - czyli zastosować jakieś techniki wear leveling, lub zapisywać tylko wtedy kiedy jest to niezbędne, inaczej wykończysz EEPROM.
    - co do zapisu dziesiętnego lub szesnastkowego. Czy procesor rozróżnia te zapisy? Raczej nie, prawda?
    - co do adresowania EEPROM - przyjrzyj się rejestrowi adresowemu EEPROM, a wyjaśni się sprawa niewykorzystanych bitów. Stosując EEMEM + operator & kompilator wygeneruje taki adres jaki jest potrzebny.
  • #8 12954137
    inmo
    Poziom 10  
    Witajcie.
    Sprawa okazała się prostsza niż myślałem. Problem byłw ustawieniach Eclipse.
    Domyślnie ustawia się, żeby nie wgrywać EEPROMa.
    Po zmianie na taki w właściwościach AVRDUDE działa ładnie.
    Atmega8A - [C/Eclipse] Zapis i odczyt zmiennych z EEPROM
    a domyślnie jest ustawiona na "do not upgrade eeprom image"

    a już żeby zamknąć temat to kod który działa wygląda tak:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #10 12954461
    tmf
    VIP Zasłużony dla elektroda
    inmo napisał:

    a już żeby zamknąć temat to kod który działa wygląda tak:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Ten kod jest błędny i działa tylko przypadkowo. uiAddress używasz niezainicjowany - nie masz żadnych ostrzeżeń kompilatora? Wywal go.
    Powinno być:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
    [/quote]
  • #11 12954495
    inmo
    Poziom 10  
    if (!kWh_stan) { kWh_stan = 0; }

    ten if jest po to, żeby na starcie wpisywał do zmiennej kWh_stan wartość 0 a nie domyślnie 0XFFFF;

    co do ostrzeżeń kompilatora to nie było żadnych błędów i kod działał.
    Ale dzięki za info - zastosuje Twoje uwagi.
  • #12 12954633
    tmf
    VIP Zasłużony dla elektroda
    ! jest operacją logiczną. Inaczej to wygląda tak - jeżeli kWh_stan jest równy zero to go wyzeruj. O to ci chodziło? To nie to samo co:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    BTW, zmienne w EEPROM są zainicjowane, przynajmniej mogą być, więc taki kod jest niepotrzebny, wystarczy napisać:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
REKLAMA