Перейти к содержанию
    

Вопрос по режиму захвата таймера Т1

Уважаемые форумчане, помогите разобраться... ATmega8 работает с кварцем 8 Мгц. На вход встроенного компаратора подаю синусоиду 20 кГц от стабильного генератора. По положительному перепаду на выходе компаратора происходит захват значения в Timer/Counter1. Возникает прерывание, значение f увеличивается на 1. Когда f достигает значения d, то PORTC.2 устанавливается в 1 на время 10мкс, а затем снова устанавливается в 0. После этого в основном цикле программы PORTC.3 устанавливается в 1 на время 10мкс, а затем снова устанавливается в 0.

Когда я задаю значение d меньше или равное 255, то все работает нормально, после каждого импульса на выходе PORTC.2 возникает импульс выходе PORTC.3, как и должно быть. Но если я задаю значение d больше или равное 256, то импульсы на выходе PORTC.3 так и продолжают идти, но не каждому из них предшествует импульс на выходе PORTC.2.

Пробовал разные частоты синусоиды - то же самое.

В чем причина?

 

Фрагмент кода:

unsigned int d=255;    // Заданное кол-во НЧ-периодов счета (кол-во сработок компаратора)

unsigned int f;    // Текущее кол-во НЧ-периодов счета (кол-во сработок компаратора)

// Timer1 input capture interrupt service routine
interrupt [TIM1_CAPT] void timer1_capt_isr(void)
{
// Place your code here

PORTC.0=1;
delay_us(10);
PORTC.0=0;                                                                     

if (f==1) {    

PORTC.1=1;
delay_us(10);
PORTC.1=0;

};

if (f==(d)) {

PORTC.2=1;
delay_us(10);
PORTC.2=0;

};

f=f+1;  

}

void main(void)
{

f=0;

// Global enable interrupts
#asm("sei")

while (1)
     {
     // Place your code here  

      while (f<(d+1));  

       #asm("cli")

      PORTC.3=1;
      delay_us(10);
      PORTC.3=0;          

         delay_us(100);

      PORTC.4=1;
      delay_us(10);
      PORTC.4=0;   

              f=0;

           #asm("sei") 

     };
}

 

Осциллограммы :

 

d=255; синий цвет - вых. РС2; желт. цвет - вых. РС3; Здесь все правильно и понятно:

 

post-72555-1459347291_thumb.jpg

 

d=256; синий цвет - вых. РС2; желт. цвет - вых. РС3; Видно, что нет импульса на РС2, а соответствующий импульс на РС3 есть:

 

post-72555-1459347300_thumb.jpg

 

Желт. цвет - сигнал на входе компаратора; синий цвет - на вых. РС0 (смотри код программы):

 

post-72555-1459347372_thumb.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Попробуйте заменить delay_us на что-то более конкретное, чтобы убедиться, что ее реализация не разрешает прерывания.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тогда осцилограммы не будет.

Если используете IAR, в нем есть удобная псевдофункция delay_cycles(const unsigned long ) - задержка на заданное количество тактов.

Либо просто пустые вложенные циклы.

 

 

Тут два возможных варианта:

Первый:

1. При выполнении оператора

while (f<(d+1));

когда значение f = 255 = [00,FF]

1. процессор загружает младший байт FF в регистр

срабатывает прерывание и увеличивает значение (f = f+1) f = 256 = [01,00]

2. процессор загружает старший байт в регистр, а теперь он уже 01, а не 00.

поэтому значение в регистах стало [01,FF] = 511, а не 256 как на самом деле.

Происходит выход из цикла while на стадии когда счетчик равен 256

 

Второй:

и второй вариант если delay_us разрешает прерывания, а на компараторе

происходит шумок.

 

Какой из них нужно судить по частоте возникновения эффекта.

 

Наверное быстрее переделать сравнение для первого варианта

  while (1)
  {
    #asm("cli")
        unsigned int f_test=f; 
    #asm("sei")
     if(f_test<(d+1)) break;
  };

Изменено пользователем aiwa

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо за ответ. Только я не совсем понял, в какое место моей программы вставить приведенный фрагмент кода:

 

 
    #asm("cli")
        unsigned int f_test=f; 
    #asm("sei")
     if(f_test<(d+1)) break;

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

вместо while (f<(d+1));

 

вставить

while(1)

{

#asm("cli")

unsigned int f_test=f;

#asm("sei")

if(f_test<(d+1)) break;

}

чтобы сделать вычитку двухбайтной переменной f "атомарной" операцией.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сделал так и почему-то исчезли импульсы на PORTC.2 (d = 256). Но идею насчет "атомарной" операции понял. Буду думать...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сделал так и почему-то исчезли импульсы на PORTC.2 (d = 256). Но идею насчет "атомарной" операции понял. Буду думать...

Извините, я забыл поменять знак в теле замене цикла c '<' на '>='

while(1)
{
#asm("cli")
unsigned int f_test=f;
#asm("sei")
if(f_test>=(d+1)) break;
}

Из-за этого выход из цикла происходит сразу же.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...