[SOLVED] How to send a signal for a set amount of time ?

GeorgeFlorian1
Posts: 160
Joined: Thu Jan 31, 2019 2:32 pm

[SOLVED] How to send a signal for a set amount of time ?

Postby GeorgeFlorian1 » Tue Dec 10, 2019 10:31 am

Hello !

I am trying to emulate a 26-Bit Wiegand Protocol data transfer. I am basically trying to send a card information through the two data wires, W0 and W1, from the ESP32 to a station card reader to emulate a card being read.
I have hooked up a card reader that acts a station to an ESP32-EVB:
  • GPIO13 is W0;
  • GPIO17 is W1.
Both the ESP32 and the card reader have a common GND.

Note: I do not know if "station" is the right word for it, but this particular card reader can act as a Standalone Card Reader or as a Central for other card readers. One device will act as a card reader, sending the data about the card that has been read to a second device that acts as a station/central/system and determines if the card has access or not.

Using a Wiegand Calculator and a decimal number from a real access card ( 12679548 ), we obtain the 26-Bit binary number ( 01100000101111001011111000 ) that has to be sent to the W0 and W1 data wires.


Reading from here we find out that between the sent bits there has to be a delay, that's in the vicinity of 100uS (microseconds) and that between card IDs there has to be a pause of 20-100ms (milliseconds).

Code: Select all

#define W0 13
#define W1 17

change = false;

void setup() {
  Serial.begin(115200);
  pinMode(W0, OUTPUT);
  pinMode(W1, OUTPUT);
  digitalWrite(W0, HIGH);
  digitalWrite(W1, HIGH);
  // decimal number 12679548 transforms into Wiegand 26-Bit binary number: 01100000101111001011111000
  // store the binary number into 'bool* wiegandArray = new bool[26];'
  // if a new card ID has come then change = true;
  int pulseWidth = 90;
}

void loop() {
  if(change) {
    for(int i = 0; i<26; i++) {
      if(wiegandArray[i] == 0) {
        digitalWrite(W0, LOW);
        delayMicroseconds(pulseWidth);
        digitalWrite(W0, HIGH);
      } else {
        digitalWrite(W1, LOW);
        delayMicroseconds(pulseWidth);
        digitalWrite(W1, HIGH);
      }
    }
  }
}
I have put the card reader device in Station mode and the wires are set as W0 and W1 inputs.

From my point of view the code is good and should be working but it's not. The only piece of code that has me worried is the part that actually puts the pins to LOW then waits then puts them to HIGH again. I am not sure if this is the proper way to send a signal with a set PulseWidth.

What do you think ?
Last edited by GeorgeFlorian1 on Thu Dec 12, 2019 2:24 pm, edited 1 time in total.

User avatar
martinayotte
Posts: 141
Joined: Fri Nov 13, 2015 4:27 pm

Re: How to send a signal for a set amount of time ?

Postby martinayotte » Tue Dec 10, 2019 8:18 pm

GeorgeFlorian1 wrote:
Tue Dec 10, 2019 10:31 am
What do you think ?
You need another delay after bringing back the lines to HIGH ...

ESP_Sprite
Posts: 9764
Joined: Thu Nov 26, 2015 4:08 am

Re: How to send a signal for a set amount of time ?

Postby ESP_Sprite » Wed Dec 11, 2019 3:08 am

Also, you can look into the RMT peripheral, which should be more-or-less ideal for these purposes.

GeorgeFlorian1
Posts: 160
Joined: Thu Jan 31, 2019 2:32 pm

Re: How to send a signal for a set amount of time ?

Postby GeorgeFlorian1 » Wed Dec 11, 2019 11:04 am

martinayotte wrote:
Tue Dec 10, 2019 8:18 pm
GeorgeFlorian1 wrote:
Tue Dec 10, 2019 10:31 am
What do you think ?
You need another delay after bringing back the lines to HIGH ...
That is indeed my bad. I have fixed that. Thank you.
This is the resulting code that sometimes gets synchronized and sends the signal correctly:

Code: Select all

void setup() {
  Serial.begin(115200);

  pinMode(W0, OUTPUT);
  pinMode(W1, OUTPUT);
  digitalWrite(W0, HIGH);
  digitalWrite(W1, HIGH);
  // ...
}
  
void loop() {
  delay(100);
  if(change) {
    Serial.println("Sending ID...");
    pulse = pulseWidth.toInt();
    portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
    portENTER_CRITICAL(&mux);
    for(int i = 0; i<26; i++) {
      if(wiegandArray[i] == 0) {
        digitalWrite(W0, LOW);
        delayMicroseconds(pulse);
        digitalWrite(W0, HIGH);
      } else {
        digitalWrite(W1, LOW);
        delayMicroseconds(pulse);
        digitalWrite(W1, HIGH);
      }
      delayMicroseconds(pulse);
    }
    portEXIT_CRITICAL(&mux);
  }

  if(change) {
    change = false;
    for(int i = 0; i<26; i++) {
      Serial.print(wiegandArray[i]);
    }
    Serial.println();
  }
}
But, as I've said, this isn't reliable because it doesn't work all the time.
ESP_Sprite wrote:
Wed Dec 11, 2019 3:08 am
Also, you can look into the RMT peripheral, which should be more-or-less ideal for these purposes.
Isn't RMT supposed to work just for one pin ? I need to send a Data train on 2 pins.
Last edited by GeorgeFlorian1 on Thu Dec 12, 2019 2:26 pm, edited 2 times in total.

ESP_Sprite
Posts: 9764
Joined: Thu Nov 26, 2015 4:08 am

Re: How to send a signal for a set amount of time ?

Postby ESP_Sprite » Thu Dec 12, 2019 3:27 am

No, you can use it for up to 8 pins. Note that you can't start the transaction on multiple pins at *exactly* the same time, but if you don't care about a tenth of an uS or so of delay, it should be fine.

GeorgeFlorian1
Posts: 160
Joined: Thu Jan 31, 2019 2:32 pm

Re: How to send a signal for a set amount of time ?

Postby GeorgeFlorian1 » Thu Dec 12, 2019 8:51 am

ESP_Sprite wrote:
Thu Dec 12, 2019 3:27 am
No, you can use it for up to 8 pins. Note that you can't start the transaction on multiple pins at *exactly* the same time, but if you don't care about a tenth of an uS or so of delay, it should be fine.
That sounds great. There is just one issue. I've literally no idea how to write the code.
This is the only understandable example I could find: http://www.buildlog.net/blog/2017/11/es ... h-the-rmt/ but it's for one pin. I have never used ESP-IDF, only PlatformIO IDE.

How do I make it for two pins ? How do I send my information in one go on two pins ?
Is it even possible ?
Wiegand Protocol starts with both pins HIGH. When I send a 0, W0 pin is pulled LOW for usually 20-100us and W1 stays HIGH. When a 1 is being send W1 is pulled LOW for usually 20-100us and W0 stays HIGH.

Thank you.

GeorgeFlorian1
Posts: 160
Joined: Thu Jan 31, 2019 2:32 pm

Re: How to send a signal for a set amount of time ?

Postby GeorgeFlorian1 » Thu Dec 12, 2019 2:23 pm

I have moved the discussion to a new thread:
viewtopic.php?f=19&t=13503&p=53201#p53201

This can be closed or deleted.

Thank you.

Who is online

Users browsing this forum: No registered users and 76 guests