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

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • 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.