Вопрос по прерываниям

Buldakov
Offline
Зарегистрирован: 17.01.2016

Подаю сигнал на INT0. Настраиваю прерывание на фронт импульса - все работает.

EIMSK  =  (1<<INT0);
EICRA=(1<<ISC01);

Подаю сигнал на INT1. Настраиваю прерывание на фронт импульса - все работает.

EIMSK  =  (1<<INT1);
EICRA=(1<<ISC11);

Вопрос. Как настроить прерывание INT0 по фронту, а INT1 по спаду импульса. При этом INT0 и INT1 соединены между собой. Что прописать в регистр EICRA?

EIMSK  =  (1<<INT0)  | (1<<INT1);// разрешение прерываний INT0 и INT1

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Опять вы что-то мудрите :) Один бит ICS01 -это спад импульса. Что бы был подъём нужны оба бита. Вот всё вместе:

EICRA=(1<<ICS01)|(1<<ICS00)|(1<<ICS11);
EIMSK=(1<<INT1)|(1<<INT0);
 

Buldakov
Offline
Зарегистрирован: 17.01.2016

Спасибо.

EIMSK  =  (1<<INT0)  | (1<<INT1);                             //разрешение прерываний INT0 и INT1
EICRA  =  (1<<ISC01) | (1<<ISC00) | (1<<ISC11) | (0<<ISC10);  //настройка INT0 по фронту INT1 по спаду

 

Buldakov
Offline
Зарегистрирован: 17.01.2016

Необходимо измерить скважность прямоугольных импульсов. Входную частоту подаем на входы INT0 и INT1. INT0 настроен на срабатывание по фронту импульса. INT1 настроен на срабатывание по спаду импульса. Таймер 1 считает количество тактовых импульсов генератора до значения 4000, а затем сбрасывается и считается количество переполнений. По фронту импульса мы считаем значение переменной : t_start. По спаду импульса мы считаем значение переменной : t_stop. В переменной : t_imp - мы получаем значение суммарного времени длительности импульса. Зная  t_imp и длительность импульса + длительность паузы мы можем найти скважность.

Переодически длительность импульса t_imp. становится на значение кратное 4000 больше. Вероятно это связано с тем, что приоритет внешних прерываний выше, чем приорител таймера 1. Допустим сработало INT1 , а после этого прерывание по таймеру.  В прерывании INT1 мы считываем значение количества переполнений таймера 1, но поскольку переполнение таймера 1 наступило,  а прерывание еще нет - мы теряем 1 импульс переполнения таймера 1.

Как можно обойти данную ситуацию?

//---Прерывание по int 0------------------------
ISR (INT0_vect){                               
  if (start_for_timer_1==1  && flag_LED==0)     
  {                                             
  TCNT1=0;TCCR1B = (1 << CS10)|(1<<WGM12);     
  t_start=0;t_imp=0;                            
  start_for_timer_1=0;ovf_tic_timer_1=0;ovf_tic_int_0=0;
  }                                         
  if (stop_for_timer_1==1  && flag_LED==0)     
  {                                             
  TCCR1B=0;                                      
  out_TCNT1=TCNT1;                             
  TCNT1=0;  //сброс счётных регистров          
  out_ovf_tic_int_0=ovf_tic_int_0;ovf_tic_int_0=0;
  out_ovf_tic_timer_1=ovf_tic_timer_1;ovf_tic_timer_1=0;
  flag_LED=1;stop_for_timer_1=0;                     
  }                                                    
  if (start_for_timer_1==0 && stop_for_timer_1==0 && flag_LED==0)
  {                                                  
  ovf_tic_int_0=ovf_tic_int_0+1;                    
  start_n2=TCNT1;start_n1=ovf_tic_timer_1;                
  }                                                    
}                                                      
//---Прерывание по int 1-----------------------
ISR (INT1_vect){
  stop_n2=TCNT1;stop_n1=ovf_tic_timer_1;
  t_start=(unsigned long)start_n1*4000+start_n2;
  t_stop =(unsigned long)stop_n1 *4000+stop_n2;
  t_imp=t_imp+(t_stop-t_start);
}
//---Прерывание по таймеру 1-------------------
ISR(TIMER1_COMPA_vect) {  // timer compare interrupt service routine
ovf_tic_timer_1=ovf_tic_timer_1+1; //считать количество переполнений таймера 1
if (ovf_tic_timer_1>=interval_izm && flag_LED==0)stop_for_timer_1=1;
}

 

Buldakov
Offline
Зарегистрирован: 17.01.2016

Дальше вопрос по прерываниям.

Допустим я подаю внешний сигнал на INT0 как прерывание с самым высоким приоритетом. Если никакого прерывания в этот момент не исполняется то мы переходим сразу к выполнению INT0. Если выполняется другое прерывание, то INT0  начнет выполняться только после завершения текущего прерывания.

Как мне сделать так, чтобы прерывание по INT0 выполнялось только при отсутствии выполнения в данный момент другого прерывания?  А если выполняется другое прерывание (например прерывание от таймера 0), то игнорировать прерывание INT0? Есть ли какой нибудь флаг для этих целей?

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Вроде ж у AVR нет приоритета прерываний? (ошибся, приоритет есть у ожидающих в очереди прерываний). Если во время срабатывания прерывания уже обрабатывается другое прерывание - только выставляется флаг сработавшего прерывания и оно ждёт, пока не завершится первое. И уже потом обработается второе, после чего флаг сбросится. То есть, в порядке очереди.

UPD: А, понял. Вы хотите, чтобы прерывание INT0 вообще не обрабатывалось, даже после завершения другого прерывания. Тогда вариант: в конце обработчика уже выполняющегося прерывания проверять флаг прерывания INT0. И если он выставлен - сбрасывать его.

ATmega48A/PA/88A/PA/168A/PA/328/P
 
• Bit 1 – INTF1: External Interrupt Flag 1
When an edge or logic change on the INT1 pin triggers an interrupt request, INTF1 becomes set (one). If the I-bit in
SREG and the INT1 bit in EIMSK are set (one), the MCU will jump to the corresponding Interrupt Vector. The flag
is cleared when the interrupt routine is executed. Alternatively, the flag can be cleared by writing a logical one to it.
This flag is always cleared when INT1 is configured as a level interrupt.
 
• Bit 0 – INTF0: External Interrupt Flag 0
When an edge or logic change on the INT0 pin triggers an interrupt request, INTF0 becomes set (one). If the I-bit in
SREG and the INT0 bit in EIMSK are set (one), the MCU will jump to the corresponding Interrupt Vector. The flag
is cleared when the interrupt routine is executed. Alternatively, the flag can be cleared by writing a logical one to it.
This flag is always cleared when INT0 is configured as a level interrupt.
Buldakov
Offline
Зарегистрирован: 17.01.2016

Jeka_M пишет:

Вроде ж у AVR нет приоритета прерываний? (ошибся, приоритет есть у ожидающих в очереди прерываний). Если во время срабатывания прерывания уже обрабатывается другое прерывание - только выставляется флаг сработавшего прерывания и оно ждёт, пока не завершится первое. И уже потом обработается второе, после чего флаг сбросится. То есть, в порядке очереди.

UPD: А, понял. Вы хотите, чтобы прерывание INT0 вообще не обрабатывалось, даже после завершения другого прерывания. Тогда вариант: в конце обработчика уже выполняющегося прерывания проверять флаг прерывания INT0. И если он выставлен - сбрасывать его.

спасибо за ответ.

Да я имел ввиду именно очерередь в ожидании.

У меня немного другой случай. У меня INT0 вызывается приходом внешнего сигнала. (Если сейчас никакого другого прерывания не выполняется). Если другое прерывание уже выполняется - то прерывание по INT0 не должно обрабатываться. Доступа к текущему прерыванию у меня нет.(например:текущее прерывание по таймеру 0 который считает время. И остановить Таймер 0 мне не нужно.)

Мне надо в обработчик прерываний INT0 вставить проверку, что прерывание по таймеру 0 (в момент подачи сигнала на INT0) в данный момент не выполняется.

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Или я чего-то не пойму, или лыжи не едут... У Вас же есть обработчик прерывания от таймера? Почему Вы не хотите в нём проверять и сбрасывать флаг INTF0?

Цитата:

Доступа к текущему прерыванию у меня нет.(например:текущее прерывание по таймеру 0 который считает время. И остановить Таймер 0 мне не нужно.)

В смысле нет доступа? Обработчик прерывания таймера есть, в котором выполняется некий код. В нём и делайте проверку в самом конце, ничего останавливать не нужно.

 

Buldakov
Offline
Зарегистрирован: 17.01.2016

Вот такой код пока имею. У меня прерывание по INT0 иногда срабатывает на 10 тактов позднее или раньше чем надо. Есть подозрение что переход на прерывание INT0 задерживается из за выполнения какого нибудь другого прерывания.

 

//Пин 2 вход измерителя частоты. 16.07.2016                                                                                        //
//---------------------------------------------------------------------------------------------------------------------------------//
#include <Wire.h>                                                                                                                  //
#include <LiquidCrystal_I2C.h>                                                                                                     //
//---------------------------------------------------------------------------------------------------------------------------------//
LiquidCrystal_I2C lcd(0x27, 16, 2); // Для экрана 16х2 (двухстрочный)                                                              //
//---------------------------------------------------------------------------------------------------------------------------------//
unsigned long interval_izm     =  1000;  //Время счета входной частоты в  миллисекундах                                            //
unsigned long interval_LCD     =  1000;  //Интервал смены показаний на LCD в миллисекундах                                         //
unsigned long lastTime_LCD     =     0;  //Время последнего изменения состояния для LCD в миллисекундах                            //
unsigned long DeltaTime_LCD    =     0;  //Время с момента последнего вывода на LCD в миллисекундах                                //
unsigned long currentTime      =     0;  //Текущее время в милисекундах                                                            //
//---------------------------------------------------------------------------------------------------------------------------------//
unsigned int  ovf_tik_int_0;                                                                                                       //
unsigned int  ovf_tik_timer_1;                                                                                                     //
unsigned int  interval_timer_1;                                                                                                    //
unsigned long tik_int_0,tik_timer_1;                                                                                               //
boolean       stop_for_timer_1,start_for_timer_1,flag_LED;                                                                         //
float f,t1;                                                                                                                        //
//---------------------------------------------------------------------------------------------------------------------------------//
void setup() {                                                                                                                     //
Serial.begin(9600);                                                                                                                //
lcd.init();                             //Задаем размерность LCD дисплея                                                           //
lcd.backlight();                        //Включаем подсветку экрана                                                                //
lcd.clear();                            //Очистка экрана                                                                           //
pinMode(2, INPUT);                      //Вывод 2 в режим ввода                                                                    //
digitalWrite(2, HIGH);                  //Включаем подтягивающий резистор                                                          //
//---------------------------------------------------------------------------------------------------------------------------------//
delay(1000);                            //Ждем 1 секунду                                                                           //
lcd.setCursor(0, 0);                                                                                                               //
lcd.print("Ver 16.08.2016");                                                                                                       //
delay(1000);                            //Ждем 1 секунду                                                                           //
//---Настройка прерывания int 0----------------------------------------------------------------------------------------------------//
EIMSK  =  (1<<INT0);                    // разрешение прерываний INT0                                                              //
EICRA  =  (1<<ISC01) | (1<<ISC00);      //настройка INT0 по фронту                                                                 //
//---Настройка таймера 1-----------------------------------------------------------------------------------------------------------//
TCCR1A = 0;                                                                                                                        //
TCCR1B = 0;                                                                                                                        //
TCNT1  = 0;                                                                                                                        //
OCR1A=63999; //отсчитать 64 000 входных импульсов до прерывания                                                                    //
TCCR1B = (1 << CS10)|(1<<WGM12); //(CS10)Коэффициент предделителя 1 (WGM12)CTC mode                                                //
TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt                                                                        //
//---------------------------------------------------------------------------------------------------------------------------------//
interval_timer_1=(unsigned int)interval_izm/4;                                                                                     //
//---------------------------------------------------------------------------------------------------------------------------------//
}                                                                                                                                  //
//---Прерывание по int 0-----------------------------------------------------------------------------------------------------------//
ISR (INT0_vect){                                                                                                                   //
if (start_for_timer_1==1 && flag_LED==0) {TCNT1=0;TCCR1B =(1<<CS10)|(1<<WGM12);start_for_timer_1=0;ovf_tik_timer_1=0;ovf_tik_int_0=0;}//
if ( stop_for_timer_1==1                        && flag_LED==0){TCCR1B=0;stop_for_timer_1=0;flag_LED=1;}                           //
if (start_for_timer_1==0 && stop_for_timer_1==0 && flag_LED==0){ovf_tik_int_0=ovf_tik_int_0+1;}                                    //
}                                                                                                                                  //
//---Прерывание по таймеру 1-------------------------------------------------------------------------------------------------------//
ISR(TIMER1_COMPA_vect) {  // timer compare interrupt service routine                                                               //
ovf_tik_timer_1=ovf_tik_timer_1+1; //считать количество переполнений таймера 1                                                     //
if (ovf_tik_timer_1>=interval_timer_1 && flag_LED==0)stop_for_timer_1=1;                                                           //
}                                                                                                                                  //
void loop()                                                                                                                        //
{                                                                                                                                  //
//---Условия для вывода показаний на LCD-------------------------------------------------------------------------------------------//
currentTime=millis();                                                                                                              //
DeltaTime_LCD  =abs(currentTime - lastTime_LCD);      //Время с момента последнего вывода на LCD                                   //
if (DeltaTime_LCD >= interval_LCD && flag_LED==1)     //Условия вывода на LCD                                                      //
{                                                                                                                                  //
//---------------------------------------------------------------------------------------------------------------------------------//
tik_timer_1=(unsigned long)ovf_tik_timer_1*64000+TCNT1;                                                                            //
tik_int_0  =(unsigned long)ovf_tik_int_0;                                                                                          //
t1=(float)tik_timer_1/tik_int_0;                                                                                                   //
f=1000000/(t1*0.0625);                                                                                                             //
//---------------------------------------------------------------------------------------------------------------------------------//
Serial.print("ovf_tic1=");Serial.print(tik_timer_1);Serial.print(" ,");                                                            //
Serial.print("  tik_int_0 =") ;Serial.print(tik_int_0)     ;Serial.print(" n.");                                                   //
Serial.print("  f  =") ;Serial.print(f,5)        ;Serial.println(" Hz");                                                           //
//---------------------------------------------------------------------------------------------------------------------------------//
lcd.clear();                            //Очистка экрана                                                                           //
lcd.setCursor(0, 0);lcd.print(tik_timer_1);                                                                                        //
lcd.setCursor(9 ,0);lcd.print(tik_int_0);                                                                                          //
lcd.setCursor(0 ,1);lcd.print(f,2);lcd.print(" Hz");                                                                               //
//---------------------------------------------------------------------------------------------------------------------------------//
lastTime_LCD = currentTime;                                                                                                        //
flag_LED=0;             //Сигнал об окончании вывода на индикатор                                                                  //
start_for_timer_1=1;                                                                                                               //
}                                                                                                                                  //
//---------------------------------------------------------------------------------------------------------------------------------//
}                                                                                                                                  //
//---------------------------------------------------------------------------------------------------------------------------------//

 

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Buldakov пишет:

Вот такой код пока имею. У меня прерывание по INT0 иногда срабатывает на 10 тактов позднее или раньше чем надо. 

Ну позднее понятно - ждёт очереди, если выполняется другое прерывание (от таймера). А как оно может быть раньше?

Buldakov пишет:

Есть подозрение что переход на прерывание INT0 задерживается из за выполнения какого нибудь другого прерывания.

Ну у Вас только от таймера другое прерывание, больше ведь нет.

Вот в обработчик прерывания от таймера добавил проверку флага прерывания INT0. Должно быть как Вы и хотели: в самом конце обработчика таймера проверяется, не пришло ли прерывание по INT0. Если пришло - то флаг сбрасывается, соответственно после выхода из обработчика таймера - МК не должен будет перейти в обработчик INT0.

ISR(TIMER1_COMPA_vect) {  // timer compare interrupt service routine
  ovf_tik_timer_1++; //считать количество переполнений таймера 1
  if (ovf_tik_timer_1>=interval_timer_1 && flag_LED==0) 
  {
    stop_for_timer_1=1;
  }
  if (EIFR & _BV(INTF0)) // проверяем, установлен ли флаг
  {
    EIFR = _BV(INTF0); // если установлен, то сбрасываем записью единички
  }
}

 

MagicianT
Offline
Зарегистрирован: 03.10.2015

Цитата:
Ну у Вас только от таймера другое прерывание, больше ведь нет.

Serial тоже на прерываниях, насколько я знаю, и millis() скорее всего не без этого. И чего там в lcd. надо посмотреть. 

Прерываний до хрена может быть. Мне кажется, подход надо другой, если задержки не избежать, то данные фильтровать надо. Мне лень код сейчас писать, но что-то типа медианного фильтра. Если автору известно, что прерывание запоздало на 10 тактов, то легко отбросить данные которые не вписываются в предсказаные.

Buldakov
Offline
Зарегистрирован: 17.01.2016

Всем спасибо попробую , что получится.

По поводу того, что прерывание приходит раньше или позже. У меня фронт и спад количества импульсов приходит на INT0. Если прерывание попадает на фронт импульса - то длительность уменьшается на время выполнения выхода из прерывания (обычно 10 тактов). Если попадает на спад импульса - то длительность увеличивается.

По поводу фильтрации это отдельная тема. В том то и дело, что я не знаю насколько тактов произойдет запаздывание. Обычно это  от 2 до 10 тактов  каждое десятое измерение. Но бывает и запаздывание на 100 тактов примерно раз в минуту.

MagicianT
Offline
Зарегистрирован: 03.10.2015

 Предсказания не нужно, это не как у мп3. Я не правильно обрисовал, медианный фильтр работает по мажоритарной системе, те значения которых больше всего- правильные. Остальные можно отбросить. Логика простая, если значения все одинаковые, то выбросив 50% ничего не изменится, а вот если в тех 50% отбрасываемых будут сильно крывые данные, то они не смогут испортить последующее усреднение результата.

http://learn.linksprite.com/programming-languages/c/median-filtering-method-for-pcduinoarduino-2/

Buldakov
Offline
Зарегистрирован: 17.01.2016

MagicianT пишет:

 Предсказания не нужно, это не как у мп3. Я не правильно обрисовал, медианный фильтр работает по мажоритарной системе, те значения которых больше всего- правильные. Остальные можно отбросить. Логика простая, если значения все одинаковые, то выбросив 50% ничего не изменится, а вот если в тех 50% отбрасываемых будут сильно крывые данные, то они не смогут испортить последующее усреднение результата.

http://learn.linksprite.com/programming-languages/c/median-filtering-method-for-pcduinoarduino-2/

Этот вариант пока не прокатит. Допустим у меня сейчас есть частота 20.004123 гц. Поскольку я подаю ее с кварца. И для этого случая я могу применить фильтр. Теперь представим, что у меня не кварц а ГУН. и мне надо поймать секундное изменение частоты между 20.004123 и 20.004122. В данном случае ваш метод не подходит.

Buldakov
Offline
Зарегистрирован: 17.01.2016

Поменял код.

Данные частоты которые были до исправления кода.

  f  =20.004123 Hz
  f  =20.004138 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004127 Hz
  f  =20.004119 Hz
  f  =20.004123 Hz
  f  =20.004117 Hz
  f  =20.004119 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004133 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004081 Hz
  f  =20.004024 Hz
  f  =20.004127 Hz
  f  =20.004121 Hz
  f  =20.004119 Hz
  f  =20.004121 Hz
  f  =20.004129 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
 

После добавления кода.

  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004129 Hz
  f  =20.004133 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004127 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004131 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004137 Hz
  f  =20.004129 Hz
  f  =20.004123 Hz
  f  =20.004133 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004123 Hz
  f  =20.004114 Hz
  f  =20.004123 Hz
  f  =20.004129 Hz

Результат стал лучше но все равно есть выбросы.

MagicianT
Offline
Зарегистрирован: 03.10.2015

Для точного измерения не надо было связываться с прерываниями вообще. Делается в хардваре, через инпут каптюре (ICP). Есть библиотека здесь. http://interface.khm.de/index.php/lab/interfaces-advanced/frequency-measurement-library/

Проблема может быть с разведением пинов для ЖКИ.
Buldakov
Offline
Зарегистрирован: 17.01.2016

MagicianT пишет:

Для точного измерения не надо было связываться с прерываниями вообще. Делается в хардваре, через инпут каптюре (ICP). Есть библиотека здесь. http://interface.khm.de/index.php/lab/interfaces-advanced/frequency-measurement-library/

Проблема может быть с разведением пинов для ЖКИ.

По данной библиотеке результат гораздо хуже моего. (Смотря по вашей ссылке рис COM 43 порта) При частоте 100 гц Точность измерения составляет 1 такт от 160000. У меня порядка 1 такта на 1600000. По крайней мере у меня в 10 раз лучше.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Buldakov пишет:

Есть подозрение что переход на прерывание INT0 задерживается из за выполнения какого нибудь другого прерывания.

Конечно. Таймер0 отключали? Он строчит прерывания каждые 4 µS для всяких миллисов и микросов

Buldakov
Offline
Зарегистрирован: 17.01.2016

dimax пишет:

Конечно. Таймер0 отключали? Он строчит прерывания каждые 4 µS для всяких миллисов и микросов

Думаю что ошибку исправил. Потестирую.

У меня был код:

void loop()
 { 
currentTime=millis(); 
DeltaTime_LCD  =abs(currentTime - lastTime_LCD); 
if (DeltaTime_LCD >= interval_LCD && flag_LED==1) 

Заменил его на такой код:

void loop()
 { 
if (ovf_tik_timer_1 >= interval_timer_1 && flag_LED==1)

Все заработало.

Никакой таймер 0 при этом не отключал. Вероятнее всего это было из за того, что вызывая

currentTime=millis();

я обращался к Таймеру 0 в цикле Loop. Убрал это обращение и все заработало. Сейчас точность плюс - минус 2 такта от 16000000.

Возможно ли неисправность была была вызвана этим?

ovf_tic1=16796534 ,  tik_int_0 =21 n.  f  =20.004127 Hz
ovf_tic1=16796533 ,  tik_int_0 =21 n.  f  =20.004129 Hz
ovf_tic1=16796531 ,  tik_int_0 =21 n.  f  =20.004129 Hz
ovf_tic1=16796534 ,  tik_int_0 =21 n.  f  =20.004127 Hz
ovf_tic1=16796533 ,  tik_int_0 =21 n.  f  =20.004129 Hz
ovf_tic1=16796535 ,  tik_int_0 =21 n.  f  =20.004123 Hz
ovf_tic1=16796534 ,  tik_int_0 =21 n.  f  =20.004127 Hz
ovf_tic1=16796535 ,  tik_int_0 =21 n.  f  =20.004123 Hz
ovf_tic1=16796532 ,  tik_int_0 =21 n.  f  =20.004129 Hz
ovf_tic1=16796533 ,  tik_int_0 =21 n.  f  =20.004129 Hz
ovf_tic1=16796533 ,  tik_int_0 =21 n.  f  =20.004129 Hz
ovf_tic1=16796535 ,  tik_int_0 =21 n.  f  =20.004123 Hz
ovf_tic1=16796534 ,  tik_int_0 =21 n.  f  =20.004127 Hz
ovf_tic1=16796532 ,  tik_int_0 =21 n.  f  =20.004129 Hz
ovf_tic1=16796532 ,  tik_int_0 =21 n.  f  =20.004129 Hz
ovf_tic1=16796534 ,  tik_int_0 =21 n.  f  =20.004127 Hz
ovf_tic1=16796533 ,  tik_int_0 =21 n.  f  =20.004129 Hz
ovf_tic1=16796533 ,  tik_int_0 =21 n.  f  =20.004129 Hz
 

Timur Shapoval
Offline
Зарегистрирован: 17.07.2016

Привет всем. 

Подскажите,пожалуйста,можно ли подключать два прерывания на один пин - одно по спаду импульса, другое- по фронту, например:

attachInterrupt (0,start,FALLING);

attachInterrupt (0,stop,RISING);

Заранее благодарю за ответы.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Timur Shapoval пишет:

Привет всем. 

Подскажите,пожалуйста,можно ли подключать два прерывания на один пин - одно по спаду импульса, другое- по фронту, например:

attachInterrupt (0,start,FALLING);

attachInterrupt (0,stop,RISING);

Заранее благодарю за ответы.

Ответ кроется в исходниках attachInterrupt:

  if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
    intFunc[interruptNum] = userFunc;

Если по исходникам неясно, то дополню: ответ на поставленный вопрос - нет.

MagicianT
Offline
Зарегистрирован: 03.10.2015

Timur Shapoval пишет:

attachInterrupt (0,start,FALLING);

attachInterrupt (0,stop,RISING);

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

growler
Offline
Зарегистрирован: 12.07.2016

Два _обработчика_ одного прерывания на одном пине (по разным фронтам сигнала) подключаются так

void start() {
	detachInterrupt(0);
	attachInterrupt(0, stop, RISING);
	...
}

void stop() {
	detachInterrupt(0);
	attachInterrupt(0, start, FALLING);
	...
}

void setup() {
	...
	attachInterrupt(0, start, FALLING);
}

если вы успеваете между струйками дождя (выполнить работу до смены фронта сигнала).

Timur Shapoval
Offline
Зарегистрирован: 17.07.2016

Спасибо большое за советы! Я после первого ответа долго раздумывал и решил попробовать в функциях обработки каждого прерывания само прерывание отключать и включать второе, а во втором - отключать второе и включать первое. Таким образом получилось мерять длительность импульса на входе прерывания (как в последнем ответе). Так что все получилось.

Еще раз спасибо за советы и удачной вам работы!

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Timur Shapoval, длительность импульса можно измерять в одном прерывании,  без всех этих лишних манипуляций. Помимо того есть специальная функция pulsein() для измерения длительности импульса.

Timur Shapoval
Offline
Зарегистрирован: 17.07.2016

dimax пишет:

Timur Shapoval, длительность импульса можно измерять в одном прерывании,  без всех этих лишних манипуляций. Помимо того есть специальная функция pulsein() для измерения длительности импульса.

Спасибо за замечание. Если честно, я с pulseln () и начал, но она надолго останавливала программу - я логировал каждый шаг печатью, и так и не смог её победить. Поэтому решил попробовать прерываниями. Тем более, у меня заранее не известно, когда прилетит импульс, и сколько будет длиться (импульс бензинового впрыска автомобиля).

Однако, если есть где почитать поподробнее о применении этой функции, или кусочек рабочего кода, буду очень признателен.