Arduino IDE pomoc w kodzie

0

Witam. Robię na arduino mini grę z przyciskami oraz zegarem, który będzie odliczał czas(minutę) do zakończenia gry. W grze losowane są diody i poprzez wciśnięcie odpowiedniego przycisku (przypisanego do diody) na wyświetlaczach doliczane są punkty. Problem mój polega na tym iż mam dwie funkcje: zegar(), który obsługuje dwa wyświetlacze 7dmio segmentowe do odliczania czasu oraz gra() w której odbywa się cały proces gry. Chciałbym zrobić aby podczas funkcji zegar() wykonywała się funkcja gra() czyli po zaczęciu gry, czas jest odliczany od 60 do 0 i gra ma się zakończyć. Nie mam bladego pojęcia jak się za to zabrać i prosiłbym o pomoc. Podaje tylko kod z tych dwóch funkcji ponieważ deklaracje zmiennych nie są ważne.

void turnOff()
{
  digitalWrite(tran1, HIGH);
  digitalWrite(tran2, HIGH);
} 

void zegar()
{
     //tran 2
  turnOff();
 
  expander3.write(displayArray[mult2]); 
  digitalWrite(tran1, LOW); 
  delay(DELAY_TIME); 
 
  //tran 1
  turnOff();
 
  expander3.write(displayArray[mult1]); 
  digitalWrite(tran2, LOW); 
  delay(DELAY_TIME); 
 
  if(millis() - czas >= 1000)
  {
    czas = millis();
    mult1--; 
 
    if ( mult1 == 0 ) 
   {
     mult1 = 9; 
     mult2--; 
   }
    if ( mult2 == 0 ) 
    { 
      mult1 = 0; 
      mult2 = 0;     
    } 
   
  }
}

void gra()
{
  if(digitalRead(bs) == LOW)
    {
      
       digitalWrite(ds, HIGH);
          iter = 0;
          iter2 = 0;
          expander.write(displayArray[iter]);
          expander2.write(displayArray[iter2]);
          delay(3000);
          
   
          for(k = 0; k < 25; k++)
          {  
              dioda = random()%4;
              digitalWrite(d[dioda], HIGH);
              int val = digitalRead(d[dioda]);
              delay(random(300,1000));
              digitalWrite(d[dioda], LOW);
              
      
              if(digitalRead(b[0]) == LOW || digitalRead(b[1]) == LOW || digitalRead(b[2]) == LOW || digitalRead(b[3]) == LOW)
              {
                //          LOW-wcisniety    HIGH-zapalona
                
                    if(digitalRead(b[0]) == LOW)
                    {
                      if(dioda==0)
                      {
                        punkty++;
                        iter2++;
                        expander2.write(displayArray[iter2]); 
                        if ( iter2 == 10 ) 
                        {
                        iter2 = 0; 
                        iter++;
                        expander.write(displayArray[iter]);
                        expander2.write(displayArray[iter2]);
                        } 
                        delay(1000);
                        Serial.print("pierwsza: ");
                        Serial.println(punkty);
                        //goto koniec;
                      }
                    }
                    if(digitalRead(b[1]) == LOW)
                    {
                      if(dioda==1)
                      {
                        punkty++;
                        iter2++;
                        expander2.write(displayArray[iter2]); 
                        if ( iter2 == 10 ) 
                        {
                        iter2 = 0; 
                        iter++;
                        expander.write(displayArray[iter]);
                        expander2.write(displayArray[iter2]);
                        } 
                        delay(1000);
                        Serial.print("druga: ");
                        Serial.println(punkty);
                        //goto koniec;
                      }
                    }
                    if(digitalRead(b[2]) == LOW)
                    {
                      if(dioda==2)
                      {
                        punkty++;
                        iter2++;
                        expander2.write(displayArray[iter2]); 
                        if ( iter2 == 10 ) 
                        {
                        iter2 = 0; 
                        iter++;
                        expander.write(displayArray[iter]);
                        expander2.write(displayArray[iter2]);
                        } 
                        delay(1000);
                        Serial.print("trzecia: ");
                        Serial.println(punkty);
                        //goto koniec;
                      }
                    }
                    if(digitalRead(b[3]) == LOW)
                    {
                      if(dioda==3)
                      {
                        punkty++;
                        iter2++;
                        expander2.write(displayArray[iter2]); 
                        if ( iter2 == 10 ) 
                        {
                        iter2 = 0; 
                        iter++;
                        expander.write(displayArray[iter]);
                        expander2.write(displayArray[iter2]);
                        } 
                        delay(1000);
                        Serial.print("czwarta: ");
                        Serial.println(punkty);
                      }
                    }

                    koniec:
                    delay(1000);                    
              }
              else
              {
                delay(1000);                
              }
              
          }
          digitalWrite(ds, LOW);
          }
}

void loop()
{
 gra();
  
    
}; 
0

Opcji masz co najmniej kilka.
Tak pare z głowy poniżej.

  • Cykliczne przerwanie co sekundę, odświeżające wartość na LCD.
  • Przełączanie kontekstu aka. multitasking. nieco bardziej zaawansowana opcja, ale zadziała znakomicie, w skrócie Round Robin (multiplexer karuzelowy) + taski cykliczne.

BTW. Jeśli nie masz absolutnie takiej potrzeby, porzuć Arduino IDE (na rzecz oczywiście zwykłego C), jest dosyc kiepawe.

0

Wybacz, ale dla mnie to co napisałeś to czarna magia ...

1

Spoko, rozumiem, też nie ogarniam jakoś super AVRów. Generalnie chcesz aby twoje Arduino robiło dwie rzeczy na raz, tak? Potrzeba ci coś w stylu wątków, bądź zadań. Nie dam uciąć sobie głowy że jest to jedyne rozwiązanie, prawdopodobnie da się to zrobić łatwiej. W każdym razie, nieco zbyt dużo tłumaczenia jak na jeden post, i proponuje abyś się trochę sam w temat zagłębił, słowa klucze: Arduino Multitasking, Arduino Context Switch

1

Koszmarnie duplikujesz kod. Zrefaktoruj go w taki sposób, aby pozbyć się duplikatów, wtedy rozwiązanie stanie się łatwiejsze do dostrzeżenia.
Rozwiązania są dwa:

  • (strzelanie z armaty do muchy) możesz skonfigurować i podczepić się pod któreś z przerwań od zegara i wykonywać w jego obsłudze (takim timerze) swój kod. Rozwiązanie o tyle słabe, że z asynchronicznie wykonywanego kodu i tak nie możesz zamknąć innego "wątku", musiałbyś ustawiać jakąś flagę, a w głównym kodzie sprawdzać jej stan i w razie czego wychodzić z głównej pętli;
  • (strzał gazetą w muchę) przed startem pętli pobierasz czas startu, potem co iteracja pętli pobierasz ten czas ponownie i sprawdzasz, czy upłynął pewien odcinek czasu, jeśli tak to z pętli wychodzisz przerywając grę; podobne wymagania jak w poprzednim rozwiązaniu, a nie musisz nic kombinować z obsługą przerwań.
    Grunt to dobranie właściwego rozwiązania do problemu. Twój problem jest prosty, więc i rozwiązanie do niego powinno być takie.
0

Przy drugim sposobie rozumiem, że w pętli loop na początku pobieram czas np. 60 sekund i później go dekrementuje tak ?

1

Nie. Skąd będziesz wiedział, że upłynęła dokładnie jedna sekunda? Przecież nie wiesz, ile czasu wykonują się poszczególne instrukcje Twojego kodu. Użyj np. millis() (zwraca ilość milisekund od uruchomienia kontrolera) - na starcie programu zapamiętaj tą wartość, a w pętli co iterację sprawdzaj, czy bieżąca wartość nie jest większa od zapamiętanej plus 60s i wtedy kończ pętlę gry.
To są podstawy programowania. Jeśli tego nie ogarniasz, to naucz się najpierw programować w łatwiejszym środowisku na PC.

0

@ŁF nie znam Arduino, ale jeśli milis zwraca czas od uruchomienia to znaczy, że i tak jest tam pod spodem jakiś działający już timer, więc jeden pies do którego się Autor podepnie.

0

A co to ma do rzeczy?

0

Dobra już rozumiem, no ale teraz gdzie ja mam wstawić funkcję, która będzie mi wyświetlacz pozostały czas na wyświetlaczach?

0

Do swojego kodu.

0

Zrobiłem coś takiego :

czas1 to funkcja millis()
czas 2 = 0 

i do loop wstawiłem

if(czas1 - czas2 <= 60000)
{
  czas2 = czas1;
reszta programu
}
else
{
kod do zakończenia gry
}

o to chodzi ?

1

Mniej-więcej tak. Ale ten kod nie zadziała, bo na dzień-dobry czas1-czas2 >> 60000, a potem czas2 - czas1 będzie zawsze oscylować w okolicach zera. Weź to przemyśl, uruchom, podebuguj, wykaż trochę samodzielności i twórczego myślenia.

Nie nazywaj zmiennych czas1, czas2, bo to do niczego nie prowadzi (ani numerki, ani polskie nazwy). Jedną nazwij startTime, druga zmienna niezbyt będzie potrzebna, ale dla przejrzystości kodu możesz zrobić currentGameDuration. Na starcie startTime = milis(), w pętli currentGameDuration = milis() - startTime. Jeśli currentGameDuration >= MaxGameDuration (MaxGameDuration to stała o wartości 60000), to koniec gry.
Więcej nie podpowiadam, bo problem jest naprawdę mało skomplikowany.

0
unsigned long startTime = millis();       
if(currentGameDuration <= MaxGameDuration)
{
currentGameDuration = millis() - startTime ;
reszta kodu 
}
else
{zakończenie
} 

I to mi nie działa. Tak wiem, że nie jestem mistrzem programowania ale zależy mi na tym i próbowałem na wiele sposobów to zrobić i dalej nic ...

0

Co to znaczy "nie działa"... Człowieku, czytaj komunikaty o błędach ze zrozumieniem. Gdzie masz definicję typu dla currentGameDuration? Gdzie masz definicję typu i wartości dla stałej MaxGameDuration? Nie przeklejaj bezmyślnie, a jak już to robisz, to CZYTAJ ZE ZROZUMIENIEM BŁĘDY ZGŁASZANE PRZEZ KOMPILATOR!!!

A to już mistrzostwo świata - nawet nie przepisałeś w prawidłowej kolejności tego, co napisałem:

if(currentGameDuration <= MaxGameDuration)
{
currentGameDuration = millis() - startTime ;
}

Ty kompletnie nie rozumiesz co robisz.

0

To że nie działa nie miałem na myśli, że wyskakują mi błędy i nie potrafię ich rozwiązać, aż tak głupi nie jestem. Program mi się kompiluje jednak nie robi tego co powinien i pisałem, że nie jestem dobry z programowania więc próbuję różnych sposobów. Tego nie napisałem ale currentGame jest zdefiniowane jako 0.

0

CurrentGameDuration nie "jest zdefiniowane jako 0", tylko w danym momencie ma wartość 0. Jeśli właśnie zaczynasz grę, to jak sądzisz, ile czasu ona trwa?

const unsigned long MaxGameDuration = 60 * 1000;

void MakeMove()
{
    // obsługa ruchu gry lub gracza
}


bool IsGameWon()
{
    // sprawdzenie warunków na to, czy graczowi udało się wygrać i zwrócenie wyniku
    return true / false; // tu domyślisz się dlaczego kod się nie kompiluje
}


void DisplayCurrentGameDuration(unsigned long currentGameDuration)
{
    // tu wyświetl sobie gdzieś zawartość currentGameDuration zawierającą czas gry w sekundach
}


void DisplayGameWon()
{
    // tu wyświetl, że gracz wygrał, możesz przekazać currentGameDuration i wypisać, że wygrał tyle i tyle w takim a takim czasie
}

void DisplayGameLost()
{
    // tu wyświetl, że gracz jest pierdołą i przegrał
}


bool MakeMoveAndCheckForWinning(unsigned long currentGameDuration)
{
    MakeMove(currentGameDuration);
    DisplayCurrentGameDuration(currentGameDuration);
    return IsGameWon();
}

void main()
{
    bool finished = false;
    bool gameWon = false;

    while (!finished && !gameWon)
    {
        unsigned long currentGameDuration = millis() - startTime;

        gameWon = MakeMoveAndCheckForWinning(currentGameDuration);
        finished = currentGameDuration > MaxGameDuration;

        delay(100); // daj kontrolerowi i peryferiom odpocząć
    }

    if (gameWon)
        DisplayGameWon();
    else
        DisplayGameLost();
}

Pisane z palca, raczej chodziło o pokazanie idei niż napisanie całości.

1 użytkowników online, w tym zalogowanych: 0, gości: 1