arduino:pinball
Dies ist eine alte Version des Dokuments!
Punkteanzeige für Flipperautomat
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)