Informatikunterricht

am Gymnasium Kirchenfeld

Benutzer-Werkzeuge

Webseiten-Werkzeuge


arduino:pinball

Dies ist eine alte Version des Dokuments!


Punkteanzeige für Flipperautomat

Zurück

Dieses Programm steuert ein Anzeigemodul für einen Flipperautomaten. Das Anzeigemodul besteht aus fünf 7-Segmentanzeigen, welche den Punktestand anzeigen. Die Anzeige wird über fünf in Serie geschalteten Schieberegister gesteuert.

Ausserdem können auf einer SD-Karte gespeicherte Audiodateien abgespielt werden.

Die Aktionen werden durch Aktivieren verschiedener Eingänge (Inputs) ausgelöst. Die Aktionen können für jeden Eingang in einer Datei auf der SD-Karte konfiguriert werden.

#include "mariamole_auto_generated.h"
#include <SD.h>
#include "TMRpcm.h"
#include "util.h"
 
// --------------------------------------------------------------------------------------------------
// Parameters
// --------------------------------------------------------------------------------------------------
 
#define STEP 50
 
// --------------------------------------------------------------------------------------------------
// Pins
// --------------------------------------------------------------------------------------------------
 
#define DISPLAY_DATA_PIN 7
#define DISPLAY_SHIFT_CLOCK_PIN 8
#define DISPLAY_STORAGE_CLOCK_PIN 3
#define LED_DATA_PIN 4
#define LED_SHIFT_CLOCK_PIN 5
#define LED_STORAGE_CLOCK_PIN 6
#define SD_CARD_CHIP_SELECT_PIN 10
#define SPEAKER_PIN 9
 
const byte INPUT_PINS[] = { A1, A2, A0, A3, 0, A4, 1, A5, 2 };
const byte INPUT_COUNT = sizeof(INPUT_PINS) / sizeof(byte);
 
// --------------------------------------------------------------------------------------------------
// 7-segment display
// --------------------------------------------------------------------------------------------------
 
const int DISPLAY_DIGIT_COUNT = 5;
 
const int DISPLAY_DIGIT[] = {
//   cbadfge
    B11111010, // 0
    B11000000, // 1
    B01110110, // 2
    B11110100, // 3
    B11001100, // 4
    B10111100, // 5
    B10111110, // 6
    B11100000, // 7
    B11111110, // 8
    B11111100  // 9
};
 
int getDigit(int digit) {
    return DISPLAY_DIGIT[digit];
}
 
//                 cbadfge
#define DISPLAY_E B00111110
#define DISPLAY_R B00000110
#define DISPLAY_O B10010110
 
const int DISPLAY_ERROR_MESSAGE[] = { DISPLAY_R, DISPLAY_O, DISPLAY_R, DISPLAY_R, DISPLAY_E };
 
class PinballDisplay {
    boolean _error; // display 'Error' when true
    unsigned long _score;
    long _scoreToAdd;
 
    void update() {
        digitalWrite(DISPLAY_STORAGE_CLOCK_PIN, LOW);
        nop();
        if (_error) {
            for (int i = 0; i < DISPLAY_DIGIT_COUNT; ++i) {
                shiftOut(DISPLAY_DATA_PIN, DISPLAY_SHIFT_CLOCK_PIN, MSBFIRST, DISPLAY_ERROR_MESSAGE[i]);
                nop();
            }
        }
        else {
            long d = 1;
            for (int i = 0; i < DISPLAY_DIGIT_COUNT; ++i) {
                int digit = getDigit((_score / d) % 10);
                shiftOut(DISPLAY_DATA_PIN, DISPLAY_SHIFT_CLOCK_PIN, MSBFIRST, digit);
                delay(10);
                d *= 10;
            }
        }
        delay(10);
        digitalWrite(DISPLAY_STORAGE_CLOCK_PIN, HIGH);
        delay(10);
    }
 
public:
    PinballDisplay() :
        _error(false),
        _score(0),
        _scoreToAdd(0)
    {
        pinMode(DISPLAY_DATA_PIN, OUTPUT);
        pinMode(DISPLAY_SHIFT_CLOCK_PIN, OUTPUT);
        pinMode(DISPLAY_STORAGE_CLOCK_PIN, OUTPUT);
        update();
    }
 
    void addScore(long amount) {
        _score += amount;
        update();
    }
 
    void addScoreSlow(long amount) {
        _scoreToAdd += amount;
        update();
    }
 
    void loop() {
        if (_scoreToAdd > 0) {
            _score = _score + STEP;
            _scoreToAdd = _scoreToAdd - STEP;
            update();
        }
    }
 
    void setError() {
        _error = true;
    }
 
    void setScore(unsigned int newScore) {
        _score = newScore;
		_error = false;
        update();
    }
};
 
PinballDisplay* display;
 
// --------------------------------------------------------------------------------------------------
// LED Animation
// --------------------------------------------------------------------------------------------------
 
const int LED_MAP[] = {
    B10000000, // Output Pin 17
    B00000001, // Output Pin 18
    B01000000, // Output Pin 19
    B00000010, // Output Pin 20
    B00100000, // Output Pin 21
    B00000100, // Output Pin 22
    B00010000, // Output Pin 23
    B00001000, // Output Pin 24
};
 
int animation[2];
const int ANIMATION_COUNT = sizeof(animation) / sizeof(int);
 
unsigned long nextAnimationUpdate[2];
 
void led_setup() {
    pinMode(LED_DATA_PIN, OUTPUT);
    pinMode(LED_SHIFT_CLOCK_PIN, OUTPUT);
    pinMode(LED_STORAGE_CLOCK_PIN, OUTPUT);
    for (int i = 0; i < ANIMATION_COUNT; ++i) {
        animation[i] = -1;
        nextAnimationUpdate[i] = 0;
    }
}
 
void led_update() {
    digitalWrite(LED_STORAGE_CLOCK_PIN, LOW);
    int data = 0;
    for (int i = 0; i < ANIMATION_COUNT; ++i) {
        if (animation[i] >= 0) {
            data = data | LED_MAP[animation[i] + 4*i];
        }
    }
 
    shiftOut(LED_DATA_PIN, LED_SHIFT_CLOCK_PIN, MSBFIRST, data);
    digitalWrite(LED_STORAGE_CLOCK_PIN, HIGH);
}
 
void led_loop() {
    for (int i = 0; i < ANIMATION_COUNT; ++i) {
        if (nextAnimationUpdate[i] <= millis() && animation[i] >= 0) {
            animation[i] = animation[i] + 1;
            if (animation[i] > 3) {
                animation[i] = -1;
            }
 
            led_update();
            nextAnimationUpdate[i] = millis() + 500;
        }
    }
}
 
void startAnimation(String name) {
    if (name.equals("a")) {
        animation[0] = 0;
    }
    else if (name.equals("b")) {
        animation[1] = 0;
    }
 
    nextAnimationUpdate[1] = millis() + 500;
    led_update();
}
 
// --------------------------------------------------------------------------------------------------
// Program
// --------------------------------------------------------------------------------------------------
 
#define MAX_COMMAND_SIZE 50
#define MAX_FILENAME_SIZE 12
 
TMRpcm _audio;
 
class PinballProgram {
    char* _command;
    char* _fileName;
    byte _inputCount;
    unsigned long* _inputLocks;
    const byte* _inputPins;
    byte* _inputPinStates;
 
    void executeProgram(int i) {
        if (_audio.isPlaying()) {
            _audio.stopPlayback();
        }
 
        sprintf(_fileName, "%04d.txt", i);
        File file = SD.open(_fileName, FILE_READ);
        if (!file) {
            display->setError();
            return;
        }
		int pos = 0;
        while (file.available()) {
            char ch = file.read();
            if (ch == '\n') {
                _command[pos] = '\0';
                executeCommand();
                pos = 0;
			}
            else if (pos < MAX_COMMAND_SIZE) {
                if (ch != '\r') {
                    _command[pos] = ch;
                    ++pos;
                }
            }
        }
 
        _command[pos] = '\0';
        executeCommand();
        file.close();
    }
 
    void executeCommand() {
        if (!strncmp(_command, "play ", 5)) {
            strnmove(_fileName, _command + 5, MAX_FILENAME_SIZE + 1);
            _audio.play(_fileName);
        }
        else if (!strncmp(_command, "+ ", 2)) {
            display->addScore(atoi(_command + 2));
        }
        else if (!strncmp(_command, "++ ", 3)) {
            display->addScoreSlow(atoi(_command + 3));
        }
        else if (!strncmp(_command, "= ", 2)) {
            display->setScore(atoi(_command + 2));
        }
    }
 
public:
    PinballProgram(int inputCount, const byte* inputPins) :
        _command(new char[MAX_COMMAND_SIZE + 1]),
        _fileName(new char[MAX_FILENAME_SIZE + 1]),
        _inputCount(inputCount),
        _inputLocks(new unsigned long[inputCount]),
        _inputPins(inputPins),
        _inputPinStates(new byte[inputCount])
    {
        _audio.speakerPin = SPEAKER_PIN;
        for (int i = 0; i < _inputCount; ++i) {
            _inputLocks[i] = 0;
            _inputPinStates[i] = 0;
            pinMode(_inputPins[i], INPUT_PULLUP);
        }
 
        if (!SD.begin(SD_CARD_CHIP_SELECT_PIN)) {
            display->setError();
            return;
        }
    }
 
    void init() {
        executeProgram(0);
    }
 
    void loop() {
        unsigned long now = millis();
        for (int i = 0; i < _inputCount; ++i) {
            if (_inputLocks[i] < now) {
                int state = digitalRead(_inputPins[i]);
                if (state == HIGH) {
                    _inputPinStates[i] = 0;
                }
                else {
                    if (_inputPinStates[i] < 100) {
                        ++_inputPinStates[i];
                    }
                    else {
                        executeProgram(i + 1);
                    }
                }
            }
        }
    }
};
 
PinballProgram* program;
 
// --------------------------------------------------------------------------------------------------
// Main
// --------------------------------------------------------------------------------------------------
 
void setup() {
    display = new PinballDisplay();
    program = new PinballProgram(INPUT_COUNT, INPUT_PINS);
    led_setup();
    program->init();
}
 
void loop() {
    display->loop();
    program->loop();
    led_loop();
}
arduino/pinball.1416422968.txt.gz · Zuletzt geändert: 2020/10/13 14:25 (Externe Bearbeitung)