Прерывания мешают друг другу?

Бублик
Бублик аватар
Offline
Зарегистрирован: 05.12.2012

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

Arduino DUE
 

#include <DueTimer.h> // таймер для Arduino DUE

#define SPEED_PIN 29 // пин датчика скорости
#define INJECTOR_PIN 30 // пин форсунки
#define INJECTOR_PIN2 31 // пин2 форсунки

volatile unsigned long schet_imp_s_dat_skor = 0; // обнуляемые раз в секунду импульсы с датчика скорости, Hz
volatile unsigned long schet_imp_s_inj = 0; // обнуляемый раз в секунду подсчет имп. с форсунки, Hz
volatile unsigned long chastota_vkluchenia_forsunki = 0; // частота включения форсунки, Hz
volatile unsigned long summa_dlitelnostei_vpriska = 0; // одна форсунка, microsec
volatile unsigned long schet_imp_s_dat_skor_za_vse_vremia = 0; // не обнуляемые импульсы с датчика скорости, штук
volatile unsigned long inj_duration = 0; // длительность импульса впрыска, microsec
volatile unsigned long inj_start = 0; // старт измерения длительности импульса впрыска, microsec
volatile unsigned long inj_start_dlit = 0; // для тахометра
volatile unsigned long inj_start_old = 0; // для тахометра
volatile unsigned long d_speed = 0; // снятие суммы показаний с датчика скорости раз в секунду, Hz
volatile unsigned long d_trim = 0; // снятие суммы показаний с форсунки раз в секунду, Hz


void setup()
{

  pinMode(INJECTOR_PIN, INPUT);
  digitalWrite(INJECTOR_PIN, HIGH);
  pinMode(INJECTOR_PIN2, INPUT);
  digitalWrite(INJECTOR_PIN2, HIGH);
  pinMode(SPEED_PIN, INPUT);
  digitalWrite(SPEED_PIN, HIGH);
  pinMode(TOUCH_INT_PIN, INPUT);
     
  Timer0.attachInterrupt(TIMER_SPD).start(1000000); // таймер подсчета кол. имп. с датчика скорости за 1 сек. 
  Timer3.attachInterrupt(TIMER_INJ).start(1000000); // таймер подсчета суммы имп. с форсунки за 1 сек.
  attachInterrupt(SPEED_PIN,SPEED_CLOCK,RISING); // прерывание пина датчика скорости
  attachInterrupt(INJECTOR_PIN,INJ_START,RISING); // прерывание пина форсунки, старт измерения длины впрыска
  attachInterrupt(INJECTOR_PIN2,INJ_STOP,FALLING); // прерывание пина форсунки, стоп измерения длины впрыска
  attachInterrupt(TOUCH_INT_PIN, TOUCH, LOW);
}

void TIMER_INJ() // таймер3, срабатывает раз в секунду
{
  d_trim = schet_imp_s_inj; // присваиваем переменной d_trim колличество импульсов с инжектора за 1 секунду
  schet_imp_s_inj = 0; // обнуляем показания счетчика
}

void TIMER_SPD() // таймер0, срабатывает раз в секунду
{
  d_speed = schet_imp_s_dat_skor; // присваиваем переменной d_speed колличество насчитанных за секунду импульсов с датчика скорости
  schet_imp_s_dat_skor = 0; // обнуляем показания счетчика
}

void INJ_START() // запуск прерывания по фронту импульса с инжектора
{
  inj_start_old = inj_start; // для тахометра, фиксируем предидущее значение прихода импульса с форсунки
  inj_start = micros(); // старт измерения длинны импульса впрыска
  inj_start_dlit = inj_start - inj_start_old; // для тахометра, вычитаем из нового старое - получаем длительность между фронтами
  schet_imp_s_inj++; // суммируем импульсы с инжектора
}

void INJ_STOP() // запуск прерывания по спаду импульса с инжектора
{
  inj_duration = micros() - inj_start; // стоп измерения длинны импульса впрыска
  summa_dlitelnostei_vpriska = summa_dlitelnostei_vpriska + inj_duration; // суммируем длительность впрысков за поездку
}

void SPEED_CLOCK() // запуск прерывания по импульсу с датчика скорости
{
  schet_imp_s_dat_skor++;  // суммируем импульсы с датчика скорости, обнуляются раз в секунду
  schet_imp_s_dat_skor_za_vse_vremia++;  // суммируем импульсы с датчика скорости, не обнуляются
}

void TOUCH()
{
  myTouch.InitTouch(PORTRAIT); // инициализация и ориентация тача (LANDSCAPE or PORTRAIT)
  myTouch.setPrecision(PREC_HI); // чувствительность тача (PREC_LOW or PREC_MEDIUM or PREC_HI or PREC_EXTREME)
}  

void waitForTouchRelease()
{
  while (myTouch.dataAvailable()==true)
  myTouch.read();
}

void loop()
{
   математика
}

 

inspiritus
Offline
Зарегистрирован: 17.12.2012

В общем то при входе в обработчик прерывания положено запрещать прерывания cli(); иначе можно застрять в обработчиках. Также надо следить, чтоы суммарное нахождение в прерывании было существенно , раз эдак в 10, меньше общего времени главного цикла.

step962
Offline
Зарегистрирован: 23.05.2011

inspiritus пишет:

В общем то при входе в обработчик прерывания положено запрещать прерывания cli(); иначе можно застрять в обработчиках. 

Я перефразировал бы:

При обработке прерывания не принято разрешать прерывания sei(); иначе можно застрять в обработчиках.

Первоисточник (известный под именем datasheet):

"• Bit 7 – I: Global Interrupt Enable
The Global Interrupt Enable bit must be set for the interrupts to be enabled. The individual interrupt
enable control is then performed in separate control registers. If the Global Interrupt Enable
Register is cleared, none of the interrupts are enabled independent of the individual interrupt
enable settings. The I-bit is cleared by hardware after an interrupt has occurred, and is set by
the RETI instruction to enable subsequent interrupts. The I-bit can also be set and cleared by
the application with the SEI and CLI instructions, as described in the instruction set reference."
 
Тот же первоисточник несколькими страницами далее:
"When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are disabled.
The user software can write logic one to the I-bit to enable nested interrupts. All enabled
interrupts can then interrupt the current interrupt routine. The I-bit is automatically set when a
Return from Interrupt instruction – RETI – is executed."
melvladimir
Offline
Зарегистрирован: 08.03.2013

А можно чуть вводных данных о том, что это строится?

Тут есть моя тема с бортовым компом для инжекторного авто, где есть расходомер: http://arduino.ru/forum/proekty/bortovoi-kompyuter-na-avto-s-inzhektornym-dvigatelem-glavnoe-raskhodomer-topliva

Сейчас все тесты уже проведены, расход показывает четко. Заканчиваю основные навороты и примерно недели через 2 проект достигнет намеченной точки.