# Measuring width of a pulse using avr capture

#### thinkanish

Joined Mar 29, 2013
8
Hi,
I want to interface a ultrasonic sensor to attiny2313. The code I developed using avrgcc. I used capture interrupt of the avr to capture the rising and falling edge of the pulse and calculate the time elapsed in doing so. In this process, after capturing the falling edge of the pulse, the timer is switched of and again it is switched on only after triggering the sensor. The code below works fine but when the distance is low (say 10cm), timer overflows and everything stops. But by seeing the speed of the avr core and timer, it has no chance to overflow. I cannot sort it out.
Rich (BB code):
#include "avr/io.h"
#include "avr/interrupt.h"
#define F_CPU 8000000
#include "util/delay.h"

volatile unsigned int pulseStart;
volatile unsigned int pulseEnd;
volatile unsigned int pulseInUs = 2013;
volatile unsigned char edge =0;
volatile unsigned int success = 0;
volatile unsigned int failure = 0;

#define START_TIMER TCCR1B |= ((1 << CS11) | (1 << CS10))
#define STOP_TIMER TCCR1B &= ~((1 << CS11) | (1 << CS10))
void pulseSensor(void){
PORTB |= (1 << 0);
_delay_us(10);
PORTB &= ~(1 << 0);
}

void initialisePorts(void){
DDRD &= ~(1 << 6);                  //PORTD.6 = INPUT
DDRB |= (1 << 0) | (1 << 1) | (1 << 2);   //PORTB.0 = PORTB.1 = OUTPUT
}

DDRB |= (1 << port);
PORTB ^= (1 << port);
_delay_ms(200);
}

int main(void){
initialisePorts();
TIMSK |= ((1 << ICIE1)| (1 << TOIE1));   //Set capture interrupt
sei();                           //Set global interrupt
TCCR1B |= (1 << ICES1);               //Set capture rising edge
pulseSensor();
START_TIMER;
for(;;){

if(success){
success = 0;
if(pulseInUs <= 200)         //Obstacle in range
PORTB |= (1 << 1);
else
PORTB &= ~(1 << 1);         //Obstacle not in range
pulseSensor();
START_TIMER;
}
if(failure){
failure = 0;
PORTB |= (1 << 2);
}
}
return 0;
}

ISR(TIMER1_CAPT_vect){
if(edge == 0){
pulseStart = ICR1;               //copy capture value
TCCR1B &= ~(1 << ICES1);         //toggle capture edge
edge = 1;
}
else{
pulseEnd = ICR1;               //copy capture value
TCCR1B |= (1 << ICES1);            //toggle capture edge
edge = 0;
STOP_TIMER;
TCNT1 = 0;
pulseInUs = pulseEnd - pulseStart;
success = 1;
}
}

ISR(TIMER1_OVF_vect){
failure = 1;
TCCR1B |= (1 << ICES1);
STOP_TIMER;
TCNT1 = 0;
edge = 0;
}
What is the problem in this code which makes the timer overflow?
Thanks.

#### Motardo

Joined Sep 21, 2011
22
Most ultrasonic ping sensors need a minimum distance of 7-10cm to work. If the distance is less than that, the sensor doesn't receive the echo, so it doesn't interrupt the uC, and the uC timer overflows. Which ultrasonic sensor are you using, and do you have a link to the datasheet?

#### Bhavin Tailor

Joined Mar 30, 2013
3
As per reply from Motardo, make ensure that are getting pulse from sensor.
Do you have any LED or display device...?
So, first make ensure you are getting rising & falling both edge from sensor. Just increment one variable on rising & falling edge & display value on LCD.
So, make ensure you are getting pulse or not from your sensor.

#### thinkanish

Joined Mar 29, 2013
8
Hi, thanks for your replies, i am using this 4 pin ultrasonic sensor : HC-SR04

The minimum resolution is 2cm but timer overflows even at 10 / 15cms

But the sensor works well with arduino pulseIn function up to (1 cm)

I have designed the program such that, if there is obstacle within some 20cm range, the LED in PORTB.1 glows. else it switches off. Also, an led is connected to PORTB.2 to indicate timer overflow. PORTB.0 is used to ping the sensor and PORTD.6 is the capture input.

Thanks.

#### kubeek

Joined Sep 20, 2005
5,724
I am not quite sure why you do it the way you do. If I were doing this, I would reset the count on the timer and start it on the rising edge, then capture the value from the timer on the falling edge.

#### thinkanish

Joined Mar 29, 2013
8
I am not quite sure why you do it the way you do. If I were doing this, I would reset the count on the timer and start it on the rising edge, then capture the value from the timer on the falling edge.
I tried even this method. Doesnt seem to work
Even in the above method, the timer overflows when distance is short. I think the controller is failing to capture the falling edge?
In that case what can be done?

#### kubeek

Joined Sep 20, 2005
5,724
Do you have an oscilloscope to crack this? I would toggle a pin to see for example when you enter and leave the ISR and use the other channel on the echo wire.

#### thinkanish

Joined Mar 29, 2013
8
Do you have an oscilloscope to crack this? I would toggle a pin to see for example when you enter and leave the ISR and use the other channel on the echo wire.
Hmm. I dont have a scope. I ll try this at my college and see.
Thanks for the tip

#### Bhavin Tailor

Joined Mar 30, 2013
3
Just for time being don't configure interrupt. As you are saying, timer overflow so there is enough time to sense. So, just make one WHILE loop to sense pin which is connected with sensor. Observe below logic,............

Rich (BB code):
PORTB.1 = 0;            // LED1 Off
PORTB.2 = 0;            // LED2 Off
while(PORTB.0==0);           // Wait here until you found High State from Sensor
PORTB.1 = 1;           // You come here when you will get rising edge from sensor,
while(PORTB.0==1);           // Wait here until you found High State from Sensor
PORTB.2 = 1;           // You come here when you will get falling edge from sensor,

So, if your both LED will glow it means, you are getting pulse from sensor and you have to look at in your code. Here, i assume that, by default state at your pin is LOW, Sensor will give High pulse & then it will maintain low state at pin.

Last edited by a moderator:

#### djsfantasi

Joined Apr 11, 2010
6,506
Rich (BB code):
while(PORTB.0==1); // Wait here until you found Low State from Sensor
I think you meant Low state in your comment.

#### thinkanish

Joined Mar 29, 2013
8
Here is what I observed in the scope. actually its not as expected / as given in the datasheet of the sensor.

The above is what i observe. See the output when there is no obstacle, for 5 meters ! the pulse is below zero.(not as given in the datasheet). But the code works regardless of this and I dont understand. As you can see, as the obstacle comes closer, the pulse width shrinks (less distance) and also, the pulse train slowly raises above zero (weird?)

Light?

#### kubeek

Joined Sep 20, 2005
5,724
Looks like you had it AC coupled maybe? Doesn´t the scope have the ability to save a screenshot?

#### thinkanish

Joined Mar 29, 2013
8
Looks like you had it AC coupled maybe? Doesn´t the scope have the ability to save a screenshot?
No. It doesnot have screen shot ability. What do you mean by AC coupled? I am completely working with DC. No way it is AC coupled.! even for the probe, i used only one probe (single channel).

I think you don't get the operation of the system?

The wave forms represented in the picture are correct. But they must be above zero.(everything)

#### kubeek

Joined Sep 20, 2005
5,724
The wave forms represented in the picture are correct. But they must be above zero.(everything)
That´s what I mean, the oscilloscope channel can be set to either ground, DC, or AC on a scope. The AC coupling on the scope would remove the DC component and would provide very similar readings to what you show in the pictures, assuming it is a purely digital output which should never go below 0V.