• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Problem z tablicami char
#1
Witam
Dzisiaj spotkałem się z problemem z tablicami na Arduino Uno.

Tworzę trzy tablice char:

char a[320];
char b[320];
char c[320];

tworzę sześć zmiennych int, które potem będą potrzebne mi do przetwarzania

int x, y, z, r, s, t;

teraz tworzę pętlę for:

for (int i=1; i<318; i++){

x = a[i];
y = b[i];
// z = c[i];
r = a[i+1];
s = b[i+1];
// t= c[i+1];
a[i] = a[i+1];


b[i] = b[i+1];
// c[i] = c[i+1];

}

jak zauważyliście trzy linijki zmienione są w komentarze, już tłumaczę dlaczego.
Całość oczywiście jest w głównej pętli void loop (). Gdy trzy linijki są jako komentarze cała pętla loop() jest wykonywana w nieskończoność, i taki jest zamysł cąłego projektu. Jednak jeśli którąkolwiek z linijek które są aktualnie komentarzami zamienię na normalną czyli usunę ukośniki // to pętla loop() jest wykonywana tylko dwukrotnie (sic!) i Arduino się wiesza, a właściwie nie wiem co się z nim dzieje bo przestaje cokolwiek robić. Kiedy znowu wstawię tą linię jako komentarz, wszystko działa prawidłowo.
Kolejną ciekawostką jest to, że dzieje się tak tylko z tą trzecią tablicą c[320], jeśli zmienię środek pętli for() na coś takiego:

x = a[i];
//y = b[i];
z = c[i];
r = a[i+1];
s = b[i+1];
// t= c[i+1];
a[i] = a[i+1];
b[i] = b[i+1];
// c[i] = c[i+1];

czyli w tym momencie wstawiłem komentarz do linijki drugiej y=b[i]; a usunąłem komentarz z linii trzeciej z=c[i]; to pętla loop() rónież zostanie wykonana tylko dwa razy.

Coś ktoś wie? Ktoś coś słyszał? Przepełnienie stosu? Przepełnienie pamięci? O co chodzi? Czemu dopiero po trzecim odwołaniu się do tych samych tablic?
Z tego co pamiętam (teraz nie jestem w stanie podać), ale po skompilowaniu pokazuje mi zajęte 75% pamięci.
 
Odpowiedź
#2
Objawy, które masz są typowe przy przepełnieniu stosu/sterty. Nie pokazałeś całego kodu, wiec nie wiadomo ile RAM pozera kod. To co wiadomo, to że prawie połowę pamięci zabierają tablice a, b, c. Jeśli do tego jest np wyświetlacz 128x64 mono, to kolejna połowa.
Wyświetlaj w konsoli index i zawartość tablic. Może coś zauważysz?
 
Odpowiedź
#3
Chwilowo zaprzestałem analizowania, zająłem się innymi sprawami. Ale nasunęło mi się pytanie:
"nie wiadomo ile RAM pożera kod" - czy kod nie jest umiejscowiony w zupełnie innej pamięci? w pamięci flash 32kb?
o ile dobrze wiem dane, tablice itp. są umieszczone w pamięci ulotnej - 2kb i z tego co mi się wydaje po kompilacji kodu ta zajętość pamięci ulotnej na zmienne powinna się nie zmieniać.
Czy się mylę?
W każdym razie wróciłem do podstaw i zaczynam optymalizować biblioteki - usuwać nieptrzebny balast, bo w pewnym momencie dotarłem do 80% zajętej pamięci z 2048 bajtów ("uważaj twoje arduino może przestać działać stabilnie" czy coś w ten deseń) i już w sumie nie miałem żadnego marginesu działania, a przesyłane dane z karty microSD do ekranu 4" TFT przestały odzwierciedlać rzeczywistoć a zaczęły być zastępowane jakimiś losowymi danymi.
 
Odpowiedź
#4
Po tym pytaniu sugeruję cofnąć się bardziej niż do optymalizacji bibliotek. Tworzony kod zajmuje FLASH (instrukcje i zmienne), a zmienne z flash zajmują od razu RAM, chyba że każesz trzymać je we FLASH aż do użycia i bezpośrednio przed je wczytasz do RAM (a to dodatkowe instrukcje które zajmują więcej FLASH). Ponadto RAM jest zajmowany przez obiekty tworzone przez instrukcje w czasie działania programu. Dlatego nawet 50% wolnego RAM przy kompilacji nie gwarantuje, że dopłyniesz do brzegu.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#5
(10-12-2018, 02:51)sitevnic napisał(a): nasunęło mi się pytanie:
"nie wiadomo ile RAM pożera kod" - czy kod nie jest umiejscowiony w zupełnie innej pamięci? w pamięci flash 32kb?
o ile dobrze wiem dane, tablice itp. są umieszczone w pamięci ulotnej - 2kb i z tego co mi się wydaje po kompilacji kodu ta zajętość pamięci ulotnej na zmienne powinna się nie zmieniać.

Czytając z czym masz problem i jak go rozumiesz nie potrafisz określić zajętości RAM ani bezpiecznej granicy. Nie jest to łatwe z kilku powodów:
- ile RAM zużywa uC w czasie przerwania?
- czy przerwania są zagnieżdżone?
- ile RAM zajmuje sterta w czasie działania programu?
Jeśli nie znasz odpowiedzi na powyższe pytania, to nie wiesz, czy 1 czy 99% jest bezpieczną granicą. Przykład dałem wcześniej, teraz dam jeszcze bardziej dosadny. Skompiluj kod:
Kod:
void setup() {
  // put your setup code here, to run once:
  DDRB |= _BV(PB3);
}

void loop() {
  // put your main code here, to run repeatedly:
char t[3000];

  for(uint16_t x=0; x<3000;x++) t[x] = x;
  PORTB ^= _BV(PB3);
  delay( 500 );  
}
Na UNO zajętość RAM 0% - 9 bajtów (ekran w załączniku).
Program powinien zmieniać stan portu PB3 co 500ms. Uruchom go. I co? Działa? Możesz dodać jakiś serial.print. Nie działa! Dlaczego? RAM przecież full a właśnie problemem jest brak pamięci RAM.

Jak chcesz,to mogę napisać kod, gdzie freemem pokazuje full wolnej ram a będzie jej brakować. Jeszcze inny przykład, problem zarządzania RAM w Arduino (tu zachowuje się jak Windows) spowodowany przez użycie C++ zamiast C gdzie możesz tak posiatkować pamięć, że masz wolne 7kB (w Mega2560) a nie możesz zarezerwować 256 bajtów.


PS
Do końca życia nie zrozumie dlaczego Arduino używa C++. To nie język na małe uC. Aby używać C++ na małych uC trzeba bardzo dobrze znać ten język a początkujący, bo dla nich powstało Arduino, nie znają dobrze C++, przeważnie, nie znają go wcale.


Załączone pliki Miniatury
   
 
Odpowiedź
#6
No dobra, to widzę, że zamiast startować od środka muszę wrócić kompletnie do podstaw i poczytać więcej na temat Arduino, pamięci i innych podstawowych elementów.
A już myślałem, że wystarczy jak w samochodzie nauczyć się jeździć, bez konieczności poznawania wszystkich elementów silnika, układu elektrycznego, zawieszenia itp. itd. Smile
Teraz potrzebuję więcej wolnego czasu i przesuwam mój projekt w odległą przyszłość zanim zrozumiem cokolwiek...
 
Odpowiedź
#7
(10-12-2018, 12:10)sitevnic napisał(a): A już myślałem, że wystarczy jak w samochodzie nauczyć się jeździć, bez konieczności poznawania wszystkich elementów silnika, układu elektrycznego, zawieszenia itp. itd. Smile
Jest dokładnie jak z samochodem. Aby nim jeździć, tak jak używać gotowca Arduino, czy komputera, nie trzeba znać jego budowy. Aby zbudować samochód (napisać program na Arduino) trzeba znać budowę silnika, zawieszenia, itp (znać język C++).
 
Odpowiedź
#8
Też racja!
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości