Цитата(domowoj @ Jun 7 2008, 08:35)

Что-то подобное делал на частоте 100Гц.
В вашем случае входной сигнал - на ITNx, меряете интервал от фронта до фронта в "тиках",
вычитаете из измеренного 1,5 мкс в тиках(при тактовой 16МГц- это число 24), полученное число в
OCRx и по прерыванию от OCRx формируете на вых. импульс.
Перый импульс пропадает.
Действительно реальный совет!
И к гадалкам не надо обращаться!

Одна немаловажная поправка:
В моменты времени 5-6 границы нулевого сигнала должны быть такими же(относительно полупериода входного сигнала) как и 3-4; Другими словами: границы 3-4, 5-6 измеряются один раз в период сигнала 1.
Вот что я делаю:
Код
#include "avr/io.h"
#include <avr/interrupt.h>
#include <avr/sleep.h>
#define LEFT_1 0
#define RIGHT_1 1
#define LEFT_2 2
//Массив границ нулевых импульсов сигнала 2
volatile uint16_t bound[3];
//bound[0] соответствует моменту времени 3 (на рисунке)
//bound[1] соответствует моменту времени 4 (на рисунке)
//bound[2] соответствует моменту времени 5 (на рисунке)
//Текущее, предыдущее значение тиков процессора и разница между ними
volatile uint16_t ICR_Current, ICR_Prev, ICR_Diff;
//Счетчик (для обращения к элементам массива bound)
volatile uint8_t count;
//========================================================
//========================================================
void InitPorts(void)
{
DDRB = 0xFF;
PORTB = 0;
DDRD = _BV(5);
PORTD = 0;
}
//========================================================
void InitTimers(void)
{
//Таймер 1 -------------------------------------------
TCCR1A = _BV(COM1A1)|_BV(FOC1A); //Сброс OC1A при совпадении с OCR1A, разрешаем вывод на ногу OC1A
TCCR1B = _BV(CS10); //Частота==16 МГц (без делителя), режим Normal
TCCR1B|= _BV(ICES1); //Прерывание по захвату положительного фронта сигнала 1
TIMSK = _BV(TICIE1)|_BV(OCIE1A); //Разрешение прерывания по захвату и сравнению с OCR1A
sei(); //Общий флаг разрешения прерываний
}
//========================================================
void InitValues(void)
{
count = 0;
ICR_Prev = 0;
}
//========================================================
int main (void)
{
InitPorts();
InitValues();
InitTimers();
for (;;)
sleep_mode();
}
//========================================================
//========================================================
ISR(TIMER1_CAPT_vect) //Прерывание по захвату сигнала 1
{
ICR_Current = ICR1;
if (count==4) //соответствует моменту времени 6 (на рисунке)
{
PORTD|= _BV(5); //Устанавливаем на выводе OC1A логическую 1
}
//Т.к. счетчик(TCNT1) циклично увеличивается до 65535 и сбрасывается в 0
//нужно обработать ситуацию, когда в момент захвата значение счетчика лежит
//в пределах [0;24]. При этом текущее значение == TCNT1, а предыдущее лежит
//в пределах [65511; 65535](т.е. текущее значение МЕНЬШЕ предыдущего)
ICR_Diff = (ICR_Current>ICR_Prev)? (ICR_Current-ICR_Prev) : (ICR_Prev-ICR_Current);
ICR_Prev = ICR_Current;
bound[RIGHT_1] = ICR_Current + ICR_Diff/2; //bound[RIGHT_1]соответствует моменту времени 4 (на рисунке)
bound[LEFT_1] = bound[RIGHT_1]-24; //bound[LEFT_1] соответствует моменту времени 3 (на рисунке)
bound[LEFT_2] = ICR_Current + ICR_Diff-24; //bound[LEFT_2] соответствует моменту времени 5 (на рисунке)
//Установка вывода OC1A в "0" в последующем прерывании по сравнению
TCCR1A&=~_BV(COM1A0);
TCCR1A|=_BV(COM1A1);
OCR1A = bound[LEFT_1]; //Установка первого прерывания по сравнению
count = 1;
}
ISR(TIMER1_COMPA_vect) //Прерывание по сравнению сигнала
{
OCR1A = bound[count];
count++;
//Режим TOGGLE (инвертирование состояния вывода OC1A в последующем прерывании по сравнению)
TCCR1A|=_BV(COM1A0);
TCCR1A&=~_BV(COM1A1);
}
Время между прерываниями по сравнению сигнала (3-4) ==24 такта, что очень мало

Я не особо силен в ассемблере, и пока не знаю: успеет ли обработаться прерывание по сравнению за 24 такта? Скольким тактам процессора соответствует код в прерывании?!
Посмотрите свежим взглядом, может быть где ошибка допущена?
Заранее благодарен!