I recently started programming with Arduino and and currently I'm making a project to read RPM and Speed of my car using Arduino Uno. So far I got everything working but the speed value does not show properly. I have used one hardware counter and two interrupts in this project.
- Timer 1 on pin 5 - Count pulses from car's ECU to calculate speed.
- Int0 on pin 2 - Read ignition pulse to calculate RPM.
- int1 on pin 3 - 5v in from headlight switch to control the brightness of the display (MAX729 7 seg 8 digit).
I can get the proper reading from RPM and also the brightness control is working properly. Here is my codes below.
#include <LedControl.h>
// inputs: DIN pin, CLK pin, LOAD pin. number of chips
LedControl display = LedControl(12, 10, 11, 1);
//SPEEDO-----------------------------------------------------------
const int hardwareCounterPin = 5;
const int samplePeriod = 1000; //in milliseconds
const float pulsesPerMile = 4000; // this is pulses per mile for Toyota. Other cars are different.
const float convertMph = pulsesPerMile/3600;
unsigned int count;
float mph;
int kph;
int roundedKph;
int previousKph;
int prevCount;
//----------------------------------------------------------------
//RPM-------------------------------------------------------------
//Configuration for the Tachometer variables
const int sensorPin = 2;
const int sensorInterrupt = 0;
const int timeoutValue = 5;
volatile unsigned long lastPulseTime;
volatile unsigned long interval = 0;
volatile int timeoutCounter;
int rpm;
int rpmlast = 3000;
int rpm_interval = 3000;
//---------------------------------------------------------------
//Brightness control---------------------------------------------
int brightnessIndicator = 13; //Light pin 13 led to show that brightness control is in action.
int brightnessIn = 3; //Sensor in from headlight positive wire to control the brightness.
//---------------------------------------------------------------
void setup(void) {
//Serial.begin(9600);
display.shutdown(0, false); // turns on display
display.setIntensity(0, 10); // 15 = brightest
printTrueno(); //Print my car's name
delay(3000);
initToZero(); //Print all zeros before going to the loop
TCCR1A = 0; //Configure hardware counter
TCNT1 = 0; // Reset hardware counter to zero
//Config for the Tach
pinMode(sensorPin, INPUT);
attachInterrupt(sensorInterrupt, &sensorIsr, RISING);
lastPulseTime = 0;
timeoutCounter = 0;
//Config for brightness control
pinMode(brightnessIndicator, OUTPUT); //LED output
pinMode(brightnessIn,INPUT); //Sensor in
attachInterrupt(1, changeBrightness, CHANGE); //Attach the 2nd interrupt
changeBrightness(); //Check for head lights on or not.
}
void loop() {
//SPEEDO-----------------------------------------------------------
// This uses the hardware pulse counter on the Arduino.
// Currently it collects samples for one second.
bitSet(TCCR1B, CS12); // start counting pulses
bitSet(TCCR1B, CS11); // Clock on rising edge
delay(samplePeriod); // Allow pulse counter to collect for samplePeriod
TCCR1B = 0; // stop counting
count = TCNT1; // Store the hardware counter in a variable
TCNT1 = 0; // Reset hardware counter to zero
mph = (count/convertMph)*10; // Convert pulse count into mph. 10x allows retaining 10th of mph resolution.
kph = ((unsigned int) mph)*1.6; // Convert to kph and cast to integer.
int x = kph / 10;
int y = kph % 10;
// Round to whole mile per hour
if(y >= 5){
roundedKph = x + 1;
}
else {
roundedKph = x;
}
//If kph is less than 1 kph just show 0kph.
//Readings of 0.9kph or lower are some what erratic and can
//occasionally be triggered by electrical noise.
//if(x == 0){
if(x < 2){ // 1 was triggered by some noise signal.
roundedKph = 0;
}
// Don't display kph readings that are more than 50 kph higher than the previous reading because it is probably a spurious reading.
if(roundedKph < 181){
if((roundedKph - previousKph) > 50) {
Serial.println(previousKph);
printNumber(previousKph, 0);
}
else {
Serial.println(roundedKph);
printNumber(roundedKph, 0);
}
}
previousKph = roundedKph; // Set previousMph for use in next loop.
//-----------------------------------------------------------------
//RPM--------------------------------------------------------------
if(rpm >= 0) { //Remove the minus values
//Let's keep this RPMr value under control, between 0 and 9999
rpm = constrain (rpm, 0, 9999);
//If the engine is not running, print 0
if ((micros() - lastPulseTime) < 5e6 ) {
rpm = rpm;
}
else {
rpm = 0;
}
if (rpm < 250)
rpm = 0;
//Serial.println(rpm);
printNumber(rpm, 1);
}
//-----------------------------------------------------------------
}
//Each time the interrupt receives a rising tach signal, it'll run this subroutine
void sensorIsr() {
unsigned long now = micros();
interval = now - lastPulseTime;
if (interval > 5000){
rpm = 61000000UL/(interval * 2);
lastPulseTime = now;
}
}
void changeBrightness() {
int val = digitalRead(brightnessIn); //Read the sensor value
if(val == 1){ //If the headlights are on, pin goes HIGH.
digitalWrite(brightnessIndicator, HIGH); //turn the LED on
display.setIntensity(0, 6); //Reduce the brightness.
}
else {
digitalWrite(brightnessIndicator, LOW); //turn the LED off
display.setIntensity(0, 14); //increase the brightness.
}
}
void printNumber(int v, int flag) {
int ones;
int tens;
int hundreds;
int thousands;
if (flag==0){
ones = v%10;
v = v/10;
tens = v%10;
v= v/10;
hundreds = v;
//Now print the number digit by digit
if (hundreds>0)
display.setDigit(0,0,(byte)hundreds,false);
else
display.setChar(0,0,' ',false);
display.setDigit(0,1,(byte)tens,false);
display.setDigit(0,2,(byte)ones,false);
}
else if (flag=1) {
ones = v%10;
v = v/10;
tens = v%10;
v = v/10;
hundreds = v%10;
v = v/10;
thousands = v%10;
//Now print the number digit by digit
display.setDigit(0,4,(byte)thousands,false);
display.setDigit(0,5,(byte)hundreds,false);
display.setDigit(0,6,(byte)tens,false);
display.setDigit(0,7,(byte)ones,false);
}
}
I think the problem is between Timer1 and first interrupt. Can someone please help me to solve this?
Thank you very much.
count = TCNT1;
andTCCR1B = 0;
. It could be that stopping the counter also resetsTCNT1
.