I am creating this temp monitoring system - arduino

I am creating this temp monitoring system...Therefore, i want to get messages/alerts when the temperature are below 6 and again when they come back to above 6. Note: I don't want the alert (sendMailNormalValue():wink: to come when the system boots up....How do I deactivate the sendMailNormalValue(); and activate it only when the temp are below 6 (only to alert me when comes back to above 6)..
#include <OneWire.h>
#include <DallasTemperature.h>
// GPIO where the DS18B20 is connected to
const int oneWireBus = 5;
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(oneWireBus);
// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);
//========================================
float t;
int period = 30000;
unsigned long time_now = 0;
bool DisplayFirstTime = true;
int period1 = 30000;
unsigned long time_now1 = 0;
void sendMailBelowValue(){
}
void sendMailNormalValue(){
}
void setup() {
// put your setup code here, to run once:
Serial.begin (9600);
}
void loop() {
// put your main code here, to run repeatedly:
sensors.requestTemperatures();
t = sensors.getTempCByIndex(0);
float p=t-2;
// Check if any reads failed and exit early (to try again).
if (isnan(t)) {
Serial.println("Failed to read from sensor !");
delay(500);
return;
}
if (t>6){
if(millis() > time_now + period){
time_now = millis();
sendMailNormalValue();
Serial.print ("You got messagae");
}
}
if (t<6){
if(millis() > time_now1 + period1 || DisplayFirstTime){
DisplayFirstTime = false;
time_now = millis();
sendMailBelowValue();
}
}
}

I think I understand what you mean. On error (temp < 6), you want to send an email every 30 seconds; when the teperature reaches 6 or mode, send a single email to say the error condition has been fixed. On boot, only send an email if in error.
If that's it, you'll need to keep track of the error condition using a global flag.
// ...
bool tempError; // initialized in setup()
void setup()
{
// ...
float t;
for(;;) // loop until we get a valid reading.
{
t = sensors.getTempCByIndex(0);
if (!isnan(t))
break;
Serial.println("Failed to read from sensor !");
delay(500);
}
tempError = (t < 6);
}
void loop()
{
// read temp and check sensor...
// ...
if (t < 6)
{
tempError = true;
// send error email, set timer, etc...
}
else if (tempError)
{
// temp is now fine, after being too low.
tempError = false; // Clear error flag.
// send OK email, only once.
// Don't forget to clear the 30 second email timer !!!
}
}
Usually, you'd want some hysteresis in an alert system. You should consider waiting some seconds after the temperature has been 'fixed' before sending the 'OK' email. Otherwise you may end up getting lots of fail/fixed emails when the temperature is around 6 degrees. This is usually done with a simple state machine engine, but that is a bit beyond the scope of this questkon.

Related

C++ how to query value outside the callback arduino

I want that the measurement interval and MQTT server settings can be changed from cellphone by BLE. I use LightBlue as a mobile application.
Here is my BLE code that works well with my mobile application
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = pCharacteristic->getValue();
if (value.length() > 0) {
Serial.println("*********");
Serial.print("New value: ");
for (int i = 0; i < value.length(); i++)
Serial.print(value[i]);
Serial.println();
Serial.println("*********");
}
}
};
void setup() {
Serial.begin(115200);
Serial.println("1- Download and install an BLE scanner app in your phone");
Serial.println("2- Scan for BLE devices in the app");
Serial.println("3- Connect to MyESP32");
Serial.println("4- Go to CUSTOM CHARACTERISTIC in CUSTOM SERVICE and write something");
Serial.println("5- See the magic =)");
BLEDevice::init("MyESP32");
BLEServer *pServer = BLEDevice::createServer();
BLEService *pService = pServer->createService(SERVICE_UUID);
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setCallbacks(new MyCallbacks());
pCharacteristic->setValue("Hello World");
pService->start();
BLEAdvertising *pAdvertising = pServer->getAdvertising();
pAdvertising->start();
}
void loop() {
// put your main code here, to run repeatedly:
delay(2000);
}
This is MQTT code :
void loop() {
unsigned long currentMillis = millis();
// Every X number of seconds (interval = 10 seconds)
// it publishes a new MQTT message
if (currentMillis - previousMillis >= interval) {
// Save the last time a new reading was published
previousMillis = currentMillis;
// New DHT sensor readings
hum = dht.readHumidity();
// Read temperature as Celsius (the default)
temp = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
//temp = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(temp) || isnan(hum)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
}
// Publish an MQTT message on topic esp32/dht/temperature
uint16_t packetIdPub1 = mqttClient.publish(MQTT_PUB_TEMP, 1, true, String(temp).c_str());
Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", MQTT_PUB_TEMP, packetIdPub1);
Serial.printf("Message: %.2f \n", temp);
// Publish an MQTT message on topic esp32/dht/humidity
uint16_t packetIdPub2 = mqttClient.publish(MQTT_PUB_HUM, 1, true, String(hum).c_str());
Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_HUM, packetIdPub2);
Serial.printf("Message: %.2f \n", hum);
}
}
Please how I can set the interval to whichever variable from the BLE code instead of 10000.
long interval = 10000;
You need to declare your variable interval as global variable to access it from everywhere in your file. A global variable can be declared outside of functions.
The value you receive is of type std::string and you want to use it as long. You can use toInt() to convert the variable from String to Long.
Try something like this:
long interval = 10000; // Set default value
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = pCharacteristic->getValue();
if (value.length() > 0) {
Serial.println("*********");
Serial.print("New value: ");
for (int i = 0; i < value.length(); i++)
Serial.print(value[i]);
Serial.println();
Serial.println("*********");
interval = value.toInt(); // <-- Set received value
}
}
};

I'm using interrupts to detect button press lengths, but it will sometimes not detect that I've released the button

#include <DS3231.h>
DS3231 clock;
RTCDateTime dt;
const int INTERRUPT_PIN = 2;
int prevTime, pressedTime, releasedTime, heldTime;
bool settingTimes = false;
int startHour1, startMin1, startHour2, startMin2, endHour1, endMin1, endHour2 = 0;
void setup() {
Serial.begin(9600);
// Initialize DS3231
clock.begin();
clock.setDateTime(__DATE__, __TIME__);
pinMode(INTERRUPT_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), actButtonPress, CHANGE);
}
void loop() {
if (!settingTimes) {
dt = clock.getDateTime();
// For leading zero look to DS3231_dateformat example
Serial.print(dt.hour); Serial.print(":");
Serial.println(dt.minute);
delay(1000);
} else {
//Serial.println("Setting Times, Check the buttons");
}
}
void actButtonPress() {
if (prevTime + 100 < millis()) {
Serial.println("This is being called");
if (digitalRead(INTERRUPT_PIN) == LOW) { //Button has been pressed
pressedTime = millis();
} else {
releasedTime = millis();
heldTime = releasedTime - pressedTime;
if (heldTime > 3000) {
settingTimes = !settingTimes;
} else {
Serial.println("Change Page");
}
}
prevTime = millis();
}
}
I want to be able to press the button for 3 seconds to set times, and anything less times, I want to change pages. I need to use interrupts because the ds3231 get date time function doesn't seem to work without the delay statement (I've already tried the millis() function)
Using interrupts is generally not a good idea for checking button presses. Switch inputs should always be considered as rather dirty signals... The initial contact is never clean-cut, there is always some noise before the signal is clean. That's called "bounce".
To debounce your switch input you should either:
wait a little while using a counter, or a time stamp, (using millis) before checking if the button is released.
or only poll the switches at regular intervals.
The duration of the bounce depends on the switch, and will degrade over time as the switch gets older. In practice, 30 ms is a good value for the delay.
I suggest you try this:
#include <DS3231.h>
DS3231 clock;
RTCDateTime dt;
// putting all switch states in this struct to take advantage of bit-sized
// storage, and save RAM space for the rest of the program.
struct SwitchStates
{
unsigned char action : 1; // state of action switch.
unsigned char sw1 : 1; // add one bit for each switch you have.
};
// you need to keep track of previous switch states to detect changes.
SwitchStates previousSwitchState;
#define ACTION_SWITCH_PIN (2)
#define SWITCH_TIME_SET_DELAY (3000) // time to hold switch for setting time in ms.
#define SWITCH_POLLING_DELAY (30) // switch polling delay, in ms.
#define RTC_READ_DELAY (1000) // RTC read delay in ms.
void setup()
{
Serial.begin(9600);
// Initialize DS3231
clock.begin();
clock.setDateTime(__DATE__, __TIME__); // imho, that's not a very good idea...
pinMode(ACTION_SWITCH_PIN, INPUT_PULLUP);
digitalWrite(ACTION_SWITCH_PIN, HIGH); // you must set the pin high
// for pull-up to work.
}
// only used witin loop()
static unsigned char switchPollingTimeStamp = 0; // char because 30 is less than 256.
static bool settingTimes = false;
static unsigned int rtcReadTimeStamp = 0;
static unsigned int modeSwitchTimeStamp = 0;
void loop()
{
// get current timestamp.
unsigned long now = millis();
if ((unsigned char)now - switchPollingTimeStamp >= SWITCH_POLLING_DELAY)
{
switchPollingTimeStamp = (unsigned char)now;
// all switch inputs will be handled within this block.
SwitchStates curSwitchState;
// polling at regular intervals, first read your inputs.
curSwitchState.action = digitalRead(ACTION_SWITCH_PIN);
// curSwitchState.sw1 = digitalRead(SW1_PIN);
// etc...
// check activity on action (mode) switch and do timing, etc...
if (curSwitchState.action && !previousSwitchState.action)
{
// keep track of how long the switch has been held
modeSwitchTimeStamp = (unsigned int)now;
if (settingTimes)
settingTimes = false; // exit time set mode, for example.
else
Serial.pritln("Next Page"); //
}
else if (curSwitchState.action)
{
// after 3000 ms, switch to timeset mode.
if ((unsigned int)now - modeSwitchTimeStamp >= SWITCH_TIME_SET_DELAY)
{
if (!settingTimes)
{
settingTimes = true:
Serial.println("Entering time set mode");
}
}
}
// That was the most complex one, others should be easier
if (settingTimes)
{
if (curState.sw1 && !previousSwitchState.sw1)
{
// whatever this switch would do in set time state.
}
// etc...
}
else
{
// the same when not in set time state.
}
// to keep track of switch activity.
// by first storing current switch states, then saving them
// like this, you cannot forget one, this avoids any 'I missed one' bugs.
previousSwitchState = curSwitchState;
}
// try to keep your code non blocking, so your device stays responsive...
// in other words, avoid calling delay().
if (!settingTimes && (unsigned int)now - rtcReadTimeStamp >= RTC_READ_DELAY)
{
rtcReadTimeStamp - (unsigned int)millis();
dt = clock.getDateTime();
// For leading zero look to DS3231_dateformat example
Serial.print(dt.hour); Serial.print(":");
Serial.println(dt.minute);
}
}
Note: I don't have an arduino with me, and the laptop I have is not set up for it, so I coud not compile and debug it. It should be very close, though.

GPS receiver + Ublox NEO-6M - Having trouble making a timeout

I'm trying to write some code that will turn on the gps module and wait for data to arrive, so that I can then do things with it. I don't need a continuous stream; I only need the first lat/long received from the gps unit, then I can turn it off. I also need this to just stop if it can't find it's location within a certain amount of time (20 seconds for example)
Here is some simple code that I've tried just to get the gps to read (full code with timeout comes later)
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
TinyGPSPlus gps; // The TinyGPS++ object
SoftwareSerial ss(D4, D3); // The serial connection to the GPS
float latitude , longitude;
int count = 0;
void setup()
{
Serial.begin(9600);
ss.begin(9600);
Serial.println();
Serial.print("Starting");
}
void loop()
{
while (ss.available() > 0)
if (gps.encode(ss.read()))
{
if (gps.location.isValid())
{
latitude = gps.location.lat();
lat_str = String(latitude , 6);
longitude = gps.location.lng();
lng_str = String(longitude , 6);
}
}
Serial.println(lat_str + ":" + lng_str);
delay(100);
count += 1;
String Count = String(count);
Serial.println(Count);
}
When the delay above is 100, then everything works fine, when the delay is 1000, then suddenly no data comes through.
Here is the full code I've tried that includes my timeout and breakout condition, again not working. The cutoff line is in the GPS_mode function here: while ((stoploop < 1) && (previous - startTime < TimeOut)).
#include <SoftwareSerial.h>
#include <TinyGPS++.h>
TinyGPSPlus gps; // The TinyGPS++ object
SoftwareSerial ss(D4, D3); // The serial connection to the GPS d
int stoploop = 0; //used for stopping gps once a signal lock or timeout is reached
unsigned long startTime = millis(); // timer used for gps timeout
const int gpsCutoffPin = D1;
void setup() {
//initialise the serial monitor
Serial.begin(9600);
gps_ss.begin(9600);
//initialise the transistor pins
pinMode(gpsCutoffPin, OUTPUT);
// Start the gps in an off state
digitalWrite(gpsCutoffPin, LOW);
}
void loop() {
Serial.println("Enter GPS mode");
GPS_mode();
Serial.println("Back to the main loop now...");
Serial.println(stoploop);
delay(100000);
}
void GPS_mode(){
//turn on the gps
digitalWrite(gpsCutoffPin, HIGH);
stoploop = 0;
startTime = millis();
previous = millis();
int TimeOut = 60*1000;
gps_ss.listen();
Serial.println(stoploop);
while ((stoploop < 1) && (previous - startTime < TimeOut))
{
while (gps_ss.available() > 0)
{
if (gps.encode(gps_ss.read()))
{
logInfo();
}
yield();
}
}
gpsLat = (gps.location.lat(), DEC);
gpsLon = (gps.location.lng(), DEC);
// turn off the gps
digitalWrite(gpsCutoffPin, LOW);
}
void logInfo(){
// Causes us to wait until we have satelite fix
if(!gps.location.isValid())
{
Serial.println("Not a valid location. Waiting for satelite data.");
//return;
}
else {
//url += String(gps.location.lat(), DEC);
//url += String(gps.location.lng(), DEC);
Serial.println(gps.location.lat(), DEC);
Serial.println(gps.location.lng(), DEC);
stoploop = 2;
//delay(1000);
}
previous = millis();
}
I expect to see some gps data printed to the screen, but I actually don't see anything. I know that the gps is working and is receiving data because the blinking LED tell me so.
I have no idea how to fix this. If anyone could help I'd very much appreciate it.
Thanks

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