Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопрос по режиму захвата таймера Т1
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
straighter
Уважаемые форумчане, помогите разобраться... 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.
Пробовал разные частоты синусоиды - то же самое.
В чем причина?

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

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; Здесь все правильно и понятно:

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

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

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

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

Нажмите для просмотра прикрепленного файла
aiwa
Попробуйте заменить delay_us на что-то более конкретное, чтобы убедиться, что ее реализация не разрешает прерывания.
straighter
Попробую сделать без delay_us, например так: PORTC.1=1; PORTC.1=0;
aiwa
Тогда осцилограммы не будет.
Если используете 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;
  };
straighter
Спасибо за ответ. Только я не совсем понял, в какое место моей программы вставить приведенный фрагмент кода:

Код

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

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

вставить
while(1)
{
#asm("cli")
unsigned int f_test=f;
#asm("sei")
if(f_test<(d+1)) break;
}
чтобы сделать вычитку двухбайтной переменной f "атомарной" операцией.
straighter
Сделал так и почему-то исчезли импульсы на PORTC.2 (d = 256). Но идею насчет "атомарной" операции понял. Буду думать...
aiwa
Цитата(straighter @ Apr 1 2016, 15:19) *
Сделал так и почему-то исчезли импульсы на PORTC.2 (d = 256). Но идею насчет "атомарной" операции понял. Буду думать...

Извините, я забыл поменять знак в теле замене цикла c '<' на '>='
Код
while(1)
{
#asm("cli")
unsigned int f_test=f;
#asm("sei")
if(f_test>=(d+1)) break;
}

Из-за этого выход из цикла происходит сразу же.
straighter
Большое спасибо, получилось!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.