[SOLVED] How to compare new value with previous value

Hello All,

I am trying to figure it out how to an unsigned long variable (3 bytes) is still same with previous reading of remote controller (433 Mhz Radio Frequency) in order to eliminate the data corruption while its arriving. (Readings indicates that received value may change, there is no checksum control or validation)

#include <RCSwitch.h> // 433 Mhz Remote Controller Library
#include <Stepper.h>  // Stepper Motor Library
#include <EEPROM.h> // We are going to read from and write to EEPROM

#define DEBUG true  // Enable serial output for debugging

int iConsRead = 0; // consecutive, identical reads - used for learning

RCSwitch mySwitch = RCSwitch(); // Create RC Instance

#define STEP 32 // 28BYJ-48 Stepper Motor's step count

// Stepper Motor pin definitions
#define motorPin1  8     // IN1 on the ULN2003 driver 1
#define motorPin2  9     // IN2 on the ULN2003 driver 1
#define motorPin3  10     // IN3 on the ULN2003 driver 1
#define motorPin4  11     // IN4 on the ULN2003 driver 1

// Initialize with pin sequence IN1-IN3-IN2-IN4 for using the Stepper Library with 28BYJ-48
Stepper stepper1(STEP, motorPin1, motorPin3, motorPin2, motorPin4);

void setup() {
  if (DEBUG){
    Serial.begin(9600);
    Serial.println("Debug is enabled");
  }
  stepper1.setSpeed(1023);
  mySwitch.enableReceive(0);  // Receiver on interrupt 0 => that is pin #2
  
  if (DEBUG){
    Serial.println("Device is initialized");
  }
}

void loop() {
  if (mySwitch.available()) {
    if (DEBUG){
      unsigned long remoteData;
      remoteData = mySwitch.getReceivedValue();
      Serial.print("Recieved Data: ");
      Serial.println(remoteData);
    }
    switch (mySwitch.getReceivedValue()) {
      case 9044632:
      if (DEBUG) {
        Serial.println("buttonA is Pressed");
      }
      stepper1.step(-2048);
      break;
      
      // Case 2
      case 9044628:
      if (DEBUG) {
        Serial.println("buttonB is Pressed");
      }
      unsigned long track = millis();
      stepper1.step(2048);
      unsigned long spent = millis() - track;
      Serial.println(spent);
      break;
    }
    mySwitch.resetAvailable();
  }
}

boolean isFirstRun() {
  // Check if it is device's first run
  if (EEPROM.read(1023) != 1) { //Assume we have 1024 byte EEPROM
    if (DEBUG) {
      Serial.println("First Run");
    }
    do {
      digitalWrite(blueLed, LED_ON);    // Visualize Master Card need to be defined
      delay(200);
      digitalWrite(blueLed, LED_OFF);
      delay(200);
    }
    while (!GetRCData());                  // Program will not go further while you not get a successful read
    for ( int j = 0; j < 4; j++ ) {        // Loop 4 times
      EEPROM.write( 2 + j, readCard[j] );  // Write scanned PICC's UID to EEPROM, start from address 3
    }
    EEPROM.write(1023, 1);                  // Write to EEPROM we defined Master Card.
    Serial.println(F("Master Card Defined"));
  }
}

int GetRCData() {
  if (mySwitch.available()) {
    if (DEBUG){
      Serial.print("Recieved Data: ");
      Serial.println(mySwitch.getReceivedValue());
    }
    iConsRead++;
    if (iConsRead == 1) {
      firstRemoteData = mySwitch.getReceivedValue();
    }

    secondRemoteData = firstRemoteData;
    if (secondRemoteData == RemoteData);

  }
  mySwitch.resetAvailable();
}

mySwitch.getReceivedValue() is an Library defined unsigned long value.

As you can see we check if there is an Interrupt, Library does its job and stores the value into getReceivedValue variable.

I tried two or three different approaches. No one of them worked. How do i make a double check inside the first “if”.

1 second of holding a button on remote controller is enough for multiple readings at least 5 times.

double or triple check is enough i guess because if data is corrupt getting same exact corrupted data again is highly not possible.

omersiar: unsigned long variable (3 bytes)

Let's try 4 bytes....

omersiar: and stores the value into getReceivedValue variable.

It's not stored there at all. getReceivedValue() is a function. It returns the value it received last.

omersiar: I tried two or three different approaches. No one of them worked.

Not showing them is a bad start ;) Not posting whole code is even worst...

omersiar: How do i make a double check inside the first "if".

What do you mean by double check?

But if you want to ignore a received byte if it was the same as the last, just store the last and check it against the new received. Act on it (or not) and make the new value the last value for next time. Because you didn't post compilable code I'm not going to try and write code here ;) If we need to figure out the details so have you :)

mySwitch.getReceivedValue() is an Library defined unsigned long value.

It is a method of a class that returns a value whose type is unsigned long.

  unsigned long prevValue = 0;
   unsigned long currValue = mySwitch.getReceivedValue();

   if(currValue != prevValue)
   {
       // Got a new value
   }
   else
   {
       // Same old same old
   }
   prevValue = currValue;

As you can see we check if there is an Interrupt,

No, we can not see that. We can see that there is a function, but we can not see that the function ever gets called, or, if it does, HOW it gets called.

That is why we send people to http://snippets-r-us.com for help with snippets.

Library does its job and stores the value into getReceivedValue variable.

getReceivedValue is NOT a variable. It is a function. Monumental difference.

Thank you for your reply,

#include <RCSwitch.h> // 433 Mhz Remote Controller Library
#include <EEPROM.h> // We are going to read from and write to EEPROM

#define DEBUG true  // Enable serial output for debugging

unsigned long firstRemoteData;
unsigned long secondRemoteData;
byte readValue[3];

RCSwitch mySwitch = RCSwitch(); // Create RC Instance

void setup() {
  if (DEBUG){
    Serial.begin(9600);
    Serial.println("Debug is enabled");
  }
  mySwitch.enableReceive(0);  // Receiver on interrupt 0 => that is pin #2  
  if (DEBUG){
    Serial.println("Device is initialized");
  }
}

void loop() {
  isFirstRun();
}

boolean isFirstRun() {
  // Check if it is device's first run
  if (EEPROM.read(1023) != 1) { //Assume we have 1024 byte EEPROM
    if (DEBUG) {
      Serial.println("First Run");
    }
    do {
      digitalWrite(13, HIGH);    
      delay(200);
      digitalWrite(13, LOW);
      delay(200);
    }
    while (!GetRCData());                  // Program will not go further while you not get a successful read
    for ( int j = 0; j < 3; j++ ) {        // Loop 3 times
      EEPROM.write( 2 + j, readValue[j] );  // 
    }
    EEPROM.write(1023, 1);                  // Write to EEPROM we defined
    Serial.println(F("RC Defined"));
  }
}

int GetRCData() {
  if (mySwitch.available()) {
    if (DEBUG){
      Serial.print("Recieved Data: ");
      Serial.println(mySwitch.getReceivedValue());
    }
    int iConsRead = 0;
    iConsRead++;
    if (iConsRead == 1) {
      firstRemoteData = mySwitch.getReceivedValue();
    }

    secondRemoteData = firstRemoteData;
    if (secondRemoteData == firstRemoteData){
     
    }

  }
  mySwitch.resetAvailable();
}

Whole code is something like that now, still trying and making stupid coding that i am really ashamed by. Since I did not saved my old coding, this is the stupidest thing you will see.

I am still making horrible mistakes when expressing myself in English. I’m sorry that I am confused by between function and variable. Thank you.

Thank you, now I have working code:

#include <RCSwitch.h> // 433 Mhz Remote Controller Library
//#include <EEPROM.h> // We are going to read from and write to EEPROM

#define DEBUG true  // Enable serial output for debugging

//byte readValue[3];

unsigned long prevValue;

RCSwitch mySwitch = RCSwitch(); // Create RC Instance

void setup() {
  if (DEBUG){
    Serial.begin(9600);
    Serial.println("Debug is enabled");
  }
  mySwitch.enableReceive(0);  // Receiver on interrupt 0 => that is pin #2  
  if (DEBUG){
    Serial.println("Device is initialized");
  }
}

void loop() {
  isFirstRun();
}

boolean isFirstRun() {
  // Check if it is device's first run
  //if (EEPROM.read(1023) != 1) { //Assume we have 1024 byte EEPROM
    if (DEBUG) {
      Serial.println("First Run");
    }
    do {
      digitalWrite(13, HIGH);    
      delay(200);
      digitalWrite(13, LOW);
      delay(200);
    }
    while (!GetRCData());                  // Program will not go further while you not get a successful read
    /*for ( int j = 0; j < 3; j++ ) {        // Loop 3 times
      EEPROM.write( 2 + j, readValue[j] );  // 
    }
    EEPROM.write(1023, 1);                  // Write to EEPROM we defined
    Serial.println(F("RC Defined"));
    */
  }
//}

int GetRCData() {
  int matched = 0;
  if (matched == 1){ 
    return 1;
  }
  if (mySwitch.available()) {
    unsigned long currValue = mySwitch.getReceivedValue();
    if (DEBUG){
      Serial.print("Recieved Data: ");
      Serial.println(currValue);
    }
    if(currValue != prevValue) {
      Serial.println("Value does not match");
      matched = 0;
    }
    else {
      Serial.println("It matches");
      matched = 1;
    }
   prevValue = currValue;
  }
  mySwitch.resetAvailable();
  return 0;
}
boolean isFirstRun() {

You lied when you said that this function would return a value of type boolean.

   int iConsRead = 0;
    iConsRead++;
    if (iConsRead == 1) {
      firstRemoteData = mySwitch.getReceivedValue();
    }

The first two lines guarantee that iConsRead will always be 1. The if test is useless.

   secondRemoteData = firstRemoteData;
    if (secondRemoteData == firstRemoteData){

What are the odds that the if statement will evaluate to false? Trump has a better chance of being re-elected.

The idea is there but like Paul said, you need to tweak it. And the first run part is kind of weird though...

Another weird thing, where does EEPROM address 1023 come from... Why 1023? Why not put it in a constant with a readable name?

I am putting a project together (which is in its early stage). I shared a code snippet not because i am hiding something but because i taught it was enough to express the situation. From now and on I will always share the full code.

I choose 1023 because i believe it's the very end of the EEPROM space of the Arduino UNO. I may need to store some stepper motor calibration data on EEPROM too, and there will be Remote Controllers button data which will start from beginning of the EEPROM, They shouldn't be collide if I limit the button storage somehow. Constants will get their shape as the projects goes on.

And also mentioned the whole code will feel stupid earlier.

Thank you.

omersiar: I choose 1023 because i believe it's the very end of the EEPROM space of the Arduino UNO.

https://www.arduino.cc/en/Main/ArduinoBoardUno

EEPROM 1 KB (ATmega328P)

"I choose 1023 because i believe it's the very end of the EEPROM space of the Arduino UNO." That's correct, there are locations 0 to 1023. If you're saving a 4-byte value (an unsigned long number for example) you would use locations 1020, 1021, 1022, 1023.

I wrote some code once thinking I had 2K (2048) to play with, got some very odd results when locations 1024, 1025 overwrote locations 0, 1 as my code used those 2 locations to keep track of how many bytes were being used.

omersiar: I choose 1023 because i believe it's the very end of the EEPROM space of the Arduino UNO. I may need to store some stepper motor calibration data on EEPROM too, and there will be Remote Controllers button data which will start from beginning of the EEPROM, They shouldn't be collide if I limit the button storage somehow.

1023 is indeed the last byte. But why? It's you coding... If you put that in the first address there is nothing that makes it collide. Or, it's as likely to collide. That's because YOU choose the addresses... There is nothing except you that says that the Remote Controller button data need to be in the first place. And no guarentee it will not cover 1023 as well. For example if that data is a array of 256 longs or floats for example... Just make a clear memory map before randomly fill the EEPROM. A Excel table can really help.

omersiar: Constants will get their shape as the projects goes on.

I would say now is the time ;) Nothing as annoying as later changing hard coded pieces of code and creating bugs because you forgot to change it in a far corner of you code.

Just 1 byte to see if device is calibrated before or not

if (EEPROM.read(1023) != 1) { //Assume we have 1024 byte EEPROM
    if (DEBUG) {
      Serial.println("First Run");
}

At some point IDE developers introduced EEPROM.length() function (after 1.6.0 i guess). Which is useful when you are going to deploy your program on various chips.

/***
Advance to the next address, when at the end restart at the beginning.

Larger AVR processors have larger EEPROM sizes, E.g:

  • Arduno Duemilanove: 512b EEPROM storage.
  • Arduino Uno: 1kb EEPROM storage.
  • Arduino Mega: 4kb EEPROM storage.

Rather than hard-coding the length, you should use the pre-provided length function.
This will make your code portable to all AVR processors.
***/

@septillion

I was trying to quickly see if the idea works (checking if device is calibrated before). Did not considered it well. I get your point, I will create an EEPROM map, still learning the best practices. Thank you.