cavrrobotics

Distance measuring from ultrasonic sensor, variable overflow


I have an ultrasonic sensor measuring distance and no matter which type my variable "range" is (uint8_t, uint16_t, 32, or 64), I always get an overflow, and then the sensor starts from 0 again... Is there a way that I can limit the "range" variable, or must I limit that on harder way with the pulsewidth?

SENSOR_DDR |= (1<<TRIGGER_PIN);
SENSOR_DDR &= ~(1<<ECHO_PIN) & ~(1<<PB3) & ~(1<<PB2) & ~(1<<PB1) & ~(1<<PB0);
DDRD = DDRD | _BV(4);
PORTD = PORTD | _BV(4);
ENGINE_DDR = 0xff;
ENGINE_PORT = 0;

lcd_init(LCD_DISP_ON);
lcd_clrscr();
lcd_puts("Something wrong...");

while(1)
{
    PORTB |= (1<<PB4); // Send trigger
    _delay_us(10);
    PORTB &= ~(1<<PB4); // Send trigger

    timer0counter = 0;
    TCNT0 = 0; // Clear timer
    while(bit_is_clear(PINB, 5)); // Wait for a rising edge
    TCCR0 |= (1<<CS02); // Select prescaler 256
    TIMSK |= (1<<TOIE0) | (1<<TOIE2); // Enable timer0 overflow interrupt

    lcd_clrscr();

    while(bit_is_set(PINB, 5) && timer0counter<9) // Wait for the alling edge of echo
    {
        _delay_us(5);
    }

    TCCR0 &= ~(1<<CS02); // Stop timer
    TIMSK &= ~(1<<TOIE0);
    if(bit_is_set(PINB, 5))
    {
        lcd_puts("No OBSTACLE");
    }
    else
    {
        range = (256*timer0counter + TCNT0)*32*0.017; // Range conversion

        lcd_clrscr();
        lcd_puts("Distance: ");
        lcd_puts(itoa(range, buffer, 10));
        lcd_puts_P("cm");
    }
    if(range<15) {
    ...


ISR(TIMER0_OVF_vect)
{
    TIMSK &= ~(1<<TOIE0);
    TCNT0 = 0;
    timer0counter++;

    TIMSK |= (1<<TOIE0);

    if(timer0counter>8)
    {
        TCCR0 &= ~(1<<CS02);
        TIMSK &= ~(1<<TOIE0);
    }

Solution

  • The calculation

    256*timer0counter + TCNT0
    

    saves a temporary value in a 'default' size int, which on AVR is 16 bits. So every time timer0counter is higher than 256, it will overflow, regardless of the final type of the variable.

    Instead of doing

    range = (256*timer0counter + TCNT0)*32*0.017;
    

    try going with:

    double range_real = 256.0 * (double)timer0counter + (double)TCNT0 * 32.0 * 0.017;
    range = (int) range_real;
    

    Being explicit about types can really save your skin.