A convenient way to measure the pulse times can be accomplished with Arduino UNO's Input Change interrupt of Timer1.
With this method no extra counter hardware or a CPLD / FPGA is required.
The Counter of Timer1 is captured when a pulse is detected at a specific input, namely Pin D8. This limits the usage of this method a bit with the traditional Arduino Motor shields which utilize this pin for Motor Break.
Howver for the I2C controlled Quad-Motor shields such as Adafruit Motorshield V2 this is no restriction.
Description:
Time Measurement with Arduino UNO's TIMER1 and Input Capture on Pin 8 Signal containing negative Start and Stop pulses (High->Low)
-- ---------------------------- ---------
| | | |
----- ---
Start (TRIG=Trigger) Stop (SIG=Signal)
Time measurement takes time between Start and Stop pulse.
Direct after Trigger the Excitation pulse generates an immediate response with lots of unwanted SIG pulses which we need to skip. The usual time in my setup are 40us. In my first attempts with software delays I observed some jitter. Therefor I decided to introduce a Hardware Delay with a CD4098 Monoflop. This is the Delay Gate Circuit which is introduced in the Build Log.
The Monoflop is simultaneously triggerd with the Excitation Pulse (TRIG). This delayed inverted Trigger signal nGTRIG is combined with the Raw signal SIG from the Amplifier/comparator with a logical AND:
nGTRIG and SIG
Ideally we will get one nGTRIG signal and one or more SIG.
.
Signals
SIG active Low Raw signal form Amplifier / Comparator
TRIG D4 active High (SEL1) Triggers Excitation Circuit and Delay Gate
nGTRIG active Low Delayed Trigger Pulse
SIG' D8 active Low SIG = GTRIG and SIG
For more position sensors we can introduce a 2:1 Multiplexer which is controlled by:
CHSEL D9 (Channel select 0 or 1) (CHSEL) Selects Measurement Channel
Setup of Timer1:
/*
* Setup Timer1 for Input Capture
*/
void setupTimer1()
{
// Input Capture setup
// ICNC1: Enable Input Capture Noise Canceler
// ICES1: =1 for trigger on rising edge
// CS10: =1 set prescaler to 1x system clock (F_CPU)
TCCR1A = 0;
TCCR1B = (0<<ICNC1) | (0<<ICES1) | (1<<CS10);
TCCR1C = 0;
//catchFallingEdge(); // initialize to catch
TCCR1B &= ~(1<<ICES1); TIFR1 |= (1<<ICF1);
// Interrupt setup
// ICIE1: Input capture
// TOIE1: Timer1 overflow
TIFR1 = (1<<ICF1) | (1<<TOV1); // clear pending
TIMSK1 = (1<<ICIE1) | (1<<TOIE1); // Enable Timer OVF & CAPT Interrupts
// Set up the Input Capture pin, ICP1, which corresponds to Arduino D8
pinMode(8, INPUT_PULLUP);
}
We then have 2 Interrupt-routines to capture Counter Overflow and the signals into Ts-Arrays.
/*
* Interrupt to count Overflows
*/
ISR(TIMER1_OVF_vect)
{
T1OVF_Counter++;
//T1OVF_Counter += 65536;
//T1 -= 65536;
}
/*
* Interrupt for Pin Change at Pin 8
*/
ISR(TIMER1_CAPT_vect)
{
long T;
if(count==0)
{
Ts[count]= (long)ICR1 + (65536 * T1OVF_Counter); ;
if(count <NMEAS) count++; else MeasEnd=0;
//digitalWrite(CTL,HIGH);delayMicroseconds(10); digitalWrite(CTL,LOW);
}
else
{
// digitalWrite(SEL3,HIGH);
if(count>0)
{
T= (long)ICR1 + (65536 * T1OVF_Counter) - Ts[0];
/*if(count <NMEAS)
{
if( Ts_new != Ts[count-1])
{Ts[count] =Ts_new; count++; }
} else MeasEnd=0;
*/
if(count <NMEAS)
if(T != Ts[count-1]) {Ts[count] =T; T_old=T; count++; }
else
{
MeasEnd=0;
cli();
}
//digitalWrite(CTL,HIGH);delayMicroseconds(20); digitalWrite(CTL,LOW);
}
}
}
The following measure routine can handle 2 channels. After emitting a Trigger pulse it waits some time (until we are sure the measurement is over) and analyzes the pulses. The code snippet below shows also some continuous averaging. This function is blocking and emits pulses until a non zero value is registrered.
/*
* read Counter value
* estimator mit analyze
*/
long measure(int ch)
{
long value=0;
long x_coil = X_COIL;
long x_mid = X_MID; // 2851;
long x_len = 0;
int fall=0;
if(ch==0)
digitalWrite(CHSEL,0);
else
digitalWrite(CHSEL,1);
do {
T1OVF_Counter = 0;
for(int i=0;i<NMEAS;i++) Ts[i]=0;
count=0; // Reset Puls Counter
MeasEnd=1;
time = micros();
sei(); // Enable Interrupt
// Emit pulses:
digitalWrite(SEL1,HIGH); // Excitation Pulse
delayMicroseconds(1);
digitalWrite(SEL1,LOW);
delayMicroseconds(40); // 30
// Wait for End of Measure
while(micros()-time < 1000)
{
delayMicroseconds(10);
}
//#define DBG2
long T[NMEAS];
noInterrupts();
for(int i=0;i<NMEAS;i++)
{
T[i]=Ts[i];
if(T[i]<0 || T[i] > 10000 ) T[i]=0;
}
interrupts();
value=analyze0(T+1,meas+ch);
if(debugmode==1)
{ Serial.print(" VAL:");
Serial.print(value);
for( int i=1;i<count;i++)
{
Serial.print(" X"); Serial.print(i); Serial.print(":"); Serial.print(T[i]);
}
Serial.println();
}
}
while(value==0);
valold[ch] = 0.333 * (double) value + 0.666* valold[ch];
value=valold[ch];
return value;
}
Note: For a well damped wire (Rubber clamps and Hot glue) only one SIG pulse is seen which can be easily evaluated. If more than one SIG pulse is detected, advanced analyzers such as the Quartet analyzer described before can be used.
Here a signal image of a single torsion wave pulse inm a well damped configuration:This image shows a linearity check of the measurements with the described method:
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.