Ultrasonic range finder HC-SR04 using one timer

42 Views Asked by At

I have the following code on C for Atmega328P:

#include <avr/io.h>
#include <avr/interrupt.h>

void timer0Init()
{
    TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00);
    TCCR0B = (1 << CS00);
    OCR0A = 159;
    TIMSK0 = (1 << OCIE0A);
}

void timer1Init()
{
    TCCR1B = (1 << ICES1) | (1 << WGM12) | (1 << CS12) | (1 << CS10);
    OCR1A = 15625;
    TIMSK1 = (1 << ICIE1) | (1 << OCIE1A);
}

void usartInit()
{
    UCSR0B = (1 << TXEN0);
    UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
    UBRR0 = 103;
}


ISR(TIMER0_COMPA_vect)
{
    TCCR0B ^= (1 << CS00);
}

ISR(TIMER1_COMPA_vect)
{
    TCCR0B ^= (1 << CS00);
}

volatile uint16_t old, temp;
ISR(TIMER1_CAPT_vect)
{
    temp = ICR1;
    TCCR1B ^= (1 << ICES1);
    
    if ((TCCR1B & (1 << ICES1)) != 0)
    {   
        uint16_t delta = 0;
        
        if (temp > old)
        {
            delta = temp - old;
        }
        else
        {
            delta = 65535 - old + temp;
        }
        
        if ((UCSR0A & (1 << UDRE0)) != 0)
        {
            UDR0 = delta * 10;
        }
    }
    else
    {   
        old = temp;
    }
}


int main(void)
{
    DDRD = 0x40;
    
    timer0Init();
    timer1Init();
    usartInit();
    
    sei();
    while (1) {}
}

This code is used to measure distances to objects using a rangefinder. For this, two timers are used - Timer0 and Timer1. Timer0 is configured to generate an initial pulse (10 µs long) in PWM mode. Timer1 is set to capture mode and is also used to restart Timer0 every second.

The problem is that you need to implement the same functionality, but using one timer (presumably Timer1).

I tried the following implementation:

#include <avr/io.h>
#include <avr/interrupt.h>

void timer1Init()  // Настройка Timer1 - используется для захвата изменения на ICP1
{   
    TCCR1A = (1 << COM1A1) | (1 << WGM10);  // режим Fast PWM
    TCCR1B = (1 << CS10) | (1 << WGM12);  // без предделителя, работа с частотой процессора
    OCR1A = 159;  // скважность 62%
    TIMSK1 = (1 << OCIE1A);  // разрешение прерывания по совпадению с A
}

void usartInit()  // Настройка UART
{
    UCSR0B = (1 << TXEN0);  // разрешение передачи
    UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);  // 1 стоп-бит, размер пакета - 8 бит
    UBRR0 = 103;  // скорость передачи - 9600 бит/с
}


ISR(TIMER1_COMPA_vect)
{
    if (OCR1A == 159)
    {
        // режим CTC, захват по фронту, предделитель - clk/1024
        TCCR1B = (1 << ICES1) | (1 << WGM12) | (1 << CS12) | (1 << CS10);
        OCR1A = 15625;  // интервал между измерениями - 1 с
        TIMSK1 = (1 << ICIE1) | (1 << OCIE1A);  // разрешение прерывания захвата    
    }
    else if (OCR1A == 15625)
    {
        TCCR1A = (1 << COM1A1) | (1 << WGM10);  // режим Fast PWM
        TCCR1B = (1 << CS10) | (1 << WGM12);  // без предделителя, работа с частотой процессора
        OCR1A = 159;  // скважность 62%
        TIMSK1 = (1 << OCIE1A);  // разрешение прерывания по совпадению с A
    }
}

volatile uint16_t old, temp;  // глобальная переменная для хранения последнего значения захвата
ISR(TIMER1_CAPT_vect)  // прерывание Timer1 по захвату
{
    temp = ICR1;  // текущее значение захвата
    TCCR1B ^= (1 << ICES1);  // изменение типа сигнала для захвата
    
    if ((TCCR1B & (1 << ICES1)) != 0)  // сигнал получен приемником
    {
        uint16_t delta = 0;  // переменная для хранения расстояния в мм
        
        if (temp > old)  // если текущее больше предыдущего
        {
            delta = temp - old;  // разница = новое - старое
        }
        else  // иначе (таймер успел переполниться)
        {
            delta = 65535 - old + temp; // разница = 65535 - старое + новое
        }
        
        if ((UCSR0A & (1 << UDRE0)) != 0)  // если UART не занят
        {
            UDR0 = delta * 10;  // отправка по UART
        }
    }
    else  // сигнал отправлен передатчиком
    {
        old = temp;  // сохранение нового значения
    }
}


int main(void)
{
    DDRB = (1 << PORTB1);
    
    timer1Init();
    usartInit();
    
    sei();
    while (1) {}
}

However, this code does not generate 10 µs pulses at 1 second intervals. The images show pulses generated on PORTB1:

enter image description here

enter image description here

0

There are 0 best solutions below