Need help with arduino nano timer 1 capture mode

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.

So here is my entire code :

#include <Arduino.h>
#include <LiquidCrystal.h>
#include <SPI.h>
#include <Wire.h>

#define interrupts() sei()
#define noInterrupts() cli()

unsigned long prevCapt=0;
unsigned long curCapt=0;
volatile unsigned long period=0;

unsigned long lastMillis=0;




const byte rs=3,en=4,d4=2,d5=6,d6=7,d7=9;
LiquidCrystal lcd (rs,en,d4,d5,d6,d7);



void setup() {
  Serial.begin(9600);
  lcd.begin(16,2);
  pinMode(5,INPUT_PULLUP);
  TIMSK1|=(1<<ICIE1); //enable t1 capture interrupt
  TCCR1A|=(0<<WGM11)|(0<<WGM10);
  TCCR1B|=(1<<CS12)|(1<<ICES1); //prescaler 256 rising edge
}

void loop()
{
  if(millis()-lastMillis>=1000)
  {
  lcd.clear();
  lcd.print("I am alive");
  unsigned long temp=period;
  Serial.println(temp);
  lastMillis=millis();
  }
}


ISR (TIMER1_CAPT_vector)
{
  curCapt=ICR1;
  Serial.println(curCapt);
  period=curCapt-prevCapt;
  prevCapt=curCapt;
  Serial.println(prevCapt);
}

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.


void setup() {
  Serial.begin(9600);
  lcd.begin(16,2);
  pinMode(8,INPUT_PULLUP); // set capture pin as input
  TCCR1A=0; //clear presets
  TCCR1B=0; //clear presets
  TCCR1B|=(1<<CS12)|(1<<CS11)|(1<<CS10)|(1<<ICES1)|(1<<ICNC1); //rising edge noise canceler
  TIMSK1|=(1<<ICIE1); //enable t1 capture interrupt
  TIFR1|=(1<<ICF1);//enable capture
  TCCR1A|=(0<<WGM11)|(0<<WGM10);
  
}


void loop()
{
  if((millis()-lastMillis>=1000))
  {
  cli();
  lcd.clear();
  lcd.print("I am alive");
  unsigned long temp;
  temp=period;
  Serial.println(temp);
  lastMillis=millis();
  sei();
  }
}


ISR (TIMER1_CAPT_vect)
{
  
  curCapt=ICR1;
  period=curCapt-prevCapt;
 // Serial.println(period);
  prevCapt=curCapt;
 
}

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;
  }
}
1 Like

test

But You didn't do the rest.....

void loop()
{
  if((millis()-lastMillis>=1000))
  {
  cli();
  lcd.clear();
  lcd.print("I am alive");
  unsigned long temp;
nointerrupts();
  temp=period;
interrupts();
  Serial.println(temp);
  lastMillis=millis();
  sei();
  }
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.