работа прерываний

ddr2
Offline
Зарегистрирован: 27.12.2020

Спасибо, отличная ссылка, всё очень понятно написано. Буду пробовать. 

 

nik182 пишет:

У таймера STM32 есть режим ворота - считает импульсы только когда на входе таймера 1. По закрытию ворот можно взять прерывание и считать данные. И тогда прерывание по ноге вообще не понадобится. 

Ну впринципе и захват таймера достаточно понятен, главное чтобы работал без фокусов, как случилось с первым вариантом (счётчик при переключение falling-rising на int0 (PD2)), хотя проблем на первый взгляд ничего не предвещало.

ddr2
Offline
Зарегистрирован: 27.12.2020

Вот такой вопрос, а если спадающий фронт будет до выхода из обработчика, который был вызван по восходящему? Может ли быть такое и как это обыгрывается? 

anatoli_nik
Offline
Зарегистрирован: 17.01.2019

Если прерывание было разрешено (активировано по спадающему фронту) оно в любом случае выполнится. Обработчик прерывания должен выполняться быстрее чем приходят запросы на прерывание, это аксиома!

Либо оптимизируете обработчик прерывания, либо берете камень более быстрый.

Как крайний случай 

ISR("название прерывания", ISR_NAKED)

Не будет создаваться пролог и эпилог в прерывании, что иногда, значительно ускоряет обработчик прерывания. Но здесь скрыто зло! Регистры использованные в прерывании, тот же SREG, будут изменены неожиданно для основной программы. Это вызовет троднонаходимые глюки. Если пришлось использовать такую запись, тогда лучше зарезервировать регистр(ы), например

register volatile uint8_t int_flags asm("r16");

И пользоваться в прерывании только ассемблером, не используя операции которые могут изменить SREG.

В любом случае, прерывание не выполнится быстрее чем за 4(такта вход)+4(такта выход).

ddr2
Offline
Зарегистрирован: 27.12.2020

volatile uint16_t impulses;

typedef enum { 
    RISING, 
    FALLING
} int_state_t;

volatile int_state_t int_state = RISING; 

ISR(INT0_vect) { 
    switch (int_state)  {
        case RISING:
            int_state = FALLING;
            EICRA |= ((1 << ISC01) | (0 << ISC00)); // int0 on FALLING
            impulses += 1;
        break;
        case FALLING:
           int_state = RISING;
           EICRA |= ((1 << ISC01) | (1 << ISC00)); // int0 on RISING
        break;
    }
}

Раз в 10 секунд в основном цикле вывожу число импульсов impulses и состояние int_state. Прерывания делаю задолго до отправки в uart(поэтому 10 секунд и чтобы вывод не влиял на прерывания), замыканием провода от +3.3V на INT0, INT0 (PD2) подтянут к GRD R=1М (чтобы быстро не спадал). 

printf("%d %d\n", impulses, int_state);

И тем не менее, иногда получаю int_state = 1 в выводе printf(), то есть не был вызван обработчик нисходящего фронта. Единственное предположение почему это произошло, это то что нисходящий фронт пришёл настолько быстро после восходящего, что мк не успел его обработать. И это без всяких таймеров. 

 

sadman41
Offline
Зарегистрирован: 19.10.2016

На мой взгляд решение с переменой фронта подходит для обработки сигналов, переключающихся с достаточно медленной (относительно исполнения обработчика прерывания) скоростью.

Сидение на таймере более устойчиво.

Bruzzer
Offline
Зарегистрирован: 17.03.2020

ddr2 пишет:

Прерывания делаю задолго до отправки в uart(поэтому 10 секунд и чтобы вывод не влиял на прерывания), замыканием провода от +3.3V на INT0, INT0 (PD2) подтянут к GRD R=1М (чтобы быстро не спадал).

Может быть вам стоит сделать из второй ардуины генератор тестовых импульсов, чтобы проверять работу придуманных алгоритмов для разных вариантов входных импульсов.

ddr2
Offline
Зарегистрирован: 27.12.2020
sadman41 пишет:
На мой взгляд решение с переменой фронта подходит для обработки сигналов, переключающихся с достаточно медленной (относительно исполнения обработчика прерывания) скоростью. Сидение на таймере более устойчиво.
 
Да действительно, захват таймера работает быстро и стабильно. Его функционал меня полностью устроил. В прошлом варианте всё это делал сам, но чаще пропадали нисходящие фронты и работало медленней.
 
Bruzzer пишет:
Может быть вам стоит сделать из второй ардуины генератор тестовых импульсов, чтобы проверять работу придуманных алгоритмов для разных вариантов входных импульсов.
Можно конечно сделать регулируемый шим-генератор, но пока протестировал просто замыканием, и всё работает, даже при 100% заполнении (долгом замыкании).
 
Да, ещё добавил атомизацию отправки в uart. 
 
 
OK0
Offline
Зарегистрирован: 06.03.2020

sadman41 пишет:
Сидение на таймере более устойчиво.

http://arduino.ru/forum/apparatnye-voprosy/lozhnye-prervaniya-arduino#co...

ddr2
Offline
Зарегистрирован: 27.12.2020

OK0 пишет:
 
sadman41 пишет:
Сидение на таймере более устойчиво.
 

http://arduino.ru/forum/apparatnye-voprosy/lozhnye-prervaniya-arduino#comment-195726

по ссылке у человека силовая автоматика, при управлении которой цепи питания ардуины должны быть защищены, у меня же в стабильных тестах питание от компа usb, да и прерывания от пина +3,3V через 10к, так что никаких значимых воздействий на стабильность таймера иметь не могут.

OK0
Offline
Зарегистрирован: 06.03.2020

ddr2, вы , по-видимому, не поняли, это и была реплика в поддержку рекомендации отказаться от прерываний int0 и int1 в пользу прерывания по захвату. Ну или я не понял...