📜 ⬆️ ⬇️

Arduino: TV viewing time limit using RFID RC522 and

This article will talk about how I have limited the time watching TV for a child using Arduino.

For some time, I began not to make a child's assessment at school. Passwords were set on the tablet and smartphone, time of use was limited to the PC, but the TV remained. Hiding the cable every day, tired, and not the fact that he had not bought his own. As a result, I decided to make a device that would limit TV viewing time, i.e. would just disconnect 220V.

To implement my idea I used:

1. Double Side Prototype PCB Tinned Universal Breadboard 2x8 cm 20mmx80mm FR4:
image
')
2. 5V One 1 Channel Relay Module Board Shield For PIC AVR DSP ARM MCU Arduino:
image

3. USB Nano V3.0 ATmega328 16M 5V Micro-controller CH340G board For Arduino:
image

4. Mifare RC522 Card Read Antenna RF Module RFID Reader IC Card Proximity Module:
image

5. White 3-5V 0.96 "SPI Serial 128X64 OLED LCD LED Display Module for Arduino:
image

When the device is turned on, it reads information from the EEPROM for the presence of recorded cards (I limited the maximum number of cards to 6). The EEPROM stores the last 4 bytes of the UID map translated into decimal format. For reading and writing to the EEPROM I used the EEPROM2.h library.

Code
cardPresent = readCards(); boolean readCards() { cardPresent = false; for(int k = 0; k <6; k++) { EEPROM_read(k*6+4, time[k]); if(time[k] >= 0) { cardPresent = true; EEPROM_read(k*6, cards[k]); } } return cardPresent; } 


To work with the MFRC522 module, I used the MFRC522.h library. Read the cards as follows:

Code
 MFRC522 mfrc522(SS_PIN, RST_PIN); void setup() { SPI.begin(); // Init SPI bus mfrc522.PCD_Init(); // Init MFRC522 void loop() { // Look for new cards if ( ! mfrc522.PICC_IsNewCardPresent()) { return; } // Select one of the cards if ( ! mfrc522.PICC_ReadCardSerial()) { return; } String s = dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); mfrc522.PICC_HaltA(); //           (  dump_byte_array    ,      ). Serial.println(s); } 


If there are no maps in the EEPROM, the first attached map is assigned by the master and is written to cell 0:

Code
  if(!cardPresent) { //  ,      short master = 0; EEPROM_write(0, uiddec); EEPROM_write(4, master); message = "NEW MASTER"; cardPresent = true; readCards(); } 


Display messages on the monitor. Used library HCuOLED.h :

Code
 /* Create an instance of the library (uncomment one of the lines below) */ //HCuOLED HCuOLED(SSD1307, SS_DI, DC_DI, RST_DI); // For SSD1307 displays (HCMODU0050 & HCMODU0052) HCuOLED HCuOLED(SH1106, CS_DI, DC_DI, RST_DI); // For SH1106 displays (HCMODU0058 & HCMODU0059) void setup() { HCuOLED.Reset(); } void drawUid(char *s) { HCuOLED.Erase(0,16,120,32); HCuOLED.SetFont(MedProp_11pt); HCuOLED.Cursor(0,16); HCuOLED.Print(s); HCuOLED.Refresh(); } void drawLong(long uid) { HCuOLED.Erase(0,33,120,48); HCuOLED.SetFont(MedProp_11pt); HCuOLED.Cursor(0,33); HCuOLED.Print(uid); HCuOLED.Refresh(); } void drawCardTime(String s) { char mess[12]; s.toCharArray(mess, 12); HCuOLED.Erase(0,49,120,80); HCuOLED.SetFont(MedProp_11pt); HCuOLED.Cursor(0,49); HCuOLED.Print(mess); HCuOLED.Refresh(); } 


Now I will give the code of the String function dump_byte_array (byte * buffer, byte bufferSize). It is called after reading the card. The operation of the device is implemented as follows:

1. We translate the last 4 bytes into decimal format and display the uid of the card in both formats, we look for the coincidence of the uid with what we considered from the EEPROM:

Code
  String s; unsigned long uiddec = 0; unsigned long temp; char uid[8]; for (byte m = (bufferSize > 4 ? (bufferSize - 4) : 0); m < bufferSize; m++) { //   4       unsigned long p = 1; for(int k = 0; k < bufferSize-m-1; k++) { p = p*256; } uiddec += p*buffer[m]; s = s + (buffer[m] < 0x10 ? "0" : ""); s = s + String(buffer[m], HEX); } s.toCharArray(uid, 8); drawUid(uid); drawLong(uiddec); message = "unknow"; short currentCard = -1; for(int k = 0; k <6; k++) { //  uid        if((time[k] >=0) && (cards[k] == uiddec)) { currentCard = k; } } 


2. Next comes the code that implements the device logic. If the card is known, but it is not a master, then the onRelay (Relay, currentCard) function is called, which checks whether the time has passed for switching on.

String onRelay (int relayPin, short card)
  String onRelay(int relayPin, short card) { String messa; if(time[card] == 0) { //  offAllCards(); //   messa = "master ON"; digitalWrite(relayPin, LOW); //  } else { if(!isOn[card]) { //    unsigned long lastOn = (lastTime[card] == NULL ? 0 : lastTime[card]); //   if((millis()-lastOn)/60000 > (freqOn - 1)) { //    ,     messa = "time:" + String(time[card]); lastTime[card] = someCardsIsOn() + time[card]*60000; //          +   isOn[card] = true; //       digitalWrite(relayPin, LOW); //  } else { //      short waitminutes = freqOn - (millis()-lastOn)/60000; //      messa = "Wait:" + String(waitminutes/60) + "h" + String(waitminutes%60)+ "m"; //messa = String(waitminutes); } } else { messa = "Allready ON"; } } return messa; } void offAllCards() { for(int k = 0; k < 10; k++) { isOn[k] = false; } } unsigned long someCardsIsOn() { // -   ,          unsigned long maxtime = millis(); for(int k = 0; k <6; k++) { if(isOn[k]&&(lastTime[k] > maxtime)) { maxtime = lastTime[k]; } } return maxtime; } 


Code
  if(currentCard > 0) { // ,     message = onRelay(Relay, currentCard); } else { if(currentCard == 0) { // ,     ,     EEPROM,  ,     if(!masterPresent) { newCard = false; masterPresent = true; message = "master in"; onRelay(Relay, currentCard); } else { if(newCard) { for(int k = 1; k < 6; k++) { if(time[k] < 0) { writeNewCard(newCardUid,k); //Serial.println("new card write to " + String(k)); newCard = false; message = "card added"; break; } } } else { masterPresent=false; offRelay(Relay); message = "master out"; } } } else { //   0,   ,   ,  ,    ,    if(masterPresent) { newCard = true; newCardUid = uiddec; message = "confirm?"; } else {message = "unknow";} } } if(!cardPresent) { //  ,      short master = 0; EEPROM_write(0, uiddec); EEPROM_write(4, master); message = "NEW MASTER"; cardPresent = true; readCards(); } if(uiddec == 696374757) { //      eraseCards(); cardPresent = readCards(); message = "ERASED"; } drawCardTime(message); } void eraseCards() { short master = -1; for(int t = 0; t < 40; t++) { EEPROM_write(t*2, master);} readCards(); //Serial.println("Cards erased"); } void writeNewCard(unsigned long uid, int k) { short time = 30; EEPROM_write(k*6, uid); EEPROM_write(k*6+4, time); readCards(); } 


Now let's not forget to turn off the device when the time runs out. To do this, add the following code to the very beginning of the loop () function

Code
  if((millis()/10000)%2 ^ i) { //check each 10 seconds i = !i; if(!masterPresent) { if(millis() > (someCardsIsOn()-1000)) { offRelay(Relay); message = "Time over"; } else { message = "Remain:" + String((someCardsIsOn() - millis())/60000+1); Serial.println(message); } drawCardTime(message); HCuOLED.Refresh(); } } 


Sketch code entirely:

Sketch code entirely
 /* * Typical pin layout used: * ----------------------------------------------------------------------------------------- * MFRC522 Arduino Arduino Arduino Arduino Arduino * Reader/PCD Uno Mega Nano v3 Leonardo/Micro Pro Micro * Signal Pin Pin Pin Pin Pin Pin * ----------------------------------------------------------------------------------------- * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST * SPI SS SDA(SS) 10 53 D10 10 10 * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 */ #include <SPI.h> #include <MFRC522.h> #include <HCuOLED.h> #include <EEPROM2.h> #define RST_PIN 6 // #define SS_PIN 7 // /* Digital pin number for the displays chip select pin */ #define CS_DI 10 /* Digital pin number for the displays data/command pin */ #define DC_DI 9 /* Digital pin number for the displays reset pin */ #define RST_DI 8 #define Relay 3 #define freqOn 300 //      unsigned long cards[6]; //uids    eeprom unsigned long newCardUid; //     boolean i = false; short time[6]; //        ,   eeprom unsigned long lastTime[6]; //    boolean isOn[6]; //      boolean cardPresent; //       eeprom boolean masterPresent = false; //   boolean newCard = false; //    String message; /* Create an instance of the library (uncomment one of the lines below) */ //HCuOLED HCuOLED(SSD1307, SS_DI, DC_DI, RST_DI); // For SSD1307 displays (HCMODU0050 & HCMODU0052) HCuOLED HCuOLED(SH1106, CS_DI, DC_DI, RST_DI); // For SH1106 displays (HCMODU0058 & HCMODU0059) MFRC522 mfrc522(SS_PIN, RST_PIN); // 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) pinMode(Relay, OUTPUT); digitalWrite(Relay, HIGH); SPI.begin(); // Init SPI bus mfrc522.PCD_Init(); // Init MFRC522 ShowReaderDetails(); // Show details of PCD - MFRC522 Card Reader details //Serial.println(F("Scan PICC to see UID, type, and data blocks...")); HCuOLED.Reset(); //HCuOLED.SetFont(MedProp_11pt); //HCuOLED.Cursor(40,0); //HCuOLED.Print("Uid:"); //eraseCards(); cardPresent = readCards(); } void loop() { if((millis()/10000)%2 ^ i) { //check each 10 seconds i = !i; if(!masterPresent) { if(millis() > (someCardsIsOn()-1000)) { offRelay(Relay); message = "Time over"; } else { message = "Remain:" + String((someCardsIsOn() - millis())/60000+1); Serial.println(message); } drawCardTime(message); HCuOLED.Refresh(); } } // Look for new cards if ( ! mfrc522.PICC_IsNewCardPresent()) { return; } // Select one of the cards if ( ! mfrc522.PICC_ReadCardSerial()) { return; } String s = dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); mfrc522.PICC_HaltA(); Serial.println(s); } void ShowReaderDetails() { // Get the MFRC522 software version byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg); Serial.print(F("MFRC522 Software Version: 0x")); Serial.print(v, HEX); if (v == 0x91) Serial.print(F(" = v1.0")); else if (v == 0x92) Serial.print(F(" = v2.0")); else Serial.print(F(" (unknown)")); Serial.println(""); // When 0x00 or 0xFF is returned, communication probably failed if ((v == 0x00) || (v == 0xFF)) { Serial.println(F("WARNING: Communication failure, is the MFRC522 properly connected?")); } } String dump_byte_array(byte *buffer, byte bufferSize) { String s; unsigned long uiddec = 0; unsigned long temp; char uid[8]; for (byte m = (bufferSize > 4 ? (bufferSize - 4) : 0); m < bufferSize; m++) { //   4       unsigned long p = 1; for(int k = 0; k < bufferSize-m-1; k++) { p = p*256; } uiddec += p*buffer[m]; s = s + (buffer[m] < 0x10 ? "0" : ""); s = s + String(buffer[m], HEX); } s.toCharArray(uid, 8); drawUid(uid); drawLong(uiddec); message = "unknow"; short currentCard = -1; for(int k = 0; k <6; k++) { //  uid        if((time[k] >=0) && (cards[k] == uiddec)) { currentCard = k; } } if(currentCard > 0) { // ,     message = onRelay(Relay, currentCard); } else { if(currentCard == 0) { // ,     ,     EEPROM,  ,     if(!masterPresent) { newCard = false; masterPresent = true; message = "master in"; onRelay(Relay, currentCard); } else { if(newCard) { for(int k = 1; k < 6; k++) { if(time[k] < 0) { writeNewCard(newCardUid,k); //Serial.println("new card write to " + String(k)); newCard = false; message = "card added"; break; } } } else { masterPresent=false; offRelay(Relay); message = "master out"; } } } else { //   0,   ,   ,  ,    ,    if(masterPresent) { newCard = true; newCardUid = uiddec; message = "confirm?"; } else {message = "unknow";} } } if(!cardPresent) { //  ,      short master = 0; EEPROM_write(0, uiddec); EEPROM_write(4, master); message = "NEW MASTER"; cardPresent = true; readCards(); } if(uiddec == 696374757) { eraseCards(); cardPresent = readCards(); message = "ERASED"; } drawCardTime(message); return s; } void drawUid(char *s) { HCuOLED.Erase(0,16,120,32); HCuOLED.SetFont(MedProp_11pt); HCuOLED.Cursor(0,16); HCuOLED.Print(s); HCuOLED.Refresh(); } void drawLong(long uid) { HCuOLED.Erase(0,33,120,48); HCuOLED.SetFont(MedProp_11pt); HCuOLED.Cursor(0,33); HCuOLED.Print(uid); HCuOLED.Refresh(); } void drawCardTime(String s) { char mess[12]; s.toCharArray(mess, 12); HCuOLED.Erase(0,49,120,80); HCuOLED.SetFont(MedProp_11pt); HCuOLED.Cursor(0,49); HCuOLED.Print(mess); HCuOLED.Refresh(); } void eraseCards() { short master = -1; for(int t = 0; t < 40; t++) { EEPROM_write(t*2, master);} readCards(); //Serial.println("Cards erased"); } boolean readCards() { cardPresent = false; for(int k = 0; k <6; k++) { EEPROM_read(k*6+4, time[k]); if(time[k] >= 0) { cardPresent = true; EEPROM_read(k*6, cards[k]); //Serial.print(cards[k]); //Serial.print(" - "); //Serial.println(time[k]); } } return cardPresent; } void writeNewCard(unsigned long uid, int k) { short time = 30; EEPROM_write(k*6, uid); EEPROM_write(k*6+4, time); readCards(); } String onRelay(int relayPin, short card) { String messa; if(time[card] == 0) { //  offAllCards(); //   messa = "master ON"; digitalWrite(relayPin, LOW); //  } else { if(!isOn[card]) { //    unsigned long lastOn = (lastTime[card] == NULL ? 0 : lastTime[card]); //   if((millis()-lastOn)/60000 > (freqOn - 1)) { //    ,     messa = "time:" + String(time[card]); lastTime[card] = someCardsIsOn() + time[card]*60000; //          +   isOn[card] = true; //       digitalWrite(relayPin, LOW); //  } else { //      short waitminutes = freqOn - (millis()-lastOn)/60000; //      messa = "Wait:" + String(waitminutes/60) + "h" + String(waitminutes%60)+ "m"; //messa = String(waitminutes); } } else { messa = "Allready ON"; } } return messa; } void offRelay(int relayPin) { offAllCards(); digitalWrite(relayPin, HIGH); } void offAllCards() { for(int k = 0; k < 10; k++) { isOn[k] = false; } } unsigned long someCardsIsOn() { unsigned long maxtime = millis(); for(int k = 0; k <6; k++) { if(isOn[k]&&(lastTime[k] > maxtime)) { maxtime = lastTime[k]; } } return maxtime; } 


Connection diagram:

image


Sketch reference

Demonstration of work:



What I would like to change / add:

1. Make it possible to change the time of use of the device for the card and remove it (putting the wizard to change the time several times: 30, 45, 60, 90, 120, -1).
2. Add a button to the circuit with which you can reset the device.

Source: https://habr.com/ru/post/357886/


All Articles