Od jakiegoś czasu bawię się AVRami, ale zawsze pisałem wszystko w C. Teraz niestety potrzebuję użyć klas. I moje pytanie czy da się to zrobić i czy działa to w pełni poprawnie. Prosta klasa jakoś się kompiluje i działa, jednak bardziej skomplikowane rzeczy niestety już nie. Mimo, że kompilują się bez problemów, to program zachowuje się zupełnie nielogicznie. Biorę pod uwagę, że to może być mój błąd (chociaż już wielokrotnie to sprawdzałem), ale wolę zapytać, bo może okazać się, że tego w ogóle nie da się zrobić :/
Da się zrobić . Pisałem trochę softu obiektowo w gcc (czyli to co masz pod WinAvr - choć tego środowiska nie używam) nawet na tn2313.
Faktycznie są problemy ale wynikają często z błędów programistycznych, które czasami uchodzą w C . Ponadto faktem jest, że czasami musiałem wyłączyć optymalizację całkiem - 0, i zwykle problemy kończyły się.
Próbuj zmienić opcje optymalizacji.
Polecam drogę właśnie w tym kierunku tzn. C++.
To zależy, co masz na myśli mówiąc regulować. Standardowo cała dostępna pamięć jest przeznaczona na stos, zmienne statyczne i zmienne dynamiczne. Tzn. na początku pamięci jest obszar zmiennych statycznych, potem ewentualnie obszar zmiennych dynamicznych, który rośnie "w górę". Na końcu jest stos, który rośnie od końca pamięci "w dół".
Jeżeli pamieci jest mało, to stos i zmienne się szybko spotkają i efekty będą nieciekawe .
Na AVR-ach jeszcze C++ nie próbowałem, ale C++ potrafi być pamięciożerne. A linker nie ostrzega, że na stos zostało np. 10 bajtów.
Aha, to tyle to chyba wiedziałem. Myślałem, że da się to jakoś kontrolować ręcznie.
W chwili obecnej nie wydaje mi się, żebym miał za mało pamięci, bo obecnie używam megi16, a program na prawdę jest ograniczony do minimum. Jedyne podejrzenie, to że źle alokuję pamięć, bo potrzebuję stringów, a inaczej to chyba się nie da.
Kolego owca2002: zdecyduj sie czy korzystasz z C czy z C++.Od zarzadzania pamiecia w C++ sa operatory new i delete a nie malloc ktora jest standardowa funkcja z bliblioteki C.Niestety wiekszosc ludzi kompletnie myli te dwa jednak znacznie rozniace sie jezyki. Musisz rowiez miec na uwadze ze zarzadzanie pamiecia w przypadku mikrokontrolerów jest duzo bardziej ubogie niz w PC-tach.Nie mozna sobie pozwolic na marnotrawstwo pamieci na struktury danych do zarzadzania sterta bo nie starczy miejsca na sama sterte.Dlatego w wiekszosci przypadkow zarzadzanie pamiecia w portach mikrokontrolerowych jest oparte na jednorazowym przydziale pamieci (tzn obszar raz przydzielony nie moze byc zwolniony).Wlasnie stad moga wynikac rozne problemy.
Kolego owca2002: zdecyduj sie czy korzystasz z C czy z C++.Od zarzadzania pamiecia w C++ sa operatory new i delete a nie malloc ktora jest standardowa funkcja z bliblioteki C.Niestety wiekszosc ludzi kompletnie myli te dwa jednak znacznie rozniace sie jezyki. Musisz rowiez miec na uwadze ze zarzadzanie pamiecia w przypadku mikrokontrolerów jest duzo bardziej ubogie niz w PC-tach.Nie mozna sobie pozwolic na marnotrawstwo pamieci na struktury danych do zarzadzania sterta bo nie starczy miejsca na sama sterte.Dlatego w wiekszosci przypadkow zarzadzanie pamiecia w portach mikrokontrolerowych jest oparte na jednorazowym przydziale pamieci (tzn obszar raz przydzielony nie moze byc zwolniony).Wlasnie stad moga wynikac rozne problemy.
Zdaję sobie sprawę z tego, że to jest C, ale z tego co wyczytałem, to operatory new i delete po prostu tutaj nie działają (zresztą jak wiele innych standardowych funkcji C++). Dlatego też używam malloc.
Jeśli masz gdzieś pod ręką jakiś tutorial na temat pisania w C++ pod AVR to chętnie poczytam, albo chociaż jakieś przykłady, tylko właśnie na mikrokontrolery, bo normalnie z pisaniem w C++ to problemów raczej nie miałem.
Nie mam nic takiego bo akurat w AVR-ach uwazam korzystanie z C++ jako przerost formy nad trescia.Niestety ten brak pewnych kluczowych operacji moze wiazac sie z ograniczona architektura tego procka.
Nie mam nic takiego bo akurat w AVR-ach uwazam korzystanie z C++ jako przerost formy nad trescia.
Absolutnie się zgadzam.
Program, którego kod wynikowy, może wynosić kilka kilobajtów nie może efektywnie korzystać z dobrodziejstwa C++. Ja już nawet nie wspominam o RAMie. Wspominałeś o wykorzystaniu wzorców. Otóż wzorce są cholernie pamięciożerne i generalnie C++ jest bardzo rozbudowanym językiem, który potrzebuje dużych zasobów zarówno pamięciowych jak i mocy obliczeniowej.
Sam fakt korzystania z klas do grupowania danych i funkcji nie oznacza, że korzystamy z dobrodziejstw C++. Wystarczy używać struktur. Jeżeli nie wystarcza Ci samo C to znaczy, że również nie wystarcza Ci ten mikrokontroler.
Sprawa jest o tyle skomplikowana, że raczej C++ będzie potrzebny, ponieważ staram się zaimplementować sieć probabilistyczną na uC. A cały projekt ma właśnie udowodnić, że nawet na czymś takim małym da się to zrobić.
Tylko w chwili obecnej to podstawowe rzeczy nie działają tak jak powinny i cały czas staram się znaleźć błędy, bo wiem, że każdy je popełnia.
Cóż, poczułem sie wywołany do tablicy, zwłaszcza przez kolegę fantom, ktory zasugerował, że nie rozróżniam C i C++, a anwet nie przeczytał linka, który wstawiłem. Cóż, tak krawiec kraje, jak mu materii staje...
upanie wrote:
Quote:
Nie mam nic takiego bo akurat w AVR-ach uwazam korzystanie z C++ jako przerost formy nad trescia.
Absolutnie się zgadzam.
Program, którego kod wynikowy, może wynosić kilka kilobajtów nie może efektywnie korzystać z dobrodziejstwa C++. Ja już nawet nie wspominam o RAMie.
A ja się absolutnie nie zgadzam. C++ ma pare zalet, które można wykorzystać, nawet w przypadku mikrokontrolerów. Wprawdzie do tej pory pisałem to w C, ale trochę cierpialem z powodu jego ograniczeń. Jeżeli programista rozumie, co robi, to program może być całkiem efektywny, vide przykład dalej.
Quote:
Wspominałeś o wykorzystaniu wzorców. Otóż wzorce są cholernie pamięciożerne i generalnie C++ jest bardzo rozbudowanym językiem, który potrzebuje dużych zasobów zarówno pamięciowych jak i mocy obliczeniowej.
Kolega pisał o szablonach. Szablony i wzorce to dwie różne rzeczy, jakby kolega nie wiedział. Akurat rzeczywiście z wzorcami to mogła by być przesada. Ale szablony to bardzo silne narzędzie.
Proszę, o to przykład. Postanowiłem sprawdzić, co da się zrobić w C++, bo podobny kod w C z użyciem długich makr zrobił sie trochę mało czytelny, a głównie ciężko poprawialny.
Jak widac są zalety:
1. Precyzyjna przestrzeń nazw.
2. Unikanie powielania kodu (źrodłowego)
3. Scisłe sprawdzanie typów
4. Bardziej precyzyjne komunikaty o błędach składniowych - znalezienie błędu w długich makrach "zastępujących" szablony nie jest czasem proste.
Są też, jak widać, wady. Głównie ograniczone możliwości odwołania do symbolicznych nazw rejestrów i/o. Trzeba by stworzyć odpowiednie pliki nagłówkowe w C++. Np. powyżej musiałem przekazać adres rejestru szesnastkowo, bo odpowiedniej stałej nie ma w plikach <avr/io.h>. Makro _SFR_IO_ADDR nie działa, bo w C jest ten adres generowany na etapie optymalizacji, a nie kompilacji.
upanie wrote:
Sam fakt korzystania z klas do grupowania danych i funkcji nie oznacza, że korzystamy z dobrodziejstw C++. Wystarczy używać struktur. Jeżeli nie wystarcza Ci samo C to znaczy, że również nie wystarcza Ci ten mikrokontroler.
fantom wrote:
Jestem pewien ze da sie to zrobic spokojnie z uzyciem C.
Oczywiście, że sie da. Wszystko się da, tylko po co sie męczyć, jeśli można prościej. Wszystko zależy od konkretnej sytuacji.
owca2002 Może jakiś kod przykładowy, który nie działa? Jak widać, "u mnie działa".
P.S. Używałem avr-gcc 3.4.3, ale nie sądzę, aby to miało istotny wpływ.
Troche sam sie wywolales do tablicy (zeby sie popisac ?) a przeciez nie o to chodzilo. Nikt nie powiedzial ze sie nie da tylko ze na tak skromna architekture jest to bez sensu. Przy czyms tak prostym kompilator nie ma problemu ale sprobuj pokorzystac troche z operatorow zarzadzania pamiecia i juz nie bedzie tak kolorowo. Podales listing kodu a ile wynosi w takim przypadku zajetosc RAM-u ? Wszystko musi miec rece i nogi. Armata tez mozesz zabic muche ale po co skoro mozna to zrobic packa na muchy.
Troche sam sie wywolales do tablicy (zeby sie popisac ?) a przeciez nie o to chodzilo. Nikt nie powiedzial ze sie nie da tylko ze na tak skromna architekture jest to bez sensu.
Raczej po to, aby oprzeć dyskusję na czymś konkretnym, a nie na ogólnym twierdzeniu "nie ma sensu".
I wydaje mi się, że pokazałem sens. Może kolega zaproponuje, jak to zrobić równie elegancko w C. Wiem, że ogólnie się da - ten kod powstał na podstawie tego, co miałem w C z makrami, ale o wadach i zaletach pisałem.
Quote:
Przy czyms tak prostym kompilator nie ma problemu ale sprobuj pokorzystac troche z operatorow zarzadzania pamiecia i juz nie bedzie tak kolorowo. Podales listing kodu a ile wynosi w takim przypadku zajetosc RAM-u ?
Przecież pisałem, że programista musi rozumieć, co robi. Korzystanie z wszystkich możliwości C++, w tym dynamicznej alokacji obiektów, oczywiście nie ma sensu.
Ale w tym wypadku zajetość RAM jest dokładnie taka, jak w C:
No to juz brzmi rozsadniej bo az sie przestraszylem (w koncu to tylko dwa obiekty ktore maja pod dwa proste pola). Z drugiej strony pisac cos w C++ i nie miec mozliwosci skorzystania ze wszystkich jego dobrodziejstw jest sztuką dla sztuki.
Bardzo mnie cieszy, że temat się tak rozwinął i są chętni do pomocy. Jak tylko będę miał chwilę, to wrzucę jakiś fragment kodu, żeby przekonać się czy to jest mój błąd, bo samemu często trudno jest wykryć własne błędy.
Moje rady na szybko:
1. Kod pisz, kompiluj i testuj na pececie z użyciem GCC dla pentium. Gdy wszystko ruszy to dopiero migracja na 8-bit.
2. Nie używaj konstrukcji:
Code:
typedef char *string;
bo może kolidować z std::string.
3. Używaj GDB gdy program się sypie i nie wiadomo o co chodzi.
Hmm...
Czy mógłbyś napisać, co właściwie znaczy "nie działa"? I jakiego masz AVR-a?
Z uwag ogólnych:
1. To, że napisałem, że moim zdaniem często warto skorzystać z C++ nie oznacza, że można szastać zasobami. malloc() to raczej ostateczność. Nie wiem, co chcesz osiagnąć, ale alokowanie łańcuchów stałej długości nie ma sensu - znacznie efektywniej byłoby po prostu zadeklarować tablice w obiekcie.
2. Wskazane jest (dla mikrokontrolerów) korzystanie z obiektów statycznych (w miare możliwości) - przeważnie daje bardziej efektywny kod, porównywałny z tym w C (mogą byc wyjątki, ale baardzo specyficzne).
3. Czy przestrzeń stanów masz zamknietą czy otwartą? Jeżeli zamkniętą, to użycie napisów do definiowania stanu jest mocno nieefektywne. Pamięć na AVR-ze zaraz się skończy.
4. Ponieważ ten program nic nie robi, to nie rozumiem, co znaczy, że nie działa. Testujesz to na symulatorze?
1. To, że napisałem, że moim zdaniem często warto skorzystać z C++ nie oznacza, że można szastać zasobami. malloc() to raczej ostateczność. Nie wiem, co chcesz osiagnąć, ale alokowanie łańcuchów stałej długości nie ma sensu - znacznie efektywniej byłoby po prostu zadeklarować tablice w obiekcie.
2. Wskazane jest (dla mikrokontrolerów) korzystanie z obiektów statycznych (w miare możliwości) - przeważnie daje bardziej efektywny kod, porównywałny z tym w C (mogą byc wyjątki, ale baardzo specyficzne).
Wiem, że program nie jest napisany efektywnie, jednak jest to spowodowane tym, że jest to bardzo okrojona wersja o wiele większej partii programu. Jednak nie chciałem wrzucać całego, bo wtedy na pewno nikomu nie chciałoby się tego sprawdzać.
szelus wrote:
3. Czy przestrzeń stanów masz zamknietą czy otwartą? Jeżeli zamkniętą, to użycie napisów do definiowania stanu jest mocno nieefektywne. Pamięć na AVR-ze zaraz się skończy.
Jeśli chodzi Ci o to, czy w czasie działania programu będą dodawane kolejne stany (węzły), to w wersji pierwotnej tak miało być jednak najpierw chcę zrobić tak, żeby wszystkie dane miał już wprowadzone ręcznie w kodzie programu.
szelus wrote:
4. Ponieważ ten program nic nie robi, to nie rozumiem, co znaczy, że nie działa. Testujesz to na symulatorze?
Po "wgraniu sieci" wyświetlam nazwy poszczególnych pól na wyświetlaczu i w tym momencie wyświetla już mi jakieś śmieci. Tak jakby miał jakieś problemy z pamięcią i czytał z innego miejsca niż powinien.
Używam tylko atmegi16 i żadnej pamięci zewnętrznej, poza tym sprawdzałem już też inny uC i jest to samo, a więc to raczej wina kodu, a nie sprzętu.
Jeszcze mam podejrzenie, że to może być przez wyświetlacz, którego używam, dlatego też jestem w trakcie uruchamiania RSa, żeby wykluczyć tę możliwość.
Sądziłem po prostu, że jest tutaj jakiś podstawowy błąd w programowaniu, którego ja nie widzę.
Po "wgraniu sieci" wyświetlam nazwy poszczególnych pól na wyświetlaczu i w tym momencie wyświetla już mi jakieś śmieci. Tak jakby miał jakieś problemy z pamięcią i czytał z innego miejsca niż powinien.
Wyświetlasz w którym miejscu w programie? W main przed pętla while?
Zwróć uwagę, że obiekt wez zadeklarowany w CProbabilisticNetwork::Load() jest lokalny! Po wyjściu z tej metody obiekt przestaje istnieć. Więc nie tworzysz żadnych węzłów. Chyba coś innego miałeś na myśli.
Quote:
Używam tylko atmegi16 i żadnej pamięci zewnętrznej, poza tym sprawdzałem już też inny uC i jest to samo, a więc to raczej wina kodu, a nie sprzętu.
Nie podejrzewałem sprzetu. Chodziło mi w zasadzie o to, ile masz pamięci. W 16-stce masz tylko 1kB RAMu, choć ten programik powinien się bez problemu zmieścić. Ale przy dynamicznej alokacji pamieci, a zwłaszcza przy tworzeniu obiektow na stosie trudno mieć pewność. Nie dostaniesz (jawnie) żadnego błędu gdy stos wjedzie na stertę.
W zasadzie w tym miejscu powinno być ok, ale z RAMem możesz być na styk.
Zobacz, obiekt typu network zajmuje (nie chciało mi sie liczyc dokładnie) ponad 256 bajtow! Stałe napisowe użyte w ten sposób też zużywaja RAM. Dodatkowo używasz pewnie ponad 70 bajtów pamięci dynamicznej na nazwę/stany na węzeł. Docelowo, na 15 węzłów, pamięci masz tak 2-3 razy za mało.
Mógłbyś nie używać malloc-a i na stałe umieścić tablice w węzłach, ale wtedy obiekt typu network nie zmieści się w pamięci.
Spróbuj przynajmniej zadeklarować obiekt network jako statyczny.
Wychodzi na to, że całe to "dziwne" zachowanie uC jest przez małą ilość pamięci. Przez kilka godzin bawiłem się kodem i po prostu w pewnym momencie, dodanie kolejnego elementu powoduje wysypanie się programu.
Także trzeba dokupić trochę RAMu i zobaczyć co wtedy. No i spróbować trochę zoptymalizować program, bo do tej pory raczej nie musiałem zwracać na to uwagi
Dzięki wszystkim za dotychczasową pomoc i jakby ktoś miał jeszcze jakieś sugestie jak to dobrze zoptymalizować to byłbym bardzo wdzięczny.
Także trzeba dokupić trochę RAMu i zobaczyć co wtedy. No i spróbować trochę zoptymalizować program, bo do tej pory raczej nie musiałem zwracać na to uwagi
Pisanie programów na mikrokontrolery, to trochę jak kiedyś na Atarynki czy Spektrusie - zacząć trzeba od zaplanowania w jaki sposób najlepiej wykorzystać dostępne zasoby.
Z konkretów - unikaj (najlepiej wyeliminuj wogóle) dynamiczną alokację pamięci i obiekty lokalne (chyba, że b. małe). Jeżeli potrzebujesz dynamicznych obiektów to znacznie lepiej sprawdzi się tablica statyczna i własny alokator -> np. statyczna metoda Create() w klasie (nawet wykorzystująca prostą flagę wolny/zajęty). Przeciążanie operatora new nie jest wskazane, bo nie da się zwrócić błędu, a wyjątki nie są zaimplementowane. Napisy stałej (maksymalnej, ale raczej krótkiej ) długości, itp. Wtedy z góry wiesz ile różnych obiektów Ci się zmieści w pamięci i program może być kompletnie deterministyczny.