Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[Atmega8][avr-gcc] USART - Przesyłanie danych - optymalizacja

skyguy 13 Dec 2012 09:55 3942 14
  • #1
    skyguy
    Level 14  
    Witam mam problem odnośnie zoptymalizowania kodu do przesyłania danych między Atmegą8 a aplikacją zrobioną w Borlandzie - skończyła mi się pamięć.

    W tej chwili mam wszystko zrobione za pomocą przesyłania znaków.
    np.
    ->Klikam w borlandzie przycisk bateria
    ->Borland wysyła po USART znak B (char)
    ->Atmega czyta i interpretuje, że trzeba wysłać na USART pomiary z ADC
    ->Pomiar wysyła jako ciąg znaków:
    Bxxxyyyzzz
    gdzie

    xxx to pomiar z pierwszej baterii np. 165 (ostatnia automatycznie wskakuje po przecinku)
    yyy zzz odpowiednio druga i trzecia

    Jak inaczej ugryźć to wysyłanie przez atmegę żeby nie pożerało tyle pamięci?
    Poprawiłem tytuł,
    LordBlick
  • #2
    BlueDraco
    MCUs specialist
    Napisać dobrze program?

    Bez żadnych informacji nt. Twojego programu trudno cokolwiek zgadywać. Tak na oko cały ten kod pisany w C zająłby jakieś 300 bajtów pamięci Flash.
  • #3
    skyguy
    Level 14  
    Poniżej źródło w którym mam:
    -pomiar ADC
    -pomiar szerokości impulsu PWM wysterowanie przekaźnika
    -USART


    Mikrokontroler ma spełniać funkcję sterownika do ledów jako oświetlenie samolotu z wyróżnieniem wszystkich etapów startu jak kołowanie włączenie silników itp.
    Code: c
    Log in, to see the code


    Sposób przesyłania danych o którym mówiłem w pierwszym poście:

    Litery zajete:
    B-bateria odczyt
    O-wyjscia odczyt
    S-swiche odczyt
    F-faza odczyt
    N-faza zapis nastepna
    T-test zapis
    K-koniec testu
    P-koniec programowania
    X-zapis baterry info
    Y-baterry off
    Q-zapis swich1
    W-zapis swich2
    E-zapis kolejnosci fazy


    Swiche
    SXXXYYY
    S028084
    Battery
    BXXXXYYYYZZZZ
    B10.412.516.6
  • #4
    loczi
    Level 13  
    Zamienienie zmiennoprzecinkowej(float) na stałoprzecinkową(nie ma takiego typu, ale można użyć dwóch uint8_t jeden jako "przed przecinkiem" drugi jako "po") na pewno spowoduje znaczne zmniejszenie się aplikacji. Oraz trzeba usunąć dzielenie, bardzo często można je zamienić przesuwaniem bitów.
  • #5
    Terminator
    Level 23  
    Funkcja _delay_ms jest typu inline więc użycie jej drastycznie zmniejsza pamięć flash.
    Jeśli chodzi o RAM , zbyt dużo zmiennych globalnych, pozamieniaj niektóre na zmienne lokalne.
    Jeśli dostajesz po USART dane do kompa i piszesz program w borlandzie to może warto niektóre obliczenia przenieść na pc a nie liczyć w uC.
    Wymyśl sobie jakiś standard kodowania danych za pomocą USART , np: pierwszy bajt to instrukcja (0x01 - wyslij, 0x02 pobierz , 0x03 tryb itp - bo nie wnikałem w Twój kod merytorycznie) , następny bajt to np dane. Na komputerze sobie z tym poradzisz. A z PC np takie coś 0xC0 + komenda (0x00 ... 0X0F - czyli 16 komend masz do dyspozycji) a w procku sprawdzasz data>=0x0C && data<=0xCF ... zamiast F6 F5 F4 itp.

    Najpierw aby zminimalizować objętość flash zajmij się _delay_ms.
    Zrób sobie funkcję :
    Code: c
    Log in, to see the code
  • #6
    skyguy
    Level 14  
    Dzięki napewno od tego zacznę,
    niestety nie mogę części przenieść na kompa. Służy on jedynie do sczytania danych oraz ewentualnej zmiany w epromie. Normalnie będzie autonomicznie działała Atmega.

    Jeszcze poproszę odpowiedź na podstawy.
    Po usarcie wysyłam za pomocą komendy

    Code: c
    Log in, to see the code


    Ale tu wysyłam znak "char" jak wysłać sam bajt w postaci 0x01 a nie znaku - czy to nie to samo np. jak wysyłam "0x42" zamiast "B"?
  • #7
    BlueDraco
    MCUs specialist
    1. Wyrzuć wszystko, co ma cokolwiek wspólnego ze zmiennym przecinkiem - zmienne float i formaty w printf.

    2. Wyrzuć strlen z procedury wyświetlanai napisu - w pętli wyświetlaj znaki aż do bajtu 0.
    while (*p)
    send_char(*p ++);

    3. Masz błędną obsługę przerwania UART. W przerwaniu nie wysyła się znaków, bo trzeba na to czekać. Wydaje mi się, że bez przerwania UART byłoby lepiej.

    4. Tak napisane przerwanie ADC nie ma sensu. Możesz czytać pomiar bez przerwania, no i oczywiście trzymaj to w postaci stałopozycyjnej, np. w mV, a nie w ułamkach Voltów.

    5. Jest jeszcze parę innych knotów, ale na razie wystarczy... ;)
  • #8
    szulat
    Level 23  
    w niektórych przypadkach sama zmiana opcji kompilatora zmniejsza kod o nawet 30%, zwłaszcza --combine -fwhole-program
    było już kilka wątków na ten temat
  • #9
    skyguy
    Level 14  
    Terminator
    Możesz mi napisać jak łopatologicznie przykład schematu jak bym mógł wysyłać z AVR-a 3napięcia?
    Chodzi mi o samą ramkę. W tej chwili mam wysyłam ciąg znaków B123456789 gdzie
    B- info o początku dla nadawania napięć baterii
    12,3 - napięcie jednej z baterii
    34,5 - druga
    78,9 - trzecia

    ps. MyDelay -zmniejszyła zapełnienie o 5% :) great, jedziemy dalej...
  • #10
    BlueDraco
    MCUs specialist
    Kiedy pozbędziesz się wszystkich float i operacji na nich zajętość pamięci spadnie o połowę. Po wyrzuceniu printf zapewne zyskasz jakieś następne 1.5 KiB.
    ;)

    Co powiesz na odpowiedź z AVR np. taką:

    B 1234 2345 6789

    gdzie te trzy liczby to np. napięcia w mV.
  • #11
    skyguy
    Level 14  
    Zamieniłem float-y na int i od razu luźniej - dzięki chłopaki :)

    Czy da się inaczej przekonwertować int z ADC to char jak
    sprintf(napiecie, "%i", adc);
    czy dużo nie zaoszczędzę?

    kompilator mi nie przepuszcza:
    char napiecie [5]
    int adc
    napięcie=char(adc)
  • #12
    tymon_x
    Level 30  
    Kolega chce mieć stringa, czyli grupę znaków znaków najczęściej ASCII z dodatkowym znakiem null na końcu '\0' oznaczającym koniec stringa.

    skyguy wrote:
    napięcie=char(adc)

    A to, co to ma być ? Masz w ogóle przy Sobie jakąkolwiek książkę o C ? Bo chyba nie masz pojęcia o funkcjach, nazwach zarezerwowanych dla języka, stringu i typach. Nawet nie mam pojęcia jak to skomentować.

    Użyj funkcji itoa() z stdlib.h, integer to ASCII.
  • #13
    BlueDraco
    MCUs specialist
    Wszystko zależy od tego ile masz wolnego czasu i pamięci mikrokontrolera. Ja np. często wysyłam napięcia w postaci szesnastkowej, bo to nie kosztuje praktycznie nic po stronie uC, a program odbierający na PC odczyta je łatwiej niż z postaci dziesiętnej. Samo dzielenie przez 10, potrzebne do konwersji na postać dziesiętną, zajmuje grube dziesiątki instrukcji procesora.
    Z kolei przeliczenie odczytu ADC na napięcie w mV można zrobić przez pomnożenie przez odpowiednią liczbę i przesunięcie w prawo. Np. przy napięciu odniesienia 5 V i 8-bitowym odczycie będzie to coś jak mV = (adcval * 5000) >> 8, czyli inaczej (adcval * 625) >> 5. Wszystko po to, żeby nie dzielić na mikrokontrolerze.
  • #14
    LordBlick
    VIP Meritorious for electroda.pl
    BlueDraco wrote:
    Samo dzielenie przez 10, potrzebne do konwersji na postać dziesiętną, zajmuje grube dziesiątki instrukcji procesora.
    istnieje efektywniejszy algorytm, ale którego implementacja najwygodniejsza będzie w asemblerze:
    http://www.classiccmp.org/cpmarchives/cpm/mir...cbfalconer.home.att.net/download/dubldabl.txt
    http://lmgtfy.com/?q=dubldabl
  • #15
    BlueDraco
    MCUs specialist
    Tak, ale brak konwersji będzie i tak szybszy od konwersji. ;)

    Gdyby tak zredukować wcześniejszy wzorek do (adcval * 39) >> 1, to mieścimy się na 16 bitach...