I am currently building myself some lighting for my apartment using Arduinos and strips of WS2812b LEDs. My plan was to control them with an app from my smartphone and a Raspberry Pi. The phone sends data (like color, mode etc.) to the Pi and the Pi transmits that via a 433MHz transmitter to three Arduino Nanos I wanted to place across the room.
Sending data from my phone through the Pi to the Arduinos works without a problem, the data is received correctly and the LEDs light up, but as soon as I do this once no more data can be received. There is no issue when I just receive and don't do anything else.
Here's my code:
#include <RCSwitch.h>
#include <Adafruit_NeoPixel.h>
#define LEDPIN 9
#define NUMPIXELS 75
#define STARTBIT 4194305
#define STOPBIT 8388609
#define SETBIT 2097153
RCSwitch rc = RCSwitch();
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, LEDPIN, NEO_GRB + NEO_KHZ800);
uint32_t data[] = {0,0,0};
bool written[] = {false, false, false};
bool led_set = false;
uint32_t wait = 0;
uint16_t j = 0;
int index = 0;
bool recording = false;
int led = 0;
unsigned long time;
static unsigned long received = 0;
void setup() {
Serial.begin(9600);
time = millis();
pinMode(LEDPIN, INPUT);
rc.enableReceive(0); // Receiver on interrupt 0 => that is pin #2
strip.begin();
for (int i = 0; i < 75; i++) {
strip.setPixelColor(i, strip.Color(255,255,255));
}
strip.show();
}
void loop() {
if (millis()-time >= 1000) {
Serial.println(*((unsigned int*)rc.nReceivedValue));
Serial.println(rc.nReceivedValue);
Serial.println(millis());
time = millis();
}
if (rc.available()) {
received = rc.getReceivedValue();
rc.resetAvailable();
Serial.print("received: ");
Serial.print(received);
Serial.println();
}
if ((received == STOPBIT) && recording) {
Serial.println("stopped");
recording = false;
}
else if ((received == STARTBIT) && not recording) {
recording = true;
led_set = false;
Serial.println("started");
}
if (recording) {
if(received == SETBIT && written[index] && index < 3) {
index++;
Serial.println("setbit");
}
else if(received != STARTBIT && received != STOPBIT && received != SETBIT && received != 0 && not written[index] && index < 3) {
data[index] = received & 0xFFFFFFFF;
written[index] = true;
//Serial.println(received);
Serial.println(data[index]);
Serial.println("written");
}
}
else if (data[0] != 0 && data[1] != 0 && data[2] != 0 && not recording && not led_set) {
Serial.println("setting LED");
for (int i = 0; i < NUMPIXELS; i++) {
strip.setPixelColor(i, data[2]);
}
strip.show();
rc.resetAvailable();
}
if (not recording) {
for (int k = 0; k < 3; k++) {
written[k] = false;
}
index = 0;
}
}
(I pretty much ripped this code to pieces and this is what's left.)
These are the transmitter/receivers and I use RC-Switch and Adafruit NeoPixel as libraries, other LED-libraries (FastLED, light_ws2812) had the same error though.
What I found out so far is that it works with less than 5 LEDs and sometimes with more if I set the colors to low values. Then it's more or less chance if I get another receive or not. If I do not set the LEDs here
else if (data[0] != 0 && data[1] != 0 && data[2] != 0 && not recording && not led_set) {
Serial.println("setting LED");
for (int i = 0; i < NUMPIXELS; i++) {
strip.setPixelColor(i, data[2]);
}
strip.show();
I can receive more data, if I hardcode the values for the colors it works only for bright white (so every color to 255) or for color values below 14.
If I comment out the last four lines in setup() the problem can't even be solved by the restart button (unplugging helps though). Switching the receiver does not work either.
All three of the Arduinos I use have the same issue.
I use a 6A power supply (at least for the strip with 75 LEDs, the other two have 30 LEDs each with a 2.4A supply) so power should be no issue.
When I hooked up my Arduino Uno to the second data pin of the receiver it couldn't receive anything either, using the Uno with another receiver next to it was fine. Using the Uno as oscilloscope and displaying the voltage on the data pin I noticed a lot of noise after first transmitting. It looked like it increased with the color values. The noise was gone after I restarted the Arduino with the LED-setting in setup() and it doesn't occur if I don't do anything with the LEDs at all. There is a 5 MOhm pull-down resistor between data and GND on the receiver module. I don't actually know if this noise has anything to do with this, because receiving was sometimes fine even with noise.
I tried disabling the receive pin before setting the LEDs and enabling it afterwards but that didn't help. Enabling interrupts manually doesn't do anything either. I changed the rc-switch interrupt handling so it prints something every time an interrupt occurs. That worked even after receiving the first data, The Arduino somehow just doesn't recognize what's been sent.
I really would like to know if there's anything I could try to solve this, besides switching to WiFi-modules or actual wire.
Related
I am trying to know whether the lights have tripped using a light sensor to detect light intensity. However, i do not know how to upload my data onto blynk, as i am new to blynk and new to arduino as well. Below is my code. I tried using a telegram bot to get the data but somehow it stopped working and i am finding alternatives to get the data remotely. If there are any other methods other than Blynk please suggest too.
#include <ESP8266WiFi.h> // WIFI LIBRARY
#include <WiFiClient.h> //CLIENT LIBRARY
#include <ESP8266WebServer.h> //WEBSERVICER LIBRARY
#include <ESP8266HTTPClient.h> //HTTP CLIENT LIBRARY
char auth[] = BLYNK_AUTH_TOKEN;
char ssid[] = "ArchiEngStudio";
char pass[] = "a12345678";
int CNT = 0, sent, i, j;
float count = 0;
int limit = 800; // SET LIMIT HERE
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
void loop() {
float reading = analogRead(A0);
Serial.println(reading);
delay(3000);
/* NO LIGHT CONDITION */
if (reading < limit)
{
if (CNT < 1) // CHECK LOOP ONLY RUNS ONCE
{
count = 0;
for (i=0; i<10; i++) //TAKING 10 READINGS TO CHECK IF LIGHTS ARE REALLY OFF
{
delay(1000);
int read2 = analogRead(A0);
Serial.println(read2);
if (read2 < limit)
{
Serial.println("(1) No Light ...");
}
else
{
Serial.println("(1) Light on...");
i= i+20;
}
}
if (i < 11) // IF ALL 10 READINGS SHOW THAT LIGHTS ARE OFF, SEND MESSAGE
{
if (sent == 0)
{
Serial.println("Tripped!");
sent = 1;
}
}
}
CNT++;
}
else
{
CNT = 0;
}
/* LIGHTS ON CONDITION */
if (sent == 1) //ONLY ALLOWED IF LIGHTS WERE OFF
{
if (reading >= limit)
{
for (j=0; j<10; j++) //TAKING 10 READINGS TO CHECK IF LIGHTS ARE REALLY ON
{
delay(1000);
int read3 = analogRead(A0);
Serial.println(read3);
if (read3 >= limit)
{
Serial.println("(2) Light on...");
}
else
{
Serial.println("(2) No light...");
j= i+10;
}
}
if (j < 11) //IF ALL 10 READINGS SHOW THAT LIGHTS ARE ON, SEND MESSAGE
{
Serial.println("Light on!");
sent = 0;
}
}
}
}
Blynk provides a decent way to display your data and is very easy to use once you are familiar with the concept.
You can store your reading variable in a virtual pin 'Vx' on the Blynk server by adding this line to your code:
Blynk.virtualWrite(Vx, reading);
If you want to display it on the app just use "value display" widget and configure it to display your virtual pin 'Vx'.
For some time I wanted to have an Arduino controlled light switcher for outdoors and few weeks ago I created it, but I have problems with it.
I needed to have a RFID reader outside, that switches lights on for some time when a proper tag is given and it works all good but only for some time. Sometimes after few hours, sometime after few days of using the tag feature doesn't work anymore until I reset whole Arduino (also have a Hall sensor mounted that turns lights on when my door is open and it works perfectly fine)
My question is - what is wrong with this code (I suspect the "rfid.PICC_HaltA(); rfid.PCD_StopCrypto1();" bottom part, cause I have no idea how to use it and what it does to be fully honest). I'm not a programmer, I'm a total noob and I would really appreciate your help.
Edit: Draw quick representation in paint to show how it looks IRL:
I didnt draw all separate colors and connections to GPIO cause they are all fine - like I said it works but only for some time until I reset the whole thing. Arduino is Nano (Old Bootloader) and RFID reader is RC522. Magnetic Hall sensor is just a normal sensor with a magnet mounted on door beneath it so it knows when the door is opened/closed. The whole idea is this:
When door open - lights up and stay up for 6 more seconds after closing the door
When door is closed and tag is presented - lights up for 15s, then go back to checking if door is opened/closed
#include <SPI.h>
#include <MFRC522.h>
//#define czas_trwania 5000
//blue
const byte UID1[] = {0xA7, 0x8C, 0x24, 0xD9};
//blacks
const byte UID2[] = {0x10, 0x84, 0xD2, 0x2A};
const byte UID3[] = {0xDC, 0x46, 0xB6, 0x91};
const byte UID4[] = {0xB0, 0xE8, 0xC4, 0x2A};
//reds
const byte UID5[] = {0x9E, 0xC8, 0xEA, 0xB3};
const byte UID6[] = {0xFE, 0xA5, 0xF7, 0xB3};
//const byte UID6[] = {0x70, 0xBA, 0x35, 0xA5};
MFRC522 rfid(10, 9);
MFRC522::MIFARE_Key key;
int in1 = 7;
int dooropen = 8;
int state = 0;
int tester = 0;
void setup() {
Serial.begin(9600);
SPI.begin();
rfid.PCD_Init();
pinMode(in1, OUTPUT);
pinMode(dooropen, INPUT);
digitalWrite(in1, LOW);
}
void loop() {
state = digitalRead(dooropen);
if (state == HIGH) {
//Serial.println("Door Opened");
tester = 1;
digitalWrite(in1, HIGH);
} else {
if (tester == 1) {
delay(6000);
tester = 0;
}
//Serial.println("Door Closed");
digitalWrite(in1, LOW);
if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) {
if (rfid.uid.uidByte[0] == UID1[0] &&
rfid.uid.uidByte[1] == UID1[1] &&
rfid.uid.uidByte[2] == UID1[2] &&
rfid.uid.uidByte[3] == UID1[3] ||
rfid.uid.uidByte[0] == UID2[0] &&
rfid.uid.uidByte[1] == UID2[1] &&
rfid.uid.uidByte[2] == UID2[2] &&
rfid.uid.uidByte[3] == UID2[3] ||
rfid.uid.uidByte[0] == UID3[0] &&
rfid.uid.uidByte[1] == UID3[1] &&
rfid.uid.uidByte[2] == UID3[2] &&
rfid.uid.uidByte[3] == UID3[3] ||
rfid.uid.uidByte[0] == UID4[0] &&
rfid.uid.uidByte[1] == UID4[1] &&
rfid.uid.uidByte[2] == UID4[2] &&
rfid.uid.uidByte[3] == UID4[3] ||
rfid.uid.uidByte[0] == UID5[0] &&
rfid.uid.uidByte[1] == UID5[1] &&
rfid.uid.uidByte[2] == UID5[2] &&
rfid.uid.uidByte[3] == UID5[3] ||
rfid.uid.uidByte[0] == UID6[0] &&
rfid.uid.uidByte[1] == UID6[1] &&
rfid.uid.uidByte[2] == UID6[2] &&
rfid.uid.uidByte[3] == UID6[3]) {
digitalWrite(in1, HIGH);
delay(15000);
digitalWrite(in1, LOW);
}
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
}
}
}
I know that this if will make some of you cringe hard, but I didn't know how to manage otherwise :(
I could not find the problem, so instead, I just re-designed your project, and it should work. I have made it more maintainable and optimized than your current project.
For the new design, I have created a schematic and the code:
Schematic:
Code:
#include <SPI.h>
#include <MFRC522.h>
#define SS_PIN 10
#define RST_PIN 9
#define LED_PIN 7
bool toggle = false;
MFRC522 mfrc522(SS_PIN, RST_PIN);
void setup()
{
Serial.begin(9600);
SPI.begin();
mfrc522.PCD_Init();
pinMode(LED, OUTPUT);
}
void loop()
{
if (!mfrc522.PICC_IsNewCardPresent())
{
return;
}
// Select one of the cards
if (!mfrc522.PICC_ReadCardSerial())
{
return;
}
// Use this function to serial print your UID.
checkUID();
if (content.substring(1) == "[Insert UID Here]")
{
Serial.println("LED Toggle");
toggleLight();
}
else
{
Serial.println(" Access denied");
}
}
void toggleLight()
{
if (toggle)
{
toggle = false;
}
else
{
toggle = true;
}
}
void checkUID()
{
String content = "";
for (byte i = 0; i < mfrc522.uid.size; i++)
{
Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
Serial.print(mfrc522.uid.uidByte[i], HEX);
content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
content.concat(String(mfrc522.uid.uidByte[i], HEX));
}
}
I do not have the resources to try this, but if you encounter any issues make sure to let me know and I will help you resolve them.
You will also need to include the library:
I have spent a lot of time making this, so I would appreciate an upvote! 🙂
MFRC522 library has the Version 2.
https://github.com/OSSLibraries/Arduino_MFRC522v2
// Halt PICC.
reader.PICC_HaltA();
// Stop encryption on PCD. (Proximity Coupling Device (PCD))
reader.PCD_StopCrypto1();
for PICC_HaltA(), read http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf
chapter 6.
6.3.5 HALT state
Description:
In the HALT state, the PICC shall respond only to a WUPA command.
State exit conditions and transitions:
The PICC enters the READY* state after it has received a
valid WUPA command and transmitted its ATQA.
For PCD_StopCrypto1,
In the source code, MFRC522V2.cpp, the note of Function MFRC522::StatusCode MFRC522::PCD_Authenticate
Executes the MFRC522 MFAuthent command.
...
...
Remember to call PCD_StopCrypto1() after communicating with the authenticated PICC - otherwise no new communications can start.
I did face similar issue with one of my project. And after carefully examining with different configurations I deducted that it's actually a power supply issue. So I recommend using a 1 or 10uf cap across the 3.3 and gnd close to the module. Also don't put any metal plates near the module.
I only started programming a few days ago and ran into a few problems.
I'm trying to make a servo turn 180 degrees when I type 1 and 180 degrees the other way when I type 0, I'm using an HC-05 Bluetooth module connected to my phone, so I tried to "merge" the servo sweep code from Arduino IDE library and another code that turns a light on by Bluetooth (which works), so I've been trying to fix this without any results.
Here's what I've done so far:
#include <Servo.h>
Servo myservo;
int pos = 0;
char data = 0;
void setup()
{
Serial.begin(9600);
pinMode(13, OUTPUT);
myservo.attach(13);
}
void loop()
{
if (Serial.available() > 0)
{
data = Serial.read();
Serial.print(data);
Serial.print("\n");
if (data == '1') for (pos = 0; pos <= 180; pos += 1)
else if (Serial.available() > 1)
digitalWrite(13, myservo(pos = 180; pos >= 0; pos -= 1));
}
}
Arduino create keeps telling me I'm missing a primary expression before else.
You've added the start of a for loop, but not told the compiler what operations to repeat.
When you're beginning, it's useful to add braces whenever you use a control statement (if, while, for, do, switch, case) irrespective of whether you have to, and indent consistently, then you can see where things should go and where the body of the control statement starts and ends.
void loop()
{
if (Serial.available() > 0)
{
data = Serial.read();
Serial.print(data);
Serial.print("\n");
if (data == '1')
{
// execute the code from the 'sweep' example if the user sends '1'
for (pos = 0; pos <= 180; pos += 1)
{
// goes from 0 degrees to 180 degrees
// in steps of 1 degree
myservo.write(pos);
delay(15);
}
}
else if (Serial.available() > 1)
{
// removed as code here made no real sense
}
}
}
I'm using an 125Khz RFID module RDM6300 with arduino nano.
While the card is near the RFID reader the loop will read the card multiple times. I want it to read only once while the card is near the reader then read it again if a new connection is being made.
*This code is not writen by me, this is the source:
https://github.com/Wookai/arduino-rfid
// define constants for pins
//int SUCCESS = 10;
//int ERROR = 13;
// variables to keep state
int readVal = 0; // individual character read from serial
unsigned int readData[10]; // data read from serial
int counter = -1; // counter to keep position in the buffer
char tagId[11]; // final tag ID converted to a string
char* authorizedTags[4]; // array to hold the list of authorized tags
// fills the list of authorzied tags
void initAuthorizedTags() {
// add your own tag IDs here
authorizedTags[0] = "0400680B85";
authorizedTags[1] = "0400063EB9";
authorizedTags[2] = "040004F3F5";
authorizedTags[3] = "04006813AB";
}
void setup() {
Serial.begin(9600);
// pinMode(SUCCESS, OUTPUT);
//pinMode(ERROR, OUTPUT);
initAuthorizedTags();
}
// check if the tag ID we just read is any of the authorized tags
int checkTag() {
int i;
for (i = 0; i < 4; ++i) {
if (strcmp(authorizedTags[i], tagId) == 0) {
return 1;
}
}
return 0;
}
// convert the int values read from serial to ASCII chars
void parseTag() {
int i;
for (i = 0; i < 10; ++i) {
tagId[i] = readData[i];
}
tagId[10] = 0;
}
// once a whole tag is read, process it
void processTag() {
// convert id to a string
parseTag();
// print it
printTag();
// check if the tag is authorized
if (checkTag() == 1) {
tagSuccess(); // if so, perform an action (blink a led, open a door, etc...)
} else {
tagFailed(); // otherwise, inform user of failure
}
}
void printTag() {
Serial.print("Tag value: ");
Serial.println(tagId);
}
// perform an action when an authorized tag was read
void tagSuccess() {
Serial.println("Tag authorized.");
// here, we simply turn on the success LED for 2s
// digitalWrite(SUCCESS, HIGH);
//digitalWrite(ERROR, LOW);
// delay(2000);
}
// inform the user that the tag is not authorized
void tagFailed() {
Serial.println("Unauthorized access!");
//digitalWrite(SUCCESS, LOW);
// digitalWrite(ERROR, HIGH);
// delay(2000);
}
// this function clears the rest of data on the serial, to prevent multiple scans
void clearSerial() {
while (Serial.read() >= 0) {
; // do nothing
}
}
void loop() {
// turn LEDs off
// digitalWrite(SUCCESS, LOW);
// digitalWrite(ERROR, LOW);
if (Serial.available() > 0) {
// read the incoming byte:
readVal = Serial.read();
// a "2" signals the beginning of a tag
if (readVal == 2) {
counter = 0; // start reading
}
// a "3" signals the end of a tag
else if (readVal == 3) {
// process the tag we just read
processTag();
// clear serial to prevent multiple reads
clearSerial();
// reset reading state
counter = -1;
}
// if we are in the middle of reading a tag
else if (counter >= 0) {
// save valuee
readData[counter] = readVal;
// increment counter
++counter;
}
}
}
Thank you.
Thank you for your answers. I tried to accept the multiple reads and print only one but it keeps printing "already read" instead of reading the card first time, this is the code:
void printTag() {
if(strcmp(tagId,previous)==1){
strcpy(previous, tagId);
Serial.print("Tag value: ");
Serial.println(tagId);
}
else
{
Serial.print("already read");
}
}
I also tried to put the delay after end of tag but it still reads the card multiple times.
I tried another code, it still reads the tag multiple times.
#include <SoftwareSerial.h>
// RFID | Nano
// Pin 1 | D2
// Pin 2 | D3
SoftwareSerial Rfid = SoftwareSerial(2,3);
int timer=0;
int reference = 1000;
int card_status = 0;
void setup() {
// Serial Monitor to see results on the computer
Serial.begin(9600);
// Communication to the RFID reader
Rfid.begin(9600);
}
void read() {
// check, if any data is available
// as long as there is data available...
while(Rfid.available() > 0 ){
// read a byte
int r = Rfid.read();
// print it to the serial monitor
Serial.print(r, DEC);
Serial.print(" ");
}
// linebreak
Serial.println();
timer=0;
}
void loop()
{
if((Rfid.available() > 0 ) && (card_status == 0) )
{
read();
}
if((!Rfid.available() > 0 ) && (card_status == 1) )
{
card_status=0;
}
}
I'm sorry for the late response. I forgot about this topic.
I solved the problem by making the arduino wait for a response after writing the RFID code for the frist time.
I was able to do that because my arduino was sending the code to a C# application via serial port.
Here is how it works: the arduino prints the RFID code on the serial, from there it is picked up by the C# application which searches a database to see if the code is stored there. Depending on the result, the application prints a character('y' or 'n') which is picked up by the arduino. Depending on the character recieved, the arduino lights up a led ( green or red) and makes a noise. Now a new RFID reading can be made.
Here is the code:
#include <SoftwareSerial.h>
#include "RDM6300.h"
SoftwareSerial rdm_serial(8, 9);
RDM6300<SoftwareSerial> rdm(&rdm_serial);
String comanda;
char c="";
int led_verde = 2;
int led_rosu = 7;
int buzzer = 12;
int i;
void buzz(int n = 1)
{
for (int i = 0; i < n; i++) {
digitalWrite(buzzer, LOW);
delay(200);
digitalWrite(buzzer, HIGH);
delay(200);
}
}
void ledVerde()
{
digitalWrite(led_verde, HIGH);
buzz(1);
delay(1000);
digitalWrite(led_verde, LOW);
}
void ledRosu()
{
digitalWrite(led_rosu, HIGH);
buzz(3);
delay(1000);
digitalWrite(led_rosu, LOW);
}
void setup()
{
pinMode(led_verde, OUTPUT);
pinMode(led_rosu, OUTPUT);
pinMode(buzzer, OUTPUT);
digitalWrite(led_verde, LOW);
digitalWrite(led_rosu, LOW);
digitalWrite(buzzer, HIGH);
Serial.begin(9600);
}
void loop()
{
static unsigned long long last_id = 0;
last_id = rdm.read();
rdm.print_int64(last_id);
Serial.println();
rdm_serial.end();
Serial.flush();
while(!Serial.available());
c=Serial.read();
if(c=='y')
{
ledVerde();
c="";
}
if(c=='n')
{
ledRosu();
}
Serial.flush();
last_id="";
c="";
rdm_serial.begin(9600);
}
You can find the RDM6300 library here: https://github.com/arliones/RDM6300-Arduino
Long time passed the original question, but maybe my answer would be useful for future visitors.
The RDM6300 works by:
automatically reading the data, and then
your code transfers the read data to the buffer for further processing.
Imagine it as a Baggage carousel in the airport. There are multiple luggage (data) on the carousel (reader), and you pick them one by one (transferring to buffer).
So, the problem of multiple reads, is that you have got read data in the reader (luggage on the carousel), that your code is gradually transferring them to the buffer (picking the luggage up).
In our example, if you don't like to collect all luggage, you can ask someone to take some of them, before they reach to you.
The below code does this. While you have data in the reader (the card is near to the reader), it transfers data from reader to buffer and then zeros all of them in the buffer:
First, place this code before "void setup()":
boolean multipleRead = false;
This defines a false/true variable to tell if this is the first time you are reading the tag (false), or it's being read multiple times (true).
Then, put this one at the end of the code block that shows the tag is fully read. If you are using Michael Schoeffler's library for your RDM6300/630 RFID, put it after "else if (ssvalue == 3) {":
multipleRead = true;
It change the variable to true, when your tag is read. That tells the program that your first read is done and the next upcoming read(s) would be "multiple read" and you don't want them.
Then put this at the end of the RFID reader code (if your RFID code is under void loop (), put the below code just after "void loop (){":
if (multipleRead) {
while (ssrfid.available() > 0) {
int ssvalue = ssrfid.read(); // read
if (ssvalue == -1) { // no data was read
break;
}
}
for (int x = 0; x < 14; x++)
{
buffer[x] = 0;
}
multipleRead = false;
}
It empties the reader and then zeros the buffer, while there is a card nearby. When you move the card away, multipleRead value would turn to false, which let another RFID reading loop to initiate.
Hope that helped :)
I guess what you want is a edge trigger instead of level trigger with time limit.
For example, you may prefer to read a RFID card when it firstly comes near to the antenna, once only; when it keeps to contact the antenna, still take no more actions. When you remove the card and place it again near to the antenna, the MCU starts to read the card again.
If so, the following code could be for your reference. What I have done is just to add 1 more flag to keep checking the card_status before checking if a RFID card comes near to the antenna.
int card_status = 0; //0:readable; 1:not-readable
if ( (Serial.available() > 0) && (card_status == 0) ) {
card_status = 1; //disable to read card after exit this loop
//your code, a card is near to the antenna, try to read it.
readVal = Serial.read();
if (readVal == 2) {
counter = 0; // start reading
} else if (readVal == 3) {
processTag();
clearSerial();
counter = -1;
} else if (counter >= 0) {
readData[counter] = readVal;
++counter;
}
}
reset the card status when no RFID signal comes in && card status is true,
if ( (!(Serial.available() > 0)) && (card_status == 1) ) {
card_status = 0; //enable to read card again
//no signal, no card is near to the antenna.
}
You can set a delay (e.g. delay(2000)) after reading the (end of tag). A delay of (say) 2 seconds will allow the user to move the card far enough away from the reader. Note that delay is a blocking command which might not suit your purposes, in which case you could be looking at using the millis count to activate/deactivate the Serial.read.
Another option is to accept the multiple reads, but keep a state of which card has been read. If the new card number is the same as the old card number (within a reasonable timeframe) then just ignore.
As part of a simple Automation project, I was trying to control some LEDs through serial port. I cannot make the following code working
int pin =0;
int state = 0;
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
if(Serial.read() == 'S' && Serial.read() == 'S') {
// Command to set the pin
pin = Serial.read() - 65;
state = Serial.read() - '0';
Serial.print("Set State Command received");
// Set the Pin
pinMode(pin, OUTPUT);
digitalWrite(pin, state == 0? LOW:HIGH);
}
}
}
I am sending "SSN1" from my python program to the Arduino serial port for testing, and nothing happens (I have an LED connected on pin 13)
SS - Set State Command
N - (pin no) + 'A' - Pin number 13
1 - State ( 0 = LOW, 1= HIGH)
You want to wait until 4 serial bytes accumulate on the serial buffer.
void loop() {
// polls the serial buffer
while (Serial.available() < 4);
if (Serial.read() == 'S' && Serial.read() == 'S') {
char type = Serial.read();
char pin = Serial.read() - 65;
// do something with the results
}
}
Note that you may want to implement some kind of padding (adding a fixed length of spaces, for example) between inputs, because the serial buffer may drop a byte or overflow, which can lead to unexpected results. Also, some people will complain about the while (Serial.available() < 4) command because computer scientists have been trained to think "polling = bad!", but in the case of an Arduino it makes no difference since it is only running a single task.
By the way, you can also use interrupts with Serial data, but that's out of the scope of this response.
actually I have also battled to get something similar right. due to the problems experienced with serial communication (sometime the messages are slow and sent in pieces, the ACII codes are difficult to remember) I went for a different solution. Basically I added a header ">" and a tail "<"to the message sent to the serial and I featured the Arduino code to consider the message between >< as command. I have then used ATOI to convert string to integer.
In the following code you will see that I have used the following numbers to get Arduino changing the status of pin2 and pin13.
Here are the commands associated to this code:
1000< set pin 13 HIGH,
2000< set pin 13 LOW,
3000< set pin 2 HIGH,
4000< set pin 2 LOW
So, simply send out to the serial those numbers between >< and it should work.
I have used the above also to set PWM speed simply manipulating the strings associated to the received messages. I have not included in this sample the PWM commands but only those related to pin 13 and pin 2. I thought that would be much simpler and safe to use numbers and string identifier to open and close the message.
Load the sketch, open the serial monitor and send >1000<, you should see the internal led on pin 13 lighting up, and so on. let me know if you need any additional help.
char inData[10];
int index;
boolean started = false;
boolean ended = false;
String message = "I am ready!, Send your command....";
void setup(){
Serial.begin(9600);
Serial.println(message);
pinMode (13, OUTPUT);
pinMode (2, OUTPUT);
}
void loop()
{
while(Serial.available() > 0)
{
char aChar = Serial.read();
if(aChar == '>')
{
started = true;
index = 0;
inData[index] = '\0';
}
else if(aChar == '<')
{
ended = true;
}
else if(started)
{
inData[index] = aChar;
index++;
inData[index] = '\0';
}
}
if(started && ended)
{
int inInt = atoi(inData);
// set pin 13 HIGH
if (inInt < 1000)
{
digitalWrite(13, HIGH);
}
//set pin 13 LOW
else if (inInt < 2000)
{
digitalWrite(13, LOW);
}
//set pin 2 HIGH
else if (inInt < 3000)
{
digitalWrite(2, HIGH);
}
//set il pin 2 LOW
else if (inInt < 4000)
{
digitalWrite(2, LOW);
}
started = false;
ended = false;
index = 0;
inData[index] = '\0';
}
}
Look at this example code from Arduino's Physical Pixel Tutorial
const int ledPin = 13; // the pin that the LED is attached to
int incomingByte; // a variable to read incoming serial data into
void setup() {
// initialize serial communication:
Serial.begin(9600);
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
}
void loop() {
// see if there's incoming serial data:
if (Serial.available() > 0) {
// read the oldest byte in the serial buffer:
incomingByte = Serial.read();
// if it's a capital H (ASCII 72), turn on the LED:
if (incomingByte == 'H') {
digitalWrite(ledPin, HIGH);
}
// if it's an L (ASCII 76) turn off the LED:
if (incomingByte == 'L') {
digitalWrite(ledPin, LOW);
}
}
Verify that you see SSN1 coming through on the serial monitor.
I improved my code as it look like this
int pin =0;
int state = 0;
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 3) { // I am using chunk of 4 characters/bytes as a command
// read the incoming byte:
if(Serial.read() == 'S' && Serial.read() == 'S') {
// Command to set the pin
pin = Serial.read() - 65;
state = Serial.read() - '0';
Serial.print("Set State Command received");
// Set the Pin
pinMode(pin, OUTPUT);
digitalWrite(pin, state == 0? LOW:HIGH);
}
delay(50);
}
}
It works perfectly for me. Due to the high frequency of looping, Arduino was not able pickup the bytes for consecutive read. So we are waiting for 4 bytes to accumulate in the buffer to read those (Arduino's serial buffer is 64 bytes).