РРМ индикатор
прочитай 10 пост.
а вобще то сервртестер сам предполагает генерацию импульсов(те передатчик ненужен!), т.о. осушествляется генерация импульсов длительностью 1-2 мкс(например от данных крутилки->ацп) и периодом 20 мс.
а вобще то сервртестер сам предполагает генерацию импульсов(те передатчик ненужен!), т.о. осушествляется генерация импульсов длительностью 1-2 мкс(например от данных крутилки->ацп) и периодом 20 мс.
В том-то и дело, что мне передатчик нужен. А 10й пост я читал, но только мне он не как не помог.
Для начала вынести ppm_display(); из прерывания в main, пока Вы там отображаете на индикаторе что угодно может происходить, так никто не делает. И кстати на какой частоте у Вас все это происходит и что Вы в действительности смотрите канальный импульс или пакет PPM ?
…Ну и у ног же у Меги8 много, а задач у Вас - мало. Так используйте две ноги внешних прерываний. Перемкните их; одну (скажем, PD2) настройте на прерывание по фронту, другую (удобнее PB0 (=ICP1), но если PortB занят обслуживанием дисплея, то можно и PD3) настройте на прерывание по тылу. В Int0 будете таймер запускать, а в INT1 останавливать и ресетить.
Я когда-то делал чем-то похожий дивайс - хронограф для измерения скорости пули пневматической винтовки. Разница только в том, что у меня были два сигнала - от старт- и стоп-оптопары. Камень - ATMEGA8535, сделано было примерно так:
//Управление прерываниями
#define TOIE1 2 // Бит 2 (в регистре TIMSK)
#define TEC1 5 // Бит 5 (в регистре TIMSK)
#define INT0 6 // Бит 6 (в регистре GICR)
#define TOV1 2 // Бит 2 (в регистре TIFR)
#define ICF1 5 // Бит 5 (в регистре TIFR)
#define INTF0 6 // Бит 6 (в регистре GIFR)
#define I_T1Ovf_Enable TIMSK |= (1<<TOIE1) //Разрешить прер. переполнения T1
#define I_T1Ovf_Disable TIMSK &= ~(1<<TOIE1) //Запретить прер. переполнения T1
#define I_T1Cpt_Enable TIMSK |= (1<<TEC1) //Разрешить прер. захвата T1
#define I_T1Cpt_Disable TIMSK &= ~(1<<TEC1) //Запретить прер. захвата T1
#define I_INT0_Enable GICR |= (1<<INT0) //Разрешить прер. INT0
#define I_INT0_Disable GICR &= ~(1<<INT0) //Запретить прер. INT0
#define F_T1Ovf_Clr TIFR |= (1<<TOV1) //Сброс флага прер. переполнения T1
#define F_T1Ovf_Set TIFR &= ~(1<<TOV1) //Уст. флага прер. переполнения T1
#define F_T1Cpt_Clr TIFR |= (1<<ICF1) //Сброс флага прер. захвата T1
#define F_T1Cpt_Set TIFR &= ~(1<<ICF1) //Уст. флага прер. захвата T1
#define F_INT0_Clr GIFR |= (1<<INTF0) //Сброс флага прер. INT0
#define F_INT0_Set GIFR &= ~(1<<INTF0) //Уст. флага прер. INT0
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void) {
//TCCR1A=0x00; //Не нужно, ибо и так ==0.
#ifdef OnNewton // Тестирование падающим сердечником
TCCR1B=0x83; // 288,000 kHz - захват с антидребезгом
#else
TCCR1B=0x81; // 18432,000 kHz - захват с антидребезгом
#endif
I_INT0_Disable; //Запрещаем реагировать на Int0
I_T1Ovf_Enable; //Разрешаем прерывание по переполнению - вдруг пропустим стоп...
I_T1Cpt_Enable; //Разрешаем прерывание ICP1 - ждем фронт стоп-импульса
F_T1Ovf_Clr; //Очищаем флаги прерываний
F_T1Cpt_Clr;
F_INT0_Clr;
}
// Timer 1 input capture interrupt service routine
interrupt [TIM1_CAPT] void timer1_capt_isr(void) {
resT=ICR1; // Сохраняем подсчитанное значение
TCCR1B=0x00; // Останов таймера
TCCR1A=0x00;
TCNT1H=0x00; // Обнуляем таймер для последующего запуска
TCNT1L=0x00;
/*
Здесь процедуры обсчета результата и занесения в значения в переменную,
которая выводится на дисплей в основном цикле программы
*/
I_INT0_Enable; //Разрешаем прерывание Int0 - ждем фронт старт-импульса
I_T1Ovf_Disable; //Запрещаем прерывание по переполнению - таймер сейчас стоит
I_T1Cpt_Disable; //Запрещаем прерывание ICP1 - пока нет старта, стоп не ловим
F_T1Ovf_Clr; //Очищаем флаги прерываний
F_T1Cpt_Clr;
F_INT0_Clr;
}
Я эмбеддер не больно продвинутый; может, я тут слишком сильно “дую на воду” - но дивайс мой давно и успешно работает.
Для начала вынести ppm_display(); из прерывания в main, пока Вы там отображаете на индикаторе что угодно может происходить, так никто не делает. И кстати на какой частоте у Вас все это происходит и что Вы в действительности смотрите канальный импульс или пакет PPM ?
Если я вынесу ppm_display(); из прерывания в main, как я буду обращаться к сабрутине void ppm_display(void)?
Всё проиходит с чстотой 8MHz.
Я хочу мереть положительную часть импульса от подъема до спада с приёмника, именно она отвечает за угол поворота сервы.
Насчет 8 МГц - это ты маненько погорячился. Не все.
16-ти битный таймер должен натикать 65535 значений не более чем за, скажем, 2.1mS (2mS+5%). Исходя из этого ты выбираешь наименьший допустимый делитель таймера. Если этот делитель =1 - ну, значит, и тик таймера у тебя тоже 8МГц.
А дисплей обновлять - это песня отдельная. Тем более, HD44780 - с собственной оперативной памятью.
Если хочешь обновлять непременно после _каждого_ пойманного импульса, то можешь поставить и в прерывание “тыла”. Но тогда, пока выполняется функция обновления дисплея, все внешние прерывания должны быть запрещены. Успеешь закончить отображение и разрешить INT0 - поймаешь следующий импульс. Не успеешь - пропустишь следующий (или следующие…) импульсы.
Только зачем так часто? Глаз все равно этого не оценит. Чаще 25 раз в секунду - только мультики рисовать.
Взгляни на обычный код, который генерит CVAVR. Там инициализация камня, потом - цикл while.
Вот внутри цикла while у тебя будет вывод на дисплей ( ppm_display(); ). Выводиться будет то, что посчитано в прерывании останова. Так часто, как это позволит содержимое прочих строк внутри while. Так что, скорее всего, еще и замедление (внутри while) ставить придется, чтобы цифры на дисплее не мельтешили. Два - три раза в секунду, а то и за значением следить не сможешь. Будут цифры мелькать, как сотые секунды на электронном секундомере. Оно тебе надо?
А вот во время этих замедлений/простоев ты будешь замерять/обсчитывать свой импульс. “Обсчитывать” - скажем, можешь поставить осреднение медианным фильтром (сохраняешь некоторое число последних замеров (условно, 10); сортируешь по возрастанию, края (условно - по три значения) отбрасываешь; по оставшимся 4-м значениям считаешь среднее арифметическое и его показываешь).
Если я вынесу ppm_display(); из прерывания в main, как я буду обращаться к сабрутине void ppm_display(void)?
…Я хочу мереть … отвечает за угол поворота сервы.
Это скорее можно назвать канальным импульсом, но не важно. В основном цикле например делаете проверку lcd_1 и lcd_2, если не нуль, то вызываете вывод на дисплей, прерывание должно коротко отрабатывать событие и выплевывать ход программы обратно, при вашей куче вызываемых в прерывании функций что там творится отследить невозможно.
В процедуре дисплея есть задержка на 200 мс. Обычно компиляторы делают её на таймере, уведомляя об это программиста только в документации. Если ppm_display рабочая, я-бы вообще без прерываний сделал, совсем их запретив. Обнуляем таймер и циклом ждём единицу на PPM ноге. По её приходу пускаем таймер, ждём обнуления ноги, и по событию сохраняем значение таймера. Полученое число отправляем в ЖК и терпеливо ждём возврата управления. И так по кольцу.
Когда код заработает правильно, его уже можно “причесать” и усложнить по необходимости.
…
Чтобы импульс гарантированно измерить с нарастающего фронта, перед ожиданием нарастания надо ещё добавить пустое ожидание спада.
forum.modelka.com.ua/index.php?showtopic=19120&st=…
вот здесь что-то подобное обсуждают но там под компорт
а вобще можно и индикатор прикрутить