Slot Game könnte mir bitte jemand weiterhelfen?

Ich versuche für meinen Sohn eine Slotmachine zu bauen. Nun mein Problem ist das ich die Simulation der Walzen etwas größer brauche. Ich habe 4 Stück Matrix Dot Display im Einsatz. Der Effekt wird aber leider nur auf den ersten 4 Dot Display in 8x8 abgespielt. Dieser müsste aber größer sein und alle 4x4 Dot Display nutzen. Ich wäre sehr dankbar wenn mir jemand dabei behilflich sein könnte.

Viele Grüße Marcus

#include <MD_MAX72xx.h>
#include <SPI.h>

// Use the MD_MAX72XX library to implements a slot machine 
// type display with scrolling symbols and simple sound effects.
// When numbers change they are scrolled up or down as if on a cylinder.
//
// Switch is on the SW_PIN digital input, buzzer driver by the toen() on 
// BUZZ_PIN digital output.
//

#include <MD_MAX72xx.h>
#include <MD_UISwitch.h>
#include <SPI.h>
#include "FontSymbols.h"

#define ALWAYS_WIN 0 // for testing
#define DEBUG 0

#if DEBUG
#define PRINT(s, v)  do { Serial.print(F(s)); Serial.print(v); } while (false);
#define PRINTX(s, v) do { Serial.print(F(s)); Serial.print(v, HEX); } while (false);
#define PRINTS(s)    do { Serial.print(F(s)); } while (false);
#else
#define PRINT(s, v)
#define PRINTS(s)
#endif

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(0) (sizeof(0)/sizeof((0)[0]))
#endif

#define SYMBOL_SIZE_PIXELS 16
#define SYMBOL_SIZE_BYTES ((SYMBOL_SIZE_PIXELS) << 1)

#define X_SEGMENTS   4
#define Y_SEGMENTS   4


int Motor (4);
 


#include <Stepper.h>

const int stepsPerRevolution = 400;  // change this to fit the number of steps per revolution
// for your motor

const int rolePerMinute = 40;         // Adjustable range of 28BYJ-48 stepper is 0~17 rpm

// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, 6, 9, 8, 10);




// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
const uint8_t MAX_DEVICES = 16;

const uint8_t CLK_PIN = 13;  // or SCK
const uint8_t DATA_PIN = 12; // or MOSI
const uint8_t CS_PIN = 11;   // or SS

// SPI hardware interface
//MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Arbitrary pins
MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

// Tone buzzer definition
const uint8_t  BUZZ_PIN = 3;    // pin
const uint16_t BUZZ_FREQ = 200; // frequency
const uint8_t  BUZZ_TIME = 12;   // duration


// Switch definition
const uint8_t SW_PIN = 7;

MD_UISwitch_Digital S(SW_PIN);

// Tumbler animation definitions
const uint32_t TIME_BASE = 1000;      // base animation time in milliseconds
const uint32_t TIME_INCREMENT = 800;  // units of time increments for random duration
const uint32_t TIME_FRAME_DELAY = 30; // in milliseconds

// Display parameters
const uint8_t SPACING = 1;        // pixels between characters
const uint8_t SYMBOL_COLS = 7;    // should accomodate the fixed width font columns
const uint8_t MAX_SYMBOLS = 4;    // number of slot machine symbols
const uint8_t TOTAL_SYMBOLS = 3; // total number of symbols in the font file (exclude 0)

// Structure to hold the data for each symbol to be displayed and animated
// this could be expanded to include other character specific data (eg, column
// where it starts if display is spaced irregularly).
typedef struct
{
  enum:uint8_t { ST_INIT, ST_WAITFRAME, ST_ANIM, ST_END } state;
  uint8_t oldValue, newValue;   // code for the value for the symbol
  uint8_t index;                // animation progression index
  bool    scrollUp;             // scroll up animation flag
  uint32_t timeDuration;        // total animaton duration for this symbol
  uint32_t timeStart;           // time the animation started
  uint32_t timeLastFrame;       // time the last frame started animating
  uint8_t cols;                 // number of valid cols in the charMap
  uint8_t charMap[SYMBOL_COLS]; // blended character font bitmap
}  symbolData_t;

symbolData_t symbol[MAX_SYMBOLS];

void updateDisplay(bool bInvert = false)
// do the necessary to display current bitmap buffer to the LED display
{
  uint8_t   curCol = 0;

  mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
  mx.clear();

  for (int8_t i = MAX_SYMBOLS - 1; i >= 0; i--)
  {
    for (int8_t j = symbol[i].cols - 1; j >= 0; j--)
    {
      mx.setColumn(curCol++, bInvert ? ~symbol[i].charMap[j] : symbol[i].charMap[j]);
    }
    curCol += SPACING;
  }

  mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
}

bool animateSingle(uint8_t idx)
// Work out the character map for the symbol specified
// Return true if there has been a change.
{
  bool b = false;

  // finite state machine to control what we do
  switch(symbol[idx].state)
  {
    case symbolData_t::ST_INIT: // Initialize the display - done once only on first call
      PRINTS("\nST_INIT");

      // Display the starting number
      symbol[idx].cols = mx.getChar(symbol[idx].oldValue, SYMBOL_COLS, symbol[idx].charMap);
      symbol[idx].timeStart = symbol[idx].timeLastFrame = millis();
      symbol[idx].newValue = random(TOTAL_SYMBOLS) + 1;
      symbol[idx].scrollUp = (random(100) >= 50);
      symbol[idx].index = 0;
      b = true;

      // Now we wait for a animation timer to expire
      symbol[idx].state = symbolData_t::ST_WAITFRAME;
      break;

    case symbolData_t::ST_WAITFRAME: // not animating waiting for the frame timer
      if (millis() - symbol[idx].timeLastFrame < TIME_FRAME_DELAY)
        break;

      // a change has been found - we will be animating something
      symbol[idx].state = symbolData_t::ST_ANIM;

      // initialize animation parameters for this symbol
      symbol[idx].timeLastFrame = millis();   // for the next time around
      break;

    case symbolData_t::ST_ANIM: // currently animating a change
      // work out the new intermediate bitmap for each character
      // 1. Get the 'new' character bitmap into temp buffer
      // 2. Shift this buffer down or up by current index amount
      // 3. Shift the current character by one pixel up or down
      // 4. Combine the new partial character and the existing character to produce a frame
      {
        uint8_t newChar[SYMBOL_COLS] = { 0 };
/*
        PRINT("\nST_ANIM Symbol ", idx);
        PRINT(" from '", symbol[idx].oldValue);
        PRINT("' to '", symbol[idx].newValue);
        PRINT("' index ", symbol[idx].index);
*/
        b = true;   // modify return indicator

        mx.getChar(symbol[idx].newValue, SYMBOL_COLS, newChar);

        // make a sound
      
               



        // now work out the scroll character map
       if (symbol[idx].scrollUp)
        {
          // scroll up
          for (uint8_t j = 0; j < symbol[idx].cols; j++)
          {
            newChar[j] = newChar[j] << (COL_SIZE - 1 - symbol[idx].index);
            symbol[idx].charMap[j] = symbol[idx].charMap[j] >> 1;
            symbol[idx].charMap[j] |= newChar[j];
          }
        }
        else
        {
        // scroll down
          for (uint8_t j = 0; j < symbol[idx].cols; j++)
          {
            newChar[j] = newChar[j] >> (COL_SIZE - 1 - symbol[idx].index);
            symbol[idx].charMap[j] = symbol[idx].charMap[j] << 1;
            symbol[idx].charMap[j] |= newChar[j];
            
          }
        }

        // Set new parameters for next animation and check if we are done.
        // We are done when the time for the animation exceeds the total 
        // duration and the character is full in place.
        symbol[idx].index++;
        symbol[idx].state = symbolData_t::ST_WAITFRAME;
        

        if (symbol[idx].index >= COL_SIZE)  // reached the end of this symbol
        {
          symbol[idx].oldValue = symbol[idx].newValue;  // done animating this transition
          symbol[idx].index = 0;

          if (millis() - symbol[idx].timeStart >= symbol[idx].timeDuration) // check duration timer
          {
                    tone(BUZZ_PIN , 400 , 10);

            PRINT("\nSymbol ", idx);
            PRINTS(" ENDED");
            symbol[idx].state = symbolData_t::ST_END;
            
          }
          else  // still animating, get the next symbol to show
          
          {
            do
            {
              symbol[idx].newValue = random(TOTAL_SYMBOLS) ;
            } while (symbol[idx].newValue == symbol[idx].oldValue); // make sure we have something different

            PRINT("\nSymbol ", idx);
            PRINT(" new value ", symbol[idx].newValue);
                  
                 

          }
        }
      }
    break;

    case symbolData_t::ST_END:    // do nothing. This will be reset externally once all have completed.
      break;

    default:
      symbol[idx].state = symbolData_t::ST_END;
      
  }

  return(b);  // true if changes occurred
  
}

bool animateAll(void)
// Animate the symbols, one at a time.
// return true if all the animations are completed

{
  bool b = false;

  // run the animations and update the display if there is a change
  for (uint8_t i = 0; i < MAX_SYMBOLS; I++)
    b |= animateSingle(i);

  if (b) updateDisplay();

  // Now check if we are done with all animations
  b = true;
  for (uint8_t i = 0; i < MAX_SYMBOLS; I++)
    b &= symbol[i].oldValue == symbol[i].newValue;
    

  return(b);
}

bool checkWinner(void)
// currently only 3 of a kind wins

{
  bool b = true;

#if ALWAYS_WIN
  b = true;
#else
  for (uint8_t i = 1; i < MAX_SYMBOLS; I++)
    b &= symbol[i - 1].newValue == symbol[i].newValue;
    
#endif

  if (b) PRINTS("WINNER!");

  return(b);
}

void setup()

{
#if DEBUG
  Serial.begin(57600);
#endif // DEBUG
  PRINTS("\n[MD_MAX72xx SimpleSlots]")

  // Matrix initialization
  mx.begin();
  mx.setFont(slotSymbols);

  // Switch initialization
  S.begin();
  S.enableDoublePress(false);
  S.enableLongPress(false);
  S.enableRepeat(false);

  // Tone Initialization
  pinMode(BUZZ_PIN, OUTPUT);
  pinMode(4, OUTPUT);
 // set the speed at 60 rpm:
  myStepper.setSpeed(rolePerMinute);
  
  
}

void loop()
{
  static enum:uint8_t { S_IDLE, S_INIT, S_RUN, S_CHECK, S_WINNER, S_END } state = S_INIT;

  switch (state)
  {
  case S_IDLE:  // wait for the switch to be released
    if (S.read() == MD_UISwitch::KEY_UP)
    {
      PRINTS("\n-> Key release!");
      state = S_INIT;
      
    }
    break;

  case S_INIT:  // initialise the timing parameters
    randomSeed(millis());   // should be good as user timing is unpredictable

    // now set up timing parameters for each symbol
    for (uint8_t i = 0; i < MAX_SYMBOLS; I++)
    {
      symbol[i].state = symbolData_t::ST_INIT;
      symbol[i].timeDuration = TIME_BASE + (random(5) * TIME_INCREMENT);
      PRINT("\nsym[", i);
      PRINT("] duration ", symbol[i].timeDuration);

    }
    state = S_RUN;
    break;

  case S_RUN:   // run the animation
        
    if (animateAll())
    {
      PRINTS("\n-> Ended with");

      
      for (uint8_t i = 0; i < MAX_SYMBOLS; I++)
      {
        PRINT(" [", i);
        PRINT("]=", symbol[i].newValue)
      }
      state = S_CHECK;
    }
    break;

  case S_CHECK:  // work out if there is a winner
    if (checkWinner())

      state = S_WINNER;
      
    else
      state = S_END;
      
    break;

  case S_WINNER:
    PRINTS("\nWINNER!");
   
    for (uint8_t j = 0; j < 3; j++)
    {


      for (uint8_t i = 0; i < MAX_SYMBOLS; I++)
      {
        myStepper.step(stepsPerRevolution);

        digitalWrite(4,HIGH);
        

        uint8_t temp[SYMBOL_COLS] = { 0 };

        memcpy(temp, symbol[i].charMap, sizeof(symbol[i].charMap));
        memset(symbol[i].charMap, 0, sizeof(symbol[i].charMap));
        updateDisplay();    // do all the even counts
        memcpy(symbol[i].charMap, temp, sizeof(symbol[i].charMap));
        delay(10);
        
      }
    }
    digitalWrite(4,LOW);
    updateDisplay();  // make sure it is clean
    state = S_END;
    break;

  case S_END:
    state = S_IDLE;
    
    break;

  default:
    state = S_IDLE;
    
  }
}

> Use code tags to format code for the forum

`

You posted in the English part of the forum. I will move your topic to the appropriate part.
Please always check that you post your topics in the correct part of the forum.

ohhh sorry,
Thank you Paul....

Ein Mix von großen und kleinen I wird nicht funktionieren. Daher ist es unbedingt notwendig, Code gleich in < CODE > Tags zu präsentieren, ohne irgendwelche Zwischenschritte.

Wo genau befindet sich der Code, der mehr Displays können soll?

Für das Durchrollen der Zeichen würde ich ein Array mit Zeilen für 2 Zeichen (alt und neu) übereinander verwenden, und dann nur den Startindex in diesem Zeilenfeld bei der Ausgabe anpassen. Für ein Array mit allen Zeichen auf einem Rad könnte der Speicher zu klein sein.

Oh okay, naja ich verstehe noch nicht so viel vom programmieren versuche es aber zu verstehen. Den Code habe ich schon fertig von Github und dachte mit nur kleinen Anpassungen könnte ich das ''Rollen'' größer über insgesamt 4x8 Led Dot Matrix darstellen. Wie meinst du das mit großen und kleinen I ?

Viele Grüße

Beim Programmieren ist ein "i" etwas anderes als ein großes "I". In der gezeigten Schleifen-Anweisung wird I++ statt i++ geschrieben. Darum kann dieser Programmteil nicht korrekt funktionieren, weil I eine andere Variable als i ist.

Guten Morgen,
okay das 'i' habe ich nun geändert. Der Code funktioniert, jedoch immer noch etwas zu klein auf dem Led Matrix Dot Display. Was kann ich tun das die 'Rollsimulation' über alle 4 Dot Matrix Segmente läuft? Danke Viele Grüße an euch

Rollen ist einfach.

Du machst eine Schleife.

Dort die erste 'Zeile an machen.
Im nächsten Lauf die 2 Zeile an machen
im nächsten Lauf die 3 Zeile an machen
in nächsten Lauf die 4 Zeile anmachen + die 1 Zeile löschen.
Das immer so weiter.

Das machst du dann auf alle X - Displays.
Wenn da ein kleines Timing ist = Sie laufen nicht Syncron ist das sogar chic.

Sobald du gelernt hast EINE LED anzusteuern reicht das.

Wenn sie stoppen sollen, Löst du den Stop aus wenn die Zeilen 2-3-4 an sind.
Dann zum passenden Routine springen und einfach die LEDS nach unten scrollen und dabei das Symbol scrollend anzeigen.

Im großen und ganzen ist das nur viel Schleifen-Funktion.

Gruß
Pucki

Zeig mal ein Link zu den von dir verwendeten Modul.
Da gibt es nämlich einiges an Ausführungen.

Gruß

Pucki

Auf dieser Seite findest du auch deine MATRIX. (würfeln)

Lad dir da mal die PDF herunter. Die verstehst du vielleicht viel besser als dein Code da.
Grund : Die nutzen einen andere Libs.

Nicht wundern das die nur 1 Display ansteuern da. Wenn du die Libs in der PDF init. kannst du die Anzahl der Module angeben.

Gruß

Pucki

Vielen Dank erstmal Pucki,
ich verwende diese Matrix Displays

https://amzn.eu/d/2g6hjU3

Ich wusste leider nicht das es da Unterschiede gibt

Viele Grüße erstmal

Doch gibt es.
Als 1 er Modul, 4er Modul , mit + ohne Treiberchip etc.

In deine Fall würde ich wie gesagt mal den Link von Fundino anschauen und die PDF bei Würfeln runter ziehen. Die ist SEHR gut erklärt, vor allen auch die Befehle mit den Parameter.

Bei deine Modul ist müsstest du den bei Befehl
LedControl Name_der_Matrix(Data-In, CLK, CS, AnzahlMatrix) // AnzahlMatrix mit 4 setzen.
Gezählt werden nämlich immer die "Blöcke" und du hast deren 4 zusammen gesetzt.

Ich halte diese Libs für viel Einfacher.

Ich rate dir zu einer Excel-Tabelle als geistige Stütze.
Da dann eine 8 x 8 große tabelle machen
wo ein Zeichen stehen soll eine 1 setzten sonst oder nix.
Dann einfach die Bits in Bytes zusammenrechnen lassen und deren Code via Libs übergeben.
Dann leuchten halt die LEDS so in der Reihe.

setRow(NummerMatrix, Zeile, Byte) //<- dürfte logisch sein oder.

Um ein bestimmtes Zeichen darzustellen musst die den Befehl halt nur 8 x aufrufen und jeweils die Zeile ändern und das erechnete Byte da eintragen.

Grundlagen des Binär-System sollten vorhanden sein, beim Arduino + Co.

Edit : wenn du ein 2 Dimensionales Byte-Array machst und die erechneten Bytes dort eingibst, reicht es völlig aus, wenn du eine Zufallszahl errechnet und nach einde des "Rollen" einfach diese Zufallszahl den Array übergibst.

Gruß

Pucki

ps. : Cool wäre es wenn du noch eine 4 Stellige LCD-Anzeige einbaust die dann ein Gewinn/Verlustzähler simuliert. Sowas wie bei den ersten Elektronischen Geldautomaten mit Walzen/Scheiben.

Oww Vielen Dank soweit. Hab mir das mal angeschaut und so einiges wird klarer…. Die Idee mit dem kleinen Display ist super, jedoch denke ich etwas zu schwer für mich am Anfang zu programmieren… aber danke erst mal für all die guten Tips…

Och das geht eigentlich.

Schau dir dazu auf der Fundino-Seite einfach mal das Beispiel :
Einstellige_7-Segment-Anzeige_Wuerfeln.pdf an

Diese Teile kann man auch erweitern.

Gruß

Pucki