Skip to content

Instantly share code, notes, and snippets.

@SimenZhor
Created October 1, 2020 09:56
Show Gist options
  • Select an option

  • Save SimenZhor/04b0f4aa3f3fd5e52bfec7202dcac961 to your computer and use it in GitHub Desktop.

Select an option

Save SimenZhor/04b0f4aa3f3fd5e52bfec7202dcac961 to your computer and use it in GitHub Desktop.
Using the Timer/Counter module to measure the width of input pulses on Arduino Uno pin 8 (and Nano (unverified)). Pin 8 (PORT B0) must be used as this is the only TC input pin.
// Pulse Width measurement using input capture unit
// Author: Simen E. Sørensen
//(overflow calculations based on code by Nick Gammon 31 August 2013:
// https://www.gammon.com.au/forum/?id=11504)
// Date: 01 October 2020
// Input: Pin D8 (Arduino Uno (and I think Arduino Nano as well))
volatile boolean risingEdge;
volatile boolean fallingEdgeFlag;
volatile unsigned long overflowCount;
volatile unsigned long pulseStartTime;
volatile unsigned long pulseFinishTime;
float pulseWidth; //us
ISR(TIMER1_OVF_vect){
// timer overflows (every 65536 counts)
overflowCount++;
}
ISR(TIMER1_CAPT_vect){
noInterrupts();
unsigned int timer1CounterValue = ICR1;
unsigned long overflowCopy = overflowCount;
// Check if we have just missed an overflow
if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 0x7FFF)
overflowCopy++;
if(risingEdge){
//Store counting value, reconfigure to trigger on falling edge
pulseStartTime = (overflowCopy << 16) + timer1CounterValue;
risingEdge = false;
// Change to trigger on falling edge
// ICES1 = 0 means Falling Edge Trigger
TCCR1B &= ~bit(ICES1); // Set ICES1 low, keep all other bits in TCCR1B
interrupts(); // Re-enable interrupts, so we can catch the falling edge
return;
}else{
//Read counting value, set flag that values can be calculated, reconfigure to trigger on rising edge
pulseFinishTime = (overflowCopy << 16) + timer1CounterValue;
fallingEdgeFlag = true;
TIMSK1 = 0; // pause interrupts until pulse width has been calculated
}
}
void initTC(){
noInterrupts (); // protected code
fallingEdgeFlag = false; // re-arming for new pulse
risingEdge = true; // This function sets rising edge as the event trigger
// reset Timer 1 configuration registers
TCCR1A = 0;
TCCR1B = 0;
TIFR1 = bit (ICF1) | bit (TOV1); // clear flags so we don't get a bogus interrupt
TCNT1 = 0; // Reset counter
overflowCount = 0; // Reset overflow counter
// Configure Timer 1
// TOIE1 = Overflow IRQ, ICIE1 = Event IRQ
TIMSK1 = bit (TOIE1) | bit (ICIE1); // interrupt on Timer 1 overflow and input capture
// Select clock, select event trigger and apply filter (filter causes 4 clock cycles on delay but does not alter the pulsewidth measurement)
// CS10 = no prescaler (TC_CLK = F_CLK), ICES1 = Rising Edge Trigger, ICNC1 = Input Capture Noise Canceller
TCCR1B = bit (CS10) | bit (ICES1) | bit(ICNC1); // Set CS10, ICES1 and ICNC1 - clear all other bits in TCCR1B
interrupts ();
}
void calculatePulseWidth(){
unsigned long numCounts = pulseFinishTime - pulseStartTime;
// Period time = 1/F_CPU (= 62.5 ns at 16 MHz)
pulseWidth = float(numCounts) / (F_CPU*0.000001); // Pulse width = Period time * Num counts
}
void reArmTC(){
//Function only added for clarity in naming
initTC(); //re-arm for next pulse
}
void setup(){
Serial.begin(9600);
Serial.println("Pulse Width Counter");
pulseWidth = 0; //us
// set up for interrupts
initTC();
}
void loop(){
if(fallingEdgeFlag){
calculatePulseWidth();
Serial.print ("PulseWidth: ");
Serial.print (pulseWidth);
Serial.println (" µs. ");
reArmTC();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment