I know the title sounds funny but I think that is what is happening in my code.
The project scans a users ID(usually a California ID) and stores their info and then the user chooses an option from a keypad. Its sort of a voting system.
I have the card scanner working and the keypad reader working individually so I know the code and hardware works but I have problems when combining it all into one project.
The ID reader uses the magstripe reader library found here which uses the arduino’s external interrupts
The keypad is a matrix style keypad and I am using Arduino’s Keypad.h Library
Problem is that when I combine the two it won’t detect the keypad presses, I think its because the loop is stopped until an ID is scanned by the user. So since the loop is being held up by the interrupt it never picks up the keypad press. I notice if I hold down a key on the keypad and reset the program it does pick up the keypress since it picks it up while it starts to go through the loop
Is there a way to somehow always be checking for a keypress
something that is always checking for a keypress and THEN get interrupted if a card is present rather than going straight to the interrupt and waiting for the card to be pressed
This is basically the loop, if you need to see the full code I'll post it later when I have access to my laptop
Void Loop()
{
//some Serial print code which only prints once at bootup and then once after each time the interrupt happens
Char key = kpd.getKey();
If(key)
{
Serial.print(key);
}
//Interrupt code here. This seems to be where the loop stops every time so it never goes back to the top to check for a button press again until a card is read. It then starts the loop again but stops here again
}//end of loop
Hi Eddie
Yes, please post all your code, using code tags (the </> icon above the text entry box).
It sounds like this part of your program ...
//*Interrupt code here*. This seems to be where the loop stops every time so it never goes back to the top to check for a button press again until a card is read. It then starts the loop again but stops here again
... is blocking and waiting for an interrupt to happen.
EDIT From a quick look at the mag stripe library, its example program seems to be non-blocking. So it should be possible to achieve what you want.
Regards
Ray
Good day Ray, I am basically using a slightly modified version of the example you looked at. Here is my loop. I hope this helps. I think that somehow this if statement is not doing what its supposed to "if (!card.available()"
void loop()
{
Serial.println("hello, begin loop");
// Don't do anything if there isn't a card present...
//this checks for a button press
char key = kpd.getKey();
if(key) // Check for a valid key.
{
Serial.println(key);
}
//I would think that this next part would make the program jump back to the begining of the loop but it doesnt seem to
if (!card.available()) {
return;
}
// Show that a card is being read...
digitalWrite(READ_LED, HIGH);
// Read the card into the buffer "data" (as a null-terminated string)...
short chars = card.read(data, DATA_BUFFER_LEN);
// Show that the card has finished reading...
digitalWrite(READ_LED, LOW);
// If there was an error reading the card, blink the error LED...
if (chars < 0) {
digitalWrite(ERROR_LED, HIGH);
delay(250);
digitalWrite(ERROR_LED, LOW);
return;
}
// Send the data to the computer...
Serial.println(data);
}
I had also just tried the example program, Eddie, without a card reader and found (a) that available returns true if no reader is attached, and (b) read() hangs if no reader is attached.
I changed the start of loop() to this:
void loop()
{
Serial.println("before available"); // THIS PRINTS
Serial.println(card.available()); // THIS PRINTS "1" FOR TRUE
Serial.println("after available"); // THIS PRINTS
if (card.available()) {
Serial.println("before read"); // THIS PRINTS
short chars = card.read(data, DATA_BUFFER_LEN);
Serial.println("after read"); // THIS DOES NOT PRINT
But you do have a reader attached and it returns correct data when you do read it?
I'll have a dig into the library code.
This is the available() function from the library:
bool MagStripe::available()
{
return digitalRead(this->pin_cls) == LOW;
}
It just reads pin_cls, which is passed to the constructor or defaults to pin 4.
#define MAGSTRIPE_CLS 4 /* card present pin (yellow) */
...
MagStripe(unsigned char cls=MAGSTRIPE_CLS);
How is your reader wired up?
Ray,
I tried changing my loop to the loop code you provided and this was my output
before available
1
after available
before read
Also, my reader is hooked up to the interrupts 0, and 1 on pin 2 and 3, and I did hook up the readers Card Present Pin to pin 17 so I edited my library to read
#define MAGSTRIPE_CLS 17 /* card present pin (yellow) */
You can specify pin 17 in the program rather then editing the library:
MagStripe card(17);
EDIT ...
Sounds like either there is a faulty connection between the reader and the Arduino input pin, or your reader is not keeping the signal low high when no card is present and only going high low when card is present.
Can you try a simple program without the card reader code that just sets the Arduino pin as input and then prints the digitalRead value to the screen, to see if the value changes when a card is presented? Or check the CLS output with a multimeter?
BTW, which Arduino are you using? And could you post a link to a datasheet for the reader?
I had not noticed that. I changed my library back to how it was and sent 17 as a parameter from the program
I tried a simple program that prints digitalPrint of 17 and it reads 0 when no card is present and then 1 when I insert one.
I am trying to find the datasheet as my reader's surface is faded but I did notice that the reader used in the original library was the type that lets you swipe the card in any direction. The one I have is the type that you insert and then eject. The Card Present pin goes High until the card is fully inserted.(I am looking for some pictures I grabbed off of the documentation some time ago)
Could this have something to do with it?
I am guessing on the reader used for the library originally makes the Card Present pin go high as soon as the card begins to swipe. The library is made to read the card in any direction
I tried a simple program that prints digitalPrint of 17 and it reads 0 when no card is present and then 1 when I insert one.
So digitalRead(17) is 0 with no card? I think that is the reverse sense to what the library is expecting.
You could try changing each card.available() to !card.available() and vice versa.
EDIT Just saw your screenshot. It's different from (for example) the KDR1000 reader which is mentioned on the library GitHub page - there is a link to its datasheet there.
The library expects the CLS to be in an active state while the data is being read. Your screenshot looks like /CLD goes active after the card is inserted but then goes inactive as the card is ejected and the data is read.
Ok that makes sense, so the Card Present on my reader goes HIGH rather than LOW.
I updated the library to read
bool MagStripe::available()
{
return digitalRead(this->pin_cls) == HIGH;
}
Which seems to make the loop behave how I want it.
When my loop reaches this part below, it does implement the return; and sends me back to the top which allows me to catch the keypress which is at the top of my loop.
// Don't do anything if there isn't a card present...
if (!card.available()) {
return;
}
// Show that a card is being read...
digitalWrite(READ_LED, HIGH);
Serial.println("read card");
// Read the card into the buffer "data" (as a null-terminated string)...
short chars = card.read(data, DATA_BUFFER_LEN);
But now it wont read the card. When I insert the card, the code above does not execute the return, I can tell because it prints this test "read card" but I get no card data.
I think it might have to do with what you mentioned about when the Library expects the CLS to be active. Which makes me wonder why it was working before. Because it WAS reading the card with no problem.
I probably have to make some heavy modification to the Library correct?
Oh, by the way I am using an Arduino Mega
The library assumes that card.read() will be called when CLS goes low. It loops within read() while the ISRs clock in the data. When CLS goes high again, it assumes all the data is in the buffer, so it decodes it, validates it and then returns to the calling program.
For your reader, you would need to call read() on a low to high transition of CLD, and then work out a way of deciding when the data has been read from the card, because there is no CLD transition at the end of card removal, until the next card is put in. Maybe use a millis()-based timeout?
short MagStripe::read(char *data, unsigned char size)
{
// Fail if no card present...
if (!this->available()) {
return -1;
}
// Empty the bit buffer...
num_bits = 0;
next_bit = 0;
// Wait while the data is being read by the interrupt routines...
while (this->available()) {}
// Decode the raw bits...
short chars = this->decode_bits(data, size);
this->direction = READ_FORWARD;
// If the data looks bad, reverse and try again...
if (chars < 0) {
this->reverse_bits();
chars = this->decode_bits(data, size);
this->direction = READ_BACKWARD;
}
// The card could not be read successfully...
if (chars < 0) {
this->direction = READ_UNKNOWN;
}
return chars;
}
Victory At Last!! Lol
I updated read() to this
short MagStripe::read(char *data, unsigned char size)
{
// Empty the bit buffer...
num_bits = 0;
next_bit = 0;
// Wait while the data is being read by the interrupt routines...
// while (this->available()) {}
long startTime = millis();
while(millis() < startTime+1000){}
// Decode the raw bits...
short chars = this->decode_bits(data, size);
this->direction = READ_FORWARD;
// If the data looks bad, reverse and try again...
if (chars < 0) {
this->reverse_bits();
chars = this->decode_bits(data, size);
this->direction = READ_BACKWARD;
}
// The card could not be read successfully...
if (chars < 0) {
this->direction = READ_UNKNOWN;
}
return chars;
}
I'm using 1 second timeout which is kind of long, I will play around with that value and see whats a reasonable size.
Thank you SO MUCH, I am not an expert programmer so without your guidance this would have been very difficult for me.
I got rid of this so hopefully I do not have issues in the future but it looks like it will work just fine
// Fail if no card present...
if (!this->available()) {
return -1;
}