How would I go about saving the boolean state in the EEPROM in case of power outage? Or is that not how the EEPROM works?
Here's what I have for code:
#include <Adafruit_Fingerprint.h>
#include <EEPROM.h>
#if (defined(__AVR__) || defined(ESP8266)) && !defined(__AVR_ATmega2560__)
// For UNO and others without hardware serial, we must use software serial...
// pin #2 is IN from sensor (GREEN wire)
// pin #3 is OUT from arduino (WHITE wire)
// Set up the serial port to use softwareserial..
SoftwareSerial mySerial(2, 3);
#else
// On Leonardo/M0/etc, others with hardware serial, use hardware serial!
// #0 is green wire, #1 is white
#define mySerial Serial1
#endif
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);
const uint8_t posMotorPin = 8;
const uint8_t negMotorPin = 9;
bool status;
void setup()
{
Serial.begin(9600);
while (!Serial); // For Yun/Leo/Micro/Zero/...
delay(100);
pinMode(posMotorPin,OUTPUT);
pinMode(negMotorPin,OUTPUT);
Serial.println("\n\nAdafruit finger detect test");
// set the data rate for the sensor serial port
finger.begin(57600);
delay(5);
if (finger.verifyPassword()) {
Serial.println("Found fingerprint sensor!");
} else {
Serial.println("Did not find fingerprint sensor :(");
while (1) { delay(1); }
}
Serial.println(F("Reading sensor parameters"));
finger.getParameters();
Serial.print(F("Status: 0x")); Serial.println(finger.status_reg, HEX);
Serial.print(F("Sys ID: 0x")); Serial.println(finger.system_id, HEX);
Serial.print(F("Capacity: ")); Serial.println(finger.capacity);
Serial.print(F("Security level: ")); Serial.println(finger.security_level);
Serial.print(F("Device address: ")); Serial.println(finger.device_addr, HEX);
Serial.print(F("Packet len: ")); Serial.println(finger.packet_len);
Serial.print(F("Baud rate: ")); Serial.println(finger.baud_rate);
finger.getTemplateCount();
if (finger.templateCount == 0) {
Serial.print("Sensor doesn't contain any fingerprint data. Please run the 'enroll' example.");
}
else {
Serial.println("Waiting for valid finger...");
Serial.print("Sensor contains "); Serial.print(finger.templateCount); Serial.println(" templates");
}
}
void loop() // run over and over again
{
getFingerprintID();
delay(50); //don't ned to run this at full speed.
}
uint8_t getFingerprintID() {
uint8_t p = finger.getImage();
switch (p) {
case FINGERPRINT_OK:
Serial.println("Image taken");
break;
case FINGERPRINT_NOFINGER:
Serial.println("No finger detected");
return p;
case FINGERPRINT_PACKETRECIEVEERR:
Serial.println("Communication error");
return p;
case FINGERPRINT_IMAGEFAIL:
Serial.println("Imaging error");
return p;
default:
Serial.println("Unknown error");
return p;
}
// OK success!
p = finger.image2Tz();
switch (p) {
case FINGERPRINT_OK:
Serial.println("Image converted");
break;
case FINGERPRINT_IMAGEMESS:
Serial.println("Image too messy");
return p;
case FINGERPRINT_PACKETRECIEVEERR:
Serial.println("Communication error");
return p;
case FINGERPRINT_FEATUREFAIL:
Serial.println("Could not find fingerprint features");
return p;
case FINGERPRINT_INVALIDIMAGE:
Serial.println("Could not find fingerprint features");
return p;
default:
Serial.println("Unknown error");
return p;
}
// OK converted!
p = finger.fingerSearch();
if (p == FINGERPRINT_OK && status == false) {
Serial.println("Found a print match!");
digitalWrite(posMotorPin,LOW);
digitalWrite(negMotorPin,HIGH);
delay(8000);
digitalWrite(posMotorPin,LOW);
digitalWrite(negMotorPin,LOW);
status = !status;
} else if (p == FINGERPRINT_OK && status == true) {
digitalWrite(posMotorPin,HIGH);
digitalWrite(negMotorPin,LOW);
delay(8000);
digitalWrite(posMotorPin,LOW);
digitalWrite(negMotorPin,LOW);
status = !status;
} else if (p == FINGERPRINT_PACKETRECIEVEERR) {
Serial.println("Communication error");
return p;
} else if (p == FINGERPRINT_NOTFOUND) {
Serial.println("Did not find a match");
return p;
} else {
Serial.println("Unknown error");
return p;
}
// found a match!
Serial.print("Found ID #"); Serial.print(finger.fingerID);
Serial.print(" with confidence of "); Serial.println(finger.confidence);
return finger.fingerID;
}
// returns -1 if failed, otherwise returns ID #
int getFingerprintIDez() {
uint8_t p = finger.getImage();
if (p != FINGERPRINT_OK) return -1;
p = finger.image2Tz();
if (p != FINGERPRINT_OK) return -1;
p = finger.fingerFastSearch();
if (p != FINGERPRINT_OK) return -1;
// found a match!
Serial.print("Found ID #"); Serial.print(finger.fingerID);
Serial.print(" with confidence of "); Serial.println(finger.confidence);
return finger.fingerID;
}
Which Arduino board are you using ?
Have you looked at and tried the EEPROM examples ?
Be aware that there is a limit on how many times that you can safely save to an EEPROM cell
Arduino Uno board. And I've tried a couple different things, but I can't seem to figure it out. I'm a bit new to coding and got a little in over my head on this project. Maybe there's a better way than EEPROM to save, change, and recall?
A few hints for processors that have EEPROM on chip.
Be sure the library you use supports update(). This only writes to EEPROM if the value is different then what is there.
The EEPROM will remember for many years without power.
It has a limit of about 100,000-1,000,000 writes per cell.
Flash is generally rated to ~1,000-100,000 writes
Reads are non destructive.
Each cell wares independently.
That is write about once a minute for two years.
Writing to EEPROM takes time it is not instant
You cannot write to it without power so when power fails it is to late.
This will not refresh a RAM location you need to do it.
EEPROM memory can generally be erased on a per-byte basis
If doing a lot of rapid reads.writes you need to spread it over many locations or use FRAM.
If it is pseudo EEPROM you need to force it to be saved maybe commit(), this actually writes the data to the external, generall FLASH in the arduino world such as many of the ESP devices.
NOTE: If the processor does not contain internal EEPROM and supposedly does it is supported by an external device. Generally that is emulated in RAM and written back to the EEPROM/FLASH when you use the commit statement. This will depend on the library etc that you are using. Here is a link that will explain what I am trying to say: EEPROM in Arduino and ESP (ESP8266 and ESP32)
Make sure you have a diode protected capacitor or similar to hold +Vcc up long enough to support the write cycle.
Use an ADC pin to measure the voltage BEFORE the diode and capacitor.
If the nominal voltage drops below your required threshold, jump to a function that ‘saves’ your status values as quickly as possible.
Try to avoid any delay/blocking code, so the response and action is as fast as possible,
Here's my best shot. I think the problem is the new bool value isn't being stored in the EEPROM or being recalled. I'm not 100% sure.
#include <Adafruit_Fingerprint.h>
#include <EEPROM.h>
#if (defined(__AVR__) || defined(ESP8266)) && !defined(__AVR_ATmega2560__)
// For UNO and others without hardware serial, we must use software serial...
// pin #2 is IN from sensor (GREEN wire)
// pin #3 is OUT from arduino (WHITE wire)
// Set up the serial port to use softwareserial..
SoftwareSerial mySerial(2, 3);
#else
// On Leonardo/M0/etc, others with hardware serial, use hardware serial!
// #0 is green wire, #1 is white
#define mySerial Serial1
#endif
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);
const uint8_t posMotorPin = 8;
const uint8_t negMotorPin = 9;
bool status = 0;
void setup()
{
Serial.begin(9600);
while (!Serial); // For Yun/Leo/Micro/Zero/...
delay(100);
pinMode(posMotorPin,OUTPUT);
pinMode(negMotorPin,OUTPUT);
Serial.println("\n\nAdafruit finger detect test");
// set the data rate for the sensor serial port
finger.begin(57600);
delay(5);
if (finger.verifyPassword()) {
Serial.println("Found fingerprint sensor!");
} else {
Serial.println("Did not find fingerprint sensor :(");
while (1) { delay(1); }
}
Serial.println(F("Reading sensor parameters"));
finger.getParameters();
Serial.print(F("Status: 0x")); Serial.println(finger.status_reg, HEX);
Serial.print(F("Sys ID: 0x")); Serial.println(finger.system_id, HEX);
Serial.print(F("Capacity: ")); Serial.println(finger.capacity);
Serial.print(F("Security level: ")); Serial.println(finger.security_level);
Serial.print(F("Device address: ")); Serial.println(finger.device_addr, HEX);
Serial.print(F("Packet len: ")); Serial.println(finger.packet_len);
Serial.print(F("Baud rate: ")); Serial.println(finger.baud_rate);
finger.getTemplateCount();
if (finger.templateCount == 0) {
Serial.print("Sensor doesn't contain any fingerprint data. Please run the 'enroll' example.");
}
else {
Serial.println("Waiting for valid finger...");
Serial.print("Sensor contains "); Serial.print(finger.templateCount); Serial.println(" templates");
}
}
void loop() // run over and over again
{
getFingerprintID();
delay(50); //don't ned to run this at full speed.
}
int val = analogRead(0)/4;
uint8_t getFingerprintID() {
uint8_t p = finger.getImage();
switch (p) {
case FINGERPRINT_OK:
Serial.println("Image taken");
break;
case FINGERPRINT_NOFINGER:
Serial.println("No finger detected");
return p;
case FINGERPRINT_PACKETRECIEVEERR:
Serial.println("Communication error");
return p;
case FINGERPRINT_IMAGEFAIL:
Serial.println("Imaging error");
return p;
default:
Serial.println("Unknown error");
return p;
}
// OK success!
p = finger.image2Tz();
switch (p) {
case FINGERPRINT_OK:
Serial.println("Image converted");
break;
case FINGERPRINT_IMAGEMESS:
Serial.println("Image too messy");
return p;
case FINGERPRINT_PACKETRECIEVEERR:
Serial.println("Communication error");
return p;
case FINGERPRINT_FEATUREFAIL:
Serial.println("Could not find fingerprint features");
return p;
case FINGERPRINT_INVALIDIMAGE:
Serial.println("Could not find fingerprint features");
return p;
default:
Serial.println("Unknown error");
return p;
}
// OK converted!
p = finger.fingerSearch();
if (p == FINGERPRINT_OK && status == false) {
Serial.println("Found a print match!");
digitalWrite(posMotorPin,LOW);
digitalWrite(negMotorPin,HIGH);
delay(8000);
digitalWrite(posMotorPin,LOW);
digitalWrite(negMotorPin,LOW);
status = !status;
} else if (p == FINGERPRINT_OK && status == true) {
digitalWrite(posMotorPin,HIGH);
digitalWrite(negMotorPin,LOW);
delay(8000);
digitalWrite(posMotorPin,LOW);
digitalWrite(negMotorPin,LOW);
status = !status;
} else if (p == FINGERPRINT_PACKETRECIEVEERR) {
Serial.println("Communication error");
return p;
} else if (p == FINGERPRINT_NOTFOUND) {
Serial.println("Did not find a match");
return p;
} else {
Serial.println("Unknown error");
return p;
}
EEPROM.update(status,val);
status = status + 1;
if (status == EEPROM.length()) {
status = 0;
}
delay(100);
// found a match!
Serial.print("Found ID #"); Serial.print(finger.fingerID);
Serial.print(" with confidence of "); Serial.println(finger.confidence);
return finger.fingerID;
}
// returns -1 if failed, otherwise returns ID #
int getFingerprintIDez() {
uint8_t p = finger.getImage();
if (p != FINGERPRINT_OK) return -1;
p = finger.image2Tz();
if (p != FINGERPRINT_OK) return -1;
p = finger.fingerFastSearch();
if (p != FINGERPRINT_OK) return -1;
// found a match!
Serial.print("Found ID #"); Serial.print(finger.fingerID);
Serial.print(" with confidence of "); Serial.println(finger.confidence);
return finger.fingerID;
}
You are saving an int variable named val in a location named status
EEPROM.update(status, val);
status = status + 1;
if (status == EEPROM.length())
{
status = 0;
}
but you only increment the address by 1 after saving even though an int uses 2 bytes. At the very least you are overwriting one of the bytes of the int next time you save a value
Why do you keep updating the address in the first place ?
For a single byte variable (your bool is one), you can use update() to write it and read() to read it. Update() checks if the value that you want to save has changed and only writes to EEPROM if it has changed.
You want to write 1 record to eeprom only when the power is removed? You need to sample the input power using 2 resistors as a voltage divider. Then trigger a pin change interrupt when power is loss while holding the 5V up with a capacitor long enough to write the data.
This is difficult to do if you are using USB power. It can be done using a power adapter and isolate the USB power.
The sketch below will save a few bytes to EEPROM on power loss using the analog comparator interrupt. This approach relieves loop() of having to monitor the voltage input.
/*
Analog comparator demo. Bandgap reference and AIN1 on D7
Board = UNO
Comparator settings based on Nick Gammon's page:
http://www.gammon.com.au/forum/?id=11916
Arduino forum page:
https://forum.arduino.cc/t/atmega328p-analog-input-comparator-using/1036684
The first time the program is run stateCount will be 255 (out of range)
(assuming no prior use of the EEPROM). When the button is pressed
stateCount will cycle through three values, 0-2. Zero = OFF, one = slow
flash, two = fast flash. When power is lost stateCount is saved to
EEPROM in the ANALOG_COMP_vect interrupt service routine. When
power returns stateCount will be restored from EEPROM and the code
will resume the previously set flash mode without user input.
Code in setup() initializes the analog comparator to generate a
rising edge interrupt when the voltage on AIN1 - connected to a
voltage divider* - drops below the internal 1.1v bandgap reference
(connected to the analog comparator positive input). The voltage
divider is connected between Vcc and GND and the wiper to AIN1 (pin 7).
This version saves only one 8-bit variable, stateCount.
* Current voltage divider values on pot - ~6800 and ~3300 ohms. With
Vcc at ~5V this provides 1.634v at divider tap.
Tested functional with fixed resistors 6.8k and 3.0k, which provides
1.32 volts at AIN1.
*/
#include <EEPROM.h>
const byte switchPin = 11;
const byte LEDpin = 6; // This pin is used intentionally to demonstrate that
// pin 6 can be used for normal digital I/O when the
// analog comparator input AIN0 is connected to the
// bandgpap reference.
const byte ACOoutput = 12; // Shows state of analog comparator ACO status
const uint16_t EEPROM_BASE = 11; // non-volatile address to store/retrieve data
uint8_t stateCount = 0; // flash or don't flash LED
ISR (ANALOG_COMP_vect)
{
/*
When board power is lost the analog comparator triggers
an interrupt which saves the current stateCount.
This state will be restored when power is reapplied.
*/
EEPROM.put(EEPROM_BASE, stateCount);
while (1); // stay here until power down
}
void setup ()
{
Serial.begin(115200);
// Prepare the analog comparator for the current setup:
// Voltage divider on pin 7, LED flasher on pin 6.
DIDR1 = AIN1D | AIN0D; // datasheet 27.3.2 Digital Input Disable Register 1
ACSR = bit (ACI) ; // (Clear) Analog Comparator Interrupt Flag
ACSR |= bit (ACIE); // Analog Comparator Interrupt Enable ON
ACSR |= bit (ACBG); // Internal bandgap reference ON
ADCSRB = 0; // (Disable) ACME: Analog Comparator Multiplexer Enable
// ACIS1, ACIS0: Analog Comparator Interrupt Mode Select (trigger on rising edge)
ACSR |= bit (ACIS0);
ACSR |= bit (ACIS1);
pinMode(LEDpin, OUTPUT); // Use the now disconnected PD6 as an output
pinMode(ACOoutput, OUTPUT);
pinMode(switchPin, INPUT_PULLUP); // with parallel .1uf capacitor debouncing
EEPROM.get(EEPROM_BASE, stateCount); // Restore stateCount from EEPROM
// Serial.println("end of setup");
//
// lamp test
//
digitalWrite(LEDpin, HIGH);
digitalWrite(ACOoutput, HIGH);
delay(1500);
digitalWrite(LEDpin, LOW);
digitalWrite(ACOoutput, LOW);
} // end of setup
void loop ()
{
static byte lastSW;
byte switchState = digitalRead(switchPin);
bool comparatorOutput = ACSR & bit(ACO); // state of analog comparator
digitalWrite(ACOoutput, comparatorOutput);
Serial.println(comparatorOutput);
if (switchState == LOW && lastSW == HIGH) { // count on switch pressed
stateCount++;
if (stateCount > 2) stateCount = 0;
}
lastSW = switchState;
if (stateCount == 1) { // LED flashes slow
delay(1000);
digitalWrite(LEDpin, HIGH);
delay(1000);
digitalWrite(LEDpin, LOW);
}
else if (stateCount == 2) { // LED flashes fast
delay(500);
digitalWrite(LEDpin, HIGH);
delay(500);
digitalWrite(LEDpin, LOW);
}
else { // LED is OFF
digitalWrite(LEDpin, LOW);
}
}