duinozone.cz - Arduino a Raspberry fórum

Autor Téma: RFID stopky - Arduino + LCD 20x4  (Přečteno 163 krát)

Offline martinius96

  • Bastlíř začátečník
  • *
  • Příspěvků: 12
RFID stopky - Arduino + LCD 20x4
« kdy: Březen 13, 2018, 00:30:49 dopoledne »
Ahoj, rád by som sa s vami podelil o projekt, ktorý som realizoval pre airsofťákov pre ich dlho-hodinový event.

Počas niekoľko hodinových eventov v extrémnych hrách typu Airsoft/Paintball/Nerf wars sa hrajú rôzne módy, napríklad King of The Hill, pre ktorý je tento projekt určený. Každý tím získava body za dobu obsadenia daného bodu, resp za dobu jeho udržania. Bol som oslovený ohľadom zostrojenia takéhoto projektu. Využil som Arduino, RFID čítačku, kĺúčenky (karty nefungovali až tak dobre, iba v presnej polohe), LCD displej, hlásič (buzzer) a relé/samostatné ledky ako indikátor, komu sa stav pripočítava, aby bol stav hry jasný.

Systém používa dva nezávislé časy pre dva tímy, ktoré fungujú po priložení niektorej z kľúčeniek tímov práve pre štart času daného tímu. Časy fungujú pod funkciou millis. V praxi má každý člen tímu RFID kľúčenku, ktorú vie priložiť na čítačku a aktivovať čas pre svoj tím a získava tým body v tomto hernom móde za celkový čas, pokým je zóna aktívna pod kľúčenkou ich tímu.

Formát času:
HH:mm:ss - hra sa začína s hodnotami 00:00:00 pre oba tímy

Organizácia tímov:
    Tím 1 - horný čas
    Tím 2 - spodný čas
    Organizátor (rozhodca) - pauzuje čas svojou kľúčenkou
    Eraser - Nuluje čas svojou kľúčenkou

Čas sa pripočítava do momentu, kým nie je zastavený druhým tímom priložením ich karty (začne sa čas pripočítavať tomuto tímu), alebo organizátorom/rozhodcom, ktorý vie čas pauzovať, alebo špeciálnou kľúčenkou/kartou vynulovať, napríklad po dohraní hry, alebo pri jej reštarte.

Hlásič signalizuje priloženie karty k čítačke a LED diódy/relé indikujú momentálny stav stopiek, signalizujú farbu tímu, ktorému sa čas pripočítava červená/modrá.

Projekt je určený pre (ne)obmedzený počet kľúčeniek, teda sa dajú nahodiť celé tímy, organizátori akcie, karty pre vymazanie výsledkov.

Kľúčenky sú spravidla odlišené farbou pre daný tím, aby bolo jednoduché kľúčenky rozlíšiť pre dané tímy. Relé sa využívajú v prípade, že sa používajú silnejšie svetlá pre signalizáciu aktívneho tímu (napr 230V), ktorému sa pripočítava čas.

Hardvér pre projekt:
    Arduino Uno
[/list]
    RFID čítačka MC522
[/list]
    Kľúčenky
[/list]
    Buzzer (hlásič)
[/list]
    Relé/diódy
[/list]
    LCD displej 20x4 (zdrojový kód kompatibilný pre čínsky model HD44780)
[/list]

Wiring:


Zdrojový kód (načítanie adries kariet, ktoré sa použijú vo finálnom sketchi):
Kód: [Vybrat]
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN         9          // Configurable, see typical pin layout above
#define SS_1_PIN        10       
#define SS_2_PIN        8         

#define NR_OF_READERS   1

byte ssPins[] = {SS_1_PIN, SS_2_PIN};

MFRC522 mfrc522[NR_OF_READERS];   // Create MFRC522 instance.

void setup() {

  Serial.begin(9600); // Initialize serial communications with the PC
  while (!Serial);    // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)

  SPI.begin();        // Init SPI bus

  for (uint8_t reader = 0; reader < NR_OF_READERS; reader++) {
    mfrc522[reader].PCD_Init(ssPins[reader], RST_PIN); // Init each MFRC522 card
    Serial.print(F("Reader "));
    Serial.print(reader);
    Serial.print(F(": "));
    mfrc522[reader].PCD_DumpVersionToSerial();
  }
}

/**
 * Main loop.
 */
void loop() {

  for (uint8_t reader = 0; reader < NR_OF_READERS; reader++) {
    // Look for new cards

    if (mfrc522[reader].PICC_IsNewCardPresent() && mfrc522[reader].PICC_ReadCardSerial()) {
      Serial.print(F("Reader "));
      Serial.print(reader);
      // Show some details of the PICC (that is: the tag/card)
      Serial.print(F(": Card UID:"));
      dump_byte_array(mfrc522[reader].uid.uidByte, mfrc522[reader].uid.size);
      Serial.println();
      Serial.print(F("PICC type: "));
      MFRC522::PICC_Type piccType = mfrc522[reader].PICC_GetType(mfrc522[reader].uid.sak);
      Serial.println(mfrc522[reader].PICC_GetTypeName(piccType));

      // Halt PICC
      mfrc522[reader].PICC_HaltA();
      // Stop encryption on PCD
      mfrc522[reader].PCD_StopCrypto1();
    } //if (mfrc522[reader].PICC_IsNewC
  } //for(uint8_t reader
}

/**
 * Helper routine to dump a byte array as hex values to Serial.
 */
void dump_byte_array(byte *buffer, byte bufferSize) {
  for (byte i = 0; i < bufferSize; i++) {
   
  }
  Serial.print("Kod:");
  unsigned long kod = 10000*buffer[4]+1000*buffer[3]+100*buffer[2]+10*buffer[1]+buffer[0]; //finalny kod karty
  Serial.print(kod);
}

Rozmýšľal som, ako reprezentovať adresy kariet, pretože to bolo pole, ktoré bolo indexované a obsahovalo 2 znaky v jednom indexe poľa. Vyriešené násobením hodnoty, najprv číslom *10000, ďalej *1000.... Funguje to pod DEC hodnotou.
Zdrojový kód (final s použitím kódov):
Kód: [Vybrat]
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9          // Configurable, see typical pin layout above
#define SS_1_PIN        10         // Configurable, take a unused pin, only HIGH/LOW required, must be diffrent to SS 2
#define SS_2_PIN        8          // Configurable, take a unused pin, only HIGH/LOW required, must be diffrent to SS 1

#define NR_OF_READERS   1

byte ssPins[] = {SS_1_PIN, SS_2_PIN};

MFRC522 mfrc522[NR_OF_READERS];   // Create MFRC522 instance.

#define I2C_ADDR    0x3F  // Define I2C Address where the PCF8574A is
                          // Address can be changed by soldering A0, A1, or A2
                          // Default is 0x27

// map the pin configuration of LCD backpack for the LiquidCristal class
#define BACKLIGHT_PIN 3
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7

LiquidCrystal_I2C lcd(I2C_ADDR,
                      En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin,
                      BACKLIGHT_PIN, POSITIVE);
unsigned long kod;
boolean run = false;
boolean run2 = false;
long timer = 0; //The timer
int second = 0;
int minute = 0;
int tenth = 0;
int hour =0;
int second2 = 0;
int minute2 = 0;
int tenth2 = 0;
int hour2 =0;
const int rfrele = 3;
const int gdprele = 4;
const int buzzer = 5;
void setup() {
  Serial.begin(9600);
  SPI.begin();
  pinMode(rfrele,OUTPUT);
  pinMode(gdprele,OUTPUT);
  pinMode(buzzer,OUTPUT);
    for (uint8_t reader = 0; reader < NR_OF_READERS; reader++) {
    mfrc522[reader].PCD_Init(ssPins[reader], RST_PIN); // Init each MFRC522 card
    Serial.print(F("Reader "));
    Serial.print(reader);
    Serial.print(F(": "));
    mfrc522[reader].PCD_DumpVersionToSerial();
  }
  lcd.begin(20, 4);                // intialise the LCD.
     lcd.setBacklight(HIGH); // Turn on backlight, LOW for off
  lcd.setCursor(0,0);
  lcd.print("  RP2018 DOMINATOR");
  lcd.setCursor(0,1);
   lcd.print("--------------------");
  lcd.setCursor(0,2);
  lcd.print("RF  00:00:00");
   lcd.setCursor(0,3);
   lcd.print("GDP 00:00:00");
}

void tickClock() {
  if((timer - millis()/100) >= 100 || timer == 0) {
    tick();
    tick2();
    timer = millis()/100;
  }
 
}

void loop() {
   for (uint8_t reader = 0; reader < NR_OF_READERS; reader++) {
    if (mfrc522[reader].PICC_IsNewCardPresent() && mfrc522[reader].PICC_ReadCardSerial()) {
      Serial.print(F("Reader "));
      Serial.print(reader);
      // Show some details of the PICC (that is: the tag/card)
      Serial.print(F(": Card UID:"));
      dump_byte_array(mfrc522[reader].uid.uidByte, mfrc522[reader].uid.size);
      Serial.println();
      Serial.print(F("PICC type: "));
      MFRC522::PICC_Type piccType = mfrc522[reader].PICC_GetType(mfrc522[reader].uid.sak);
      Serial.println(mfrc522[reader].PICC_GetTypeName(piccType));

      // Halt PICC
      mfrc522[reader].PICC_HaltA();
      // Stop encryption on PCD
      mfrc522[reader].PCD_StopCrypto1();
    } //if (mfrc522[reader].PICC_IsNewC
  } //for(uint8_t reader
  if(kod==4294946665 || kod==23101 || kod==8151 || kod==4294951443 || kod==4294953039 || kod==24519 || kod==4294945657 || kod==3801 || kod==4294945187){
     
       digitalWrite(rfrele, LOW);
             digitalWrite(gdprele, HIGH);
      run = false;
      run2 = true;
        }else if(kod==4294956915 || kod==4294958051 || kod==4294961082 || kod==4294960491 || kod==4294958039 || kod==4294958091 || kod==4294946987 || kod==4294961057 || kod==4294959927){
       
           digitalWrite(rfrele, HIGH);
             digitalWrite(gdprele, LOW);
          run = true;
      run2 = false;
          }else if(kod==12619){
           
             digitalWrite(rfrele, LOW);
             digitalWrite(gdprele, LOW);
            run = false;
      run2 = false;
            }else if(kod==4294962506){
           
             digitalWrite(rfrele, LOW);
             digitalWrite(gdprele, LOW);
       second = 0;
 minute = 0;
 tenth = 0;
 hour =0;
 second2 = 0;
 minute2 = 0;
 tenth2 = 0;
 hour2 =0;
 updateLCD();
 updateLCD2();
  run = false;
      run2 = false;
              }
  tickClock(); //Start ticking the clock
}

void tick() {
  if(run) {
    updateLCD();
   
   
   
    if(tenth == 9) {
      tenth = 0;
     
      if(second == 59) {
        second = 0;
        minute++;
       
      }else {
        second++;
      }
     
      if(minute == 60) {
        minute = 0;
        hour++;
       
      }
    } else {
    tenth++;
    }
  }
}
void tick2() {
  if(run2) {
    updateLCD2();
   
   
   
    if(tenth2 == 9) {
      tenth2 = 0;
     
      if(second2 == 59) {
        second2 = 0;
        minute2++;
       
      }else {
        second2++;
      }
     
      if(minute2 == 60) {
        minute2 = 0;
        hour2++;
       
      }
    } else {
    tenth2++;
    }
  }
}
void updateLCD() {
   lcd.setCursor(4,2);
 if(hour < 10) {      // If hour does not have 2 digits
    lcd.print("0");
  }
   lcd.print(hour, DEC);
  lcd.print(":");
  if(minute < 10) {      // If hour does not have 2 digits
    lcd.print("0");
  }
  lcd.print(minute, DEC);
  lcd.print(":");

  if(second < 10) {    // If minute does not have 2 digits
    lcd.print("0");
  }
  lcd.print(second, DEC);
  //
 
}
void updateLCD2() {
  lcd.setCursor(4,3);
  if(hour2 < 10) {      // If hour does not have 2 digits
    lcd.print("0");
  }
   lcd.print(hour2, DEC);
  lcd.print(":");
  if(minute2 < 10) {      // If hour does not have 2 digits
    lcd.print("0");
  }
  lcd.print(minute2, DEC);
  lcd.print(":");

  if(second2 < 10) {    // If minute does not have 2 digits
    lcd.print("0");
  }
  lcd.print(second2, DEC);
 
}












void dump_byte_array(byte *buffer, byte bufferSize) {
  for (byte i = 0; i < bufferSize; i++) {

  }
  kod = 10000*buffer[4]+1000*buffer[3]+100*buffer[2]+10*buffer[1]+buffer[0]; 
    tone(buzzer, 4000, 100);
  Serial.println("Zaznamenany kod karty: ");
  Serial.println(kod);
}

Táto časť kódu reprezentuje časy pre každý z tímov:
Kód: [Vybrat]
boolean run = false;
boolean run2 = false;

Keď je niektorý z booleanov nastavený na true, čas beží pre daný tím.

Táto časť kódu reprezentuje použitie viacerých kódov kariet zistených v prvom sketchi pre účely jedného tímu (po priložení ktorejkoľvek karty z vpísaných v if podmienke sa začne čas pripočítavať pre druhý tím:
Kód: [Vybrat]
if(kod==4294946665 || kod==23101 || kod==8151 || kod==4294951443 || kod==4294953039 || kod==24519 || kod==4294945657 || kod==3801 || kod==4294945187){ // || = operator OR (alebo)
     
       digitalWrite(rfrele, LOW); //vypni diodu/rele pre prvy tim
             digitalWrite(gdprele, HIGH); //zapni diodu/rele pre druhy tim
      run = false; //zastav cas prveho timu
      run2 = true; //spust cas druheho timu
     

Kód a aktuálne knižnice predpokladajú  využitie LCD displeja 20x4 HD44780 s I2C prevodníkom. Kód je ale ľahké prispôsobiť aj pre ostatné znakové i grafické displeje po zmene knižnice a niektorých inicializačných funkcií..


Prepisovanie kódov do sketchu je dosť zdĺhavé, ale výsledok stojí zato. Verím, že si vašu hru užijete s Arduino stopkami.

Pozor pri používaní relé modulov, majú obrátenú logiku (stav LOW spína, HIGH rozpína)
Knižnice k projektu: https://www.ulozto.sk/!tRA0Xhu83OXP/rfi%20...%20iznice-zip
Ďalšie zaujímavé projekty môžete nájsť i na mojom webe: https://arduino.php5.sk/