Want to get GPS data at every 5 sec using arduino - arduino

I wrote the following codes in Arduino uno with the header file TinyGPSPlus,and uses GPS SKG 13BL(GPS module).
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
/*
This program sketch obtain and print the lati,logi,speed,date and time
It requires the use of SoftwareSerial, and assumes that you have a
9600-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
void setup()
{
Serial.begin(9600);
ss.begin(GPSBaud);
Serial.println(F("GPS LOADING....."));
Serial.println(F("Obtain and print lati,logi,speed,date and time"));
Serial.println(F("Testing by : "));
Serial.println(F("Billa"));
Serial.println();
}
void loop()
{
// This sketch displays information every time a new sentence is correctly encoded.
while (ss.available() > 0)
if (gps.encode(ss.read()))
displayInfo();
if (millis() > 5000 && gps.charsProcessed() < 10)
{
Serial.println(F("No GPS detected: check wiring."));
while(true);
}
}
void displayInfo()
{
Serial.print(F("Location: "));
if (gps.location.isValid())
{
Serial.print(gps.location.lat(), 6);
Serial.print(F(","));
Serial.print(gps.location.lng(), 6);
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" Speed: "));
if (gps.speed.isValid())
{
Serial.print(gps.speed.kmph());
Serial.print(F(" KMPH "));
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" Date : "));
if (gps.date.isValid())
{
Serial.print(gps.date.month());
Serial.print(F("/"));
Serial.print(gps.date.day());
Serial.print(F("/"));
Serial.print(gps.date.year());
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" Time : "));
if (gps.time.isValid())
{
int hour= gps.time.hour() + 5;
if (hour < 10) Serial.print(F("0"));
if(hour > 12) hour-=11;
Serial.print(hour);
Serial.print(F(":"));
int minute = gps.time.minute() + 30;
if(minute >= 60) minute-=60;
if (minute < 10) Serial.print(F("0"));
Serial.print(minute);
Serial.print(F(":"));
if (gps.time.second() < 10) Serial.print(F("0"));
Serial.print(gps.time.second());
}
else
{
Serial.print(F("INVALID"));
}
Serial.println();
}
It obtained the required output.Displays the lines of data continusly on serial monitor.
But now i need to get these data exactly at every 5 secs (i.e At every 5 Secs the above code should generate output as per that instant).I tried to do this using delay and rewrote the loop code as follows
void loop()
{
delay(5000);
// This sketch displays information every time a new sentence is correctly encoded.
while (ss.available() > 0)
if (gps.encode(ss.read()))
displayInfo();
if (millis() > 5000 && gps.charsProcessed() < 10)
{
Serial.println(F("No GPS detected: check wiring."));
while(true);
}
}
But this doesnt obtained the output as desired.Can anyone please help me to solve this.Where should i edit and what changes should i make.

This is EXACTLY why I wrote NeoGPS. The example programs for all other libraries are just not structured properly. I'm looking at you, smartDelay()...
NeoGPS is structured around receiving a complete fix from the GPS device. This usually requires several sentences to be received. Other GPS libraries only tell you when one sentence is received. Furthermore, it's difficult to tell if two sentences are from the same 1-second update interval, or two consecutive intervals.
You want to display information once every 5 seconds, but that may be once every 20 sentences. And according to the Arduino millis() clock, it will be about 5000ms, but not exactly. millis() will drift against the GPS interval, depending on how accurate your crystal is. The GPS interval is very accurate,to the limits of the atomic clock, serial baud rate, and GPS device calculation time.
Here is your sketch, modified to use NeoGPS:
#include <NMEAGPS.h>
/*
This program sketch obtain and print the lati,logi,speed,date and time
It requires the use of SoftwareSerial, and assumes that you have a
9600-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
#include <NeoSWSerial.h>
static const int RXPin = 4, TXPin = 3;
NeoSWSerial gpsPort(RXPin, TXPin);
static const uint32_t GPSBaud = 9600;
NMEAGPS gps;
gps_fix fix;
uint8_t fixCount = 0;
void setup()
{
Serial.begin(9600);
gpsPort.begin(GPSBaud);
Serial.println(F("GPS LOADING....."));
Serial.println(F("Obtain and print lati,logi,speed,date and time"));
Serial.println(F("Testing by : "));
Serial.println(F("Billa"));
Serial.println();
}
void loop()
{
while (gps.available( gpsPort )) {
fix = gps.read();
// Once every 5 seconds...
if (++fixCount >= 5) {
displayInfo();
fixCount = 0;
}
}
if ((gps.statistics.chars < 10) && (millis() > 5000)) {
Serial.println( F("No GPS detected: check wiring.") );
while(true);
}
}
void displayInfo()
{
Serial.print(F("Location: "));
if (fix.valid.location) {
Serial.print( fix.latitude(), 5 );
Serial.print( ',' );
Serial.print( fix.longitude(), 5 );
} else {
Serial.print(F("INVALID"));
}
Serial.print(F(" Speed: "));
if (fix.valid.speed) {
Serial.print(fix.speed_kph());
Serial.print(F(" KMPH "));
} else {
Serial.print(F("INVALID"));
}
// Shift the date/time to local time
NeoGPS::clock_t localSeconds;
NeoGPS::time_t localTime;
if (fix.valid.date && fix.valid.time) {
using namespace NeoGPS; // save a little typing below...
localSeconds = (clock_t) fix.dateTime; // convert structure to a second count
localSeconds += 5 * SECONDS_PER_HOUR + 30 * SECONDS_PER_MINUTE; // shift timezone
localTime = localSeconds; // convert back to a structure
}
Serial.print(F(" Date : "));
if (fix.valid.date) {
Serial.print(localTime.month);
Serial.print('/');
Serial.print(localTime.date);
Serial.print('/');
Serial.print(localTime.year);
} else {
Serial.print(F("INVALID"));
}
Serial.print(F(" Time : "));
if (fix.valid.time) {
Serial.print(localTime.hours);
Serial.print(':');
if (localTime.minutes < 10) Serial.print('0');
Serial.print(localTime.minutes);
Serial.print(':');
if (localTime.seconds < 10) Serial.print(F("0"));
Serial.print(localTime.seconds);
} else {
Serial.print(F("INVALID"));
}
Serial.println();
}
This sketch displays every fifth fix, without using the inaccurate millis(), or the nasty delay(). Ain't nobody got time for dat!
And each fix is accumuated from all the sentences in each 1-second interval, whether it's one sentence (RMC?), or 8 sentences (GGA, GLL, RMC, GSV*3, GSA and VTG). In NeoGPS, counting fixes is equivalent to counting seconds.
NOTE: if you need a super-accurate 5-second interval, consider using the PPS pin, if available.
The local time is CORRECTLY computed in this sketch, even if the timezone shift steps into a new hour, day, month or year. Your sketch does not cross day boundaries correctly. 5.5 hour shift, if I read your sketch correctly.
Should I mention NeoGPS is smaller, faster and more accurate than all other libraries? :) It's available from the Arduino IDE Library Manager, under the menu Sketch -> Include Library -> Manage Libraries.
You should also consider using something besides SoftwareSerial. It is very inefficient, because it disables interrupts for long periods of time. This can interfere with other parts of your sketch or with other libraries.
The best software serial port library is AltSoftSerial. If you can switch to pins 8 & 9, I would strongly recommend doing so.
If you can't switch pins (are you really sure?), you should use my NeoSWSerial. It works on any two pins, and is almost as efficient. It supports the 9600 baud rate you are using.

You should avoid using the normal delay function when working with this library, as it requires a new fix at a regular interval. In the example code you will find a function called smartDelay()copy this function in to your code and use this instead. It looks like this.
static void smartDelay(unsigned long ms)
{
unsigned long start = millis();
do
{
while (ss.available())
gps.encode(ss.read());
} while (millis() - start < ms);
}
Put this code in the bottom of your code at call smartDelay(5000); instead of delay(5000); in the bottom of the void loop()
You should also place the call to displayInfo(); just below smartDelay() like this.
void loop()
{
while (ss.available() > 0)
if (gps.encode(ss.read()))
if (millis() > 5000 && gps.charsProcessed() < 10) {
Serial.println(F("No GPS detected: check wiring."));
while(true);
}
smartDelay(5000);
displayInfo();
}
Edit: A even better way
A even better way, especially if you like to do other stuff while you showing the data, is to use millis(). this will also be called more precise every 5 sec.
You wil have to declare a variable at the top for this to work. It will look like this.
long timeToDisplay = 0; // Declare this at the top
void loop()
{
while (ss.available() > 0)
if (gps.encode(ss.read()))
if (millis() > 5000 && gps.charsProcessed() < 10) {
Serial.println(F("No GPS detected: check wiring."));
while(true);
}
if(timeToDisplay <= millis()) {
timeToDisplay = millis() + 5000;
displayInfo();
}
}

slash-dev give me an answer on how to get data in 5 secs interval from GPS.He also provided some improved methods, which when i followed obtains perfect output.It solved some bugs in the code i provided too.Link to the answer :
https://stackoverflow.com/a/43009260/7699452
result :
https://i.stack.imgur.com/pzvsu.png

Related

Arduino AccelStepper Library: Instant speed never reaches set speed

I am trying to develop a arduino code which runs a stepper motor with C# program via serial communication. I also use Accelstepper library, especially moveTo() and run() functions. I sent maxSpeed and step values as 3500 and 200.000 from C# and motor start to run immediately. I sure that it completes all steps, but after a while, I noticed that stepper motor never reaches its max Speed and it stuck at 3200-3300 range. So because of that finish time is increased. If I give steps more than 200.000, the gap between estimated finish time and real finish time is increased exponentially. If I sent speed as 1000, real speed more or less 970. I have to use acceleration function by the reason of needed torque. Then I search the problem and some people said that it occurs because of Accelstepper library which consist run() function and other stuff that I wrote in the loop section. Especially I could not ensure the reason of the problem is Arduino, AccelStepper library or code that I wrote. Can you please help me to solve problem?
NOTE: Arduino Mega 2560 is used.
Arduino code is below:
#include <AccelStepper.h>
#include <stdio.h>
#define STEP_PIN_C 5 //31
#define DIRECTION_PIN_C 23 //32
#define ENABLE_PIN_C 24 //33
#define SET_ACCELERATION 600.0
AccelStepper stepper(1, STEP_PIN_C, DIRECTION_PIN_C);
unsigned long oldTime=0;
unsigned long now;
float newSpeed;
float maxSpeed = 3500.0;
bool newDataBit, runAllowed = false,addingProg=false,mainProg=false;
char commandChar;
long currentPosition;
long int steps = 0, mainNewStep, addedNewStep,memMainStep;
void checkSerial();
void checkRunning();
void stopMotor();
void runMotor();
void sendInfo();
const unsigned long delayTime = 1000;
unsigned long timer;
int count = 0;
bool running = false;
void setup()
{
Serial.begin(9600);
pinMode(ENABLE_PIN_C, OUTPUT);
digitalWrite(ENABLE_PIN_C, HIGH);
stepper.setCurrentPosition(0); //initial value
stepper.setMaxSpeed(0.0); //initial value
stepper.setAcceleration(SET_ACCELERATION); //initial value
}
void loop()
{
sendInfo();
checkRunning();
checkSerial();
}
void checkRunning()
{
if (runAllowed == true)
{
if (stepper.distanceToGo() == 0)
{
stopMotor();
checkSerial();
}
else
{
runMotor();
checkSerial();
}
}
}
void checkSerial()
{
if (Serial.available())
{
newDataBit = true;
commandChar = Serial.read();
}
if (newDataBit == true)
{
///DoStuff depends on what is received as commandChar via serial port
mainProgram(stepper.currentPosition(),newSpeed,mainNewStep);
newDataBit = false;
}
}
void runMotor(){
digitalWrite(ENABLE_PIN_C, LOW);
stepper.run();
running = true;
}
void stopMotor(){
stepper.setCurrentPosition(0);
digitalWrite(ENABLE_PIN_C, HIGH);
stepper.stop();
running = false;
timer = millis() + delayTime;
}
void mainProgram(long currentPositionValue,float maxSpeedValue,long stepValue)
{
mainProg = true;
if (stepper.distanceToGo() == 0) //YOLUMU TAMAMLADIM
{
addingProg = false;
steps = stepValue;
stepper.setCurrentPosition(currentPositionValue);
//stepper.setSpeed(0);
stepper.setMaxSpeed(maxSpeedValue);
stepper.moveTo(steps);
}
else
{
steps = stepValue + steps;
stepper.setCurrentPosition(currentPositionValue);
//stepper.setSpeed(0);
stepper.setMaxSpeed(newSpeed);
stepper.moveTo(steps);
}
}
void sendInfo(){
now = millis();
if(now-oldTime > 1000){ //saniyede 1
Serial.print(stepper.currentPosition());
Serial.print(" ");
Serial.print(stepper.isRunning());
Serial.print(" ");
Serial.println(stepper.speed());
oldTime = now;
}
}
From AccelStepper documentation:
The fastest motor speed that can be reliably supported is about 4000
steps per second at a clock frequency of 16 MHz on Arduino such as Uno
etc.
This is if you do nothing else but running the stepper.
You check your serial interface and send multiple lines every second. Both is quite expensive.

In an Arduino project, what does it mean to be missing a primary expression before else?

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
}
}
}

Set function generator frequency to observe sine wave form in android app

I built an app to observe real-time graph. I set the sampling rate to 256hz in my Arduino code. I gave the output of 100hz through a function generator, but I obtained a random waveform instead of the sine waveform.
this is my Arduino code:
#include <SoftwareSerial.h> //import Software Serial library
SoftwareSerial myStream(0, 1); //pins for Rx and Tx respectively
int ECG;
void setup()
{
// put your setup code here, to run once:
pinMode(A0, INPUT); //LDR
myStream.begin(115200);
Serial.begin(9600);
}
void loop()
{
ECG = analogRead(A0);
Serial.println(ECG);
if (myStream.available() > 0)
{
char re = myStream.read();
switch (re)
{
case 'E':
start();
break;
}
}
//about 256Hz sample rate
delayMicroseconds(3900);
}
void start()
{
while (1)
{
myStream.print('s');
myStream.print(floatMap(analogRead(ECG), 0, 1023, 0, 255), 2);
//about 256Hz sample rate
delayMicroseconds(3900);
if (Serial.available() > 0)
{
if (Serial.read() == 'Q')
return;
}
}
}
float floatMap(float x, float inMin, float inMax, float outMin, float outMax)
{
return (x - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
}
This is my circuit diagram. In addition, I connected the oscilloscope output to A0 and common ground.
enter image description here
How can I get the sine waveform in my app.Any help on this would be greatly appreciated.
With your ~ 256 Hz sampling rate you just get about 2 asynchronous readings per period of a 100 Hz source.
analogRead adds (100 .. 150 µs on a 16 MHz Arduino) a considerable jitter to your delay.
Not sure about SoftwareSerial sending #115200. (receive won't work well at that speed)
And float is slow, too.
Not sure what you expect.
Check the raw data first:
void setup() {
Serial.begin(115200); // allows for 10 char/ms
}
void loop() {
static unsigned long oldmillis;
if (millis() != oldmillis) {
oldmillis = millis();
// 1 kHz sample rate :
int ECG = analogRead(A0)*100L / 1024;
Serial.println(ECG); // 0 .. 99
}
}
Perhaps add your start/stop communication or check with Arduino SerialPlotter.
When that's ok, test if you get those numbers via bluetooth to your app...

How to stop multiple reads of an RFID card

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.

Arduino Serial Input to Stop and Start

I am trying to wait for user input to start a program operation and then when the user sends a stop command, the loop stops running. I have been unable to get the Serial port to keep reading an input while the loop is running.
So I want the user to Press 1 and then it'll go into the loop and will display the data from the interrupt. But I want it to keep monitoring the Serial Input so when I type in 2, I will get out of the loop and stop printing to the Serial Port.
The serial port isn't registering my second input.
I left out some of the code, but the important stuff should be there.
int userStart = 0; // Holder for user input to start program
int userStop = 0; // Holder for user input to stop program
void setup() {
Serial.begin(115200);
pinMode(motorEncoderA, INPUT);
digitalWrite(motorEncoderA, HIGH); // Pull up resistor
pinMode(motorEncoderB, INPUT);
digitalWrite(motorEncoderB,HIGH); // Pull up resistor
// Interrupt on change of Pin A
attachInterrupt(digitalPinToInterrupt(2), encoderFunc, CHANGE);
Serial.print("Press 1 to start the Process & 2 to Stop");
}
void loop() {
if (Serial.available() > 0)
{
userStart = Serial.read();
if (userStart = 1) {
Serial.print('\n');
while(userStop != 2) {
unsigned long timee = millis();
// Only update if the shaft has moved
if (encoderPositionLast != rotationCounter) {
Serial.print("Time: ");
Serial.print(timee);
Serial.print(" Count: ");
Serial.print (rotationCounter);
Serial.print('\n');
encoderPositionLast = rotationCounter;
Serial.print(userStart);
}
if (Serial.available() > 0) {
userStop = Serial.read();
Serial.print(userStop);
}
}
}
}
Well, I think your problem is that userStart and userStop should not be 1 and 2, but '1' and '2'.
That said, there are some things in your code I dislike.
First of all why is everybody using int as the base type for all numeric variables? If one single byte is enough, use it. On 32bit machines int and byte are almost the same, but on 8bit ones working with ints wastes space and time.
Secondly, I highly discourage you to block the loop function, otherwise you won-t be able to do anything else. Instead, use a variable to track wheter you are running or not, update it with the serial interface, and then execute the code if you are running.
This code should do it. And IMHO it is much better than blocking the loop:
bool running = false;
void setup()
{
...
running = false;
}
void loop()
{
if (Serial.available() > 0)
{
switch(Serial.read())
{
case '1':
running = true;
Serial.print('\n');
break;
case '2':
running = false;
Serial.print("stopped");
break;
}
}
if (running)
{
unsigned long timee = millis();
// Only update if the shaft has moved
if (encoderPositionLast != rotationCounter) {
Serial.print("Time: ");
Serial.print(timee);
Serial.print(" Count: ");
Serial.print (rotationCounter);
Serial.print('\n');
encoderPositionLast = rotationCounter;
Serial.print("running");
}
}
}

Resources