Hi legends,
I'm working on a project that runs a stopwatch based on the below conditions
Inputs
Day start pushbutton: To start the program
Reset pushbutton: To reset the stopwatch counting
0 – 10v Analog input: To start/pause the stopwatch
RFID: To authorize the Day start & Reset
Outputs
Max7219: to drive four common cathode 7 segment for hours and minutes.
The targeted scenario:
The operator will scan the RFID and within 5 seconds will press the Day start pushbutton to start the program.
The stopwatch will be waiting for the analog input to be less than 10 to start counting.
If the value of the analog input is greater than 10, the counting will pause.
To reset the count, the operator must scan again the RFID and within 5 seconds will press Reset push button.
I have finished pretty much most of the work, but I need help with the last point to reset the count.
#include <SPI.h>
#include <MFRC522.h>
#include "DigitLedDisplay.h"
#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.
#define bt_start_day A4
#define bt_reset A5
#define DIN 5
#define CS 6
#define CLK 7
DigitLedDisplay ld = DigitLedDisplay(DIN, CS, CLK);
bool stopwatch = false;
bool reset = false;
void writevalue(int, int, int);
int hh=0, mm=0, ss=0, ms=0;
int start_stop = 0;
bool timerStart = false;
const int sec_led = 4;
//int sec_led = 0;
void setup() {
Serial.begin(9600); // Initiate a serial communication
SPI.begin(); // Initiate SPI bus
mfrc522.PCD_Init(); // Initiate MFRC522
//Serial.println("Approximate your card to the reader...");
//Serial.println();
/* Set the brightness min:1, max:15 */
ld.setBright(10);
/* Set the digit count */
ld.setDigitLimit(8);
pinMode(sec_led, OUTPUT);
pinMode(bt_start_day, INPUT_PULLUP);
pinMode(bt_reset, INPUT_PULLUP);
if(ss<10){ld.write(2, B01111110);}
if(mm<10){ld.write(5, B01111110);}
if(hh<10){ld.write(8, B01111110);}
noInterrupts(); // disable all interrupts
TCCR1A = 0; // set entire TCCR1A register to 0 //set timer1 interrupt at 1kHz // 1 ms
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // set timer count for 1khz increments
OCR1A = 1999; // = (16*10^6) / (1000*8) - 1
//had to use 16 bit timer1 for this bc 1999>255, but could switch to timers 0 or 2 with larger prescaler
// turn on CTC mode
TCCR1B |= (1 << WGM12); // Set CS11 bit for 8 prescaler
TCCR1B |= (1 << CS11); // enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
interrupts(); // enable
}
//==========================================================================
void loop()
{
// Look for new cards
if ( ! mfrc522.PICC_IsNewCardPresent())
{
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial())
{
return;
}
//Show UID on serial monitor
//Serial.print("UID tag :");
String content= "";
byte letter;
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));
}
//Serial.println();
//Serial.print("Message : ");
content.toUpperCase();
if (content.substring(1) == "93 27 0F 1F" || content.substring(1) == "63 7B C9 1B") //change here the UID of the card/cards that you want to give access
{
// Serial.println("Authorized access");
// Serial.println();
for (int i = 0; i <= 5; i++) {
if(digitalRead(bt_start_day) == 0) stopwatch = true;
//else stopwatch = false;
if(digitalRead(bt_reset) == 0) reset = true;
//else reset = false;
delay(1000);
}
/*else
{
Serial.println(" Access denied");
Serial.println();
stopwatch = false;
}*/
//==========================================================================
while(1) {
//if(digitalRead(bt_start_day) == 0 && stopwatch == true) {
start_stop = analogRead(A0);
Serial.println(start_stop);
if (start_stop < 10 && stopwatch == true){
timerStart = true; // Start stopwatch
delay(100);}
else timerStart = false; // Stop stopwatch
delay(100);
if(reset == true){
ms=0, ss=0, mm=0, hh=0; // Reset stopwatch
ld.write(2, B01111110);
ld.write(4, B01111110);
//ld.write(8, B01111110);
delay(100);
}
ld.printDigit(hh, 2);
ld.printDigit(mm, 0);
//ld.printDigit(ss, 0);
if ( (ss % 2) == 0) {digitalWrite(sec_led, 1);}
else digitalWrite(sec_led, 0);
if(timerStart == true){
//if(ss<10){ld.write(2, B01111110);}
if(mm<10){ld.write(2, B01111110);}
if(hh<10){ld.write(4, B01111110);}
}
}
}
}
//=======================================================================
ISR(TIMER1_COMPA_vect){
if(timerStart == true){ms=ms+1;
if(ms>999){ms=0;ss=ss+1;
if(ss>59){ss=0; mm=mm+1;}
if(mm>59){mm=0; hh=hh+1;}
}
}
}
Not too sure I understand what you are trying to do or why. But the use of while(1) sticks the code into an infinite loop from which you will never escape. This is very bad practice and depending on the type of Arduino can severely screw up things.
I am loathed to give you advice to make this sort of thing "work" but one way of doing so would be to use a watch dog timer and make sure you don't kick it inside the while(1) loop. This will restart all the code again from the beginning after the watch dog times out.
However, basically don't design code that works like this.
I'm using a While loop to keep the loop of the stopwatch separated from the rest of the code.
The reset function is triggered by the user and not by a timer. When the user wants to reset the stopwatch, they can scan the RFID and press the reset pushbutton.
Then you don't understand that this is not the way to do it.
If you want to keep anything separate you use a state machine to perform your functions. See the blink without delay example in the IDE, or search the forum for state machine. Problems that require a state machine solution are posted more than once a day on this forum.
Grumpy_Mike:
state machine
I have checked the state machine mechanism and found that it must be assigned with the number of millis. How I can apply that to a stopwatch?
Please correct me if I misunderstood.
I did some modifications here and the code now seems to work fine, except I have to keep the card on the reader all the time.
Any suggestions?
#include <SPI.h>
#include <MFRC522.h>
#include "DigitLedDisplay.h"
#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.
#define bt_start_day A4
#define bt_reset A5
#define DIN 5
#define CS 6
#define CLK 7
DigitLedDisplay ld = DigitLedDisplay(DIN, CS, CLK);
bool stopwatch = false;
bool reset = false;
void writevalue(int, int, int);
int hh=0, mm=0, ss=0, ms=0;
int start_stop = 0;
bool timerStart = false;
const int sec_led = 4;
//int sec_led = 0;
void setup() {
Serial.begin(9600); // Initiate a serial communication
SPI.begin(); // Initiate SPI bus
mfrc522.PCD_Init(); // Initiate MFRC522
/* Set the brightness min:1, max:15 */
ld.setBright(14);
/* Set the digit count */
ld.setDigitLimit(4);
pinMode(sec_led, OUTPUT);
pinMode(bt_start_day, INPUT_PULLUP);
pinMode(bt_reset, INPUT_PULLUP);
if(ss<10){ld.write(2, B01111110);}
if(mm<10){ld.write(5, B01111110);}
if(hh<10){ld.write(8, B01111110);}
noInterrupts(); // disable all interrupts
TCCR1A = 0; // set entire TCCR1A register to 0 //set timer1 interrupt at 1kHz // 1 ms
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // set timer count for 1khz increments
OCR1A = 1999; // = (16*10^6) / (1000*8) - 1
//had to use 16 bit timer1 for this bc 1999>255, but could switch to timers 0 or 2 with larger prescaler
// turn on CTC mode
TCCR1B |= (1 << WGM12); // Set CS11 bit for 8 prescaler
TCCR1B |= (1 << CS11); // enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
interrupts(); // enable
}
//==========================================================================
void loop()
{
// Look for new cards
if ( ! mfrc522.PICC_IsNewCardPresent())
{
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial())
{
return;
}
String content= "";
byte letter;
for (byte i = 0; i < mfrc522.uid.size; i++)
{
content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
content.concat(String(mfrc522.uid.uidByte[i], HEX));
}
content.toUpperCase();
if (content.substring(1) == "93 27 0F 1F" || content.substring(1) == "63 7B C9 1B") //change here the UID of the card/cards that you want to give access
{
if(digitalRead(bt_start_day) == 0) stopwatch = true;
if(digitalRead(bt_reset) == 0) reset = true;
else reset = false;
}
//==========================================================================
start_stop = analogRead(A0);
Serial.println(start_stop);
if (start_stop < 10 && stopwatch == true) timerStart = true;
else timerStart = false; // Stop stopwatch
//==========================================================================
if(reset == true){
ms=0, ss=0, mm=0, hh=0; // Reset stopwatch
ld.write(2, B01111110);
ld.write(4, B01111110);
delay(100);
}
ld.printDigit(hh, 2);
ld.printDigit(mm, 0);
if ( (ss % 2) == 0) {digitalWrite(sec_led, 1);}
else digitalWrite(sec_led, 0);
if(timerStart == true){
if(mm<10){ld.write(2, B01111110);}
if(hh<10){ld.write(4, B01111110);}
}
}
//=======================================================================
ISR(TIMER1_COMPA_vect){
if(timerStart == true){ms=ms+1;
if(ms>999){ms=0;ss=ss+1;
if(ss>59){ss=0; mm=mm+1;}
if(mm>59){mm=0; hh=hh+1;}
}
}
}
This is because on every iteration of the loop function you check for a card being present. Therefore if it is removed at any time the rest of your code falls over.
Try setting a boolean variable that gets set to true once you see a card. Then put an if statement round the card checking part of the loop function so that it only checks the card when this variable is false.
Then in the rest of your code set this variable to true again once you have finished with what ever the code was doing with the card present at the moment has finished. Then you will go back to checking for a new card at the start of the loop function.
I have the "stopwatch" variable to do exactly this function when the card is present and the bt_start_day is pressed at the same time. But it doesn't stay true, however, there is nothing in the loop to reset it to false.
True but there is a place and / or condition in the loop function where you could set the variable to be true and force another card read.
When posting code you have modified it is always best to post all the code, as well as the bits you are asking questions about.
As to the bit of the code you have posted I am puzzled as to why you are reading a pin? What is this pin connected to and why is this an indication that the flag needs resetting.
Is there a chance to modify my code to get what you mean?
I have listed here the inputs, outputs, and the code which are connected to a Nano board.
Inputs
Day start pushbutton: To start the program
Reset pushbutton: To reset the stopwatch counting
0 – 10v Analog input: To start/pause the stopwatch
RFID: To authorize the Day start & Reset
Outputs
Max7219: to drive four common cathode 7 segment for hours and minutes.
#include <SPI.h>
#include <MFRC522.h>
#include "DigitLedDisplay.h"
#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.
#define bt_start_day A4
#define bt_reset A5
#define DIN 5
#define CS 6
#define CLK 7
DigitLedDisplay ld = DigitLedDisplay(DIN, CS, CLK);
bool stopwatch = false;
bool reset = false;
void writevalue(int, int, int);
int hh=0, mm=0, ss=0, ms=0;
int start_stop = 0;
bool timerStart = false;
const int sec_led = 4;
//int sec_led = 0;
void setup() {
Serial.begin(9600); // Initiate a serial communication
SPI.begin(); // Initiate SPI bus
mfrc522.PCD_Init(); // Initiate MFRC522
/* Set the brightness min:1, max:15 */
ld.setBright(14);
/* Set the digit count */
ld.setDigitLimit(4);
pinMode(sec_led, OUTPUT);
pinMode(bt_start_day, INPUT_PULLUP);
pinMode(bt_reset, INPUT_PULLUP);
if(ss<10){ld.write(2, B01111110);}
if(mm<10){ld.write(5, B01111110);}
if(hh<10){ld.write(8, B01111110);}
noInterrupts(); // disable all interrupts
TCCR1A = 0; // set entire TCCR1A register to 0 //set timer1 interrupt at 1kHz // 1 ms
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // set timer count for 1khz increments
OCR1A = 1999; // = (16*10^6) / (1000*8) - 1
//had to use 16 bit timer1 for this bc 1999>255, but could switch to timers 0 or 2 with larger prescaler
// turn on CTC mode
TCCR1B |= (1 << WGM12); // Set CS11 bit for 8 prescaler
TCCR1B |= (1 << CS11); // enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
interrupts(); // enable
}
//==========================================================================
void loop()
{
// Look for new cards
if ( ! mfrc522.PICC_IsNewCardPresent())
{
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial())
{
return;
}
String content= "";
byte letter;
for (byte i = 0; i < mfrc522.uid.size; i++)
{
content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
content.concat(String(mfrc522.uid.uidByte[i], HEX));
}
content.toUpperCase();
if (content.substring(1) == "93 27 0F 1F" || content.substring(1) == "63 7B C9 1B") //change here the UID of the card/cards that you want to give access
{
if(digitalRead(bt_start_day) == 0) stopwatch = true;
if(digitalRead(bt_reset) == 0) reset = true;
else reset = false;
}
//==========================================================================
start_stop = analogRead(A0);
Serial.println(start_stop);
if (start_stop < 10 && stopwatch == true) timerStart = true;
else timerStart = false; // Stop stopwatch
//==========================================================================
if(reset == true){
ms=0, ss=0, mm=0, hh=0; // Reset stopwatch
ld.write(2, B01111110);
ld.write(4, B01111110);
delay(100);
}
ld.printDigit(hh, 2);
ld.printDigit(mm, 0);
if ( (ss % 2) == 0) {digitalWrite(sec_led, 1);}
else digitalWrite(sec_led, 0);
if(timerStart == true){
if(mm<10){ld.write(2, B01111110);}
if(hh<10){ld.write(4, B01111110);}
}
}
//=======================================================================
ISR(TIMER1_COMPA_vect){
if(timerStart == true){ms=ms+1;
if(ms>999){ms=0;ss=ss+1;
if(ss>59){ss=0; mm=mm+1;}
if(mm>59){mm=0; hh=hh+1;}
}
}
}
Not without a schematic of your system.
However, the code at the start of the loop function:-
Is nothing like I told you to do in post #7 .
khaledelrady:
press Reset push button.
What reset button? You can't simply wire an output to the reset button and expect it to work.
This is because as part of the reset process the outputs get set to inputs and so remove any hardware reset. This is at a point before the minimum length of the reset signal has been achieved.
I'm just clearing the variables, not resetting the whole program.
What do you think?
#include <SPI.h>
#include <MFRC522.h>
#include "DigitLedDisplay.h"
#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.
#define bt_start_day A4
#define bt_reset A5
#define DIN 5
#define CS 6
#define CLK 7
DigitLedDisplay ld = DigitLedDisplay(DIN, CS, CLK);
bool stopwatch = false;
bool reset = false;
bool newcard = false;
void writevalue(int, int, int);
int hh=0, mm=0, ss=0, ms=0;
int start_stop = 0;
bool timerStart = false;
const int sec_led = 4;
//int sec_led = 0;
void setup() {
Serial.begin(9600); // Initiate a serial communication
SPI.begin(); // Initiate SPI bus
mfrc522.PCD_Init(); // Initiate MFRC522
/* Set the brightness min:1, max:15 */
ld.setBright(14);
/* Set the digit count */
ld.setDigitLimit(4);
pinMode(sec_led, OUTPUT);
pinMode(bt_start_day, INPUT_PULLUP);
pinMode(bt_reset, INPUT_PULLUP);
if(ss<10){ld.write(2, B01111110);}
if(mm<10){ld.write(5, B01111110);}
if(hh<10){ld.write(8, B01111110);}
noInterrupts(); // disable all interrupts
TCCR1A = 0; // set entire TCCR1A register to 0 //set timer1 interrupt at 1kHz // 1 ms
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // set timer count for 1khz increments
OCR1A = 1999; // = (16*10^6) / (1000*8) - 1
//had to use 16 bit timer1 for this bc 1999>255, but could switch to timers 0 or 2 with larger prescaler
// turn on CTC mode
TCCR1B |= (1 << WGM12); // Set CS11 bit for 8 prescaler
TCCR1B |= (1 << CS11); // enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
interrupts(); // enable
}
//==========================================================================
void loop()
{
// Look for new cards
if ( ! mfrc522.PICC_IsNewCardPresent())
{ newcard == true;
return;
}
else newcard == false;
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial())
{
return;
}
String content= "";
byte letter;
for (byte i = 0; i < mfrc522.uid.size; i++)
{
content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
content.concat(String(mfrc522.uid.uidByte[i], HEX));
}
content.toUpperCase();
if (newcard == true) {
if (content.substring(1) == "93 27 0F 1F" || content.substring(1) == "63 7B C9 1B") //change here the UID of the card/cards that you want to give access
{
if(digitalRead(bt_start_day) == 0) stopwatch = true;
if(digitalRead(bt_reset) == 0) reset = true;
else reset = false;
}
}
//==========================================================================
start_stop = analogRead(A0);
Serial.println(start_stop);
if (start_stop < 10 && stopwatch == true) timerStart = true;
else timerStart = false; // Stop stopwatch
//==========================================================================
if(reset == true){
ms=0, ss=0, mm=0, hh=0; // Reset stopwatch
ld.write(2, B01111110);
ld.write(4, B01111110);
delay(100);
}
ld.printDigit(hh, 2);
ld.printDigit(mm, 0);
if ( (ss % 2) == 0) {digitalWrite(sec_led, 1);}
else digitalWrite(sec_led, 0);
if(timerStart == true){
if(mm<10){ld.write(2, B01111110);}
if(hh<10){ld.write(4, B01111110);}
}
}
//=======================================================================
ISR(TIMER1_COMPA_vect){
if(timerStart == true){ms=ms+1;
if(ms>999){ms=0;ss=ss+1;
if(ss>59){ss=0; mm=mm+1;}
if(mm>59){mm=0; hh=hh+1;}
}
}
}
khaledelrady:
What do you think
Not a lot.
You still haven't got
So that code should start:-
void loop()
{
// Look for new card
if(newcard == false)
{
// now begin to look at what the card is and if it is valid
// if you find it is not valid then exit the if statement
// if it is valid then set newcard = true and exit the if statement
//later when you have finished what ever you do when currently the card is removed,
// then set newcard to be false.
This way you only look for a new card once you have finished doing what ever it is you need to do. And you don't need to hold the card over the reader.
There is still something missing/wrong
I still have to keep the card on the reader!!!!!!!
#include <SPI.h>
#include <MFRC522.h>
#include "DigitLedDisplay.h"
#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.
#define bt_start_day A4
#define bt_reset A5
#define DIN 5
#define CS 6
#define CLK 7
DigitLedDisplay ld = DigitLedDisplay(DIN, CS, CLK);
bool stopwatch = false;
bool reset = false;
bool nonewcard = false;
void writevalue(int, int, int);
int hh=0, mm=0, ss=0, ms=0;
int start_stop = 0;
bool timerStart = false;
const int sec_led = 4;
//int sec_led = 0;
void setup() {
Serial.begin(9600); // Initiate a serial communication
SPI.begin(); // Initiate SPI bus
mfrc522.PCD_Init(); // Initiate MFRC522
/* Set the brightness min:1, max:15 */
ld.setBright(14);
/* Set the digit count */
ld.setDigitLimit(4);
pinMode(sec_led, OUTPUT);
pinMode(bt_start_day, INPUT_PULLUP);
pinMode(bt_reset, INPUT_PULLUP);
if(ss<10){ld.write(2, B01111110);}
if(mm<10){ld.write(5, B01111110);}
if(hh<10){ld.write(8, B01111110);}
noInterrupts(); // disable all interrupts
TCCR1A = 0; // set entire TCCR1A register to 0 //set timer1 interrupt at 1kHz // 1 ms
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // set timer count for 1khz increments
OCR1A = 1999; // = (16*10^6) / (1000*8) - 1
//had to use 16 bit timer1 for this bc 1999>255, but could switch to timers 0 or 2 with larger prescaler
// turn on CTC mode
TCCR1B |= (1 << WGM12); // Set CS11 bit for 8 prescaler
TCCR1B |= (1 << CS11); // enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
interrupts(); // enable
}
//==========================================================================
void loop()
{
// Look for new cards
if ( ! mfrc522.PICC_IsNewCardPresent())
{nonewcard == true;
return;
}
if(nonewcard == false)
{
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial())
{
return;
}
String content= "";
byte letter;
for (byte i = 0; i < mfrc522.uid.size; i++)
{
content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
content.concat(String(mfrc522.uid.uidByte[i], HEX));
}
content.toUpperCase();
if (content.substring(1) == "93 27 0F 1F" || content.substring(1) == "63 7B C9 1B") //change here the UID of the card/cards that you want to give access
{
nonewcard = true;
if(digitalRead(bt_start_day) == 0) stopwatch = true;
if(digitalRead(bt_reset) == 0) reset = true;
else (reset = false);
}
}
//==========================================================================
start_stop = analogRead(A0);
Serial.println(start_stop);
if (start_stop < 10 && stopwatch == true) timerStart = true;
else timerStart = false; // Stop stopwatch
//==========================================================================
if(reset == true){
ms=0, ss=0, mm=0, hh=0; // Reset stopwatch
ld.write(2, B01111110);
ld.write(4, B01111110);
delay(100);
}
ld.printDigit(hh, 2);
ld.printDigit(mm, 0);
if ( (ss % 2) == 0) {digitalWrite(sec_led, 1);}
else digitalWrite(sec_led, 0);
if(timerStart == true){
if(mm<10){ld.write(2, B01111110);}
if(hh<10){ld.write(4, B01111110);}
}
nonewcard = false;
}
//=======================================================================
ISR(TIMER1_COMPA_vect){
if(timerStart == true){ms=ms+1;
if(ms>999){ms=0;ss=ss+1;
if(ss>59){ss=0; mm=mm+1;}
if(mm>59){mm=0; hh=hh+1;}
}
}
}
Yes you are failing to test if you need to read the card reader and reading it every time. Just like you always do.
See my last reply.
This should be your first statement in the loop function.