I thought I better test my interrupt routine that calculated RPM. So made a square wave oscillator from a 555, and input it into D2 port on my Nano. My cycle tachometer goes up to around 12K, red-line at 9500. So want to test those frequencies. Also looked at this signal with a scope to get frequency and look at duty cycle (trying to maintain 50%). Here are the results I collected...
I've attached my code, anyone have any ideas why the RPM is not matching the input signal at the higher frequencies?
/* StopWatch/Tachometer Software Sketch
16 character 2 line I2C Display
Backpack Interface labelled "LCM1602 IIC A0 A1 A2" or similar
*/
// Variables/settings for the Stop-Watch function
unsigned long previousMillis = 0; //last time updated
unsigned long elapsed;
long interval = 1000; //1 second is interval at which to do update stopwatch (milliseconds)
unsigned long Ctr = 0;
// Variables settings for the Tachometer...
int decades;
int monades;
const int ignitionPin = 2;
const int ignitionInterrupt = 0;
const unsigned int pulsesPerRev = 1;
unsigned long lastPulseTime = 0;
unsigned long rpm = 0;
int rpm_int;
int rpm_to_disp;
int shift_light_rpm;
/*-----( Import needed libraries )-----*/
#include <Wire.h> // Comes with Arduino IDE
// Get the LCD I2C Library here:
// https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
// Move any other LCD libraries to another folder or delete them
// See Library "Docs" folder for possible commands etc.
#include <LiquidCrystal_I2C.h>
/*-----( Declare Constants )-----*/
//none
/*-----( Declare objects )-----*/
// set the LCD address to 0x20 for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
// addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address
//NOTE: Some of this type board come with the A0 A1 A2 connections (See photo) that are
//NOT bridged with solder as in the photo. Those will have address 0x27 not address 0x20.
/*-----( Declare Variables )-----*/
//none
//============================================================
void setup() /*----( SETUP: RUNS ONCE )----*/
{
Serial.begin(9600); // Used to type in characters
lcd.begin(16,2); // initialize the lcd for 16 chars 2 lines and turn on backlight
pinMode(ignitionPin, INPUT);
attachInterrupt(ignitionInterrupt, &ignitionIsr, RISING);
// ------- Quick 3 blinks of backlight -------------
for(int i = 0; i< 3; i++)
{
lcd.backlight();
lcd.setCursor(2,1); //x=0, row=1
lcd.print("Version 5.0");
delay(250);
lcd.noBacklight();
delay(250);
}
lcd.backlight(); // finish with backlight on
//-------- Write characters on the display ----------------
// NOTE: Cursor Position: CHAR, LINE) start at 0
lcd.setCursor(0,0); //Start at character 4 on line 0
lcd.print("Tachometer/Watch");
delay(1000);
lcd.setCursor(0,1);
lcd.print("From Nano-duino");
Serial.print("Starting Tachometer/Watch Program...@");
Serial.print(millis());Serial.print(" mSeconds\n");
delay(2000);
// Wait and then tell user they can start the Serial Monitor and type in characters to
// Display. (Set Serial Monitor option to "No Line Ending")
lcd.setCursor(0,0); //Start at character 0 on line 0
lcd.print("Start Serial Mon");
lcd.setCursor(0,1);
lcd.print("Type characters");
delay(6000);
}/*--(end setup )---*/
//============================================================
void DisplayTachometer(int valu)
{
//if (valu > 500) {
lcd.setCursor(6,0); //Start at character 6 on line 0
lcd.print(" ");
lcd.setCursor(0,0); //Start at character 0 on line 0
lcd.print("RPM=");
lcd.setCursor(4,0); //Start at character 6 on line 0
lcd.print(valu);
lcd.setCursor(10,0); // for Hz
lcd.print(valu/60.0);
delay(700);
// }
}
//============================================================
void DisplayShiftIndicator() // By flashing backlight 3 times
{
for(int i = 0; i< 3; i++)
{
lcd.backlight();
delay(150);
lcd.noBacklight();
delay(150);
}
lcd.backlight(); // finish with backlight on
}
//============================================================
void HandleTachometer()
{
noInterrupts(); //Disable interrupts temp to display results...
rpm_to_disp=int(rpm);
interrupts(); // Turn interrupts back on to count pulses...
if ((rpm_to_disp>100) && (rpm_to_disp<15000)){
rpm_to_disp=rpm_to_disp;
DisplayTachometer(rpm_to_disp);
//DisplayShiftIndicator(); //not used yet.
/* Somewhere in external loop should as the user for the value when to indicate time to shift
this will be stored in variable "shift_light_rpm". Could also look into making this an array
and store a specific value for each gear. (then or course would need a gear sensor too). For testing
purposes with just use value of 65...
*/
}
else if(rpm_to_disp>15000) //RedLine at 9500, tach goes to 11000
{
lcd.setCursor(0,0); //Start at character 6 on line 0
lcd.print("RPM exceeds 15K");
}
else if (rpm_to_disp<100)
{
lcd.setCursor(6,0); //Start at character 6 on line 0
lcd.print("RPM below 100...");
}
//============================================================
void loop() /*----( LOOP: RUNS CONSTANTLY )----*/
{
unsigned long currentMillis;
float h, m, s;
unsigned long over;
currentMillis = millis();
HandleTachometer();
{
// when characters arrive over the serial port...
if (Serial.available()) {
// wait a bit for the entire message to arrive
delay(100);
// clear the screen
lcd.clear();
// read all the available characters
while (Serial.available() > 0) {
// display each character to the LCD
lcd.write(Serial.read());
} //wend
} //endif Serial.available
elapsed = currentMillis - previousMillis;
if (elapsed > interval) {
Serial.print(currentMillis);
Serial.print(" ");
Serial.print(Ctr);
Serial.print("\n");
lcd.clear();
Ctr++;
h = int(Ctr / 3600);
over = Ctr % 3600;
m = int(over / 60);
over = over % 60;
s = int(over);
// Print results to serial port
Serial.print("Elapsed time: ");
Serial.print(h, 0);
Serial.print("h ");
Serial.print(m, 0);
Serial.print("m ");
Serial.print(s, 0);
Serial.print("s ");
Serial.println();
// print results of 16x2 LCD display
lcd.setCursor(0,1);
lcd.print("Time: ");
lcd.setCursor(5,1);
lcd.print(h);
lcd.setCursor(7,1);
lcd.print("h ");
lcd.setCursor(9,1);
lcd.print(m);
lcd.setCursor(11,1);
lcd.print("m ");
lcd.setCursor(13,1);
lcd.print(s);
lcd.setCursor(15,1);
lcd.print("s");
previousMillis = currentMillis;
} //endif
}
}/* --(end main loop )-- */
//============================================================
void ignitionIsr()
{
unsigned long now = micros();
unsigned long interval = now - lastPulseTime;
if (interval > 5000)
{
rpm = 60000000UL/(interval * pulsesPerRev);
lastPulseTime = now;
//rpm_int=int(rpm);
}
}
/* ( THE END ) */