Jump to content

    
Sign in to follow this  
straighter

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

Recommended Posts

Уважаемые форумчане, помогите разобраться... 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

Share this post


Link to post
Share on other sites

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

Если используете 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;
  };

Edited by aiwa

Share this post


Link to post
Share on other sites

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

 

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

 

Share this post


Link to post
Share on other sites

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

 

вставить

while(1)

{

#asm("cli")

unsigned int f_test=f;

#asm("sei")

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

}

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

Share this post


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

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

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

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this