Hi can someone help me to optimize my code used for a tachometer?
I need to make the resolution better ie. right now it jumps 60rmp up or down. I would like it to be under 10 - can anyone
help with that?
Im using a UNO and when the tachometer is running it jumps to 0 and them up again.. is this a buffer problem?
Thanks for any help..
This the code:
// using a hall sensor as a tachometer with a LCD display using U8glib / 12864 graphic LCD ST7920
#include "U8glib.h"
#define PMS_PIN 2 // Pin for signal from hall sensor
//#define LED_PIN 13 //Using Arduino's Internal LED as an hall sensor indicator for testing the signal.
boolean counted=false;
int t1=0,t2=0;
int hits=0;
int rps=0;
U8GLIB_ST7920_128X64_4X u8g(11, 10, 12); // this is the 12864 graphic LCD ST7920 using pin 11,10,12
//:::::::::::::::::::
void u8g_prepare(void) {
 u8g.setFont(u8g_font_helvB18);
 u8g.setFontRefHeightExtendedText();
 u8g.setDefaultForegroundColor();
 u8g.setFontPosTop();
}
void setup(){
 pinMode(PMS_PIN, INPUT);
// pinMode(LED_PIN, OUTPUT);
 //:::::::::::::::::::::::::::::::::
 // flip screen, if required
 //u8g.setRot180();
 // assign default color value
 if ( u8g.getMode() == U8G_MODE_R3G3B2 )
  u8g.setColorIndex(255);  // white
 else if ( u8g.getMode() == U8G_MODE_GRAY2BIT )
  u8g.setColorIndex(3);    // max intensity
 else if ( u8g.getMode() == U8G_MODE_BW )
  u8g.setColorIndex(1);    // pixel on
 //u8g.setContrast(0x30);
//Â pinMode(13, OUTPUT);Â Â Â Â Â
// digitalWrite(13, HIGH);Â
 u8g_prepare();Â
}
Â
void loop(){
 t2 = millis();
 if(t2 >= (t1 + 1000)){
  rps = hits;
  hits = 0;
  t1=t2;
   u8g.firstPage();Â
 do {
  u8g.setPrintPos(0,20);Â
  u8g.print("RPM: ");
  u8g.print(rps*60);
 } while( u8g.nextPage() );
 }Â
Â
 if(digitalRead(PMS_PIN) == HIGH){
  if(!counted){
   counted = true;
   hits++;
  }
 } else {
  counted = false;
 }
Â
// digitalWrite(LED_PIN, digitalRead(PMS_PIN));
}
to get the idea - not most efficient , give it a try
volatile uint32_t diff = 0;
volatile uint32_t p1 = 0;
void setup()
{
 Serial.begin(115200);
 Serial.println("Start");
 attachInterrupt(0, counter, RISING);
}
void loop()
{
 uint16_t RPM = 60000000UL/ (diff + (diff==0)); // prevent divide by zero
 Serial.print("RPM:\t");
 Serial.println(RPM);
 delay(1000);
}
void counter()
{
 if (p1 == 0) p1 = micros();
 else
 {
  diff = micros() - p1;
  p1 = 0;
 }
}
benzon:
10 to 2800rpm and 1 to 2 sec update can i perhaps run buffer interrupt?
In that case using an interrupt to increment the counter, and a timed function once per second to compare the new counter with the previous counter, calculate the frequency and update the display would seem like a sensible approach. If you can tolerate updating the display slightly more frequently or accept a slightly increased latency in reflecting speed changes then it would be a good idea to put a little smoothing (averaging) in the output to reduce the effects of jitter at low speed when consecutive sample periods will contain inconsistent numbers of samples.
Hi again Iam still working on the code and i got it to work ok now, I made a small video about it - I thought I would share it with you here is the link:
Very good video, good timing, not too long or too short, shows enough detail (for now
I noticed the screen makes steps of 10 even 20 RPM . some math:
RPM
500 => 2000 micros/pulse
499 => 2004
498 => 2008
...
220 => 4545
221 => 4524
so at 500RPM the timing is at its limit (micros() makes steps of 4us, next step would be HW timer),
that means that stepsize of ~2% of RPM is possible. Typical rounding steps are 1,2,5, 10
int raw = getRawRPM();
if (raw > 500) RPM = ((raw+5)/10)*10;
else if (raw > 300) RPM= (((raw+3)/5)*5; // in general ((raw+rounding/2)/rounding*rounding);
else if (raw > 150) RPM =Â (((raw+1)/2)*2;
else RPM = raw;