RPM meter problem

hello to everyone. i am sorry for my bad english but i will try the best. i work on motorcycle meter. i have found a spark plug circuit that worked and i have readings and i will fint a code that will works. i have correct readings and everything its good and stable. my problem is this. i want to display it more accurate and more fine to look. i mean i want to display seems rpm for example : 1000 after 1110 then 1120 then 1130 then 1140 etc. i want all the number to show in screen. with this i have its goes from 1000 to 1560 for example and i dont like it. its easy this? even 50 by 50 rpm i dont have problem to show.
the code is this. i have a oled screen. i think its better for fast update. please help me if you want.

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>


#define OLED_RESET 4

Adafruit_SSD1306 display(OLED_RESET);


#define SSD1306_LCDHEIGHT 64

#if (SSD1306_LCDHEIGHT != 64)

#error("Height incorrect, please fix Adafruit_SSD1306.h!");

#endif



int val ; 


volatile byte half_revolutions;
unsigned int rpm;
unsigned long timeold;


void setup() {
  
 attachInterrupt(0, rpm1, RISING); // the output from spark plug sensor
  half_revolutions = 0;
  rpm = 0;
  timeold = 0;

 
  

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64)

  Serial.begin(9600);

}



void loop() {
 
val = map(rpm, 0, 8000, 0, 100);
if (half_revolutions >= 20) { 
    //Update RPM every 20 counts, increase this for better RPM resolution,
    //decrease for faster update
    rpm = 30*1000/(millis() - timeold)*half_revolutions;
    timeold = millis();
    half_revolutions = 0;  
  }
  
   display.clearDisplay();
 
   drawPercentbar( 0, 16, 128, 15,p3);
   
   text () ;
   
   display.display();


 p3 = val ;

   delay(5);

}

void text () {
 display.setCursor (0,0) ;
   display.setTextSize(2);
   display.setTextColor(WHITE);
display.print (rpm) ;
display.print (" RPM") ; 
}

void drawPercentbar(int x,int y, int width,int height, int progress)
{

  progress = progress > 100 ? 100 : progress;
  progress = progress < 0 ? 0 :progress;

  float bar = ((float)(width-4) / 100) * progress; 
 
  display.drawRect(x, y, width, height, WHITE);
  display.fillRect(x+2, y+2, bar , height-4, WHITE);


 if( height >= 15){
   display.setCursor((width/2) -3, y+5 );
   display.setTextSize(1);
   display.setTextColor(WHITE);
  if( progress >=50)
    display.setTextColor(BLACK, WHITE); 
    display.print(progress);
    display.print("%");
 }


}

void rpm1()
{
  half_revolutions++;
}

Your English is pretty good by the look of it, but please follow the advice in this sticky post from the top of the form page read this before posting a programming question and follow the advice on posting code using code tags. Auto Formatting the code in the IDE before posting is a good idea too.

please anyone?? its so difficult this i want to do? :frowning:

I have not looked to your code in detail but as you say that the RPM increases in increments of 20 then these lines of code stand out

  if (half_revolutions >= 20)
  {
    //Update RPM every 20 counts, increase this for better RPM resolution,
    //decrease for faster update

Change the value being tested in the first line of code but note the comments about the trade off between resolution and rate of update.

UKHeliBob i have do it. i have change the 20 to 1 etc
nothing changes. i want show like this : 1000-1010-1020-1030-1040 etc. not from 1000 to 1400 and anything like this

Instead of displaying the RPM every 20 revolutions, this version displays the RPM many times per second if it changes. I changed it to using microseconds instead of milliseconds to get more resolution.

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>


const unsigned long MICROSECONDS_PER_HALF_MINUTE = 30 * 1000000UL;


const byte OLED_RESET_PIN = 4;


Adafruit_SSD1306 display(OLED_RESET_PIN);


#if (SSD1306_LCDHEIGHT != 32)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif


volatile unsigned long MicrosecondsInHalfRevolution = 0;


void setup() {
  Serial.begin(9600);


  attachInterrupt(0, HalfRevolutionISR, RISING); // the output from spark plug sensor


  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x32)
}


void HalfRevolutionISR()
{
  static unsigned long lastMicroseconds = 0;
  unsigned long currentMicroseconds = micros();
  MicrosecondsInHalfRevolution = currentMicroseconds - lastMicroseconds;
  lastMicroseconds = currentMicroseconds;
}


void loop() {
  static unsigned int OldRPM = 0;
  
  // Copy volatile varaibles while interrupts are disabled
  noInterrupts();
  unsigned long microsecondsHalfRev = MicrosecondsInHalfRevolution;
  interrupts();


  // Calculate RPM
  unsigned int RPM = MICROSECONDS_PER_HALF_MINUTE / microsecondsHalfRev;


  // Display only on change to avoid flicker
  if (RPM != OldRPM) {
    display.clearDisplay();
    drawPercentbar( 0, 16, 128, 15, map(RPM, 0, 8000, 0, 100));
    text(RPM);
    display.display();
    OldRPM = RPM;
  }
}


void text (unsigned int RPM) {
  display.setCursor (0, 0) ;
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.print (RPM) ;
  display.print (" RPM") ;
}


void drawPercentbar(int x, int y, int width, int height, int progress)
{


  progress = constrain(progress, 0, 100);


  float bar = ((float)(width - 4) / 100) * progress;


  display.drawRect(x, y, width, height, WHITE);
  display.fillRect(x + 2, y + 2, bar , height - 4, WHITE);


  if ( height >= 15) {
    display.setCursor((width / 2) - 3, y + 5 );
    display.setTextSize(1);
    display.setTextColor(WHITE);
    if ( progress >= 50)
      display.setTextColor(BLACK, WHITE);
    display.print(progress);
    display.print("%");
  }
}

I have the impression that the OP's code is measuring the RPM correctly and what he is concerned about is the process of displaying it.

When the actual RPM changes from (say) 1100 to 1560 I think he does not want the display o change instantly between those numbers but, instead o go through the display steps 1100, 1020, 1130, 1140 etc to give the impression of the digits scrolling.

But I may be wrong. I will await confirmation before thinking about a solution.

...R

I think the oled display is slow, and causing the updates to be at more than 20 counts and not responsive to rapid changes in rpm.

Try the sketch without the drawPercentbar().

Even with @johnwassers code to look at the time between two pulses in microseconds will not help if the time between rpm updates is controlled by the display and not the pulse detection algorithm.

What are the rates of change in rpm you are looking at? If you are sitting in neutral and winding the bike from idle to several thousand rpm in a second or so the display of rpm will have large jumps. If you are on the road and slowly changing speed, is the displayed rpm changing in smaller jumps? What are your expectations for responsiveness?

Robin2 : this exactly i want. not the screen change instantly. i want to change with all the step of 20 rpm or 50 rpm. i am glad to understand what exactly i want. thanks for reply. if you cant help me please. i try many things and nothing changes. is that difficult or impossible to do this? i think not but i dont know. i am open to try and different codes. thanks again!!!

cattledog : i try it without the drawPercentbar and nothing changed. i think the oled is fast enough because i try it with a potentiometer with a map 0 to 8000 and changed very fast. so my opion is that the oled is fast enough for this. tell me if i was wrong. thanks!!!

OK. Here is a version that will show each step between the previously displayed RPM and the current RPM:

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>


const unsigned long MICROSECONDS_PER_HALF_MINUTE = 30 * 1000000UL;


const int RPM_GRANULARITY = 20;


const byte OLED_RESET_PIN = 4;


Adafruit_SSD1306 display(OLED_RESET_PIN);


#if (SSD1306_LCDHEIGHT != 32)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif


volatile unsigned long MicrosecondsInHalfRevolution = 0;


void setup() {
  Serial.begin(9600);


  attachInterrupt(0, HalfRevolutionISR, RISING); // the output from spark plug sensor


  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x32)
}


void HalfRevolutionISR()
{
  static unsigned long lastMicroseconds = 0;
  unsigned long currentMicroseconds = micros();
  MicrosecondsInHalfRevolution = currentMicroseconds - lastMicroseconds;
  lastMicroseconds = currentMicroseconds;
}


void loop() {
  static unsigned int OldRPM = 0;


  // Copy volatile varaibles while interrupts are disabled
  noInterrupts();
  unsigned long microsecondsHalfRev = MicrosecondsInHalfRevolution;
  interrupts();


  // Calculate RPM
  unsigned int RPM = MICROSECONDS_PER_HALF_MINUTE / microsecondsHalfRev;


  // Reduce the resolution to match the desired granularity.
  // Note that the division is done in integers
  RPM = (RPM / RPM_GRANULARITY) * RPM_GRANULARITY;


  // Display only on change to avoid flicker
  if (RPM != OldRPM) {
    // Display each step of size RPM_GRANULARITY
    if (RPM > OldRPM)
      OldRPM += RPM_GRANULARITY;
    else
      OldRPM -= RPM_GRANULARITY;
    display.clearDisplay();
    drawPercentbar( 0, 16, 128, 15, map(RPM, 0, 8000, 0, 100));
    text(RPM);
    display.display();
  }
}


void text (unsigned int RPM) {
  display.setCursor (0, 0) ;
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.print (RPM) ;
  display.print (" RPM") ;
}


void drawPercentbar(int x, int y, int width, int height, int progress)
{


  progress = constrain(progress, 0, 100);


  float bar = ((float)(width - 4) / 100) * progress;


  display.drawRect(x, y, width, height, WHITE);
  display.fillRect(x + 2, y + 2, bar , height - 4, WHITE);


  if ( height >= 15) {
    display.setCursor((width / 2) - 3, y + 5 );
    display.setTextSize(1);
    display.setTextColor(WHITE);
    if ( progress >= 50)
      display.setTextColor(BLACK, WHITE);
    display.print(progress);
    display.print("%");
  }
}

johnwasser:
OK. Here is a version that will show each step between the previously displayed RPM and the current RPM:

#include <SPI.h>

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

const unsigned long MICROSECONDS_PER_HALF_MINUTE = 30 * 1000000UL;

const int RPM_GRANULARITY = 20;

const byte OLED_RESET_PIN = 4;

Adafruit_SSD1306 display(OLED_RESET_PIN);

#if (SSD1306_LCDHEIGHT != 32)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

volatile unsigned long MicrosecondsInHalfRevolution = 0;

void setup() {
  Serial.begin(9600);

attachInterrupt(0, HalfRevolutionISR, RISING); // the output from spark plug sensor

display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x32)
}

void HalfRevolutionISR()
{
  static unsigned long lastMicroseconds = 0;
  unsigned long currentMicroseconds = micros();
  MicrosecondsInHalfRevolution = currentMicroseconds - lastMicroseconds;
  lastMicroseconds = currentMicroseconds;
}

void loop() {
  static unsigned int OldRPM = 0;

// Copy volatile varaibles while interrupts are disabled
  noInterrupts();
  unsigned long microsecondsHalfRev = MicrosecondsInHalfRevolution;
  interrupts();

// Calculate RPM
  unsigned int RPM = MICROSECONDS_PER_HALF_MINUTE / microsecondsHalfRev;

// Reduce the resolution to match the desired granularity.
  // Note that the division is done in integers
  RPM = (RPM / RPM_GRANULARITY) * RPM_GRANULARITY;

// Display only on change to avoid flicker
  if (RPM != OldRPM) {
    // Display each step of size RPM_GRANULARITY
    if (RPM > OldRPM)
      OldRPM += RPM_GRANULARITY;
    else
      OldRPM -= RPM_GRANULARITY;
    display.clearDisplay();
    drawPercentbar( 0, 16, 128, 15, map(RPM, 0, 8000, 0, 100));
    text(RPM);
    display.display();
  }
}

void text (unsigned int RPM) {
  display.setCursor (0, 0) ;
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.print (RPM) ;
  display.print (" RPM") ;
}

void drawPercentbar(int x, int y, int width, int height, int progress)
{

progress = constrain(progress, 0, 100);

float bar = ((float)(width - 4) / 100) * progress;

display.drawRect(x, y, width, height, WHITE);
  display.fillRect(x + 2, y + 2, bar , height - 4, WHITE);

if ( height >= 15) {
    display.setCursor((width / 2) - 3, y + 5 );
    display.setTextSize(1);
    display.setTextColor(WHITE);
    if ( progress >= 50)
      display.setTextColor(BLACK, WHITE);
    display.print(progress);
    display.print("%");
  }
}

johnwasser you save me!!! i 'll try the first code you post me. its brilliant and exactly that i want!!!!!
tomorrow i will try the second code you post before minutes. you save me and thank you very much for direct help and anwser!!!!! we can keep communication for my project??? thanks a lot for the help!!!! trully you are the best so far!!! :slight_smile: