johnerrington:
Can you show your code?
howw do you know? Did you calibrate it at idle - if so the value would naturally be "correct".
Also - youre powering your arduino from the cars "12V" supply which is VERY noisy, and also can go as high as 14 - 15V (still within spec) but it means you do have some headroom to add an RC filter. Say a 10 ohm resistor and 1000uF cap.
Simple experiment - if the ig uses a single crankshaft sensor you COULD have a signal of 600rpm = 10HZ at idle. So why not write (or crib) a sketch to time the interval between rising (or falling) edges?
Here's my code, I'm really sorry it's kind of a mess. But basically I run an introduction / welcome loop, then display the RPM value on the top row. I set ranges for the RPM values and have a little bar increase on the second row as the RPM increases. I did subtract 180 from the value in the "int averagedRpm" line to calibrate it at idle, so you're right that it's naturally "correct".
/*
* SIMPLE ARDUINO CAR TACHOMETER
*/
#include <LiquidCrystal.h>
}*/
#define countof(array) ( sizeof(array) / sizeof(*(array)) )
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int DATA_PIN = 9;
const int PINS_COUNT = 4;
const int NUMBER_OF_CYLINDERS = 6;
const int LED_UPDATE_INTERVAL = 200;
/* Last led state update time in ms, used to calculate the time from last update */
unsigned long lastUpdateTime = 0;
/* Amount of spark fires in a single interval */
volatile int sparkFireCount = 0;
/* Rpm value from last update used to average the last 2 rpms for smoother output */
int lastRpmValue = 0;
int lastlastRpmValue = 0;
void incrementRpmCount () {
sparkFireCount++;
}
/* Defines data pin function and opens serial for communication */
void setup() {
pinMode(DATA_PIN, INPUT_PULLUP);
attachInterrupt(1, incrementRpmCount, FALLING);
Serial.begin(9600);
lcd.createChar(0, box);
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.setCursor(1,0);
lcd.print("*** WELCOME ***");
lcd.setCursor(1,1);
lcd.print("*** DRIVER ***");
delay(2000);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("2003 IMPALA 3.8L");
lcd.setCursor(0,1);
lcd.print("ALL SYSTEMS GO");
delay(2000);
lcd.clear();
lcd.setCursor(2,0);
lcd.print("PREPARE FOR");
lcd.setCursor(4,1);
lcd.print("LIFTOFF");
delay(2000);
lcd.clear();
}
// 4 stroke engine fires every spark in 2 revolutions
// so calculate at what degree interval sparks fires and divide 360 by it,
// to find the number of fires per rotation
const int FIRES_PER_REV = (360 / (720 / NUMBER_OF_CYLINDERS));
char rpm[16];
void loop() {
if ((millis() - lastUpdateTime) > LED_UPDATE_INTERVAL) {
// multiply the amount the spark fires in one interval by the number of intervals per
// second, to find the amount in one second
// then multiply the amount in one second by 60, to find the spark fires in one minute and
// divide the result by the number of fires per revolution to find the rpm
int currentRpm = (sparkFireCount * (1000 / LED_UPDATE_INTERVAL) * 60) / FIRES_PER_REV;
// average the current and last 2 rpm for smoother results, subtract 180 to account for noise
int averagedRpm = ((currentRpm + lastRpmValue + lastlastRpmValue) / 3)-180;
Serial.println(averagedRpm);
sprintf(rpm,"RPM: %d", averagedRpm);
if(averagedRpm<1000){
lcd.setCursor(3,0);
lcd.print(rpm);
lcd.setCursor(11,0);
lcd.print(" ");
}
if(averagedRpm>1000){
lcd.setCursor(3,0);
lcd.print(rpm);
}
sparkFireCount = 0;
lastUpdateTime = millis();
lastlastRpmValue = lastRpmValue;
lastRpmValue = currentRpm;
}
}
I think the issue does lie in the power supply. The power from the vehicle would be noisy since at a higher RPM the alternator is suppling more voltage to charge the battery. That would explain why the ferrite clamps helped!
So, I think you're right in that I should run the power through an RC filter before I put it to the board. If I understand the concept correctly, the extra noise from the alternator will be regulated by the charging and discharging of the capacitor? Or should I use an LC circuit as Grumpy_Mike suggested?