Skocz do zawartości

Kostka do gry


Lech

Pomocna odpowiedź

Witajcie. Zrobiłem pierwszy projekt na Arduino, i potrzebuję wyjaśnić pewne wątpliwości.

Na początek schemat urządzenia:Kostka.pdf  i wygląd prototypu: 20200413_194638.thumb.jpg.2e7f4753d458d6ca0c1305c11ec5a6ab.jpg

Przygotowałem dwa warianty kodu:

Pierwszy, w  którym po włączeniu układ wskazuje gotowość poprzez miganie kropki dziesiętnej na wyświetlaczu, potem po wciśnięciu przycisku wyświetlacz symuluje losowanie i na koniec zwraca wylosowaną  cyfrę,  generuje sygnał dźwiękowy i miga kropką zachęcając do ponownego losowania.

Co zaobserwowałem a co mnie dziwi: Jeśli jako ziarno funkcji losowej wziąłem wejście analogowe (0), to w przypadku wielokrotnego losowania raz po razie bardzo często pada ta sama liczba. Przy podłączeniu do pinu zero kawałka przewodu jako antenki,  powtarza się to, ale z mniejszą częstotliwością.  Jeśli ziarno weźmie się z funkcji millis(), powtórki się trafiają, ale rzadziej. Niby OK, zrozumiał bym powtórzenie kilka razy ale nie kilkanaście.  Ma ktoś pomysł jak zwiększyć chaos w tym losowaniu?

Druga rzecz - żeby rozpocząć losowanie przycisk trzeba przytrzymać odpowiednio długo - około sekundy. Związane to jest (chyba) z tym, że program musi sczytać pin w odpowiednim miejscu.. mam rację?

Trzecia sprawa - ani razu  w kilkuset losowaniach nie padła szóstka.  Czy random(1,6) podaje liczbę włącznie z 6? Jedynka pada, więc chyba tak? Statystycznie powinna przecież kiedyś wypaść?

Pierwszy wariant:

#define SEG_A 7
#define SEG_B 8
#define SEG_C 12
#define SEG_D 11
#define SEG_E 10
#define SEG_F 5
#define SEG_G 6
#define KR 9

 

void setup() {
  pinMode (5, OUTPUT); 
  pinMode (6, OUTPUT);
  pinMode (7, OUTPUT);
  pinMode (8, OUTPUT);
  pinMode (9, OUTPUT);
  pinMode (10, OUTPUT);
  pinMode (11, OUTPUT);
  pinMode (12, OUTPUT);
  pinMode (A5, OUTPUT); // ustawia pin A5 na wyjście buzzera
  pinMode (3, INPUT_PULLUP); //ustawia pin 3 jako  przycisk z podciągnięciem

  digitalWrite (SEG_A, HIGH);  // gasi wyświetlacz przed starterm zabawy
  digitalWrite (SEG_B, HIGH);  // Wartość HIGH jest bo wyświetlacz ma wspólny plus i podanie plusa na zasilanie przerywa obwód
  digitalWrite (SEG_C, HIGH);
  digitalWrite (SEG_D, HIGH);
  digitalWrite (SEG_E, HIGH);
  digitalWrite (SEG_F, HIGH);
  digitalWrite (SEG_G, HIGH);
  digitalWrite (KR, HIGH);


}

void loop() {                             //Mryga kropką aż zostanie wsciśnięty przycisk na pinie 3
    do {
      digitalWrite (KR, HIGH);
      delay(500);
      digitalWrite (KR, LOW);
      delay(500);
      digitalWrite (KR, HIGH);
      } while (digitalRead(3) == HIGH);  


  digitalWrite (SEG_A, HIGH);  // gasi wyświetlacz przed losowaniem
  digitalWrite (SEG_B, HIGH);  // Wartość HIGH jest bo wyświetlacz ma wspólny plus i podanie plusa na zasilanie przerywa obwód
  digitalWrite (SEG_C, HIGH);
  digitalWrite (SEG_D, HIGH);
  digitalWrite (SEG_E, HIGH);
  digitalWrite (SEG_F, HIGH);
  digitalWrite (SEG_G, HIGH);
  digitalWrite (KR, HIGH);

                            
  digitalWrite (SEG_A, LOW);             //Robi trzy pętle po wyswietlaczu jako symbol losowania
  delay(250);   
  digitalWrite (SEG_A, HIGH);
  digitalWrite (SEG_B, LOW);
  delay(250);   
  digitalWrite (SEG_B, HIGH);
  digitalWrite (SEG_C, LOW);
  delay(250);   
  digitalWrite (SEG_C, HIGH);
  digitalWrite (SEG_D, LOW);
  delay(250);   
  digitalWrite (SEG_D, HIGH);
  digitalWrite (SEG_E, LOW);
  delay(250);   
  digitalWrite (SEG_E, HIGH);
  digitalWrite (SEG_F, LOW);
  delay(250);   
  digitalWrite (SEG_F, HIGH);
  digitalWrite (SEG_A, LOW);             
  delay(250);   
  digitalWrite (SEG_A, HIGH);
  digitalWrite (SEG_B, LOW);
  delay(250);   
  digitalWrite (SEG_B, HIGH);
  digitalWrite (SEG_C, LOW);
  delay(250);   
  digitalWrite (SEG_C, HIGH);
  digitalWrite (SEG_D, LOW);
  delay(250);   
  digitalWrite (SEG_D, HIGH);
  digitalWrite (SEG_E, LOW);
  delay(250);   
  digitalWrite (SEG_E, HIGH);
  digitalWrite (SEG_F, LOW);
  delay(250);   
  digitalWrite (SEG_F, HIGH);
  digitalWrite (SEG_A, LOW);             
  delay(250);   
  digitalWrite (SEG_A, HIGH);
  digitalWrite (SEG_B, LOW);
  delay(250);   
  digitalWrite (SEG_B, HIGH);
  digitalWrite (SEG_C, LOW);
  delay(250);   
  digitalWrite (SEG_C, HIGH);
  digitalWrite (SEG_D, LOW);
  delay(250);   
  digitalWrite (SEG_D, HIGH);
  digitalWrite (SEG_E, LOW);
  delay(250);   
  digitalWrite (SEG_E, HIGH);
  digitalWrite (SEG_F, LOW);
  delay(250);   
  digitalWrite (SEG_F, HIGH);

 delay(1000);
  //randomSeed(analogRead(0));   //ziarno losowania zbiera śmieci z pinu 0
  randomSeed(millis());    //ziarno losowania - stoper wewnętrzny
 int liczba = random(1,6);    // Losuje liczbę od 1 do 6
  //Petla od 0 do 9
//  for (i = 0; i < 10; i++) {
   wyswietlacz(liczba); //Wyswietl wartosc na wyswietlaczu
    delay(500); //Poczekaj 500 ms
 // }
}
 
void wyswietlacz(int cyfra) {
  //Instrukcja switch ustawia odpowiednie stany na wyjsciach
  //w zaleznosci od podanej cyfry
  switch (cyfra) {
    case 0:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, LOW);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, HIGH);
    break; 
    
    case 1:
        digitalWrite(SEG_A, HIGH);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, HIGH);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, HIGH);
    break; 
    
    case 2:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, HIGH);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, LOW);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, LOW);
    break; 
    
    case 3:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, LOW);
    break; 
    
    case 4:
        digitalWrite(SEG_A, HIGH);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, HIGH);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
    break; 
    
    case 5:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, HIGH);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
    break; 
    
    case 6:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, HIGH);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, LOW);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
    break;
   
    case 7:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, HIGH);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, HIGH);
    break;
    
    case 8:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, LOW);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
    break;
    
    case 9:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
    break;
  }
  tone (A5,400);
  delay (200);
  noTone (A5);
}

Drugi wariant to wariant z zastosowaniem przerwania.  Przerwanie zastosowałem, żeby wyeliminować problem długiego naciskania przycisku do startu losowania. Tutaj pojawiły się pewne problemy, bo nie mogę użyć poza pętlą loop czegokolwiek co zawiera opóźnienia... niby w  instrukcji piszą że funkcja wywołana przez przerwanie nie realizuje opóźnień, to nawet jak wstawiam dalej, na końcu to niestety nie działa.  Tak więc drugi kod jest bez bajerów typu brzęczyk i symulacja losowania.  Reaguje pięknie na krótkie naciśnięcie przycisku, ale:  czasami po naciśnięciu przycisku potrafi przeskoczyć przez dwie cyfry, a czasem nie zareagować wcale.  Moje podejrzenie to stany nieustalone na przycisku, po prostu zbocze bardziej przypomina jeża niż normalne zbocze opadające.  Albo coś zwaliłem w kodzie.  Dodatkowo tak samo jak za pierwszym razem nie padła szóstka.  Ani razu.  Zastanawiam się też, bo tego do końca nie rozumiem: Czy stosując przerwanie  nie powinno się już do końca programu korzystać z "delay ()"?

Drugi wariant:

#define SEG_A 7   //przypisanie segmentów wyświetlacza do poszczególnych pinów
#define SEG_B 8
#define SEG_C 12
#define SEG_D 11
#define SEG_E 10
#define SEG_F 5
#define SEG_G 6
#define KR 9

 
void setup() {
  pinMode (5, OUTPUT);   //ustawienie pinów na wjścia
  pinMode (6, OUTPUT);
  pinMode (7, OUTPUT);
  pinMode (8, OUTPUT);
  pinMode (9, OUTPUT);
  pinMode (10, OUTPUT);
  pinMode (11, OUTPUT);
  pinMode (12, OUTPUT);
  pinMode (A5, OUTPUT); // ustawia pin A5 na wyjście buzzera
  pinMode (3, INPUT_PULLUP); //ustawia pin 3 jako  przycisk z podciągnięciem
  attachInterrupt(digitalPinToInterrupt(3), start, FALLING); // Przerwanie reagujące na zbocze malejące na pinie 3

  digitalWrite (SEG_A, HIGH);  // gasi wyświetlacz przed starterm zabawy
  digitalWrite (SEG_B, HIGH);  // Wartość HIGH jest bo wyświetlacz ma wspólny plus i podanie plusa na katode wyświetlacza przerywa obwód
  digitalWrite (SEG_C, HIGH);
  digitalWrite (SEG_D, HIGH);
  digitalWrite (SEG_E, HIGH);
  digitalWrite (SEG_F, HIGH);
  digitalWrite (SEG_G, HIGH);
  digitalWrite (KR, HIGH);
}


void loop() {                             //Mryga kropką aż zostanie wsciśnięty przycisk na pinie 3
       digitalWrite (KR, HIGH);
      delay(500);
      digitalWrite (KR, LOW);
      delay(500);
      digitalWrite (KR, HIGH);
      } 
      
void start(){
  randomSeed(analogRead(0)); // ziarno losowania - zbiera śmieci z pinu 0
 int liczba = random(1,6);    // Losuje liczbę od 1 do 6
   wyswietlacz(liczba); // Wyswietla wartosc na wyswietlaczu
      }
void wyswietlacz(int cyfra) {
 
  switch (cyfra) {                     //Instrukcja switch ustawia odpowiednie stany na wyjsciach w zaleznosci od podanej cyfry
    case 0:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, LOW);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, HIGH);
    break; 
    
    case 1:
        digitalWrite(SEG_A, HIGH);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, HIGH);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, HIGH);
    break; 
    
    case 2:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, HIGH);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, LOW);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, LOW);
    break; 
    
    case 3:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, LOW);
    break; 
    
    case 4:
        digitalWrite(SEG_A, HIGH);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, HIGH);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
    break; 
    
    case 5:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, HIGH);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
    break; 
    
    case 6:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, HIGH);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, LOW);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
    break;
  }
}

 

Link do komentarza
Share on other sites

Dnia 13.04.2020 o 20:25, Lech napisał:

nie padła szóstka.  Ani razu

Zamiast 

int liczba = random(1,6);

napisz

int liczba = random(1,7);

Dnia 13.04.2020 o 20:25, Lech napisał:

przycisk trzeba przytrzymać odpowiednio długo - około sekundy

digitalWrite (KR, HIGH);

delay(500);

digitalWrite (KR, LOW); 

delay(500); 

digitalWrite (KR, HIGH);

Może po prostu program w tym czasie wykonuje ten odcinek .

Dnia 13.04.2020 o 20:25, Lech napisał:

jak zwiększyć chaos w tym losowaniu?

Wiem że to nie jest praktyczny sposób ale możesz przy każdym losowaniu poruszać antenką.

 

Link do komentarza
Share on other sites

(edytowany)

Dzięki,

Cytat

Zamiast 

int liczba = random(1,6);

napisz

int liczba = random(1,7);

Faktycznie jest tak, że  górną granicę trzeba zwiększyć o 1.  Moja wina, nie doczytałem w Arduino Reference

 

Co do powtórzeń losowanych liczb - patent z antenką jest raczej mało realny  poza stołem warsztatowym.  Co sądzicie o pomyśle podania na to wejście np. szumu  białego. Akurat nie mam takiego przyrządu w warsztacie, ale prosty generator można zrobić na tranzystorach, przynajmniej tak twierdzi pewien znany w kraju producent kitów elektronicznych...

Edytowano przez Lech
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.