Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Формирование сигнала определенного вида длительностью 1,5 мкс
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему
Sprite
Доброго всем времени суток! Программирую atmga8535 с кварцем на 16 Мгц.
Возникла такая задача:

Имеется входной сигнал вида 1.
Нужно получить сигнал вида 2:

Нажмите для просмотра прикрепленного файла

Длительность нулевых уровней сигнала 2 - строго фиксированная и составляет 1,5 мкс. Нулевой уровень сигнала 2 должен заканчивается в момент смены фронта сигнала 1.
Проблема в том, что частота сигнала 1 заранее не известна и может меняться в пределах 10-20 кГц.
Думаю, что придется использовать таймер 1 и захватывать сигнал по ICP.
Уважаемые эксперты, какой режим таймера выбрать?
Буду очень признателен за изложение алгоритма (хотя бы на словах)!
Flasher
Алгоритм простой- берем гадалку и пусть она говорит когда нужно начинать выдавать ноль на втором сигнале. Если гадалка правильная, то ровно через 1,5 мкс произойдет смена уровня первого сигнала.
singlskv
Цитата(Flasher @ Jun 6 2008, 23:26) *
Алгоритм простой- берем гадалку и пусть она говорит когда нужно начинать выдавать ноль на втором сигнале. Если гадалка правильная, то ровно через 1,5 мкс произойдет смена уровня первого сигнала.
Ну зря Вы так про гадалку... smile.gif Взять то ее не откудаю... smile.gif
поэтому предлагаю другой вариант, пишем(на С или асм) гадалку, которая будет "предсказывать"
когда же этот переход должен был бы произойти... smile.gif
Flasher
Итак в рамках темы обсуждаем как писать гадалок. Определимся с методами написанной гадалки- кофейная гуща, воск, карты таро, хрустальный шар, куриные кости. Какой из методов лучше выбрать?
singlskv
Цитата(Flasher @ Jun 7 2008, 00:00) *
Итак в рамках темы обсуждаем как писать гадалок. Определимся с методами написанной гадалки- кофейная гуща, воск, карты таро, хрустальный шар, куриные кости. Какой из методов лучше выбрать?
Ну это Вы опять же зазря...
то что я наставил смайликов в своем сообщении еще ни к чему не обязывает...

Ну а если серьезно...

Если частота не меняеться скачкообразно... это стандартная задачка которую
приходится решать при ловле 0 для сети, там тоже иногда хочется
знать предполагаемый момент перехода через 0...
так что пока обойдемся без карт таро smile.gif
по крайней мере пока топикстартер точно не объяснит что ему нужно...
DRUID3
По маразму задачи, я так понимаю, что это ВУЗовское задание? Ну если входной сигнал заранее не известен но стационарен то...

По внешнему прерыванию начинаем считать тики "таймера". Первый перепад ничего не делаем - просто считаем, дальше работаем - уже знаем сколько "тиков" период. Смотря какой контроллер - вычитываем из DATA SHEET - что выставлять для какого таймера, Ваш не знаю и там ничего сложного, сами разберетесь. Таймер должен сосчитать и успеть сгенерить прерывание. При приходе такого-то тика выдаем импульс длительностью столько-то (опять же, меряем таймером)...

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

если сигнал периодический пусть даже с изменением частоты -то

по входному сигналу измерять непрерывно длительность а потом исходя из дилтельности за вычетом ваших полтора отсчитывать от фронта и менять сигнал на выходе

по фронту менять обратно

- усё a14.gif
INT1
Если бы знал, где упаду(отрицательный перепад) , там соломки бы подстелил
Цитата(Sprite @ Jun 6 2008, 22:07) *
.....
Проблема в том, что частота сигнала 1 заранее не известна.....

В прошлое вернуться нельзя, можно только предсказать будущее, и то, при определенных условиях и в определенных пределах...
Sprite
Цитата(domowoj @ Jun 7 2008, 08:35) *
Что-то подобное делал на частоте 100Гц.
В вашем случае входной сигнал - на ITNx, меряете интервал от фронта до фронта в "тиках",
вычитаете из измеренного 1,5 мкс в тиках(при тактовой 16МГц- это число 24), полученное число в
OCRx и по прерыванию от OCRx формируете на вых. импульс.
Перый импульс пропадает.


Действительно реальный совет! a14.gif
И к гадалкам не надо обращаться! smile.gif

Одна немаловажная поправка:
Нажмите для просмотра прикрепленного файла

В моменты времени 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 такта, что очень малоsad.gif
Я не особо силен в ассемблере, и пока не знаю: успеет ли обработаться прерывание по сравнению за 24 такта? Скольким тактам процессора соответствует код в прерывании?!
Посмотрите свежим взглядом, может быть где ошибка допущена?
Заранее благодарен!
otrog
Для работы с временами порядка микросекунд просто необходимо писать на ассемблере, и размещать все переменные в регистрах.
Если с асмом туго, рекомендую Algorithm Builder - графический ассемблер. Осваивается буквально за часы.
Успехов.
Sprite
Цитата(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


И понял, что получается полная лажа sad.gif
Всего выполняется 37 asm-операций, а максимум должно быть 24. Как быть?

Может лучше такой вариант?:
1) Вызывать прерывания по захвату два раза в период (т.е. по возрастающему и ниспадающему фронтам).
2) При захвате каждого фронта определять прерывания по сравнению
3) В прерывании по сравнению делать задержку на 24 такта (т.е. 24 команды "nop")
rv3dll(lex)
Цитата(Sprite @ Jun 7 2008, 10:35) *
После компиляции программы посмотрел я lss-файл:
[
И понял, что получается полная лажа sad.gif
Всего выполняется 37 asm-операций, а максимум должно быть 24. Как быть?

Может лучше такой вариант?:
1) Вызывать прерывания по захвату два раза в период (т.е. по возрастающему и ниспадающему фронтам).
2) При захвате каждого фронта определять прерывания по сравнению
3) В прерывании по сравнению делать задержку на 24 такта (т.е. 24 команды "nop")


вопрос ребром - вы ассемблер знаете??

си всё всегда делает через стек - посмотрите сколько времени отнимают пуш и поп
если писать на ассемблере всё (на си наверное тоже можно - но я его не смог выучить - не дано) можно выделить регистры специально под это и сохранять только необходимые вещи
Ledmaster
Цитата(Sprite @ Jun 7 2008, 01:07) *
Доброго всем времени суток! Программирую atmga8535 с кварцем на 16 Мгц.
Возникла такая задача:

Имеется входной сигнал вида 1.
Нужно получить сигнал вида 2:

Нажмите для просмотра прикрепленного файла

Длительность нулевых уровней сигнала 2 - строго фиксированная и составляет 1,5 мкс. Нулевой уровень сигнала 2 должен заканчивается в момент смены фронта сигнала 1.
Проблема в том, что частота сигнала 1 заранее не известна и может меняться в пределах 10-20 кГц.
Думаю, что придется использовать таймер 1 и захватывать сигнал по ICP.
Уважаемые эксперты, какой режим таймера выбрать?
Буду очень признателен за изложение алгоритма (хотя бы на словах)!

Пацаны, я конечно все понимаю, микроконтроллеры там, ассемблеры...
А что, попроще решения уже никого не устраивают? 07.gif
Задерживаете входной сигнал на 1.5 мкс и называете задержанный сигнал входным.
Для того, чтобы получить теперь сигнал вида 2, достаточно одного элемента XNOR ( например, LittleLogic от TI).
Как задержать сигнал, объяснять надо? rolleyes.gif
Sprite
Цитата(rv3dll(lex) @ Jun 7 2008, 14:05) *
вопрос ребром - вы ассемблер знаете??

си всё всегда делает через стек - посмотрите сколько времени отнимают пуш и поп
если писать на ассемблере всё (на си наверное тоже можно - но я его не смог выучить - не дано) можно выделить регистры специально под это и сохранять только необходимые вещи


Спасибо за совет! Ассемблер я не знаю, но чувствую, что без него здесь не обойтись, постараюсь переписать прерывание на asm'e - скажу что получится.
rv3dll(lex)
Цитата(Ledmaster @ Jun 7 2008, 11:44) *
Пацаны, я конечно все понимаю, микроконтроллеры там, ассемблеры...
А что, попроще решения уже никого не устраивают? 07.gif
Задерживаете входной сигнал на 1.5 мкс и называете задержанный сигнал входным.
Для того, чтобы получить теперь сигнал вида 2, достаточно одного элемента XNOR ( например, LittleLogic от TI).
Как задержать сигнал, объяснять надо? rolleyes.gif


я бы тоже на плисине сделал на самой дохлой тока задача судя по всему про контроллер
MrYuran
Я знаю как надо поступить.

1. засекаем входной период (таймером, через ICP или как его там)
2. вычисляем 2 константы - время установки вых. сигнала и время сброса (в тиках таймера).
3. таймер работает в непрерывном режиме
4. заносим наши константы в регистры сравнения А и В.
5. настраиваем так чтобы по 1-му совпадению сигнал на выходе устанавливался, а по 2-му - сбрасывался.
6. это всё непрерывно в цикле.
7. вуаля!
Ledmaster
Цитата(rv3dll(lex) @ Jun 7 2008, 14:12) *
я бы тоже на плисине сделал на самой дохлой тока задача судя по всему про контроллер

Ну, ради бога, пусть на контроллере, принцип тот же самый: формируем задержанный сигнал, который далее считаем входным. Для этого падаем в прерывание по фронту/спаду, тупо формируем там импульс 1.5мкс без всяких таймеров, просто по времени выполнения последовательности команд типа

OutPort1 = 0
NOP
NOP
...
OutPort1 = 1

затем формируем задержанную копию входного сигнала

OutPort2 = InPort1


Естественно, такой подход неприменим, если требуется реакция на опережение в реальном времени
Sprite
Цитата(MrYuran @ Jun 7 2008, 15:44) *
Я знаю как надо поступить.

1. засекаем входной период (таймером, через ICP или как его там)
2. вычисляем 2 константы - время установки вых. сигнала и время сброса (в тиках таймера).
3. таймер работает в непрерывном режиме
4. заносим наши константы в регистры сравнения А и В.
5. настраиваем так чтобы по 1-му совпадению сигнал на выходе устанавливался, а по 2-му - сбрасывался.
6. это всё непрерывно в цикле.
7. вуаля!


Вот оно! то, что надо!
Сделал как вы посоветовали - проблема решилась!
Респект!
a14.gif a14.gif a14.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.