Skocz do zawartości

Problem z wyjściem z pętli nieskończonej


Pomocna odpowiedź

Napisano

Witajcie, studiuje wszystkie części poradnika o wskaźnikach i strukturach p. Kardasia, gdzie efektem ubocznym ma być gra snake. Gra działa, sterowanie, ekrany startowe i końcowe również. Jednak zaczynam się samemu bawić, przerabiając ich wygląd itp. Jedną z opcji, którą chciałem to, aby ekran nie znikał po czasie zadanym w _delay_ms jak jest orginalnie w poradniku, tylko, aby reagował na naciśnięcie klawisza, wtedy gra ma się rozpocząć. I tu pojawił się problem. Miałem troszkę przerwy od programowania i sporo rzeczy wyleciało z głowy i ciężko mi się czasem myśli  Oto jak kombinuje to rozwiązać.

void display_init( uint8_t usr_cnt ) {
        lcd_locate(0,0);
        lcd_str("****************");
        lcd_locate(1,0);
        lcd_str("*     SNAKE    *");
        lcd_locate(2,0);
        lcd_str("*  PRESS  KEY  *");
        lcd_locate(3,0);
        lcd_str("****************");
        while(1){
                IR_EVENT();
                if(command == 1)break;
               
        }
        lcd_cls();
}

Wrzucam pętle nieskończoną, aby zatrzymać ekran, w środku pętli wywołuje zdarzenie, które bada, czy nadleciała jakaś ramka. W ifie sprawdzam czy kod się zgadza, jeśli tak to program ma wyjść z pętli, a jednak tego nie robi. Kombinowałem na kilka innych sposobów, ale nie potrafie znaleźć rozwiązania wyjścia z pętli.
Ktoś podpowie, co robię nie tak ?

Gdy zamiast pętli jest zwykły delay, to po zakończeniu oczekiwania gra się uruchamia. 

(edytowany)

Return nie dziala??...no to zamiast jedynki daj jakas zmienna ktora bedzie w warunku while..

bool zmienna = 0;

while(zmienna == 0){
    IR_EVENT();
    if(command == 1) {
    zmienna = 1;
    }
}

Chociaz w twoim przypadku lepszy jest break, bo konczy while i wszystko dalej sie wykonac ma, z return to nie wykonala by sie ta funkcja po while i bys wyskoczyl z tej glownej funkcji...hmm, dziwne ze nie dziala ani jedno ani drugie🤔 a jestes pewny ze guzik dziala i "command" zostaje zmienione??

Edytowano przez farmaceuta

Nie, to nie działa. Muszę się zastanowić jak działa dokładnie ta biblioteka do IR, bo gdy na tym ekranie wyświetlam zmienną command to mam cały czas 0. Jakby nie odbierał ramek, choć TSOP działa. 

(edytowany)
13 minut temu, Krawi92 napisał:

  bo gdy na tym ekranie wyświetlam zmienną command to mam cały czas 0. 

A no wlasnie, czyli returny brejki i inne wynalazki zapewne dzialaja, a problem to ze nie wykrywasz wcisniecia guzika...nie korzystam z IR wiec i nic nie doradze..

Edytowano przez farmaceuta
(edytowany)

Na razie przetestuje, jak to działa jak microswitcha podłącze i na nim zrobie warunek. Pewnie zadziała normalnie.

No i na sztywno jak microswitch podłączę to OK, działa. 

Edytowano przez Krawi92
(edytowany)

Przerwania masz włączone? Callback pod obsługę IR podpięty? IR też musisz mieć "pewny" w sensie czy wgl przylatuje command == 1

Edytowano przez _LM_

Zrobie obiad i opiszę jak działa ta biblioteka tj. ile z niej kumam. Bo normalnie IR działa, jak gra uruchomi się to sterowanie jest, a przy ekranie początkowym nie mam. Zaraz wkleję trochę więcej kodu. Wczoraj dopiero łyknąłem trochę o callbackach i jeszcze nie bardzo wiem jak sobie radzić. 

To może zacznijmy co to ten IR_EVENT

void IR_EVENT(void) {

	if( Ir_key_press_flag ) {

		Ir_key_press_flag=0;

		// wywo³anie w³asnej funkcji obs³ugi u¿ytkownika jeœli
		// uprzednio zosta³a ona zarejestrowana

		if(ir_event_callback) (*ir_event_callback)(address, command, key_time);


		address=0xff;
		command=0xff;

	}
}

No więc musimy napisać i zarejestrować własną funkcje do obsługi IR.

Więc w pliku main mam taką oto funkcję:

void snake_ir_keys(uint8_t adr,uint8_t cmd,uint8_t key_time){
	if (command == snakes(0)->keys[left]) snakes(0)->direction = left;
	else if (command == snakes(0)->keys[right]) snakes(0)->direction = right;
	else if (command == snakes(0)->keys[up]) snakes(0)->direction = up;
	else if(command == snakes(0)->keys[down]) snakes(0)->direction = down;
	//else if (command == KEY_OK) restart = 1;
}

Stała KEY_OK ma wartość 1. Ogólnie powinienem mieć 6 klawiszy, niestety mam zlutowany pilot RC5 tylko na 5. Pierwotnie command == 1 miał restartować grę, gdy wyświetli się ekran końcowy, gdy przegramy. Wtedy wciskamy restart, włącza nam się główny ekran i rusza gra. Zakomentowałem tą linie, bo pomyślałem ze może to robić jakiś konflikt, jeśli będzie sie zmieniała ta zmienna restart w nieodpowiednim momencie, jednak to nic nie daje.

register_ir_event_callback(snake_ir_keys);

w main zarejestrowałem funkcję.

do ekranów początkowych i końcowych również mam callbacki, taka możliwość, aby móc samemu tworzyć jakiś własny ekran.

register_start_screen_callback(display_init);
register_end_screen_callback(ekran_koncowy);

funkcje display_init i ekran_koncowy znajdują się w osobnym pliku ekrany.c

I w tym właśnie pliku próbuje użyć podczerwieni, a mi się to nie udaję. 

Pętla nieskończona w pliku main w sumie składa się tylko z tego:

while(1){
		IR_EVENT();
		if(!timer1){
			if(snakes(0)->draw_snake_fun)snakes(0)->draw_snake_fun(snakes(0));

			timer1=70;
		}

Wywołujemy zdarzenie IR_EVENT, które bada czy nie nadleciała jakaś ramka, w timerze wywołujemy poprzez wskaźnik funkcje do rysowania węża.

(edytowany)

Może byś odpowiedział na zadane pytania, zdaje się że to jest kluczowe. Co ci po dziesiątkach linii kodu jak z prostej pętli nie można wyjść? 

Edytowano przez _LM_

Callback mam włączony, przerwania też, podczas gry, kiedy wąż jest rysowany sterowanie działa, komendy przylatują. Po zakończeniu gry gdy przegram, command == 1 resetuje grę od początku. Więc takto działa ok, problem tylko ze nie przylatują żadne ramki gdy jestem w ekranie początkowym 

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "lcd.h"
#include "SNAKE/snake.h"
#include "IR_UNI/ir_config.h"
#include "uart.h"
#include "ekrany.h"

void snake_ir_keys(uint8_t adr,uint8_t cmd,uint8_t key_time);

volatile uint16_t timer1;
int main (){
	PORTD |= (1<<PD7);
	register_ir_event_callback(snake_ir_keys);
	check_and_load_defaults();
	USART_Init(__UBRR);
	ir_init();
	lcd_init();
	register_start_screen_callback(display_init);
	register_end_screen_callback(ekran_koncowy);
	snake_init(1);
	// konfiguracja timera//
	TCCR0 |= (1 << WGM01); // tryb ctc
	TCCR0 |= (1<< CS00)|(1<<CS02); // prescaler 1024
	OCR0 = 78;
	TIMSK |= (1 << OCIE0);



	sei();

 

Tak jak myślałem 😉 zobacz w której linii jest Snake init a w której globalne zezwolenie na przerwania. Bo zakładam ze w "poczęciu" węża program wisi? 

  • Pomogłeś! 1

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