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:

