Getting Arduino to Read Wiegand Keypad

I have a VSIONIS keypad set up in Wiegand mode and I'm having trouble figuring out how to get the code set up so Arduino can read the data properly to produce a simple output.

The keypad is set in a data mode so that it will transmit PIN data when it receives the last key (#). It will provide a Decimal card number with 10-digits. Facility code (which I have set to 0, so it will be "0000") + PIN code (up to 6 digits, of which I'm only using 4, so "001234", making the output format 0000001234.

I also have the option of using 4-bit or 8-bit, if either of those options turn out to be simpler.

I have a library for Wiegand that I found HERE, but I'm guessing I need more.

I have digital pins 2 and 3 set to INPUT_PULLUP with the D0 and D1 wire from the keypad there, as well.

I'm guessing I can't use the usual rows/columns code for Matrix keypads here. Any help would be greatly appreciated.

Thanks.

Wiegand sends a low-going pulse on the D0 wire for 0 bits and a low-going pulse on the D1 wire for 1 bits. Don't forget to connect a Ground wire as well. Pulses are about 1000 per second and typically 50 microseconds long.

What makes you guess you will need more than the library? The fact that the library says it works on 24- or 32-bit values and you have 40, or maybe 80 bits? It shouldn't be too hard to adapt.

johnwasser: Wiegand sends a low-going pulse on the D0 wire for 0 bits and a low-going pulse on the D1 wire for 1 bits. Don't forget to connect a Ground wire as well. Pulses are about 1000 per second and typically 50 microseconds long.

What makes you guess you will need more than the library? The fact that the library says it works on 24- or 32-bit values and you have 40, or maybe 80 bits? It shouldn't be too hard to adapt.

Yeah, I have the ground wire connected, as well.

I don't have a lot of programming experience, but the little I do have tells me that if I want

if (code = 0000001234) {

digitalWrite(relay2, HIGH); delay(D); digitalWrite(relay2, LOW); }

then I need a way to tell arduino what "code" is, specifically from the keypad. Right?

EscapePoint:

if (code = 0000001234) {

digitalWrite(relay2, HIGH);
    delay(D);
    digitalWrite(relay2, LOW);
}

You probably need something more like:

if (strcmp(code,"0000001234") == 0) {
}

or

if (code == 1234) {
}

It depends on how the value is delivered to you. You can start by just displaying the raw bits with a sketch like:

// Connect D0 to Pin 2 and D1 to Pin 3 on an Arduino UNO
const byte PinD0 = 2;
const byte PinD1 = 3;
const byte IntD0 = 0;
const byte IntD1 = 1;

volatile unsigned BitCount;
volatile byte Bits[100];
volatile unsigned long LastBitTime;

void setup() {
  pinMode(PinD0, INPUT);          // Set D0 pin as input
  pinMode(PinD1, INPUT);          // Set D1 pin as input
  attachInterrupt(IntD0, ReadD0, FALLING); // Hardware interrupt - high to low pulse
  attachInterrupt(IntD1, ReadD1, FALLING); // Hardware interrupt - high to low pulse
}

void loop() {
  byte localBits[100];
  // Grab volatile variables with interupts disabled
  noInterrupts();
  unsigned long interval = millis() - LastBitTime;
  unsigned count = BitCount;
  interrupts();

  // Process data when we have new bits, but not for a while.
  if (interval > 100 && count != 0) {
    noInterrupts();
    for (unsigned i = 0; i < count; i++) {
      localBits[i] = Bits[i];
    }
    BitCount = 0;
    interrupts();

    Serial.print(count);
    Serial.print(" bits: ");
    for (unsigned i = 0; i < count; i++) {
      Serial.print(localBits[i]);
      if (i % 8 == 7)
        Serial.write(' ');
    }
    Serial.println();
  }
}

void ReadD0() {
  if (BitCount < 100) {
    LastBitTime = millis();
    Bits[BitCount++] = 0;
  }
}

void ReadD1() {
  if (BitCount < 100) {
    LastBitTime = millis();
    Bits[BitCount++] = 1;
  }
}

johnwasser:   attachInterrupt(IntD0, ReadD0, FALLING); // Hardware interrupt - high to low pulse   attachInterrupt(IntD1, ReadD1, FALLING); // Hardware interrupt - high to low pulse

I'm not sure what ReadD0 or ReadD1 is supposed to be here. Should I have declared it as something before?

EDIT:

I think I might have fixed it by rearranging the order that void ReadD0/ReadD1 was in. But I still need a way to declare what "code" is from this. Any ideas?

int relay1 = 4;
int relay2 = 5;
int relay3 = 6;
int relay4 = 7;
int relay5 = 8;
int relay6 = 9;
int relay7 = 10;
int relay8 = 11;
int code;


#include <Wiegand.h>
WIEGAND wg;

// Connect D0 to Pin 2 and D1 to Pin 3 on an Arduino UNO
const byte PinD0 = 2;
const byte PinD1 = 3;
const byte IntD0 = 0;
const byte IntD1 = 1;

volatile unsigned BitCount;
volatile byte Bits[100];
volatile unsigned long LastBitTime;
  
 void setup(){
  Serial.begin(9600); //open serial port
  wg.begin();


   pinMode(PinD0, INPUT);          // Set D0 pin as input
  pinMode(PinD1, INPUT);          // Set D1 pin as input
  attachInterrupt(IntD0, ReadD0, FALLING); // Hardware interrupt - high to low pulse
  attachInterrupt(IntD1, ReadD1, FALLING); // Hardware interrupt - high to low pulse
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(relay1, OUTPUT);
pinMode(relay2, OUTPUT);
pinMode(relay3, OUTPUT);
pinMode(relay4, OUTPUT);
pinMode(relay5, OUTPUT);
pinMode(relay6, OUTPUT);
pinMode(relay7, OUTPUT);
pinMode(relay8, OUTPUT);

digitalWrite(relay1, LOW);
digitalWrite(relay2, LOW);
digitalWrite(relay3, LOW);
digitalWrite(relay4, LOW);
digitalWrite(relay5, LOW);
digitalWrite(relay6, LOW);
digitalWrite(relay7, LOW);
digitalWrite(relay8, LOW);

  }

void ReadD0() {
  if (BitCount < 100) {
    LastBitTime = millis();
    Bits[BitCount++] = 0;
  }
}

void ReadD1() {
  if (BitCount < 100) {
    LastBitTime = millis();
    Bits[BitCount++] = 1;
  }
}
    







void loop() {
  byte localBits[100];
  // Grab volatile variables with interupts disabled
  noInterrupts();
  unsigned long interval = millis() - LastBitTime;
  unsigned count = BitCount;
  interrupts();

  // Process data when we have new bits, but not for a while.
  if (interval > 100 && count != 0) {
    noInterrupts();
    for (unsigned i = 0; i < count; i++) {
      localBits[i] = Bits[i];
    }
    BitCount = 0;
    interrupts();

    Serial.print(count);
    Serial.print(" bits: ");
    for (unsigned i = 0; i < count; i++) {
      Serial.print(localBits[i]);
      if (i % 8 == 7)
        Serial.write(' ');
    }
    Serial.println();
  }

  
if (code == 1469){
digitalWrite(relay1, HIGH);
}
if (code == 6219){
digitalWrite(relay2, HIGH);
}
if (code == 2020){
digitalWrite(relay3, HIGH);
}
if (code == 5123){
digitalWrite(relay4, HIGH);
}
if (code == 617){
digitalWrite(relay5, HIGH);
}
if (code == 8670){
digitalWrite(relay6, HIGH);
}
if (code == 3313){
digitalWrite(relay7, HIGH);
}
if (code == 7117){
digitalWrite(relay8, HIGH);
}
if (code == 9731){
digitalWrite(relay1, LOW);
digitalWrite(relay2, LOW);
digitalWrite(relay3, LOW);
digitalWrite(relay4, LOW);
digitalWrite(relay5, LOW);
digitalWrite(relay6, LOW);
digitalWrite(relay7, LOW);
digitalWrite(relay8, LOW);
}

}

This is what I’m currently working with. “code” is the only thing left undefined.

EscapePoint: I'm not sure what ReadD0 or ReadD1 is supposed to be here. Should I have declared it as something before?

The code I provided is complete and compiles fine for me. Do you get an error when you compile? Do you get a problem when you run it? Do you get output when you enter a number?

You want to turn a bit pattern into a number. To help you with that I need to know what bit patterns you are receiving. That is what that sketch is supposed to to. Run the sketch AS WRITTEN and report back with the bit patterns you get for each number. THEN I can help you convert the Wiegand data to a usable 'code' number.

Run the sketch AS WRITTEN and report back with the bit patterns you get for each number.

Yes, please show the complete arrays of localBits[i]for the 9 codes you want to test against. You should be able to use memcmp() to compare any received array against the arrays for the 9 code values.

johnwasser:
The code I provided is complete and compiles fine for me. Do you get an error when you compile? Do you get a problem when you run it? Do you get output when you enter a number?

You want to turn a bit pattern into a number. To help you with that I need to know what bit patterns you are receiving. That is what that sketch is supposed to to. Run the sketch AS WRITTEN and report back with the bit patterns you get for each number. THEN I can help you convert the Wiegand data to a usable ‘code’ number.

johnwasser:
The code I provided is complete and compiles fine for me. Do you get an error when you compile? Do you get a problem when you run it? Do you get output when you enter a number?

You want to turn a bit pattern into a number. To help you with that I need to know what bit patterns you are receiving. That is what that sketch is supposed to to. Run the sketch AS WRITTEN and report back with the bit patterns you get for each number. THEN I can help you convert the Wiegand data to a usable ‘code’ number.

I completely misunderstood the purpose of the code, my bad. Never used serial monitor before, but that really made it easier. So from what I’ve got:

1469: 00000000 00000010 11011110 11
6219: 10000000 00001100 00100101 10
2020: 00000000 00000011 11110010 00
5123: 10000000 00001010 00000001 10
0617: 00000000 00000001 00110100 10
8670: 10000000 00010000 11101111 00
3313: 00000000 00000110 01111000 10
7117: 10000000 00001101 11100110 11
9731: 10000000 00010011 00000001 11

I might be able to figure it out now that I’ve got an input, but I’d still like to hear how to properly do it so I can learn to be more efficient. Thanks!

This compiles but is untested. storedPatterns can go in progmem if a large number of them are required

const byte relay1 = 4;
const byte relay2 = 5;
const byte relay3 = 6;
const byte relay4 = 7;
const byte relay5 = 8;
const byte relay6 = 9;
const byte relay7 = 10;
const byte relay8 = 11;

//#include <Wiegand.h>//library not actually used
//WIEGAND wg;

// Connect D0 to Pin 2 and D1 to Pin 3 on an Arduino UNO
const byte PinD0 = 2;
const byte PinD1 = 3;

const byte IntD0 = 0;
const byte IntD1 = 1;

volatile unsigned BitCount;
volatile byte Bits[26];
volatile unsigned long LastBitTime;

const byte storedPattern[9][26] =
{
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,1,1,1,1,0,1,1},//1469
  {1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,1,1,0},//6219
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,0,0,0},//2020
  {1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,1,0},//5123
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0,1,0,0,1,0},//0617
  {1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,0,1,1,1,1,0,0},//8670
  {0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,1,0},//3313
  {1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,1,0,0,1,1,0,1,1},//7117
  {1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,1,1,1},//9731
};

byte matchPattern = 99;

void setup() {
  Serial.begin(9600);
  // wg.begin();
  pinMode(PinD0, INPUT_PULLUP);// Set D0 pin as input
  pinMode(PinD1, INPUT_PULLUP);// Set D1 pin as input
  attachInterrupt(IntD0, ReadD0, FALLING); // Hardware interrupt - high to low pulse
  attachInterrupt(IntD1, ReadD1, FALLING); // Hardware interrupt - high to low pulse
  //pinMode(2, INPUT_PULLUP);//duplicate
  //pinMode(3, INPUT_PULLUP);//duplicate
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  pinMode(relay3, OUTPUT);
  pinMode(relay4, OUTPUT);
  pinMode(relay5, OUTPUT);
  pinMode(relay6, OUTPUT);
  pinMode(relay7, OUTPUT);
  pinMode(relay8, OUTPUT);

  digitalWrite(relay1, LOW);
  digitalWrite(relay2, LOW);
  digitalWrite(relay3, LOW);
  digitalWrite(relay4, LOW);
  digitalWrite(relay5, LOW);
  digitalWrite(relay6, LOW);
  digitalWrite(relay7, LOW);
  digitalWrite(relay8, LOW);
}

//interrupt service routines
void ReadD0() {
  if (BitCount < 100) {
    LastBitTime = millis();
    Bits[BitCount++] = 0;
  }
}

void ReadD1() {
  if (BitCount < 100) {
    LastBitTime = millis();
    Bits[BitCount++] = 1;
  }
}

void loop() {

  byte localBits[26];
  // Grab volatile variables with interrupts disabled
  noInterrupts();
  unsigned long interval = millis() - LastBitTime;
  unsigned count = BitCount;
  interrupts();

  // Process data when we have new bits, but not for a while.
  if (interval > 100 && count != 0)
  {
    noInterrupts();
    for (unsigned i = 0; i < count; i++) {
      localBits[i] = Bits[i];
    }
    BitCount = 0;
    interrupts();

    Serial.print(count);
    Serial.print(" bits: ");
    for (unsigned i = 0; i < count; i++) {
      Serial.print(localBits[i]);
      if (i % 8 == 7)
        Serial.write(' ');
    }
    Serial.println();

    //test for match with memcmp
    matchPattern = 99;//reset to no match
    for (byte i = 0; i <= 9; i++)
    {
      if ((memcmp(localBits, storedPattern[i], 26)) == 0)
      {
        matchPattern = i;
      }
    }

    Serial.print("Entered number matches ");
    switch (matchPattern)
    {
      case 0:
        Serial.println("1469");
        digitalWrite(relay1, HIGH);
        break;

      case 1:
        Serial.println("6219");
        digitalWrite(relay2, HIGH);
        break;

      case 2:
        Serial.println("2020");
        digitalWrite(relay3, HIGH);
        break;

      case 3:
        Serial.println("5123");
        digitalWrite(relay4, HIGH);
        break;

      case 4:
        Serial.println("0617");
        digitalWrite(relay5, HIGH);
        break;

      case 5:
        Serial.println("8670");
        digitalWrite(relay6, HIGH);
        break;

      case 6:
        Serial.println("3313");
        digitalWrite(relay7, HIGH);
        break;

      case 7:
        Serial.println("7117");
        digitalWrite(relay8, HIGH);
        break;

      case 8:
        Serial.println("9731");
        digitalWrite(relay1, LOW);
        digitalWrite(relay2, LOW);
        digitalWrite(relay3, LOW);
        digitalWrite(relay4, LOW);
        digitalWrite(relay5, LOW);
        digitalWrite(relay6, LOW);
        digitalWrite(relay7, LOW);
        digitalWrite(relay8, LOW);
        break;

      default:
        Serial.println("No Code Match");//case 99
        break;
    }
  } 
}

cattledog:
This compiles but is untested. storedPatterns can go in progmem if a large number of them are required

const byte relay1 = 4;

const byte relay2 = 5;
const byte relay3 = 6;
const byte relay4 = 7;
const byte relay5 = 8;
const byte relay6 = 9;
const byte relay7 = 10;
const byte relay8 = 11;

//#include <Wiegand.h>//library not actually used
//WIEGAND wg;

// Connect D0 to Pin 2 and D1 to Pin 3 on an Arduino UNO
const byte PinD0 = 2;
const byte PinD1 = 3;

const byte IntD0 = 0;
const byte IntD1 = 1;

volatile unsigned BitCount;
volatile byte Bits[26];
volatile unsigned long LastBitTime;

const byte storedPattern[9][26] =
{
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,1,1,1,1,0,1,1},//1469
  {1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,1,1,0},//6219
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,0,0,0},//2020
  {1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,1,0},//5123
  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0,1,0,0,1,0},//0617
  {1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,0,1,1,1,1,0,0},//8670
  {0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,1,0},//3313
  {1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,1,0,0,1,1,0,1,1},//7117
  {1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,1,1,1},//9731
};

byte matchPattern = 99;

void setup() {
  Serial.begin(9600);
  // wg.begin();
  pinMode(PinD0, INPUT_PULLUP);// Set D0 pin as input
  pinMode(PinD1, INPUT_PULLUP);// Set D1 pin as input
  attachInterrupt(IntD0, ReadD0, FALLING); // Hardware interrupt - high to low pulse
  attachInterrupt(IntD1, ReadD1, FALLING); // Hardware interrupt - high to low pulse
  //pinMode(2, INPUT_PULLUP);//duplicate
  //pinMode(3, INPUT_PULLUP);//duplicate
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  pinMode(relay3, OUTPUT);
  pinMode(relay4, OUTPUT);
  pinMode(relay5, OUTPUT);
  pinMode(relay6, OUTPUT);
  pinMode(relay7, OUTPUT);
  pinMode(relay8, OUTPUT);

digitalWrite(relay1, LOW);
  digitalWrite(relay2, LOW);
  digitalWrite(relay3, LOW);
  digitalWrite(relay4, LOW);
  digitalWrite(relay5, LOW);
  digitalWrite(relay6, LOW);
  digitalWrite(relay7, LOW);
  digitalWrite(relay8, LOW);
}

//interrupt service routines
void ReadD0() {
  if (BitCount < 100) {
    LastBitTime = millis();
    Bits[BitCount++] = 0;
  }
}

void ReadD1() {
  if (BitCount < 100) {
    LastBitTime = millis();
    Bits[BitCount++] = 1;
  }
}

void loop() {

byte localBits[26];
  // Grab volatile variables with interrupts disabled
  noInterrupts();
  unsigned long interval = millis() - LastBitTime;
  unsigned count = BitCount;
  interrupts();

// Process data when we have new bits, but not for a while.
  if (interval > 100 && count != 0)
  {
    noInterrupts();
    for (unsigned i = 0; i < count; i++) {
      localBits[i] = Bits[i];
    }
    BitCount = 0;
    interrupts();

Serial.print(count);
    Serial.print(" bits: ");
    for (unsigned i = 0; i < count; i++) {
      Serial.print(localBits[i]);
      if (i % 8 == 7)
        Serial.write(’ ');
    }
    Serial.println();

//test for match with memcmp
    matchPattern = 99;//reset to no match
    for (byte i = 0; i <= 9; i++)
    {
      if ((memcmp(localBits, storedPattern[i], 26)) == 0)
      {
        matchPattern = i;
      }
    }

Serial.print("Entered number matches ");
    switch (matchPattern)
    {
      case 0:
        Serial.println(“1469”);
        digitalWrite(relay1, HIGH);
        break;

case 1:
        Serial.println(“6219”);
        digitalWrite(relay2, HIGH);
        break;

case 2:
        Serial.println(“2020”);
        digitalWrite(relay3, HIGH);
        break;

case 3:
        Serial.println(“5123”);
        digitalWrite(relay4, HIGH);
        break;

case 4:
        Serial.println(“0617”);
        digitalWrite(relay5, HIGH);
        break;

case 5:
        Serial.println(“8670”);
        digitalWrite(relay6, HIGH);
        break;

case 6:
        Serial.println(“3313”);
        digitalWrite(relay7, HIGH);
        break;

case 7:
        Serial.println(“7117”);
        digitalWrite(relay8, HIGH);
        break;

case 8:
        Serial.println(“9731”);
        digitalWrite(relay1, LOW);
        digitalWrite(relay2, LOW);
        digitalWrite(relay3, LOW);
        digitalWrite(relay4, LOW);
        digitalWrite(relay5, LOW);
        digitalWrite(relay6, LOW);
        digitalWrite(relay7, LOW);
        digitalWrite(relay8, LOW);
        break;

default:
        Serial.println(“No Code Match”);//case 99
        break;
    }
  }
}

Tested it and it works great so far. Seems like I completely went the wrong way in all of my attempts. Thanks so much!

1469: 0 0000 0000 0000 0101  1011  1101  1
6219: 1 0000 0000 0001 1000  0100  1011  0
2020: 0 0000 0000 0000 0111 1110 0100 0
5123: 1 0000 0000 0001 0100 0000 0011 0
0617: 0 0000 0000 0000 0010 0110 1001 0
8670: 1 0000 0000 0010 0001 1101 1110 0
3313: 0 0000 0000 0000 1100 1111 0001 0
7117: 1 0000 0000 0001 1011 1100 1101 1
9731: 1 0000 0000 0010 0110 0000 0011 1

So it looks like each code is 26 bits long with the middle 24 bits being the number. It looks like the first bit is a parity bit for the first 12 data bits and the last bit is a parity bit for the last 12 data bits.

To turn bits into a number, shift the number one to the left (==multiply by 2) and add the new bit. You don’t need to store each bit into an array… that was for display. Your ISR’s would look something like this:

void ReadD0() {
    Code <<= 1;  
    BitCount++;
   LastBitTime = millis();
}

void ReadD1() {
   Code <<= 1; 
   Code += 1;
   Parity = !Parity;
   BitCount++;
   LastBitTime = millis();
}

When the bits stop arriving you can check BitCount == 26 and Parity == 0 (or 1, I’m not sure but is should always be the same). The number to check against is (Code/2 & 0xFFFFFFUL). The ‘/2’ throws away the last bit and the ‘& 0xFFFFFFUL’ masks away the first bit.

So it looks like each code is 26 bits long with the middle 24 bits being the number. It looks like the first bit is a parity bit for the first 12 data bits and the last bit is a parity bit for the last 12 data bits.

Nice work John. EscapePoint can now see how to do it when you know what you are doing.

memcmp = brute force for when you don't know what you have other than a mysterious byte array