Created
September 17, 2025 16:36
-
-
Save Cheaterman/19bd895873d3b494639bec52137e0d8d to your computer and use it in GitHub Desktop.
aptar-rfid-firmware.ino
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <SoftPWM.h> | |
| #include <SPI.h> | |
| #include "MFRC522.h" | |
| #include "demux.h" | |
| #define DEBUG false | |
| //#define DEBUG true | |
| #define MAX_UIDS 12 | |
| #define MAX_ATTEMPTS 3 | |
| #define MAX_MISSED_READS 4 | |
| #define NUM_READERS 6 | |
| #define LED_ANIMATION_DURATION 500 | |
| #define LED_MIN_BRIGHTNESS 0 | |
| #define LED_MAX_BRIGHTNESS 255 | |
| byte MUXER_PINS[] = {3, 4, 5, 6, 7}; | |
| byte LED_PINS[] = {14, 15, 16, 17}; | |
| MFRC522 const readers[NUM_READERS]; | |
| struct MissedRead { | |
| String tag; | |
| int reads; | |
| }; | |
| template <unsigned int T> struct MissedReads { | |
| MissedRead missed_read[T]; | |
| bool has(String tag) { | |
| for (unsigned int i = 0; i < T; ++i) { | |
| if (missed_read[i].tag == tag) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| int& operator[](const String& tag) { | |
| for (unsigned int i = 0; i < T; ++i) { | |
| if (missed_read[i].tag == tag) { | |
| return missed_read[i].reads; | |
| } | |
| } | |
| for (unsigned int i = 0; i < T; ++i) { | |
| if (missed_read[i].tag == "") { | |
| missed_read[i].tag = tag; | |
| missed_read[i].reads = 0; | |
| return missed_read[i].reads; | |
| } | |
| } | |
| } | |
| erase(const String& tag) { | |
| for (unsigned int i = 0; i < T; ++i) { | |
| if (missed_read[i].tag == tag) { | |
| missed_read[i].tag = ""; | |
| missed_read[i].reads = 0; | |
| break; | |
| } | |
| } | |
| } | |
| }; | |
| MissedReads<MAX_UIDS> missed_reads; | |
| void setup() { | |
| SoftPWMBegin(); | |
| for ( | |
| unsigned int led_id = 0; | |
| led_id < (sizeof(LED_PINS) / sizeof(byte)); | |
| ++led_id | |
| ) { | |
| SoftPWMSet(LED_PINS[led_id], 0); | |
| SoftPWMSetFadeTime(LED_PINS[led_id], LED_ANIMATION_DURATION, LED_ANIMATION_DURATION); | |
| } | |
| SoftPWMSet(LED_PINS[0], 255); | |
| Serial.begin(115200); | |
| while (!Serial); | |
| demux_init(MUXER_PINS); | |
| SPI.begin(); | |
| for (unsigned int reader_id = 0; reader_id < NUM_READERS; ++reader_id) { | |
| readers[reader_id] = MFRC522(reader_id); | |
| } | |
| for (unsigned int reader_id = 0; reader_id < NUM_READERS; ++reader_id) { | |
| const MFRC522& mfrc522 = readers[reader_id]; | |
| unsigned int attempts = 0; | |
| byte version = 0; | |
| while(true) { | |
| mfrc522.PCD_Init(); | |
| mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max); | |
| version = mfrc522.PCD_ReadRegister(MFRC522::VersionReg); | |
| byte gain = mfrc522.PCD_GetAntennaGain(); | |
| if( | |
| (0x88 <= version && version <= 0x92) | |
| && gain == mfrc522.RxGain_max | |
| ) { | |
| Serial.print("Reader "); | |
| Serial.print(reader_id); | |
| Serial.print(": Version 0x"); | |
| Serial.println(version, HEX); | |
| break; | |
| } | |
| else if(++attempts <= 10) { | |
| continue; | |
| } | |
| else { | |
| Serial.print("Reader "); | |
| Serial.print(reader_id); | |
| Serial.print(": Bad version 0x"); | |
| Serial.println(version, HEX); | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| void loop() { | |
| unsigned int found = 0; | |
| String uids[MAX_UIDS]; | |
| for (unsigned int attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) { | |
| for (unsigned int reader_id = 0; reader_id < NUM_READERS; ++reader_id) { | |
| const MFRC522& mfrc522 = readers[reader_id]; | |
| mfrc522.PCD_AntennaOn(); | |
| while (true) { | |
| if ( | |
| !mfrc522.PICC_IsNewCardPresent() | |
| || !mfrc522.PICC_ReadCardSerial() | |
| ) { | |
| break; | |
| } | |
| char uid[9]; | |
| for (unsigned int i = 0; i < mfrc522.uid.size; ++i) { | |
| sprintf(&uid[i * 2], "%02X", mfrc522.uid.uidByte[i]); | |
| } | |
| uids[found] = uid; | |
| #if DEBUG | |
| Serial.print("Found tag "); | |
| Serial.print(uids[found]); | |
| Serial.print(" at index "); | |
| Serial.print(found); | |
| Serial.print(" on attempt "); | |
| Serial.println(attempt); | |
| #endif | |
| if (!missed_reads.has(uids[found])) { | |
| Serial.print("A:"); | |
| Serial.println(uids[found]); | |
| } | |
| // Will be incremented in the missed reads check below | |
| missed_reads[uids[found]] = -1; | |
| mfrc522.PICC_HaltA(); | |
| found += 1; | |
| } | |
| mfrc522.PCD_AntennaOff(); | |
| } | |
| } | |
| #if DEBUG | |
| if (found == 0) { | |
| Serial.println("No tags found"); | |
| } | |
| #endif | |
| for (unsigned int i = 0; i < MAX_UIDS; ++i) { | |
| MissedRead& missed_read = missed_reads.missed_read[i]; | |
| if (missed_read.tag == "") { | |
| continue; | |
| } | |
| ++missed_read.reads; | |
| if (missed_read.reads >= MAX_MISSED_READS) { | |
| Serial.print("R:"); | |
| Serial.println(missed_read.tag); | |
| missed_reads.erase(missed_read.tag); | |
| } | |
| } | |
| updateLeds(); | |
| } | |
| void updateLeds() { | |
| static unsigned long last_millis = 0; | |
| static unsigned long current_channel = 0; | |
| static byte current_target = LED_MAX_BRIGHTNESS; | |
| unsigned long time = millis() - last_millis; | |
| if (time >= LED_ANIMATION_DURATION) { | |
| last_millis += LED_ANIMATION_DURATION; | |
| if (current_target == 255) { | |
| current_target = LED_MIN_BRIGHTNESS; | |
| } | |
| else { | |
| current_channel = (current_channel + 1) % (sizeof(LED_PINS) / sizeof(byte)); | |
| current_target = LED_MAX_BRIGHTNESS; | |
| } | |
| SoftPWMSet(LED_PINS[current_channel], current_target); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment