|
Формирование сигнала определенного вида длительностью 1,5 мкс |
|
|
|
Jun 6 2008, 19:07
|

Частый гость
 
Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414

|
Доброго всем времени суток! Программирую atmga8535 с кварцем на 16 Мгц. Возникла такая задача: Имеется входной сигнал вида 1. Нужно получить сигнал вида 2:
Длительность нулевых уровней сигнала 2 - строго фиксированная и составляет 1,5 мкс. Нулевой уровень сигнала 2 должен заканчивается в момент смены фронта сигнала 1. Проблема в том, что частота сигнала 1 заранее не известна и может меняться в пределах 10-20 кГц. Думаю, что придется использовать таймер 1 и захватывать сигнал по ICP. Уважаемые эксперты, какой режим таймера выбрать? Буду очень признателен за изложение алгоритма (хотя бы на словах)!
Эскизы прикрепленных изображений
|
|
|
|
|
Jun 6 2008, 20:09
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Flasher @ Jun 7 2008, 00:00)  Итак в рамках темы обсуждаем как писать гадалок. Определимся с методами написанной гадалки- кофейная гуща, воск, карты таро, хрустальный шар, куриные кости. Какой из методов лучше выбрать? Ну это Вы опять же зазря... то что я наставил смайликов в своем сообщении еще ни к чему не обязывает... Ну а если серьезно... Если частота не меняеться скачкообразно... это стандартная задачка которую приходится решать при ловле 0 для сети, там тоже иногда хочется знать предполагаемый момент перехода через 0... так что пока обойдемся без карт таро  по крайней мере пока топикстартер точно не объяснит что ему нужно...
|
|
|
|
|
Jun 6 2008, 22:07
|

山伏
    
Группа: Свой
Сообщений: 1 827
Регистрация: 3-08-06
Из: Kyyiv
Пользователь №: 19 294

|
По маразму задачи, я так понимаю, что это ВУЗовское задание? Ну если входной сигнал заранее не известен но стационарен то...
По внешнему прерыванию начинаем считать тики "таймера". Первый перепад ничего не делаем - просто считаем, дальше работаем - уже знаем сколько "тиков" период. Смотря какой контроллер - вычитываем из DATA SHEET - что выставлять для какого таймера, Ваш не знаю и там ничего сложного, сами разберетесь. Таймер должен сосчитать и успеть сгенерить прерывание. При приходе такого-то тика выдаем импульс длительностью столько-то (опять же, меряем таймером)...
P.S.: кстати, так сразу и не посмотрел - очень короткое время этих маленьких переключений, контроллер может и не успевать (скорее всего).
--------------------
Нас помнят пока мы мешаем другим... //-------------------------------------------------------- Хороший блатной - мертвый... //-------------------------------------------------------- Нет старик, это те дроиды которых я ищу...
|
|
|
|
|
Jun 7 2008, 04:25
|
deleted
   
Группа: Свой
Сообщений: 555
Регистрация: 28-08-05
Пользователь №: 8 024

|
Если бы знал, где упаду(отрицательный перепад) , там соломки бы подстелил Цитата(Sprite @ Jun 6 2008, 22:07)  ..... Проблема в том, что частота сигнала 1 заранее не известна..... В прошлое вернуться нельзя, можно только предсказать будущее, и то, при определенных условиях и в определенных пределах...
|
|
|
|
|
Jun 7 2008, 04:29
|

Частый гость
 
Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414

|
Цитата(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 такта? Скольким тактам процессора соответствует код в прерывании?! Посмотрите свежим взглядом, может быть где ошибка допущена? Заранее благодарен!
|
|
|
|
|
Jun 7 2008, 06:35
|

Частый гость
 
Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414

|
Цитата(otrog @ Jun 7 2008, 11:47)  Для работы с временами порядка микросекунд просто необходимо писать на ассемблере, и размещать все переменные в регистрах. Если с асмом туго, рекомендую Algorithm Builder - графический ассемблер. Осваивается буквально за часы. Успехов. После компиляции программы посмотрел я lss-файл: Код ISR(TIMER1_COMPA_vect) //Прерывание по сравнению сигнала { 190: 1f 92 push r1 192: 0f 92 push r0 194: 0f b6 in r0, 0x3f; 63 196: 0f 92 push r0 198: 11 24 eor r1, r1 19a: 8f 93 push r24 19c: 9f 93 push r25 19e: ef 93 push r30 1a0: ff 93 push r31 OCR1A = bound[count]; 1a2: e0 91 68 00 lds r30, 0x0068 1a6: ff 27 eor r31, r31 1a8: ee 0f add r30, r30 1aa: ff 1f adc r31, r31 1ac: e0 5a subi r30, 0xA0; 160 1ae: ff 4f sbci r31, 0xFF; 255 1b0: 80 81 ld r24, Z 1b2: 91 81 ldd r25, Z+1; 0x01 1b4: 9b bd out 0x2b, r25; 43 1b6: 8a bd out 0x2a, r24; 42 count++; 1b8: 80 91 68 00 lds r24, 0x0068 1bc: 8f 5f subi r24, 0xFF; 255 1be: 80 93 68 00 sts 0x0068, r24 //Режим TOGGLE (инвертирование состояния вывода OC1A в последующем прерывании по сравнению) TCCR1A|=_BV(COM1A0); 1c2: 8f b5 in r24, 0x2f; 47 1c4: 80 64 ori r24, 0x40; 64 1c6: 8f bd out 0x2f, r24; 47 TCCR1A&=~_BV(COM1A1); 1c8: 8f b5 in r24, 0x2f; 47 1ca: 8f 77 andi r24, 0x7F; 127 1cc: 8f bd out 0x2f, r24; 47 1ce: ff 91 pop r31 1d0: ef 91 pop r30 1d2: 9f 91 pop r25 1d4: 8f 91 pop r24 1d6: 0f 90 pop r0 1d8: 0f be out 0x3f, r0; 63 1da: 0f 90 pop r0 1dc: 1f 90 pop r1 1de: 18 95 reti И понял, что получается полная лажа  Всего выполняется 37 asm-операций, а максимум должно быть 24. Как быть? Может лучше такой вариант?: 1) Вызывать прерывания по захвату два раза в период (т.е. по возрастающему и ниспадающему фронтам). 2) При захвате каждого фронта определять прерывания по сравнению 3) В прерывании по сравнению делать задержку на 24 такта (т.е. 24 команды "nop")
Сообщение отредактировал Sprite - Jun 7 2008, 06:35
|
|
|
|
|
Jun 7 2008, 07:05
|

Полное ничтожество
    
Группа: Banned
Сообщений: 1 991
Регистрация: 20-03-07
Из: Коломна
Пользователь №: 26 354

|
Цитата(Sprite @ Jun 7 2008, 10:35)  После компиляции программы посмотрел я lss-файл: [ И понял, что получается полная лажа  Всего выполняется 37 asm-операций, а максимум должно быть 24. Как быть? Может лучше такой вариант?: 1) Вызывать прерывания по захвату два раза в период (т.е. по возрастающему и ниспадающему фронтам). 2) При захвате каждого фронта определять прерывания по сравнению 3) В прерывании по сравнению делать задержку на 24 такта (т.е. 24 команды "nop") вопрос ребром - вы ассемблер знаете?? си всё всегда делает через стек - посмотрите сколько времени отнимают пуш и поп если писать на ассемблере всё (на си наверное тоже можно - но я его не смог выучить - не дано) можно выделить регистры специально под это и сохранять только необходимые вещи
|
|
|
|
|
Jun 7 2008, 07:44
|
Частый гость
 
Группа: Свой
Сообщений: 142
Регистрация: 18-02-08
Из: Челябинск
Пользователь №: 35 141

|
Цитата(Sprite @ Jun 7 2008, 01:07)  Доброго всем времени суток! Программирую atmga8535 с кварцем на 16 Мгц. Возникла такая задача: Имеется входной сигнал вида 1. Нужно получить сигнал вида 2:
Длительность нулевых уровней сигнала 2 - строго фиксированная и составляет 1,5 мкс. Нулевой уровень сигнала 2 должен заканчивается в момент смены фронта сигнала 1. Проблема в том, что частота сигнала 1 заранее не известна и может меняться в пределах 10-20 кГц. Думаю, что придется использовать таймер 1 и захватывать сигнал по ICP. Уважаемые эксперты, какой режим таймера выбрать? Буду очень признателен за изложение алгоритма (хотя бы на словах)! Пацаны, я конечно все понимаю, микроконтроллеры там, ассемблеры... А что, попроще решения уже никого не устраивают? Задерживаете входной сигнал на 1.5 мкс и называете задержанный сигнал входным. Для того, чтобы получить теперь сигнал вида 2, достаточно одного элемента XNOR ( например, LittleLogic от TI). Как задержать сигнал, объяснять надо?
|
|
|
|
|
Jun 7 2008, 07:50
|

Частый гость
 
Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414

|
Цитата(rv3dll(lex) @ Jun 7 2008, 14:05)  вопрос ребром - вы ассемблер знаете??
си всё всегда делает через стек - посмотрите сколько времени отнимают пуш и поп если писать на ассемблере всё (на си наверное тоже можно - но я его не смог выучить - не дано) можно выделить регистры специально под это и сохранять только необходимые вещи Спасибо за совет! Ассемблер я не знаю, но чувствую, что без него здесь не обойтись, постараюсь переписать прерывание на asm'e - скажу что получится.
|
|
|
|
|
Jun 7 2008, 08:12
|

Полное ничтожество
    
Группа: Banned
Сообщений: 1 991
Регистрация: 20-03-07
Из: Коломна
Пользователь №: 26 354

|
Цитата(Ledmaster @ Jun 7 2008, 11:44)  Пацаны, я конечно все понимаю, микроконтроллеры там, ассемблеры... А что, попроще решения уже никого не устраивают? Задерживаете входной сигнал на 1.5 мкс и называете задержанный сигнал входным. Для того, чтобы получить теперь сигнал вида 2, достаточно одного элемента XNOR ( например, LittleLogic от TI). Как задержать сигнал, объяснять надо?  я бы тоже на плисине сделал на самой дохлой тока задача судя по всему про контроллер
|
|
|
|
|
Jun 7 2008, 09:40
|
Частый гость
 
Группа: Свой
Сообщений: 142
Регистрация: 18-02-08
Из: Челябинск
Пользователь №: 35 141

|
Цитата(rv3dll(lex) @ Jun 7 2008, 14:12)  я бы тоже на плисине сделал на самой дохлой тока задача судя по всему про контроллер Ну, ради бога, пусть на контроллере, принцип тот же самый: формируем задержанный сигнал, который далее считаем входным. Для этого падаем в прерывание по фронту/спаду, тупо формируем там импульс 1.5мкс без всяких таймеров, просто по времени выполнения последовательности команд типа OutPort1 = 0 NOP NOP ... OutPort1 = 1 затем формируем задержанную копию входного сигнала OutPort2 = InPort1 Естественно, такой подход неприменим, если требуется реакция на опережение в реальном времени
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|