Hi, I am a student during my Internship and I am trying to create a tachometer using an IR sensor. I will describe my program the problem.
Materials : arduino mega2560 ,IR sensor TCRT5000 Infrared Sensor Module - Line Track, LCD screen 16x2 , SD module MicroSD Module with SPI interface (for Arduino) and a couple of buttons.
The way my program works. As the program begins I initialize the sd module , the screen , the serial and my interrupts. When someone presses the first button an ISR routine sets a flag that enables the timer1 and the external interrupt for the IR sensor. Every time the IR sensor sends a pulse another ISR increments a counter. When timer 1 reaches a value (0.5seconds in my case) from another ISR sets another flag which allows a funtion on loop to stop the timer and the external interrupts from the IR sensor in order to calculate the RPM. I am using a homemade encoder disc with 4 pulses per revolution. The way I calculate the rpm=Tcounter60 /4where T is the period of the timer1 count and counter is the number of pulses i got in that time. Besides that within loop every second I call uppon another function that displays the rpm value on the LCD screen.
The problem is that i get almost 3 times less RPMs that what it should report.
I am hosting all of my code down below. Any ideas on what I am doing wrong ? Any advice is welcome around all of my code but my main concern at the moment is to get the correct value out of my tachomereter.
Thanks in advance
#include <SPI.h>
#include <SD.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <LiquidCrystal.h>
#include <RTClib.h>
#define interrupts() sei()
#define noInterrupts() cli()
//debug
volatile int debugCounter=0;
//sd module
int CS_PIN=53;
File file;
//buttons
const byte toggleButton=3;
const byte dataSaveButton=18;
//sensor
const int pinIRd = 2;
const int pinIRa = A0;
//screen
const int rs=40, en=41, d4=42, d5=43, d6=44, d7=45; //lcd-arduino pins
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
//used for calculations
unsigned int rpm=0;
unsigned long lastMillis=0;
unsigned long lastMillisData=0;
unsigned long timeToDisplay=1000;
bool meterSet=false;
//volatile variables to be used inside int routines
volatile int counter=0;
volatile bool readyToCalculate=0;
volatile unsigned long lastInt_time=0;
volatile unsigned long currentInt_time=0;
volatile bool meterActive=0;
volatile bool writeToSD=0;
volatile unsigned int counterTable[10];
volatile byte counterTableIndex=0;
//measurement values
double firq=2;
unsigned int prescaler=1024;
unsigned long compVal=0;
void setup()
{
displaySetUp();
sdSetUp();
pinSetUp();
extIntSetUp();
}
void extIntSetUp(){
//setting external interrupts
EIMSK=0;//avoid unwanted interrupts
EICRB=0x0F;//trigger INT4 INT5 rising edge
EICRA=0xC0;//trigger INT3 on rising edge
EIMSK=0x28;//only INT5 and INT3
}
void sdSetUp()
{
//file test
initializeSD();
//createFile("test.txt");
//writeToFile("This is a sample text!");
//closeFile();
lcd.clear();
lcd.print("Sd initialized");
}
void displaySetUp()
{
//serial and screen init
Serial.begin(57600);
lcd.begin(16,2);
lcd.print("RPM counter v3.2");
}
void pinSetUp()
{
//setup for the pins
pinMode(pinIRd,INPUT);//attached to external interrupt device
pinMode(pinIRa,INPUT);
pinMode(toggleButton,INPUT_PULLUP);
pinMode(dataSaveButton,INPUT_PULLUP);
lcd.clear();
lcd.print("Sensor Init/zed");
}
void rpmMeterSetUP()
{
//initializing the timers
compVal=(16000000*((1/firq)/1024));
TCCR1A |=(1<<COM1A1);//reset OC1A on parity
TCCR1B = 0;
TCNT1=0;
TCCR1B |=(1<<WGM12); //turn on ctc mode
//set prescaler
TCCR1B |=(1<<CS12) | (0<<CS11) | (1<<CS10); //set prescaler 1024
OCR1A=compVal; //value at which the timer interrupts
TIMSK1 |= (1<<OCIE1A); //output compare interrupt enable 1
EIMSK=0x38;
lcd.clear();
lcd.print("setting up meter");
}
void loop()
{
rpmCalc();
if(millis()-lastMillis-timeToDisplay<=0)
{
lastMillis=millis();
storeData();
messagePrint();
}
}
void storeData()
{
if(writeToSD==1)
{
cli();
char text [16];
itoa(rpm,text,10);
createFile("TestLog.txt");
writeToFile(text);
closeFile();
Serial.println("writeToSD run");
sei();
}
}
void rpmCalc()
{
if (readyToCalculate==1)
{
readyToCalculate=0;
byte tempReg=TCCR1B;
EIMSK=0x28;//stops the external interrupts of int4
TCCR1B=0; //stops the timer
rpm=0;
rpm=((1/firq)*counter*60)/4; //rpm=T * pulses *60 sec /4 pulses per revolution
counter=0;
TCCR1B=tempReg; //starts the timer
EIMSK=0x38;//starts the external interrupts int
}
}
void messagePrint()
{
if(!meterActive)
{
stopDevice();
lcd.clear();
lcd.print("Ready to measure");
lcd.setCursor(0,1);
lcd.print("Press Start btn");
}
else if(meterActive && !meterSet)
{
lcd.clear();
lcd.print("Measureing");
startDevice();
}
else if (meterActive && meterSet)
{
// DateTime now = rtc.now();
Serial.print("RPM : ");
Serial.println(rpm);
Serial.println(".....................");
Serial.print("writeToSD : ");
Serial.println(writeToSD);
//Serial.println(now.hour(),DEC);
//lcd
lcd.clear();
if(rpm>0)
{
lcd.setCursor(4,0);
lcd.print("RPM : ");
lcd.print(rpm);
lcd.setCursor(1,1);
lcd.print("Logging : ");
if(writeToSD==1)
{
lcd.print("YES");
}
else if(writeToSD==0)
{
lcd.print("NO");
}
}
else if (rpm==0)
{
lcd.print("RPM : SLOW!!");
}
}
}
void startDevice(){
rpmMeterSetUP(); //sets up timer and ir interrupts
meterSet=1;
}
void stopDevice()
{
EIMSK=0x28;//stops the external interrupts of int4
TCCR1B=0; //stops the timer
counter=0;
meterSet=0;
}
void initializeSD()
{
Serial.println("init SD card...");
pinMode(CS_PIN,OUTPUT);
if (SD.begin())
{
Serial.println("SD card ready");
}
else
{
Serial.println("SD card failed");
lcd.clear();
lcd.print("Enter SD Card");
return;
}
}
int createFile (char filename[])
{
file=SD.open(filename,FILE_WRITE);
if(file)
{
Serial.println("File created");
return 1;
}
else
{
Serial.println("File Error");
return 0;
}
}
int writeToFile(char text[])
{
if (file)
{
file.println(text);
Serial.println("Writing");
Serial.println(text);
return 1;
}
else
{
Serial.println("Write Failed!");
return 0;
}
}
void closeFile()
{
if(file)
{
file.close();
Serial.println("File closed");
}
}
ISR (INT4_vect){
currentInt_time=micros();
if(currentInt_time-lastInt_time>1) //skips the counter++ if the interrupt occurs in less than 10milliseconds
{
counter++;
lastInt_time=currentInt_time;
}
}
ISR(TIMER1_COMPA_vect)
{
readyToCalculate=1;
}
ISR(INT5_vect)
{
meterActive=!meterActive;
}
ISR (INT3_vect)
{
writeToSD=!writeToSD;
}