MezData-Logo

Discovery-Room

RFID-Station mit 2 Modulen

RFID Station

SchaltplanFür ein Spiel sollen 4 Stationen mit jeweils 2 RFID-Modulen abgefragt werden. An den Stationen sind bei den Modulen jeweils ein RGB-Streifen montiert. Die Stationen werden über I2C mit einem Steuerrechner verbunden.

5V RGB-LED-Streifen mit 3 Segmenten zieht bei 5V ca. 50mA pro Farbe, Reduktion mit Vorwiderständen auf ca. 15mA: Rot 150Ω; Blau&Grün: 120Ω

Info-Schnipsel

Beispiele für I2C sind teilweise fehlerhaft, Slave-Adresse erst ab Adr. 8 einstellen... Funktionsbeschreibung folgt...

Mega 2560: hat bei Pins 20-21 10kΩ Pull-Ups eingebaut

Uno: SCL=A5=D19; SDA=A4=D18

Nano: A6 und A7 funktionierten als Digitalpins nicht, PullUps gingen nicht an usw.

Verhalten des RFID-Lesens verständlich beschreiben, auf interne Zustände der Karten eingehen..

Strombedarf der RFID-Reader ca. 30mA ergibt bei allen LED aus 70mA LEDs an 150mA für Station, Problem mit Kühlung der Nanos bei 12V Vin: (12V-5V)*0,15A = 1,05W. Manche Nanos gehen auf Reset... Lösungen:

DFPlayerMini_Fast.h: isPlaying() funktioniert nicht mit SoftwareSerial, auch mit Serial1 beim Mega2560 ist die Funktion nicht zuverlässig, musste auf Busy-Pin am Player ausweichen.

Weitere Belegung Master

    GND GND    
Telefonklingel N Relais1 53 52 Telefon-Gabel N 4,7kΩ VCC
Türmagnet Eingang N Relais2 51 50 Telefon-Knopf N 4,7kΩ VCC
Verstärker N Relais3 49 48 Telefon-Wählscheibe 4,7kΩ VCC
Mausklick N Relais4 47 46 Taschenl. Ausgabe Taster N 4,7kΩ VCC
Türmagnet Ausgang N Relais5 45 44 Türen Taster N 4,7kΩ VCC
Spot4 Taschl. Fach N Relais6 43 42 Taschenl. Rückgabe N 4,7kΩ VCC
Reserve N Relais7 41 40 IR1  
Reserve N Relais8 39 38 IR2  
    37 36 IR3  
Telefon
1 OR/WS Telfon-Gabel 52
2 OR Telefon-Wählschebe 48
3 GN/WS Lautsprecher DF-Player
4 BL Masse GND
5 BL/WS Lautsprecher DF-Player
6 GN Telefon-Knopf 50
7 BR/WS Klingel Relais
8 BR Klingel Relais
Lichter
2 Spot1 (PWM) Hauptlicht
3 Spot2 (PWM)  
4 Spot3 (PWM)  
5 Spot5 (PWM)  
43 Spot4 Relais Taschenlampenfach blinkt

 

 

Software für Station

Quellcode [Discovery-Game-Rfid/Discovery-Game-Rfid.ino]
  1. #include <SPI.h>
  2. #include <MFRC522.h>
  3. #include <Wire.h>
  4. #include "GameLib.h"
  5. #define vers "1.0"
  6.  
  7. // SPI-Bus: RFID PIN Numbers : RESET + SDAs
  8. #define RST_PIN 2
  9. #define SS_O_PIN 4
  10. #define SS_U_PIN 3
  11. // i2c Bus-Adresse, beim Setup ermitteln
  12. #define I2C_ADR_LOW_PIN A2 // A6 und A7 haben nicht funktioniert!
  13. #define I2C_ADR_HIGH_PIN A3 // auch nicht D20, D21
  14. byte i2cAdr; // Busnummer des Slave
  15.  
  16. #define NR_OF_READERS 2 // Anzahl der RFID-Reader
  17.  
  18. byte ssPins[] = {SS_O_PIN, SS_U_PIN}; // Select-Pins der Reader
  19. // Create an MFRC522 instance :
  20. MFRC522 mfrc522[NR_OF_READERS];
  21. RGBStrip rgb_oben(8,9,10); // RGB-Strip
  22. RGBStrip rgb_unten(7,5,6); // RGB-Strip
  23. rfid_t rfidErg=Rfid_nix;
  24. void setup() {
  25. Serial.begin(115200); // Initialize serial communications with the PC
  26. while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
  27. pinMode(I2C_ADR_LOW_PIN,INPUT_PULLUP); // Adresse durch Jumper setzen
  28. pinMode(I2C_ADR_HIGH_PIN,INPUT_PULLUP);
  29. i2cAdr = 8 + !digitalRead(I2C_ADR_LOW_PIN)+ (!digitalRead(I2C_ADR_HIGH_PIN)<<1);
  30. SPI.begin(); // Init SPI bus
  31. rgb_oben.setRGB(Ws,0);
  32. rgb_unten.setRGB(Ws,0);
  33. Serial.print(F("Discovery-Game RFID-Server V"));
  34. Serial.print(vers);
  35. Serial.print(F(" (c) Oliver Mezger I2C-Adresse: "));
  36. Serial.println(i2cAdr);
  37. readerReset();
  38. Wire.begin(i2cAdr); // I2C-Adresse festlegen
  39. Wire.onReceive(receiveEvent); // erstelle ein Empfangen-Ereignis
  40. Wire.onRequest(requestEvent); // erstelle ein Anfrage-Ereignis
  41. }
  42.  
  43. void receiveEvent(int bytes) { // Komando-Empfang
  44. byte x;
  45. int y;
  46. if (bytes > 1){ // Befehl fuer RGB-Blinker
  47. x = Wire.read(); // lies Muster für RGB Bit 7 = 0 oben 1 unten
  48. y = Wire.read(); // lies Blinkerperiodendauer
  49. Serial.print(F("RGB-Befehl: "));
  50. Serial.print(x,BIN);
  51. Serial.print(F(" Dauer "));
  52. Serial.println(y);
  53. //Serial_printf(Serial,F("RGB-Befehl: %b, Dauer %d \n"),x,y);
  54. if(!(x&128)){ //Bit 7 = 0: RGBoben
  55. rgb_oben.setRGB((rgb_t)x,y*10);
  56. }
  57. else{ //Bit 7 = 1: RGBunten
  58. rgb_unten.setRGB((rgb_t)x,y*10);
  59. }
  60. }
  61. else {
  62. x = Wire.read(); // lies die gesendeten Daten aus
  63. Serial.print(F("RFID-Leser-Befehl: "));
  64. Serial.println(x);
  65. switch (x){
  66. case RFID_reset: // Leser zuruecksetzen um liegengebliebne Karten zu erkennen
  67. readerReset();
  68. break;
  69. case RFID_oben: // Karte lesen
  70. if (mfrc522[0].PICC_IsNewCardPresent() && mfrc522[0].PICC_ReadCardSerial()) {
  71. rfidErg=Rfid_karte_o;
  72. mfrc522[0].PICC_HaltA();
  73. mfrc522[0].PCD_StopCrypto1();
  74. Serial.println("Karte oben gelesen");
  75. }
  76. else rfidErg=Rfid_nix;
  77. break;
  78. case RFID_unten:
  79. if (mfrc522[1].PICC_IsNewCardPresent() && mfrc522[1].PICC_ReadCardSerial()) {
  80. rfidErg=Rfid_karte_u;
  81. mfrc522[0].PICC_HaltA();
  82. mfrc522[0].PCD_StopCrypto1();
  83. Serial.println("Karte unten gelesen");
  84. }
  85. else rfidErg=Rfid_nix;
  86. break;
  87. case C_Hallo: // Server Hallo fragen
  88. rfidErg=A_Ok; // Bei nächster Datenanfrage "OK" senden
  89. break;
  90. }
  91. }
  92. }
  93. void requestEvent(){ // Antwort auf Datenanfrage
  94. switch (rfidErg){
  95. case Rfid_nix: // Keine neue Karte erkannt
  96. //nodePayload[0] = NODE_ADDRESS;
  97. Wire.write(0);
  98. break;
  99. case Rfid_karte_o:
  100. Wire.write(mfrc522[0].uid.size);
  101. Wire.write(mfrc522[0].uid.uidByte, mfrc522[0].uid.size);
  102. break;
  103. case Rfid_karte_u:
  104. Wire.write(mfrc522[0].uid.size);
  105. Wire.write(mfrc522[1].uid.uidByte, mfrc522[1].uid.size);
  106. break;
  107. case A_Ok:
  108. Wire.write("OK");
  109. break;
  110. }
  111. }
  112.  
  113. void loop() {
  114. byte key_command;
  115. if(Serial.available()) {
  116. key_command=Serial.read(); // get command from serial input
  117. Serial.print(F("Kommando "));
  118. Serial.write(key_command);
  119. Serial.println("");
  120. switch (key_command){
  121. case 'q':
  122. rgb_oben.setRGB(Off,0);
  123. rgb_unten.setRGB(Off,0);
  124. Serial.println(F("Alle LED aus"));
  125. break;
  126. case 'r': rgb_unten.setRGB(Rt,0); Serial.println(F("Rot")); break;
  127. case 'g': rgb_unten.setRGB(Gn,0); Serial.println(F("Grün")); break;
  128. case 'b': rgb_unten.setRGB(Bl,0); Serial.println(F("Blau")); break;
  129. case 'l': rgb_unten.setRGB(Li,0); break;
  130. //case 'b': rgb_unten.setRGB(Gn,200); break;
  131. case 'o': // oberen RFID auslesen
  132. if (mfrc522[0].PICC_IsNewCardPresent() && mfrc522[0].PICC_ReadCardSerial()) {
  133. dump_byte_array(mfrc522[0].uid.uidByte, mfrc522[0].uid.size);
  134. mfrc522[0].PICC_HaltA();
  135. mfrc522[0].PCD_StopCrypto1();
  136. }
  137. else Serial.println(F("Keine neue Karte"));
  138. break;
  139. case 'c': mfrc522[0].PCD_Init(); mfrc522[0].PCD_DumpVersionToSerial(); break;
  140. case 'i': dump_byte_array(mfrc522[0].uid.uidByte, mfrc522[0].uid.size); break;
  141. }
  142. }
  143. delay(50);
  144. rgb_oben.service();
  145. rgb_unten.service();
  146. }
  147. /**
  148.   Helper routine to dump a byte array as hex values to Serial.
  149. */
  150. void readerReset(){
  151. for (uint8_t reader = 0; reader < NR_OF_READERS; reader++) {
  152. mfrc522[reader].PCD_Init(ssPins[reader], RST_PIN);
  153. Serial.print(F("Reader "));
  154. Serial.print(reader);
  155. Serial.print(F(": "));
  156. mfrc522[reader].PCD_DumpVersionToSerial();
  157. }
  158. }
  159. void dump_byte_array(byte * buffer, byte bufferSize) {
  160. for (byte i = 0; i < bufferSize; i++) {
  161. Serial.print(buffer[i] < 0x10 ? " 0" : " ");
  162. Serial.print(buffer[i], HEX);
  163. }
  164. }
  165.  
Quellcode [Discovery-Game-Master/GameLib.h]
  1. // GameLib.h
  2. #ifndef GameLib_h
  3. #define GameLib_h
  4. #endif
  5.  
  6. enum rgb_t : byte {Off=0,Bl=0b001,Gn=0b010,Tk=0b011,Rt=0b100,Li=0b101,Ge=0b110,Ws=0b111}; // Welches RGB-Muster
  7. enum command_t: byte {RFID_reset=3,RFID_oben,RFID_unten,C_Hallo};
  8. enum rfid_t : byte {Rfid_nix,Rfid_karte_o,Rfid_karte_u,A_Ok};
  9.  
  10. class RGBStrip{
  11. public:
  12. RGBStrip(byte r_pin,byte g_pin,byte b_pin); // Initialisierung
  13. void setRGB(rgb_t l,unsigned int d); // Verhalten einstellen
  14. void service(); // periodisch aufgerufen
  15. private:
  16. byte red_pin;
  17. byte green_pin;
  18. byte blue_pin;
  19. unsigned long myTime; // Startzeitpunkt
  20. unsigned int myDelay; // Zeitverzoegerung
  21. byte leds; // welche LED blinken sollen
  22. byte zyklus; // fuer Blinken
  23. void setLed(); // Led an
  24. void clearLed(); // alle Led aus
  25. };
  26.  
  27. class Zeit{ // Ruft die Potistellung an AD-Pin ab und skaliert die Zeit zwischen min und max
  28. public:
  29. Zeit(byte pin, byte minZ, byte maxZ); // Zeit in Sekunden
  30. void start(); // Zeit starten
  31. void start(byte n); // n-fache Zeit
  32. byte vorbei(); // 1 falls Zeit um ist
  33. private:
  34. byte adPin;
  35. byte minZeit;
  36. byte maxZeit;
  37. unsigned long zeitmarke;
  38. };
  39.  
  40. class Taster{
  41. public:
  42. Taster(byte pin,byte aktiv); // lowaktiv=0
  43. byte aktiv(byte dauer); // dauer bis aktiv in 10tel Sekunden
  44. private:
  45. byte tPin;
  46. unsigned long zeitmarke;
  47. byte tAktiv; // lowaktiv=0
  48. byte merker; // für Flankendetektion
  49. };
  50.  
Quellcode [Discovery-Game-Master/GameLib.cpp]
  1. // GameLib.cpp
  2. #include <Arduino.h>
  3. #include "GameLib.h"
  4.  
  5. RGBStrip::RGBStrip(byte r_pin,byte g_pin,byte b_pin){ // Initialisierung
  6. red_pin=r_pin;
  7. green_pin=g_pin;
  8. blue_pin=b_pin;
  9. pinMode(red_pin,OUTPUT);
  10. pinMode(green_pin,OUTPUT);
  11. pinMode(blue_pin,OUTPUT);
  12. clearLed();
  13. }
  14.  
  15. void RGBStrip::setRGB(rgb_t l,unsigned int d){ // Verhalten einstellen
  16. leds = l&0b111; // nicht beteiligte Bits ausmaskieren
  17. zyklus=0;
  18. if (l==Off){
  19. myDelay=0;
  20. }
  21. else{
  22. myDelay=d;
  23. myTime=millis();
  24. }
  25. }
  26.  
  27. void RGBStrip::service(){ // periodisch aufgerufen für Blinken
  28. if(myDelay > 0){ // soll blinken
  29. if (millis() - myTime > myDelay) { // schauen, ob die Zeit um ist
  30. myTime = millis();
  31. switch (zyklus){
  32. case 0:
  33. clearLed();
  34. zyklus++;
  35. break;
  36. case 1:
  37. setLed();
  38. zyklus =0;
  39. }
  40. }
  41. }
  42. else if (zyklus == 0){ // kein Blinken nur einmal setzen
  43. setLed();
  44. zyklus++;
  45. }
  46. }
  47.  
  48. void RGBStrip::clearLed(){
  49. digitalWrite(red_pin,HIGH);
  50. digitalWrite(green_pin,HIGH);
  51. digitalWrite(blue_pin,HIGH);
  52. }
  53.  
  54. void RGBStrip::setLed(){
  55. if(leds&0b100) digitalWrite(red_pin,LOW); else digitalWrite(red_pin,HIGH);
  56. if(leds&0b010) digitalWrite(green_pin,LOW); else digitalWrite(green_pin,HIGH);
  57. if(leds&0b001) digitalWrite(blue_pin,LOW); else digitalWrite(blue_pin,HIGH);
  58. }
  59.  
  60. Zeit::Zeit(byte pin, byte minZ, byte maxZ){ // Zeit in Sekunden 0.255
  61. adPin = pin;
  62. minZeit = minZ;
  63. maxZeit = maxZ;
  64. }
  65.  
  66. void Zeit::start(){ // Zeit starten
  67. start(1);
  68. }
  69. void Zeit::start(byte n){ // n-fache Zeit
  70. int z = map(analogRead(adPin),0,1023,minZeit,maxZeit);
  71. zeitmarke = millis()+z*1000*n; // ab Zeitmarke ist Zeit um
  72. Serial.print(F("Zeit gesetzt (Sekunden): "));
  73. Serial.println(z);
  74. }
  75.  
  76. byte Zeit::vorbei(){
  77. return (millis()>zeitmarke);
  78. }
  79.  
  80. Taster::Taster(byte pin,byte aktiv){ // lowaktiv=0
  81. tPin=pin;
  82. tAktiv=aktiv;
  83. if(!aktiv) pinMode(pin,INPUT_PULLUP); // Pullup an
  84. else pinMode(pin,INPUT);
  85. }
  86.  
  87. byte Taster::aktiv(byte dauer){ // dauer bis aktiv in 10tel Sekunden
  88. if(digitalRead(tPin)!=tAktiv){ // Taster nicht aktiv
  89. merker=0;
  90. return 0;
  91. }
  92. else{
  93. if(!merker){ // pos. Flanke
  94. merker = 1;
  95. zeitmarke=millis();
  96. return 0;
  97. }
  98. else{ // Taster noch aktiv Dauer checken
  99. return millis()-zeitmarke > dauer*100;
  100. }
  101. }
  102. }
  103.  

Master-Steuerung

Quellcode [Discovery-Game-Master/Discovery-Game-Master.ino]
  1. #include "GameLib.h"
  2. #include <Wire.h>
  3. #include <SoftwareSerial.h>
  4. #include <DFPlayerMini_Fast.h> //https://github.com/PowerBroker2/DFPlayerMini_Fast
  5.  
  6. const byte karten[][7] PROGMEM = {{0xFA,0x60,0x84,0xAD},{0x4,0x70,0xD4,0x72,0x5E,0x5C,0x80},{0x8C,0x6D,0x4F,0x2E},{0x7C,0x4B,0x55,0x30}};
  7. #define vers "1.0"
  8. //char buff[40]; // Puffer für printf-Ausgaben
  9. #define RFID_DELAY 20 // Zeit in ms zwischen Anfrage und Empfang
  10. SoftwareSerial mySerial(22, 23); // RX, TX
  11. #define MP3_Busy 24
  12. DFPlayerMini_Fast myMP3;
  13. byte kartentest = 0;
  14. enum zustand_t: byte {Z_reset,Z_tuerenZu,Z_taschenlampeDa,Z_taschenlampenLade,Z_hauptlichtMax,Z_warteAufMitspieler,Z_zwischenzeitTelefon,
  15. Z_telefonAbnehmen,Z_begruessung,Z_wartenWaehlscheibe};
  16. zustand_t zustand = Z_reset;
  17. Zeit zeit1(A0,1,5); // AD-Pin,min,max in Sekunden
  18.  
  19. Taster taster1(4,0);
  20.  
  21. void setup() {
  22. Serial.begin(115200);
  23. mySerial.begin(9600);
  24. Wire.begin();
  25. if(!myMP3.begin(mySerial,false)){ // true für debug
  26. Serial.println(F("Unable to begin:"));
  27. }
  28. pinMode(MP3_Busy,INPUT);
  29. delay(100);
  30. //sprintf(buff, "Discovery-Game Master V %s (c) Oliver Mezger \n", vers);
  31. Serial.print(F("Discovery-Game Master V "));
  32. Serial.print(vers);
  33. Serial.println(F(" (c) Oliver Mezger"));
  34. //Serial.println(buff);
  35. Serial.print(F("Anzahl gespeicherter Karten: "));
  36. Serial.println(sizeof(karten)/sizeof(karten[0])); // Anzahl Karten anzeigen
  37. Serial.println(F("Setting volume to 20"));
  38. myMP3.volume(20); // 0..30
  39. for(byte i=0;i<=3;i++){
  40. if(pruefeHallo(i)){
  41. setzeRGB(i,0,0b000,0);
  42. setzeRGB(i,1,0b000,0);
  43. Serial.println(F(" Station OK"));
  44. }
  45. else Serial.println(F(" Falsche Antwort"));
  46. }
  47. kartentest = 0;
  48. zustand= Z_reset;
  49. }
  50. #define maxTerminals 2
  51. void loop() {
  52. byte test;
  53. serialKommandos(); // über seriellen Monitor steuern
  54. if (kartentest){
  55. byte k = leseRfid(1,0);
  56. if(k){
  57. myMP3.play(k);
  58. }
  59. else Serial.print(F("."));
  60. }
  61. switch (zustand){
  62. case Z_reset: // Akt=10 Reset mit Aufräumen vor jedem Neustart:
  63. //- falls Hörer nicht aufgelegt: MP3-Datei 56: ("Bitte Telefonhörer auflegen")
  64. //- falls per RFID etwas erkennt wird MP3-Datei 57: ("Bitte Gegenstände oder Karten aufräumen" und rot blinken)
  65. test=0;
  66. for(byte i=0;i<maxTerminals;i++){ // für alle Stationen
  67. resetRfid(i);
  68. delay(RFID_DELAY);
  69. for(byte k=0;k<=1;k++){ // für oben und unten
  70. if(leseRfid(i,k)){ // RFID-Tag erkannt
  71. setzeRGB(i,k,Rt,20); // 200 ms Blinken
  72. test=1; // merken für Spruch ausgeben
  73. }
  74. else setzeRGB(i,k,Off,0); // kein Tag kein Licht
  75. }
  76. }
  77. if(test) spreche(57);
  78. else zustand=Z_tuerenZu;
  79. break;
  80. case Z_tuerenZu: // beide Türen zu?
  81. zustand=Z_taschenlampeDa;
  82. break;
  83. case Z_taschenlampeDa: // Taschenlampenfach MP3-Datei 59 bestückt (Sensor1)?
  84. spreche(59);
  85. zustand=Z_taschenlampenLade;
  86. break;
  87. case Z_taschenlampenLade: // Taschenlampenschublade offen (Sensor2)? MP3-Datei 60
  88. spreche(60);
  89. zustand=Z_hauptlichtMax;
  90. break;
  91. case Z_hauptlichtMax: // Spot1 an, Spot 2..5 aus,
  92. for(byte i=0;i<maxTerminals;i++){ // alle RFID-Terminals leuchten oben und unten blau
  93. for(byte k=0;k<=1;k++){
  94. setzeRGB(i,k,Bl,0);
  95. }
  96. }
  97. zustand=Z_warteAufMitspieler;
  98. break;
  99. case Z_warteAufMitspieler: // Akt20
  100. //- wenn Bewegungsmelder IR1 oder IR2 oder IR3 anspricht => Akt=30
  101. zustand=Z_zwischenzeitTelefon;
  102. //- wenn Hörer (obwohl nicht läutend) abgenommen wird => Akt=50 (für den Fall, dass kurz nach Läuten-Ende abgenommen wurde)
  103. break;
  104. case Z_zwischenzeitTelefon: // Akt=30: Zwischenzeit bis Telefon läutet
  105. //- Zeit1 beginnt (eingestellt an Poti1, ca. 20 Sekunden) zu laufen:
  106. //- wenn ein kurzer Druck auf Knopf1 erfolgt: => Akt=10 (Reset mit Totzeit für Museumsbedienstete, die aus Versehen vom IR erfasst wurden)
  107. //- wenn Hörer (obwohl nicht läutend) abgenommen wird => Akt=50 (falls Telefon kurz nach Läuten-Ende abgenommen wurde und IR schon weitergeschaltet hat)
  108. //- nach Zeit1 => Akt=40
  109. zustand=Z_telefonAbnehmen;
  110. break;
  111. case Z_telefonAbnehmen: //Akt=40: Telefon soll abgenommen werden
  112. //- Telefon läutet (Dauer des Läutens Zeit2 eingestellt an Poti2, ca. 4 mal): Relais1
  113. //- wenn Hörer abgenommen oder Knopf1 kurz gedrückt => Akt=50
  114. zustand=Z_begruessung;
  115. //- wenn Zeit2 überschritten Akt=20 (Reset ohne Totzeit)
  116. break;
  117. case Z_begruessung: //Akt=50: Begrüßung per Telefonhörer und per Lautsprecher
  118. //- MP3 Datei1: ("Begrüßung...bitte Spielerzahl 2, 3 oder 4 wählen"), danach Akt=60
  119. spreche(1);
  120. zustand=Z_wartenWaehlscheibe;
  121. break;
  122. case Z_wartenWaehlscheibe: //Akt=60: warten auf Teilnehmerzahleingabe per Wählscheibe
  123. //- bis maximal Zeit3 (eingestellt an Poti3, ca. 10 Sekunden) dann Akt=70
  124. //- 0 oder 1 gewählt => Akt=80 (zu wenig Mitspieler)
  125. //- 2 oder 3 oder 4 gewählt = Spielerzahl. => Akt=100 (Fortsetzung des Spiels)
  126. //- mehr als 4 gewählt => Akt=90 (zu viele Mitspieler)
  127. //- wenn aufgelegt wurde Akt=10 (Reset)
  128. break;
  129. /*
  130. Akt=70: noch nichts gewählt
  131. - MP3 Datei2: ("...wieviel seid ihr? ...evtl. Mitspieler suchen...") => Akt=60
  132. - falls dieser Akt schon mehrfach durchlaufen wurde => Akt=20 (Reset)
  133.  
  134. Akt=80: zu wenig Mitspieler
  135. - MP3 Datei41: ("es müssen mindestens zwei Spieler sein") => Akt=70
  136.  
  137. Akt=90: zu viele Mitspieler gewählt
  138. - MP3 Datei42: ("es dürfen maximal vier Mitspieler sein!") danach: Akt=60
  139.  
  140. Akt=100: Spielbeginn mit der gewählten Mitspielerzahl
  141. - MP3 Datei 43/44/ oder 45: ("Willkommen Ihr zwei/ drei/ vier, jetzt kann's losgehen")
  142. - Spot1 (Regalbeleuchtung) wird hochgedimmt
  143. - und je nach Spielerzahl blinken zwei, drei oder vier Terminals oben gelb, die anderen schalten von Dauer-Blau auf Dauer-Rot (was geschieht, wenn ein Terminal erkannt hat und auf einen anderen gelegt wird?)
  144. - danach Akt=110
  145.  
  146. Akt=110: Spieler 1 soll loslegen
  147. - MP3 Datei4: ("Spieler 1 soll Gegenstand auf gelb blinkenden Terminal legen") danach: Akt=120
  148.  
  149. Akt=120: Warten auf Gegenstand von Spieler 1
  150. - wenn nach Zeit4 (einstellbar an Poti4) nichts aufgelegt wurde => MP3-Datei46:("Bitte Gegenstand auf gelb blinkenden Terminal legen")
  151. - wenn Zeit4 drei Mal durchlaufen MP3-Datei47:("Ohne Gegenstand muss das Spiel leider enden - 5 4 3 2 1 aus")=> Akt=10 (Reset)
  152. - Gegenstand per RFID erkannt => statt Gelb-Blinken hier nun Dauergelb und passende Datei von MP3 Datei-Register 21-40 danach: Akt=130
  153.  
  154. Akt=130: Spieler 2 soll loslegen
  155. - MP3 Datei5: ("Spieler 2 soll Gegenstand auf gelb blinkenden Terminal legen") danach: Akt=140
  156.  
  157. Akt=140: Warten auf Gegenstand von Spieler 2
  158. - wenn nach Zeit4 (einstellbar an Poti4) nichts aufgelegt wurde => MP3-Datei46:("Bitte Gegenstand auf gelb blinkenden Terminal legen")
  159. - wenn Zeit4 drei Mal durchlaufen MP3-Datei47:("Ohne Gegenstand muss das Spiel leider enden - 5 4 3 2 1 aus")=> Akt=10 (Reset)
  160. - Gegenstand perRFID erkannt => statt Gelb-Blinken hier nun Dauergelb und passende Datei von MP3 Datei-Register 21-40 danach: Akt=150
  161.  
  162. Akt=150: Spieler 3 (falls vorhanden) soll loslegen
  163. - wenn mehr Spieler vorhanden: MP3 Datei6: ("Spieler 3 soll Gegenstand auf gelb blinkenden Terminal legen") danach: Akt=160
  164. - wenn die Spielerzahl abgearbeitet => Akt=200
  165.  
  166. Akt=160: Warten auf Gegenstand von Spieler 3
  167. - wenn nach Zeit4 (einstellbar an Poti4) nichts aufgelegt wurde => MP3-Datei46:("Bitte Gegenstand auf gelb blinkenden Terminal legen")
  168. - wenn Zeit4 drei Mal durchlaufen MP3-Datei47:("Ohne Gegenstand muss das Spiel leider enden - 5 4 3 2 1 aus")=> Akt=10 (Reset)
  169. - Gegenstand perRFID erkannt => statt Gelb-Blinken hier nun Dauergelb und passende Datei von MP3 Datei-Register 21-40 danach: Akt=170
  170.  
  171. Akt=170: Spieler 4 (falls vorhanden) soll loslegen
  172. - wenn mehr Spieler vorhanden: MP3 Datei7: ("Spieler 4 soll Gegenstand auf gelb blinkenden Terminal legen") danach: Akt=180
  173. - wenn die Spielerzahl abgearbeitet => Akt=200
  174.  
  175. Akt=180: Warten auf Gegenstand von Spieler 4
  176. - wenn nach Zeit4 (einstellbar an Poti4) nichts aufgelegt wurde => MP3-Datei46:("Bitte Gegenstand auf gelb blinkenden Terminal legen")
  177. - wenn Zeit4 drei Mal durchlaufen MP3-Datei47:("Ohne Gegenstand muss das Spiel leider enden - 5 4 3 2 1 aus")=> Akt=10 (Reset)
  178. - Gegenstand perRFID erkannt => statt Gelb-Blinken hier nun Dauergelb und passende Datei von MP3 Datei-Register 21-40 danach: Akt=200
  179.  
  180. Akt=200: Zweiter Spielteil beginnt: Kompetenz-Karten auswählen, Spieler 1 soll wählen
  181. - Spot1 (Regalbeleuchtung) dimmt herunter
  182. - Spot2 (Beleuchtung der Kompetenzkarten) dimmt hoch
  183. - Von den genutzten Terminals beginnt nun der erste unten gelb zu blinken
  184. - MP3 Datei8: ("... Spieler 1 - jetzt bitte eine Kompetenzkarte wählen und in den gelb blinkenden Schlitz stecken") danach: Akt=210
  185.  
  186. Akt=210: Warten auf Karte von Spieler 1
  187. - wenn nach Zeit4 (einstellbar an Poti4) nichts aufgelegt wurde => MP3-Datei48:("Bitte Karte in den gelb blinkenden Schlitz stecken")
  188. - wenn Zeit4 drei Mal durchlaufen MP3-Datei49:("Ohne Karte muss das Spiel leider enden - 5 4 3 2 1 aus")=> Akt=10 (Reset)
  189. - wenn Karte per RFID erkannt
  190. => statt Gelb-Blinken hier nun Dauergelb
  191. und passende Datei von MP3 Datei-Register 61-80
  192. danach: statt Dauergelb jetzt Dauergrün,
  193. danach Akt=220
  194.  
  195. Akt=220: Spieler 2 soll Karte wählen
  196. - MP3 Datei9: ("... Spieler2 - jetzt bitte eine Kompetenzkarte wählen und in den gelb blinkenden Schlitz stecken") danach: Akt=230
  197. - Von den genutzten Terminals beginnt nun der zweite unten gelb zu blinken
  198.  
  199. Akt=230: Warten auf Karte von Spieler 2
  200. - wenn nach Zeit4 (einstellbar an Poti4) nichts aufgelegt wurde => MP3-Datei48:("Bitte Karte in den gelb blinkenden Schlitz stecken")
  201. - wenn Zeit4 drei Mal durchlaufen MP3-Datei49:("Ohne Karte muss das Spiel leider enden - 5 4 3 2 1 aus")=> Akt=10 (Reset)
  202. - wenn Karte per RFID erkannt
  203. => statt Gelb-Blinken hier nun Dauergelb
  204. und passende Datei von MP3 Datei-Register 61-80
  205. danach: statt Dauergelb jetzt Dauergrün,
  206. danach Akt=240
  207.  
  208. Akt=240: Spieler 3 - falls vorhanden - soll Karte wählen
  209. - wenn die Spielerzahl abgearbeitet => Akt=300
  210. - wenn mehr Spieler vorhanden: MP3 Datei10: ("... Spieler3 - jetzt bitte eine Kompetenzkarte wählen und in den gelb blinkenden Schlitz stecken") danach: Akt=250
  211. - Von den genutzten Terminals beginnt nun der dritte unten gelb zu blinken
  212.  
  213. Akt=250: Warten auf Karte von Spieler 3
  214. - wenn nach Zeit4 (einstellbar an Poti4) nichts aufgelegt wurde => MP3-Datei48:("Bitte Karte in den gelb blinkenden Schlitz stecken")
  215. - wenn Zeit4 drei Mal durchlaufen MP3-Datei49:("Ohne Karte muss das Spiel leider enden - 5 4 3 2 1 aus")=> Akt=10 (Reset)
  216. - wenn Karte per RFID erkannt
  217. => statt Gelb-Blinken hier nun Dauergelb
  218. und passende Datei von MP3 Datei-Register 61-80
  219. danach: statt Dauergelb jetzt Dauergrün,
  220. danach Akt=260
  221.  
  222. Akt=260: Spieler 4 - falls vorhanden - soll Karte wählen
  223. - wenn die Spielerzahl abgearbeitet => Akt=300
  224. - wenn mehr Spieler vorhanden: MP3 Datei11: ("... Spieler4 - jetzt bitte eine Kompetenzkarte wählen und in den gelb blinkenden Schlitz stecken") danach: Akt=270
  225. - Von den genutzten Terminals beginnt nun der vierte unten gelb zu blinken
  226.  
  227. Akt=270: Warten auf Karte von Spieler 4
  228. - wenn nach Zeit4 (einstellbar an Poti4) nichts aufgelegt wurde => MP3-Datei48:("Bitte Karte in den gelb blinkenden Schlitz stecken")
  229. - wenn Zeit4 drei Mal durchlaufen MP3-Datei49:("Ohne Karte muss das Spiel leider enden - 5 4 3 2 1 aus")=> Akt=10 (Reset)
  230. - wenn Karte per RFID erkannt
  231. => statt Gelb-Blinken hier nun Dauergelb
  232. und passende Datei von MP3-Register 61-80
  233. danach: statt Dauergelb jetzt Dauergrün,
  234. danach Akt=300
  235.  
  236. Akt=300: Sesam öffne dich
  237. - MP3 Datei 13: ("Überleitung/ Türknarzen und Begrüßung/ Taschenlampen entnehmen..."), danach Akt=310
  238. - Hauptlicht wird heruntergedimmt
  239. - Spot 2 dimmt herunter
  240. - Türe springt auf per EMagnet1 per Relais 2
  241. - Spot 3 Blinkfunktion auf Taschenlampenfach an
  242.  
  243. Akt=310: Spielbeginn Innenraum per Klynt-Technik
  244. - Relais 3 schaltet Verstärker von außen nach Verstärker innen
  245. - wenn Taschenlampen entnommen (Sensor1): Blinkfunktion Taschenlampenfach aus
  246. - wenn noch Taschenlampen da: MP3-Datei 50 („Bitte ALLE Taschenlampen mitnehmen)
  247. - nach Zeit5 Mausklick per Relais4 zum Starten der Klynt, evtl. Datei
  248. - nach Zeit6 Raumlicht wird leicht hochgedimmt
  249. - evtl. MP3 Datei 15
  250.  
  251. Akt=320: Vor Spielende: Taschenlampenfach wird zugeschoben
  252. - evtl. MP3-Datei17 und/ oder 18
  253. - nach Zeit7 wird Raumlicht maximal hochgedimmt
  254. und E-Magnet2 per Relais5 öffnet die Ausgangstüre
  255.  
  256.  
  257. Akt>=40 Neustartmöglichkeit
  258. - wenn Knopf1 lange gedrückt wird Akt=10 (Reset)
  259.  
  260. Akt>=40 und Akt<310: Besucher haben sich unerwartet verabschiedet
  261. - wenn Zeit8 ereignislos abläuft wird Akt=10 (Reset)
  262.   */
  263. }
  264. if(taster1.aktiv(10)){
  265. Serial.print("t");
  266. delay(100);
  267. }
  268. }
  269.  
  270. void spreche(byte n){ // Nachricht bis zum Ende ausgeben (blockierend)
  271. myMP3.play(n);
  272. Serial.print(F("Nachricht: "));
  273. Serial.println(n);
  274. delay(1000);
  275. while(!digitalRead(MP3_Busy)); // warten bis Ende
  276. }
  277.  
  278. void resetRfid(byte station){ // RFID-Leser zurücksetzen um liegengebliebene Karten zu entdecken
  279. Wire.beginTransmission(station+8); // sendet zu Node empfaenger
  280. Wire.write(RFID_reset); // sendet daten
  281. Wire.endTransmission(); // Übermittlungsstop
  282. }
  283.  
  284. void setzeRGB(byte station, byte p, byte muster, byte dauer){ // p=0: oben dauer*10ms
  285. if(p) muster |= 128; // Bit 7 setzen für unten
  286. Wire.beginTransmission(station+8); // sendet zu Node empfaenger
  287. Wire.write(muster); // sendet daten
  288. Wire.write(dauer); // sendet daten
  289. Wire.endTransmission(); // Übermittlungsstop
  290. //Serial.println(F("Daten gesendet"));
  291. }
  292.  
  293. byte pruefeHallo(byte station){ // Station 0..3 Adresse 8..11
  294. Wire.beginTransmission(station+8); // sendet zu Node empfaenger
  295. Wire.write(C_Hallo); // Hallo senden
  296. Wire.endTransmission(); // Übermittlungsstop
  297. Serial.print(F("Hallo Anfrage gesendet an: "));
  298. Serial.print(station);
  299. delay(RFID_DELAY); // Zeit zum antworten lassen
  300. Wire.requestFrom(station+8, 2); // sollte mit "OK" antworten
  301. if(Wire.read()!='O') return 0;
  302. if(Wire.read()!='K') return 0;
  303. return 1; // OK geantwortet
  304. }
  305.  
  306. byte leseRfid(byte station, byte platz){ // 0..3 platz=0 ist oben
  307. byte l,i,k;
  308. byte id[7]; // Puffer für Karten id
  309. byte treffer=0;
  310. Wire.beginTransmission(station+8); // sendet zu Node empfaenger
  311. if(!platz) Wire.write(RFID_oben); // oben lesen
  312. else Wire.write(RFID_unten); // unten lesen
  313. Wire.endTransmission(); // Übermittlungsstop
  314. delay(RFID_DELAY); // Zeit zum antworten lassen
  315. Wire.requestFrom(station+8, 8); // Fragt Daten von Node empfaenger ab
  316. l = Wire.read(); // erstes Byte gibt Anzahl der Bytes an
  317. if (l==0){
  318. //Serial.println(F("Keine neue Karte"));
  319. return 0;
  320. }
  321. else if (l>7){
  322. Serial.print(F("leseRfid: Falsche Byteanzahl: "));
  323. Serial.println(l);
  324. return 0;
  325. }else{
  326. Serial.print(F("Karte mit ID: "));
  327. for (i=0;i<l;i++){ // lies die ID ein
  328. id[i]=Wire.read();
  329. Serial.print(id[i],HEX);
  330. }
  331. Serial.println("");
  332. k=sizeof(karten)/sizeof(karten[0]); // Karte bestimmen
  333. for(k=0;k<sizeof(karten)/sizeof(karten[0]);k++){ // für alle gespeicherten Karten
  334. for(i=0;i<l;i++){ // für alle Bytes
  335. if(id[i]!=pgm_read_byte(&karten[k][i])) break; // hat nicht gepasst
  336. }
  337. if(i==l) {
  338. treffer = 1;
  339. break;
  340. }
  341. }
  342. if (treffer){
  343. //Serial.print(F("Karte erkannt: "));
  344. //Serial.println(k);
  345. return k+1;
  346. }
  347. else{
  348. Serial.print(F("Neue Karte: {"));
  349. for (i=0;i<l-1;i++){ // zwecks Speicherung ausgeben
  350. Serial.print(F("0x"));
  351. Serial.print(id[i],HEX);
  352. Serial.print(F(","));
  353. }
  354. Serial.print(F("0x"));
  355. Serial.print(id[i],HEX);
  356. Serial.println(F("}"));
  357. return 255; // unbekannte Karte
  358. }
  359. }
  360. }
  361. void serialKommandos(){ // über seriellen Monitor steuern
  362. byte key_command;
  363. if (Serial.available()){
  364. key_command=Serial.read();
  365. Serial.print(F("Komando "));
  366. Serial.write(key_command);
  367. Serial.println("");
  368. switch (key_command){
  369. case 'q':
  370. zustand=Z_reset;
  371. break;
  372. case 'r': setzeRGB(1,0,0b100,0); break;
  373. case 'g': setzeRGB(1,0,0b010,0); break;
  374. case 'b': setzeRGB(1,0,0b001,0); break;
  375. case 'x': resetRfid(1); break;
  376. case 'o':
  377. Serial.println(leseRfid(1,0));
  378. break;
  379. case 't': setzeRGB(1,0,0b110,10);
  380. break;
  381. case 's': setzeRGB(1,1,0b011,30);
  382. break;
  383. case 'k': kartentest=!kartentest;
  384. Serial.println(F("Dauerkartentest umschalten"));
  385. break;
  386. case 'p': myMP3.play(2); // spiele Stueck 1..10
  387. break;
  388. case 'z': zeit1.start();
  389. setzeRGB(1,0,0b111,0);
  390. zustand = Z_reset;
  391. break;
  392. }
  393. }
  394. }
  395.