Skocz do zawartości

[C] Problem z zapetleniem


iperius93

Pomocna odpowiedź

Witam.

Jestem początkującym programistą w języku c, napisałem program który ma zapalać po kolei 8 diod, a później w odwrotnej kolejności je gasić. To działa. Wszystkie się fajnie 🙂 zapalają po kolej a później gaszą. Ale te dwie pętle umieściłem w pętli while w warunkiem zawsze prawdziwym aby cały proces zapalania i gaszenia zapętlić. I tu jest problem, bo cykl zapalania i gaszenia diod jest wykonywany tylko raz a nie nieskończenie wiele razy.

Program do posta dodałem jako cytat (sorry, nie wiem jak inaczej dodawać ) i dlatego nie ma wcięć mam nadzieje ze się rozczytacie.

#include

#include

uint8_t i;

int main(void)

{

DDRD |= ((1<

while(1)

{

for(i=0;i<8;i++)

{

_delay_ms(1000);

PORTD |= (1<

}

for(i=7;i>-1;i--)

{

_delay_ms(1000);

PORTD &= ~(1<

}

}

}

Zapomniałem: mikrokontroler to Atmega8 a środowisko AVR Studio 4.18 , program wgrywam do uC za pomocą MkAvr Calculator przez STK200/300.

Link do komentarza
Share on other sites

for(i=7;i>-1;i--)
uint8_t i;

warunek w drugim for jest zawsze spełniony, ponieważ pętla się kręci tak długo jak i >-1 - a z racji iż jest unsigned, to po dojściu do zera się przekrąca i liczy od 65535. Zmień deklaracją zmiennej tak, aby był znak.

Link do komentarza
Share on other sites

Witam.

A co ma się dziać po tej jednej sekwencji?

Czy procek ma coś robić, ma czekać na jakiś sygnał, ma się wyłączyć?

W pierwszym (i drugim przypadku) należałoby sekwencję przenieść przed pętlę i

w pętli wpisać zadanie do wykonania (pierwszy przypadek) lub zostawić pustą

pętlę plus obsługa przerwań (drugi przypadek).

W trzecim przypadku usuwasz pętlę while i po wykonaniu sekwencji procesor się wyłączy.

Powtórzenie sekwencji odbywa się po resecie.

Pozdrawiam

Zuk

Link do komentarza
Share on other sites

W trzecim przypadku usuwasz pętlę while i po wykonaniu sekwencji procesor się wyłączy.

Powtórzenie sekwencji odbywa się po resecie.

Niby tak, ale pomiędzy wykonaniami będzie przerwa równa czasowi watchdoga+czas inicjowania i opóźnienie na starcie procesora.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

No TAK. Dzięki OldSkull. Zrobiłem tak jak mówiłeś (czyli zmieniłem na int8_t) i działa. Już wiem w czym był problem. Zuk zawartość pętli while miała się tylko zapętlać nieskończenie wiele razy i tak sobie nieskończenie wiele razy (aż do wyłączenia zasilania) zapalać diody po kolei i gasić je w odwrotnym kierunku. Jeszcze raz dzięki za pomoc.

Link do komentarza
Share on other sites

Tzn., że źle zrozumiałem pierwszy post.

Zuk napisał/a:

W trzecim przypadku usuwasz pętlę while i po wykonaniu sekwencji procesor się wyłączy.

Powtórzenie sekwencji odbywa się po resecie.

Niby tak' date=' ale pomiędzy wykonaniami będzie przerwa równa czasowi watchdoga+czas inicjowania i opóźnienie na starcie procesora.[/quote']

Po pierwsze trochę upraszczałem sytuację, po drugie zakładałem brak watchdoga.

Na jakiej podstawie tak twierdzisz?

generalnie nie ładuję do avrków systemu operacyjnego.

W momencie dotarcia do końca pętli main (np. return 0 w mainie) nic więcej w procku się nie dzieje do najbliższego resetu - program przeskakuje poziom wyżej do SO, ale jak pisałem brak SO.

Jeżeli jestem w błędzie to proszę o wyjaśnienie co dzieje się jak program trafia na return 0 w mainie.

Pozdrawiam

Zuk

Link do komentarza
Share on other sites

Na jakiej podstawie tak twierdzisz?

generalnie nie ładuję do avrków systemu operacyjnego.

W momencie dotarcia do końca pętli main (np. return 0 w mainie) nic więcej w procku się nie dzieje do najbliższego resetu - program przeskakuje poziom wyżej do SO, ale jak pisałem brak SO.

Jeżeli jestem w błędzie to proszę o wyjaśnienie co dzieje się jak program trafia na return 0 w mainie.

Zgadza się - na komputerach tak własnie jest. Jednakże w mikrokontrolerach jak słusznie zauważyłeś nie ma nadrzędnego systemu operacyjnego.

Pisałeś o wyłączeniu się procesora - on nie ma takiej funkcji - procesor realizuje dalej program i jeżeli program kończyłby się brakiem pętli, nastąpiłoby wykonywanie następnych pobranych z pamięci programu rozkazów, które byłyby bliżej nieokreślonymi wartościami pamięci czyli w konsekwencji - chaos 🙂

Kompilator GCC dla AVR dla takiego programu:

#include <avr/io.h>

int main(void)
{

DDRC	|=	(1<<PC5);

while(1){}   //pętla główna
}

wygeneruje kod:

+00000000:   C012        RJMP      PC+0x0013      Relative jump
+00000001:   C019        RJMP      PC+0x001A      Relative jump
+00000002:   C018        RJMP      PC+0x0019      Relative jump
+00000003:   C017        RJMP      PC+0x0018      Relative jump
+00000004:   C016        RJMP      PC+0x0017      Relative jump
+00000005:   C015        RJMP      PC+0x0016      Relative jump
+00000006:   C014        RJMP      PC+0x0015      Relative jump
+00000007:   C013        RJMP      PC+0x0014      Relative jump
+00000008:   C012        RJMP      PC+0x0013      Relative jump
+00000009:   C011        RJMP      PC+0x0012      Relative jump
+0000000A:   C010        RJMP      PC+0x0011      Relative jump
+0000000B:   C00F        RJMP      PC+0x0010      Relative jump
+0000000C:   C00E        RJMP      PC+0x000F      Relative jump
+0000000D:   C00D        RJMP      PC+0x000E      Relative jump
+0000000E:   C00C        RJMP      PC+0x000D      Relative jump
+0000000F:   C00B        RJMP      PC+0x000C      Relative jump
+00000010:   C00A        RJMP      PC+0x000B      Relative jump
+00000011:   C009        RJMP      PC+0x000A      Relative jump
+00000012:   C008        RJMP      PC+0x0009      Relative jump
+00000013:   2411        CLR       R1             Clear Register
+00000014:   BE1F        OUT       0x3F,R1        Out to I/O location
+00000015:   E5CF        LDI       R28,0x5F       Load immediate
+00000016:   E0D4        LDI       R29,0x04       Load immediate
+00000017:   BFDE        OUT       0x3E,R29       Out to I/O location
+00000018:   BFCD        OUT       0x3D,R28       Out to I/O location
+00000019:   D002        RCALL     PC+0x0003      Relative call subroutine
+0000001A:   C003        RJMP      PC+0x0004      Relative jump
+0000001B:   CFE4        RJMP      PC-0x001B      Relative jump
@0000001C: main
---- PROBY.c --------------------------------------------------------------------------------------
4:        {
+0000001C:   9AA5        SBI       0x14,5         Set bit in I/O register       <--- ustaw bit PC5 
+0000001D:   CFFF        RJMP      PC-0x0000      Relative jump        <--- pętla główna - kręci się w kółko w tym miejscu
+00000020:   FFFF        ???                      Data or unknown opcode
+00000021:   FFFF        ???                      Data or unknown opcode
+00000022:   FFFF        ???                      Data or unknown opcode
+00000023:   FFFF        ???                      Data or unknown opcode
+00000024:   FFFF        ???                      Data or unknown opcode

A co gdy pozbawimy program pętli głównej?

#include <avr/io.h>

int main(void)
{

DDRC	|=	(1<<PC5);
}

wtedy ujawnia się problem:

+00000000:   C012        RJMP      PC+0x0013      Relative jump
+00000001:   C019        RJMP      PC+0x001A      Relative jump
+00000002:   C018        RJMP      PC+0x0019      Relative jump
+00000003:   C017        RJMP      PC+0x0018      Relative jump
+00000004:   C016        RJMP      PC+0x0017      Relative jump
+00000005:   C015        RJMP      PC+0x0016      Relative jump
+00000006:   C014        RJMP      PC+0x0015      Relative jump
+00000007:   C013        RJMP      PC+0x0014      Relative jump
+00000008:   C012        RJMP      PC+0x0013      Relative jump
+00000009:   C011        RJMP      PC+0x0012      Relative jump
+0000000A:   C010        RJMP      PC+0x0011      Relative jump
+0000000B:   C00F        RJMP      PC+0x0010      Relative jump
+0000000C:   C00E        RJMP      PC+0x000F      Relative jump
+0000000D:   C00D        RJMP      PC+0x000E      Relative jump
+0000000E:   C00C        RJMP      PC+0x000D      Relative jump
+0000000F:   C00B        RJMP      PC+0x000C      Relative jump
+00000010:   C00A        RJMP      PC+0x000B      Relative jump
+00000011:   C009        RJMP      PC+0x000A      Relative jump
+00000012:   C008        RJMP      PC+0x0009      Relative jump
+00000013:   2411        CLR       R1             Clear Register
+00000014:   BE1F        OUT       0x3F,R1        Out to I/O location
+00000015:   E5CF        LDI       R28,0x5F       Load immediate
+00000016:   E0D4        LDI       R29,0x04       Load immediate
+00000017:   BFDE        OUT       0x3E,R29       Out to I/O location
+00000018:   BFCD        OUT       0x3D,R28       Out to I/O location
+00000019:   D002        RCALL     PC+0x0003      Relative call subroutine
+0000001A:   C005        RJMP      PC+0x0006      Relative jump
+0000001B:   CFE4        RJMP      PC-0x001B      Relative jump
@0000001C: main
---- PROBY.c --------------------------------------------------------------------------------------
4:        {
+0000001C:   9AA5        SBI       0x14,5         Set bit in I/O register
12:       }
+0000001D:   E080        LDI       R24,0x00       Load immediate
+0000001E:   E090        LDI       R25,0x00       Load immediate
+0000001F:   9508        RET                      Subroutine return        <--- tutaj problem!!!
+00000022:   FFFF        ???                      Data or unknown opcode
+00000023:   FFFF        ???                      Data or unknown opcode
+00000024:   FFFF        ???                      Data or unknown opcode
+00000025:   FFFF        ???                      Data or unknown opcode

Zaznaczyłem moment w którym powstaje problem, który w symulatorze od razu wyskakuje, gdy CPU dojdzie do zaznaczonego miejsca:

AVR Simulator: Uninitialized stack pointer used at 0x0019

AVR Simulator: Stack pointer below start of RAM

Innymi słowy, brak pętli głównej czy Return 0 nie powodują "zatrzymania się procesora" o którym piszesz, ale skok do do początku programu, a w niesprzyjających warunkach do bliżej nieprzewidywalnej części programu - można to fajnie prześledzić w symulatorze w AVR Studio.

Ale można za to wykorzystać uśpienie procesora, jako alternatywę rozwiązania, które zaproponowałeś, z tym że jeżeli nie będzie pętli nieskończonej po rozkazie uśpienia, to nie może on wyjść z uśpienia (trzeba o to zadbać) w inny sposób niż przez Watchdog, bo znowu byłby wspomniany wyżej problem.

Jednakże dla własnego bezpieczeństwa w GCC na AVR (i nie tylko) należy zawsze zapewnić pętlę nieskończoną na końcu programu, by nasz mikrokontroler w krzaki bez naszej zgody nie polazł 🙂

  • Lubię! 1
Link do komentarza
Share on other sites

Dzięki za wyjaśnienie.

Nie pamiętam, żebym kiedykolwiek potrzebował pisać program bez pętli głównej w AVRku.

Jest więc to sytuacja na prawdę wyjątkowa.

Gdzieś się tego doczytałem, a może po prostu z czasem coś mi się pomyliło.

Należałoby się "pomógł" ale musi tylko "piwo" wystarczyć.

Teraz już wiem, że w takim przypadku mam stosować pustą pętlę ZAWSZE.

Pozdrawiam

Zuk

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.