Получение редактируемых данных из памяти RFID (RC522)

Lord_elf
Offline
Зарегистрирован: 06.05.2016

Добрый день, уважаемые старожилы)

Вопрос наверное до безумия глупый, но бьюсь уже второй день с ним(

Исходные данные: Есть ридер RC552, куча меток-брелков к ней, горячее желание сделать что-то полезное и не особо понимающая как это сделать голова(

Цель: Есть куча меток, поднося которые к ридеру можно получить определенное количество баллов. Количество баллов записано в памяти метки.

Реализация: Используя библиотеку <MFRC522.h> и стандартные примеры в ней (rfid_read_personal_data.ino и rfid_write_personal_data.ino) записываем в память метки 4 числа, для примера 7010, где "7" - пароль, для того чтобы мы понимали что это наша метка используется (для исключения использования сторонними метками), а "010" это количество баллов на конкретной метке (будет от 000 до 999). 

Используя пример rfid_write_personal_data.ino на запрос Name вводим через монитор порта "7010". Запись проходит. Хорошо, с этим мы справились)

Код примера записи (он стандартный в библиотеке):


#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9           // Configurable, see typical pin layout above
#define SS_PIN          10          // Configurable, see typical pin layout above

MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance

void setup() {
  Serial.begin(9600);        // Initialize serial communications with the PC
  SPI.begin();               // Init SPI bus
  mfrc522.PCD_Init();        // Init MFRC522 card
  Serial.println(F("Write personal data on a MIFARE PICC "));
}

void loop() {

  // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
  MFRC522::MIFARE_Key key;
  for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;

  // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    return;
  }

  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial()) {
    return;
  }

  Serial.print(F("Card UID:"));    //Dump UID
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
    Serial.print(mfrc522.uid.uidByte[i], HEX);
  }
  Serial.print(F(" PICC type: "));   // Dump PICC type
  MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
  Serial.println(mfrc522.PICC_GetTypeName(piccType));

  byte buffer[34];
  byte block;
  MFRC522::StatusCode status;
  byte len;

  Serial.setTimeout(20000L) ;     // wait until 20 seconds for input from serial
  // Ask personal data: Family name
  Serial.println(F("Type Family name, ending with #"));
  len = Serial.readBytesUntil('#', (char *) buffer, 30) ; // read family name from serial
  for (byte i = len; i < 30; i++) buffer[i] = ' ';     // pad with spaces

  block = 1;
  //Serial.println(F("Authenticating using key A..."));
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("PCD_Authenticate() success: "));

  // Write block
  status = mfrc522.MIFARE_Write(block, buffer, 16);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("MIFARE_Write() success: "));

  block = 2;
  //Serial.println(F("Authenticating using key A..."));
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  // Write block
  status = mfrc522.MIFARE_Write(block, &buffer[16], 16);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("MIFARE_Write() success: "));

  // Ask personal data: First name
  Serial.println(F("Type First name, ending with #"));
  len = Serial.readBytesUntil('#', (char *) buffer, 20) ; // read first name from serial
  for (byte i = len; i < 20; i++) buffer[i] = ' ';     // pad with spaces

  block = 4;
  //Serial.println(F("Authenticating using key A..."));
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  // Write block
  status = mfrc522.MIFARE_Write(block, buffer, 16);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("MIFARE_Write() success: "));

  block = 5;
  //Serial.println(F("Authenticating using key A..."));
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  // Write block
  status = mfrc522.MIFARE_Write(block, &buffer[16], 16);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("MIFARE_Write() success: "));


  Serial.println(" ");
  mfrc522.PICC_HaltA(); // Halt PICC
  mfrc522.PCD_StopCrypto1();  // Stop encryption on PCD

}

Далее загружаем пример rfid_read_personal_data.ino считываем данные из метки и выводим в монитор порта заветное значение Name: 7010.

Код примера чтения:

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9           // Configurable, see typical pin layout above
#define SS_PIN          10          // Configurable, see typical pin layout above

MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance

//*****************************************************************************************//
void setup() {
  Serial.begin(9600);                                           // Initialize serial communications with the PC
  SPI.begin();                                                  // Init SPI bus
  mfrc522.PCD_Init();                                              // Init MFRC522 card
  Serial.println(F("Read personal data on a MIFARE PICC:"));    //shows in serial that it is ready to read
}

//*****************************************************************************************//
void loop() {

  // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
  MFRC522::MIFARE_Key key;
  for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;

  //some variables we need
  byte block;
  byte len;
  MFRC522::StatusCode status;

  //-------------------------------------------

  // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    return;
  }

  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial()) {
    return;
  }

  Serial.println(F("**Card Detected:**"));

  //-------------------------------------------

  mfrc522.PICC_DumpDetailsToSerial(&(mfrc522.uid)); //dump some details about the card

  //mfrc522.PICC_DumpToSerial(&(mfrc522.uid));      //uncomment this to see all blocks in hex

  //-------------------------------------------

  Serial.print(F("Name: "));

  byte buffer1[18];

  block = 4;
  len = 18;

  //------------------------------------------- GET FIRST NAME
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 4, &key, &(mfrc522.uid)); //line 834 of MFRC522.cpp file
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("Authentication failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  status = mfrc522.MIFARE_Read(block, buffer1, &len);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("Reading failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  //PRINT FIRST NAME
  for (uint8_t i = 0; i < 16; i++)
  {
    if (buffer1[i] != 32)
    {
      Serial.write(buffer1[i]);
    }
  }
  Serial.print(" ");

  //---------------------------------------- GET LAST NAME

  byte buffer2[18];
  block = 1;

  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 1, &key, &(mfrc522.uid)); //line 834
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("Authentication failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  status = mfrc522.MIFARE_Read(block, buffer2, &len);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("Reading failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  //PRINT LAST NAME
  for (uint8_t i = 0; i < 16; i++) {
    Serial.write(buffer2[i] );
  }


  //----------------------------------------

  Serial.println(F("\n**End Reading**\n"));

  delay(1000); //change value if you want to read cards faster

  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();
}

Казалось бы победа, НО я вот честно не могу понять как мне перевести buffer1 и buffer2 в десятичные цифры. В мониторе порта отображается все верно, выводится мое число, но при присваивании любого из буфера хоть в переменную, хоть в массив побайтово - выходит какая то ахинея(

Я честно признаю что не могу понять как перевести и из-за этого стопорится все, мне же потом эти баллы суммировать надо в итоге, да и проверку по паролю первой цифры нужно провести...

Поэтому очень прошу помощи, как мне из этих буферов получить две цифры (первое число и 2-4)?

b707
Offline
Зарегистрирован: 26.05.2017

в первом примере вы записываете свое число не как число, а как строку - "7010". Cоответвенно и читаетеся обратно строка, где в первом символе - ваш пароль, а со второго - номер.

Lord_elf
Offline
Зарегистрирован: 06.05.2016

b707 пишет:

в первом примере вы записываете свое число не как число, а как строку - "7010". Cоответвенно и читаетеся обратно строка, где в первом символе - ваш пароль, а со второго - номер.

Хм... теперь стало понятнее, а каким образом мне можно из строки получить число?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

читай за atoi()

Lord_elf
Offline
Зарегистрирован: 06.05.2016

Большое спасибо за наводку, все получилось!) Правда пришлось байтовый массив перевести в строчный, а потом уже перевести в цифры. Хоть и с костылями, но он работает!)

b707
Offline
Зарегистрирован: 26.05.2017

Lord_elf пишет:

Правда пришлось байтовый массив перевести в строчный, а потом уже перевести в цифры. Хоть и с костылями, но он работает!)

лучше не в строчный (String), а в символьный - char[]. И не такой уж это костыль, а довольно типовое решение

Lord_elf
Offline
Зарегистрирован: 06.05.2016

Перевел!!!!) И даже все заработало!

  byte buffer2[18];   //Байтовая переменная чтобы записать информацию из памяти метки
  char buffer3[18];   //Символьная переменная чтобы записать информацию из байтовой
  
  status = mfrc522.MIFARE_Read(block, buffer2, &len);

  for (uint8_t i = 0; i < 16; i++) { Serial.write(buffer2[i]); buffer3[i] = buffer2[i];}
  lcd.setCursor(0,0);
  int z=atoi(buffer3);  //Переводим строку в число, получаем

Но теперь нужен обратный цикл, чтобы в команду на запись отправить число интовое, что я только не пытался делать - нифига не выходит(( При прочтении показывает абракадабру( То есть примером с терминала все хорошо записывается и читается, а когда пытаюсь с устройства записать интовое значение - не выходит.

byte buffer[34];
  byte block;
  MFRC522::StatusCode status;
  byte len;

  Serial.setTimeout(20000L) ;     // wait until 20 seconds for input from serial
  // Ask personal data: Family name
  Serial.println(F("Type Family name, ending with #"));
  len = Serial.readBytesUntil('#', (char *) buffer, 30) ; // read family name from serial
  for (byte i = len; i < 30; i++) buffer[i] = ' ';     // pad with spaces

  block = 1;
  //Serial.println(F("Authenticating using key A..."));
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("PCD_Authenticate() success: "));

  // Write block
  status = mfrc522.MIFARE_Write(block, buffer, 16);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("MIFARE_Write() success: "));

Вот кусок из примера на запись, в buffer нужно загнать предыдущее значение z. Пните меня пожалуйста в нужном направлении) Потому что пробовал z разбивать на числа, присваивать символьной переменной, а ее через buffer[0]=(byte)buffer2[0]; присваивать буферу, на выходе какая то пакость(

sadman41
Offline
Зарегистрирован: 19.10.2016

Обратное к atoi - ltoa, ultoa

Lord_elf
Offline
Зарегистрирован: 06.05.2016

sadman41 пишет:
Обратное к atoi - ltoa, ultoa

Попробовал, все равно абра-кадабра((

char buffer3[18];
byte buffer[34];

ltoa (5001, buffer3, 16);
         buffer[0]=buffer3[0];
         buffer[1]=buffer3[1];
         buffer[2]=buffer3[2];
         buffer[3]=buffer3[3];
         
  // Write block
  status = mfrc522.MIFARE_Write(block, buffer, 16);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("MIFARE_Write() success: "));

Выдает:

Read personal data on a MIFARE PICC:
PCD_Authenticate() success: 
MIFARE_Write() success: 
Read personal data on a MIFARE PICC:
**Card Detected:**
Card UID: 6C 92 9E 83
Card SAK: 08
PICC type: MIFARE 1KB
Name: іlҐЈ¶ё
**End Reading**

 

sadman41
Offline
Зарегистрирован: 19.10.2016

А что, в карту нужно строку писать? Я всегда число писал числом.

Lord_elf
Offline
Зарегистрирован: 06.05.2016

Да я бы с удовольствием)) Только не понимаю как((

sadman41
Offline
Зарегистрирован: 19.10.2016

numberR=0;
numberW=2022;
...write(..., (uint8_t*)&numberW, sizeof(numberW));
...read(..., (uint8_t*)&numberR, sizeof(numberR));
...print(numberR);

Считали из памяти N байт, начиная с адреса, по которому лежит numberW.

Записали в память N байт, начиная с адреса, по которому находится numberR.

Обе переменные должны быть одинакового типа.

Вроде как-то так.