Прерывания мешают друг другу?
- Войдите на сайт для отправки комментариев
Вс, 22/09/2013 - 20:15
Привет, форумчане)
Решаю банальнейшую задачу: подсчет длительности и колличества импульсов за единицу времени с одного источника и колличества импульсов за единицу времени с другого. Точность крайне важна, поэтому естественно используются прерывания для фиксирования фронта и спада импульсов в первом и фронта во втором случае. Временной интервал задается хардверными таймерами. Так вот, по отдельности счет идет идеально, но как только всё запущено в комплексе - валят нереальные цифры, скорее всего лажа в невозможности использовать несколько прерываний в одно время. Есть ли решение данной проблемы?
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() { математика }
В общем то при входе в обработчик прерывания положено запрещать прерывания cli(); иначе можно застрять в обработчиках. Также надо следить, чтоы суммарное нахождение в прерывании было существенно , раз эдак в 10, меньше общего времени главного цикла.
В общем то при входе в обработчик прерывания положено запрещать прерывания cli(); иначе можно застрять в обработчиках.
Я перефразировал бы:
При обработке прерывания не принято разрешать прерывания sei(); иначе можно застрять в обработчиках.
Первоисточник (известный под именем datasheet):
А можно чуть вводных данных о том, что это строится?
Тут есть моя тема с бортовым компом для инжекторного авто, где есть расходомер: http://arduino.ru/forum/proekty/bortovoi-kompyuter-na-avto-s-inzhektornym-dvigatelem-glavnoe-raskhodomer-topliva
Сейчас все тесты уже проведены, расход показывает четко. Заканчиваю основные навороты и примерно недели через 2 проект достигнет намеченной точки.