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.

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

skyguy 13 Gru 2012 09:55 3561 14
  • #1 13 Gru 2012 09:55
    skyguy
    Poziom 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

    0 14
  • #2 13 Gru 2012 10:17
    BlueDraco
    Specjalista - Mikrokontrolery

    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.

    0
  • #3 13 Gru 2012 11:03
    skyguy
    Poziom 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.

    Kod: c
    Zaloguj się, aby zobaczyć kod


    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

    0
  • #4 13 Gru 2012 11:42
    loczi
    Poziom 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.

    0
  • #5 13 Gru 2012 11:49
    Terminator
    Poziom 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ę :

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #6 13 Gru 2012 12:02
    skyguy
    Poziom 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

    Kod: c
    Zaloguj się, aby zobaczyć kod


    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"?

    0
  • #7 13 Gru 2012 12:27
    BlueDraco
    Specjalista - Mikrokontrolery

    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... ;)

    0
  • #8 13 Gru 2012 13:07
    szulat
    Poziom 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

    0
  • #9 13 Gru 2012 16:55
    skyguy
    Poziom 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...

    0
  • #10 13 Gru 2012 19:20
    BlueDraco
    Specjalista - Mikrokontrolery

    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.

    0
  • #11 14 Gru 2012 23:48
    skyguy
    Poziom 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)

    0
  • #12 15 Gru 2012 09:22
    tymon_x
    Poziom 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 napisał:
    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.

    0
  • #13 15 Gru 2012 12:56
    BlueDraco
    Specjalista - Mikrokontrolery

    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.

    0
  • #15 15 Gru 2012 23:09
    BlueDraco
    Specjalista - Mikrokontrolery

    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...

    0