Hi, I am trying to make an instrument to measure the period of a square wave. The square wave is generated from a rotating disc infront of an IR sensor (its a tachometer basically).
My background is from AVR programing using assembly so i am trying to recreate something i have tried in the past and it works but i cant make it work now.
The serial prints in ISR where used to find out if it gets in the ISR and it doesnt. I have tried both the PB0 pin (D8) and PD5 (d5) as the input for the timer 1 capture. Obvisouly I am doing something wrong. can you help me ?
Serial.print in an ISR is no, no!
When reading "period", outside the ISR, You need to turn off the interrupts, then read and then turn of the interrupt. Else an interrupt during the moment those 4 bytes are being read will give corrupt values now and then.
I did just that. The thing is that while period inside the ISR is updated (tested it with the nono method aformentioned when I try to print it in the loop it gets values of 0 and 1.
Here is an example sketch I wrote a while back for measuring RPM from a pulse signal using Input Capture.
// This example sketch uses the Input Capture Register (Timer1)
// and MedianFilterLibrary to measureRPM given a pulse stream.
// Because of the Median Filter, this should work with tooth-gap
// sensors like crank position sensors. The missing tooth will
// be thrown out with the rest of the noise.
//
// Note: Since this uses Timer1, Pin 9 and Pin 10 can't be used for
// analogWrite().
const boolean MeasureRisingEdges = true;
const float PulsesPerRevolution = 1.0 / 2.0; // One pulse every two revolutions (Spark Plug)
#include <MedianFilterLib.h>
MedianFilter<uint32_t> InterpulseFilter(5); // 5 samples
void setup()
{
Serial.begin(115200);
delay(200);
while (!Serial);
// For testing, uncomment one of these lines and connect
// Pin 3 or Pin 5 to Pin 8
// analogWrite(3, 64); // 490.20 Hz 58823.53 RPM
// analogWrite(5, 64); // 976.56 Hz 117181.50 RPM
noInterrupts (); // protected code
// reset Timer 1
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
TIMSK1 = 0;
TCCR1B |= _BV(CS10); // start Timer 1, prescale = 1
TCCR1B |= (MeasureRisingEdges << ICES1); // Input Capture Edge Select (1=Rising, 0=Falling)
TIFR1 |= _BV(ICF1); // clear Input Capture Flag so we don't get a bogus interrupt
TIFR1 |= _BV(TOV1); // clear Timer Overflow so we don't get a bogus interrupt
TIMSK1 |= _BV(ICIE1); // Enable Timer 1 Input Capture Interrupt
TIMSK1 |= _BV(TOIE1); // Enable Timer 1 Timer Overflow Interrupt
interrupts ();
}
volatile uint16_t Overflows = 0;
ISR(TIMER1_OVF_vect)
{
Overflows++; // Just count them
}
// Input Capture has triggered.
ISR(TIMER1_CAPT_vect)
{
static uint32_t previousEdgeTime = 0;
uint32_t thisEdgeTime;
uint16_t overflows = Overflows;
uint32_t interpulseTime = 0;
// If an overflow happened but has not been handled yet
// and the timer count was close to zero, count the
// overflow as part of this time.
if ((TIFR1 & _BV(TOV1)) && (ICR1 < 1024))
overflows++;
// Interrupted on Rising Edge
thisEdgeTime = overflows; // Upper 16 bits
thisEdgeTime = (thisEdgeTime << 16) | ICR1;
//uint32_t pulseDuration = thisRisingEdgeTime - previousRisingEdgeTime;
interpulseTime = thisEdgeTime - previousEdgeTime;
previousEdgeTime = thisEdgeTime;
// This is a good place to add 'interpulseTime' to the median filter.
// Make sure the median filter is only ued with interrupts disabled
InterpulseFilter.AddValue(interpulseTime);
}
float GetRPM()
{
uint32_t medianInterpulseTime;
noInterrupts();
// Make sure the median filter is only ued with interrupts disabled
medianInterpulseTime = InterpulseFilter.GetFiltered();
interrupts();
// Calculate RPM from inter-pulse time
// First calculate how many pulses are happening per second,
// Times are measured in clock ticks (16 MHz for UNO and 5V Nano)
float pulsesPerSecond = (float)F_CPU / medianInterpulseTime;
// Multiply by 60 for pulses per minute and
// divide by PulsesPerRevolution to get RPM
float RPM = pulsesPerSecond * 60.0 / PulsesPerRevolution;
return RPM;
}
void loop()
{
static float previousRPM = 0.0;
const float MinChangeOfRPM = 100.0;
float RPM = GetRPM();
// Display RPM only if it has changed enough
if (RPM > previousRPM + MinChangeOfRPM ||
RPM < previousRPM - MinChangeOfRPM)
{
Serial.println(RPM);
previousRPM = RPM;
}
}