Combing code for hall effect RPM and Nextion tacho

Im struggling a bit to figure out the correct way to combine these two piece of code to do as I want.

The first part of code is an example of how to make a tachometer on a Nextion display, however, it is written to use a potentiometer to map the ADC bits to a series of pictures of the actual gauge. It also has some code to make extra indicators blink but Im only worried about the tach at this point.

This is a link to Youtube of the project Nextion+Arduino Tutorial #4 Custom Gauge And Play Video - YouTube

int sensorPin = A0;  // Potentiometer pin to simulate an rpm sensor, for testing
int sensorValue;  // Variable to store the value of potentiometer

// Calibration for smoothing RPM:
const int numReadings = 20;     // number of samples for smoothing. The higher, the more smoothing, but slower to react. Default: 20

// Calibration for tachometer deadzone:
const int TachometerDeadzoneSamples = 2;  // amount of samples for dead zone (1 would be no dead zone). Default: 2

// Calibration for tachometer limit:
const int TachLimitAmount = 20;  // how many cycles we are going to wait when tach reach limit value, before showing that value. Default: 20

// Variables for smoothing tachometer:
int readings[numReadings];  // the input
int readIndex = 0;  // the index of the current reading
long total = 0;  // the running total
int average = 0;  // the average

// Variables for deadzone for tachometer:
int TachometerWithDeadzone;

// Variables for tachometer limit:
int TachLimitCounter1 = 0;  // counter to wait for how long we see a limit value for tach, before showing that value
int TachLimitCounter2 = 0;  // counter to wait for how long we see a limit value for tach, before showing that value

// Variable to store the tachometer value after remaped:
int TachometerRemaped;

// Variable to store rpm:
int RealRPM = 0;

void setup() {  // Put your setup code here, to run once:
  
  Serial.begin(9600);  // Start serial comunication at baud=9600
 // I am going to change the Serial baud to a faster rate.
  delay(500);  // This dalay is just in case the nextion display didn't start yet, to be sure it will receive the following command.
  Serial.print("baud=115200");  // Set new baud rate of nextion to 115200, but it's temporal. Next time nextion is power on,
                                // it will retore to default baud of 9600.
                                // To take effect, make sure to reboot the arduino (reseting arduino is not enough).
                                // If you want to change the default baud, send the command as "bauds=115200", instead of "baud=115200".
                                // If you change the default baud, everytime the nextion is power ON is going to have that baud rate, and
                                // would not be necessery to set the baud on the setup anymore.
  Serial.write(0xff);  // We always have to send this three lines after each command sent to nextion.
  Serial.write(0xff);
  Serial.write(0xff);

  Serial.end();  // End the serial comunication of baud=9600

  Serial.begin(115200);  // Start serial comunication at baud=115200
}  // End of setup
void loop() {  // Put your main code here, to run repeatedly:
  delay(20);  // I put this delay because without it, the timer on the display would stop running.
              // Aparently we shouldn't send data to the display too often.

  sensorValue = analogRead(sensorPin);  // Read analog pin where the potentiometer is connected
  RealRPM = map (sensorValue, 0, 1023, 0, 8000);  // Remap pot to simulate an RPM value
  RealRPM = constrain(RealRPM, 0, 8000);  // Constrain the value so it doesn't go below or above the limits


  int TachometerRemapedWithoutSmoothing = map (RealRPM, 0, 8000, 0, 208);  // Remap the raw RPM to match the tachometer value range
  TachometerRemapedWithoutSmoothing = constrain(TachometerRemapedWithoutSmoothing, 0, 208);  // Constrain the value so it doesn't go below or above the limits

  // Smoothing RPM:
  // subtract the last reading:
  total = total - readings[readIndex];
  // read speed:
  readings[readIndex] = RealRPM;  // takes the value we are going to smooth
  // add the reading to the total:
  total = total + readings[readIndex];
  // advance to the next position in the array:
  readIndex = readIndex + 1;

  // if we're at the end of the array...
  if (readIndex >= numReadings) {
    // ...wrap around to the beginning:
    readIndex = 0;
  }
  
  // calculate the average:
  average = total / numReadings;  // the average value it's the smoothed result

  TachometerRemaped = map (average, 0, 8000, 0, 208);  // Remap the smoothed RPM to match the tachometer value range
  TachometerRemaped = constrain(TachometerRemaped, 0, 208);  // Constrain the value so it doesn't go below or above the limits

  // Deadzone for tachometer:
  // This is another layer of smoothing the tachometer. It adds some dead zone so it doesn't go back and forward to the same
  // adjacent values. This is because RPM sensors have some error range and jump between different values for the same speed.
  TachometerWithDeadzone = TachometerWithDeadzone + ((TachometerRemaped - TachometerWithDeadzone)/TachometerDeadzoneSamples);

  // By putting dead zone on tachometer, the limits can't be reached anymore. Because of this we need to check min and max limits:
  // Min limit:
  if (TachometerRemaped == 0)  // if tachometer is 0
  {
    if(TachLimitCounter1 == TachLimitAmount)  // if we wait long enough and still is 0
    {
      TachometerWithDeadzone = 0;  // show real tach as 0
    }
    else  // since we didn't wait long enough if tachometer it's still 0
    {
      TachLimitCounter1++;  // count to wait if tachometer it's going to remain 0
    }
  }
  else  // since tachometer its not 0
  {
    TachLimitCounter1 = 0;  // reset counter
  }


  // Max limit:
  if (TachometerRemaped == 208)  // if tachometer is 208 (the maximun limit)
  {
    if(TachLimitCounter2 == TachLimitAmount)  // if we wait long enough and still is 208
    {
      TachometerWithDeadzone = 208;  // show real tach as 208
    }
    else  // since we didn't wait long enough if tachometer it's still 208
    {
      TachLimitCounter2++;  // count to wait if tachometer it's going to remain 208
    }
  }
  else  // since tachometer its not 208
  {
    TachLimitCounter2 = 0;  // reset counter
  }

   // Send tachometer value:
  Serial.print("tach.pic=");  // This is sent to the nextion display to set what object name (before the dot) and what atribute (after the dot) are you going to change.

  // Choose one of the folling two, on what value to send to the tachometer:
  //Serial.print(TachometerWithDeadzone);  // Send RPM smoothed and with deadzone
  Serial.print(TachometerRemapedWithoutSmoothing);  // Send RPM without any smoothing at all

  Serial.write(0xff);  // We always have to send this three lines after each command sent to the nextion display.
  Serial.write(0xff);
  Serial.write(0xff);

}  // End of loop

I have successfully copied the project and it worked as I want.

Since I would like this to actually read RPM, I found this code that reads a hall effect sensor and I have verified that it also works when I hook up the Hall signal and read data in the serial monitor.

 int refsig=200;//for converting the analog signal coming from hall sensor to digital through arduino code
 int val;//the digital value of the incoming analog signals
 int prev_val=0;
 unsigned long t,cur_t;//time variables
 void setup()
 {
   Serial.begin(115200);
   pinMode(A0,INPUT);
 }
 void loop()//Measure RPM
 {
  int sig=analogRead(A0);//read raw value of hall sensor
  if(sig>refsig) val=HIGH;//convert it to digital 0,1 form
  else val=LOW;
  if(prev_val==0 && val==1) {//check for rising edge
    cur_t=micros();
    Serial.println(1000000*60/(cur_t-t));//print the rpm
    t=micros();
  }
   prev_val=val;
   
}

What I am having a hard time with is mapping the second code to have it work within the first code. I have a feeling that I need to do a few extra steps to make it work, but Im lost on what that is. Ive tried searching for Mapping Frequency and similar things, but it doesnt appear to be what Im looking for. I believe that this line in the second code

Serial.println(1000000*60/(cur_t-t));//print the rpm

Needs to be changed to something else so that it will read in this portion of the first code

sensorValue = analogRead(sensorPin);  // Read analog pin where the potentiometer is connected
  RealRPM = map (sensorValue, 0, 1023, 0, 8000);  // Remap pot to simulate an RPM value
  RealRPM = constrain(RealRPM, 0, 8000);  // Constrain the value so it doesn't go below or above the limits


  int TachometerRemapedWithoutSmoothing = map (RealRPM, 0, 8000, 0, 208)

Nextion_Tutorial4-1.ino (21 KB)

halltach.ino (789 Bytes)

If you have tested the halltach code and it prints the rpm correctly then you don't need to map it.
Just save it to RealRPM and constrain it.

I think the saving it as RealRPM is my issue that Im having I dont know how or where to do that.

I may be missing the forest through the trees on this and could use a hint on it.

I keep thinking I need to blend them and maybe thats not necessarily the case where I can just paste them together, but the HallTach code serial.write as its own entity has me mixed up. How do I make that RealRPM instead?

Change this:
Serial.println(1000000*60/(cur_t-t));//print the rpmto this:RealRPM = (1000000*60/(cur_t-t));//save the rpm

Hutkikz:
Change this:

Serial.println(1000000*60/(cur_t-t));//print the rpm

to this:

RealRPM = (1000000*60/(cur_t-t));//save the rpm

Just changing that doesnt deal with declaring variables. Or where to put the hall effect code into the rest of the code which is what is going over my head.

In the Tutorial code, the A0 input is in the comment section while the HallTach code has it in the Setup portion. I think I having a bigger issue with knowing what I can delete from one and not from the other. Ive tried to mix them up multiple different ways and it wont compile as Im not declaring everything, but I dont think I should be declaring things twice.

Case in point

this is in the Tutorial Code

int sensorPin = A0;  // Potentiometer pin to simulate an rpm sensor, for testing

and this is in the HallTach code

void setup()
{
  Serial.begin(115200);
  pinMode(A0,INPUT);

I think this is more about combining codes that dont necessarily work together than the RPM thing. I have figured out how to use the Tutorial code to run a temperature and fuel level gauge using ADC as its clear how to use it that way, but adding in new stuff is what is hanging me up.

A0 input is in the comment section while the HallTach code has it in the Setup portion

It's not the comment section it is the global space where global variables can be declared/initialized.
There are always several ways to do things. The halltach code uses the predefined( in the arduino library) pin name A0 so it doesn't need to be declared. While the nextion code assignes it a name that more clearly indicates what it is doing. Also the nextion code takes advantage of the fact that all pins by default are set as inputs so they do not bother to set them in setup.

If you comment out these two lines:

int sensorPin = A0;  // Potentiometer pin to simulate an rpm sensor, for testing
int sensorValue;  // Variable to store the value of potentiometer

and add in the variables from the halltach code:

// int sensorPin = A0;  // Potentiometer pin to simulate an rpm sensor, for testing
// int sensorValue;  // Variable to store the value of potentiometer

 int refsig=200;//for converting the analog signal coming from hall sensor to digital through arduino code
 int val;//the digital value of the incoming analog signals
 int prev_val=0;
 unsigned long t,cur_t;//time variables

then comment out these 2 lines:

  sensorValue = analogRead(sensorPin);  // Read analog pin where the potentiometer is connected
  RealRPM = map (sensorValue, 0, 1023, 0, 8000);  // Remap pot to simulate an RPM value

and add the halltach code right there:

//  sensorValue = analogRead(sensorPin);  // Read analog pin where the potentiometer is connected
//  RealRPM = map (sensorValue, 0, 1023, 0, 8000);  // Remap pot to simulate an RPM value

  int sig=analogRead(A0);//read raw value of hall sensor
  if(sig>refsig) val=HIGH;//convert it to digital 0,1 form
  else val=LOW;
  if(prev_val==0 && val==1) {//check for rising edge
    cur_t=micros();
    RealRPM = (1000000*60/(cur_t-t));//print the rpm
    t=micros();
  }
   prev_val=val;

  RealRPM = constrain(RealRPM, 0, 8000);  // Constrain the value so it doesn't go below or above the limits

That should do it. It isn't the way I would do it but it follows the style they used. Like I said always lots of different ways to do stuff.

Hutkikz:
It's not the comment section it is the global space where global variables can be declared/initialized.
There are always several ways to do things. The halltach code uses the predefined( in the arduino library) pin name A0 so it doesn't need to be declared. While the nextion code assignes it a name that more clearly indicates what it is doing. Also the nextion code takes advantage of the fact that all pins by default are set as inputs so they do not bother to set them in setup.

If you comment out these two lines:

int sensorPin = A0;  // Potentiometer pin to simulate an rpm sensor, for testing

int sensorValue;  // Variable to store the value of potentiometer



and add in the variables from the halltach code:


// int sensorPin = A0;  // Potentiometer pin to simulate an rpm sensor, for testing
// int sensorValue;  // Variable to store the value of potentiometer

int refsig=200;//for converting the analog signal coming from hall sensor to digital through arduino code
int val;//the digital value of the incoming analog signals
int prev_val=0;
unsigned long t,cur_t;//time variables



then comment out these 2 lines:

sensorValue = analogRead(sensorPin);  // Read analog pin where the potentiometer is connected
  RealRPM = map (sensorValue, 0, 1023, 0, 8000);  // Remap pot to simulate an RPM value



and add the halltach code right there:

//  sensorValue = analogRead(sensorPin);  // Read analog pin where the potentiometer is connected
//  RealRPM = map (sensorValue, 0, 1023, 0, 8000);  // Remap pot to simulate an RPM value

int sig=analogRead(A0);//read raw value of hall sensor
  if(sig>refsig) val=HIGH;//convert it to digital 0,1 form
  else val=LOW;
  if(prev_val==0 && val==1) {//check for rising edge
    cur_t=micros();
    RealRPM = (1000000*60/(cur_t-t));//print the rpm
    t=micros();
  }
  prev_val=val;

RealRPM = constrain(RealRPM, 0, 8000);  // Constrain the value so it doesn't go below or above the limits




That should do it. It isn't the way I would do it but it follows the style they used. Like I said always lots of different ways to do stuff.

That did not work unfortunately. I tried to add the A0 code in the Global area, tried to remove that and add the sensor declaration in the Setup and tried a few different curley bracket combinations to see if it would work and none did.

I am thinking that maybe sensorValue = analogRead(sensorPin); shouldnt be commented out but should be where the HALLTACH code should be, but then we are back to the next line where RealRPM is mapping ADC bits.

Stepping back a bit, can you maybe explain how the modifications to the code you recommended should work? I know that the tutorial code works by mapping the 0-8000 to the 209 pictures that make up a sweeping needle on the screen and prior to that it maps the ADC from 0-1023 into 0-8000. How does the modification do the same thing? Im almost thinking that I use the HALLTACH code and add the serial writes to the nextion within that, but either way, I need to figure out how to call out particular pictures based on a mapped RPM range.

I suppose what Im asking is not so much how to do this, but how would you do things like this in general? You said you wouldn't do it the way you posted, but there are multiple ways to do it, so how would you do it? The only reason Im picking out the two parts of code that I posted is that both function perfectly on their own, but maybe there is a better way to approach this and I should start with my own code (although that troubles me as I still dont understand why this doesnt work).

How did it not work? This is necessary info.

I am thinking that maybe
Code: [Select]

sensorValue = analogRead(sensorPin);

shouldnt be commented out

The halltach code already has that line here:int sig=analogRead(A0);//read raw value of hall sensor

You said you tested the nextion code but you never responded on whether you tested halltach code. Do you know that it works? Most code I've seen that that tests for the length of time between pulses (as this one does) use the pulsein() function but without testing I cannot tell if it works, but I have doubts.

Actually the nextion code as you posted it cannot possibly work either. but since you said that it did I'm assuming you posted a snippet and actually do have a tested working version??

In the nextion code the simulated RPM is aquired in these 2 lines.

  sensorValue = analogRead(sensorPin);  // Read analog pin where the potentiometer is connected
  RealRPM = map (sensorValue, 0, 1023, 0, 8000); //  Remap pot to simulate an RPM value

It reads the potentiometer and maps it to a raw(not yet smoothed) RPM reading that is saved to the variable RealRPM.

If the halltach code is working correctly then it also generates a raw RPM reading that just needs to be saved in RealRPM.

Yes, I have tested both sets of code and the are added as attachments direct from their sources.

I have tested the Nextion code along with the Arduino code attached and it definitely follows the potentiometer when you twist it back and forth just like is shown in the Youtube link I posted in my original post.

I have also tested the Halltach code and it reads properly in the Serial Monitor of the IDE. I utilized my function generator to create a 5v squarewave and it reads exactly the same.

I do not know why it doesnt work when I did as you said, but the screen is most definitely not reacting to the changes, it just sits at zero. Unfortunately, I have no idea how to read what, if anything is being sent to the screen while its hooked up.

Looking at the nextion code again I see that I failed to notice the delay right at the beginning of loop().
That is most certainly interfering with the halltach code. Also all those serial.write’s in the testing indicators section are not helping either.

Start by commenting out the entire “testing indicators” section for now. then you need to get rid of the delay.

According to the comments the delay is only there to keep from updating the display to fast. Since we are getting rid of the testing indicators section, that leaves only this section:

  // Send tachometer value:
  Serial.print("tach.pic=");  // This is sent to the nextion display to set what object name (before the dot) and what atribute (after the dot) are you going to change.

  // Choose one of the folling two, on what value to send to the tachometer:
  //Serial.print(TachometerWithDeadzone);  // Send RPM smoothed and with deadzone
  Serial.print(TachometerRemapedWithoutSmoothing);  // Send RPM without any smoothing at all

  Serial.write(0xff);  // We always have to send this three lines after each command sent to the nextion display.
  Serial.write(0xff);
  Serial.write(0xff);

So lets wrap it in a timer and then remove the delay.

// Timing Variables - put these at the top with the others
unsigned long screenUpdateInterval = 20;
unsigned long previousUpdateTime;





  if(millis() - previousUpdateTime >= screenUpdateInterval )  // Timer that replaces the delay() for updating the display
 {
  // Send tachometer value:
  Serial.print("tach.pic=");  // This is sent to the nextion display to set what object name (before the dot) and what atribute (after the dot) are you going to change.

  // Choose one of the folling two, on what value to send to the tachometer:
  //Serial.print(TachometerWithDeadzone);  // Send RPM smoothed and with deadzone
  Serial.print(TachometerRemapedWithoutSmoothing);  // Send RPM without any smoothing at all

  Serial.write(0xff);  // We always have to send this three lines after each command sent to the nextion display.
  Serial.write(0xff);
  Serial.write(0xff);
 }

Im definitely going to try to clean this up but wanna let you know that I got it to work as you suggested, albeit a bit fiddly (Ithink it has to do with what you said about the delay).

I had to make the delay to 1500 for everything to get situated on power up, but I also found that I had hardware issues when everything was tied together which I needed to deal with. Basically, I had the function generator, arduino and screen all on separate power sources and I think I had floating grounds between boards as everything waas on its own power. I tied everything to a single power source and it started functioning.

I gotta do 3 Mothers Day events this weekend so I wont be able to get back to this until Monday and employ your recommended changes, but I really appreciate your help.

albeit a bit fiddly.

Have a look at using interrupts.

ReadingRPM