millis и прерывания

rene
Offline
Зарегистрирован: 21.01.2014

Доброго времени суток

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

01unsigned long inductDuration; // длительность срабатывания датчика
02boolean inductChange = false;
03 
04void setup(){
05  attachInterrupt(0, _InductionOn, RISING);
06  attachInterrupt(0, _InductionOff, FALLING);
07}
08 
09void loop(){
10    if (inductChange){
11    Serial.println(inductDuration);
12    inductChange = false;
13 
14    остальной код программы
15  }
16}
17 
18// >>>>>>>>>>>>>>> функция прерывания, высокий уровень на датчике индуктивности
19void _InductionOn(){
20  inductDuration = millis();
21}
22 
23// >>>>>>>>>>>>>>> функция прерывания, низкий уровень на датчике индуктивности
24void _InductionOff(){
25  inductDuration = millis() - inductDuration;
26  inductChange = true;
27}

Но поскольку в прерывании millis() нельзя использовать, нужен какой то другой вариант решения. Что то ничего в голову не приходит.

Datak
Offline
Зарегистрирован: 09.10.2014

А что, в прерывании действительно нельзя использовать  millis()  ?

rene
Offline
Зарегистрирован: 21.01.2014

Datak пишет:

А что, в прерывании действительно нельзя использовать  millis()  ?

Ну у меня почему то первое прерывание возвращает в mills() - 0.

Вот тут   написано

Замечание по использованию

Внутри функции обработки прерывания не работает delay(), значения возвращаемые millis() не изменяются. Возможна потеря данный передаваемых по последовательному соединению (Serial data) в момент выполнения функциии обработки прерывания. Переменные, изменяемые в функции, должным быть объявлены как volatile.

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

использовать внешний счетчик времени, DS1302/DS1307.

Datak
Offline
Зарегистрирован: 09.10.2014

Проверять сейчас не буду, поэтому сразу мои извинения, если навру. :)

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

Думаю,  delay()  не работает как раз по этой причине - он ждёт изменения  millis()  на заданное значение.

Потеря данных последовательного порта - тоже понятно. Данные теряются, если не удалось вовремя вызвать обработчик прерывания com-порта, из-за того что слишком долго обрабатывалось какое-то другое прерывание.

Так что, пробуйте. Не вижу причин, чтобы не работало. Главное, чтобы время между RISING и FALLING прерываниями не было слишком коротким - иначе счётчик  millis  действительно может просто не успеть ничего насчитать.

rene
Offline
Зарегистрирован: 21.01.2014

Эхех, так и думал что часы реального времени применять придется

rene
Offline
Зарегистрирован: 21.01.2014

Datak пишет:

Проверять сейчас не буду, поэтому сразу мои извинения, если навру. :)

Накатал такой код для проверки:

01unsigned long inductDuration1;
02unsigned long inductDuration2;
03boolean inductChange = false;
04 
05void setup(){
06  Serial.begin(9600);
07  attachInterrupt(0, _InductionOn, RISING);
08  attachInterrupt(0, _InductionOff, FALLING);
09}
10 
11void loop(){
12  if (inductChange){
13    Serial.println(inductDuration1);
14    Serial.println(inductDuration2);
15    inductChange = false;
16  }
17}
18 
19// >>>>>>>>>>>>>>> функция прерывания, высокий уровень на датчике индуктивности
20void _InductionOn(){
21  inductDuration1 = millis();
22}
23 
24// >>>>>>>>>>>>>>> функция прерывания, низкий уровень на датчике индуктивности
25void _InductionOff(){
26  inductDuration2 = millis();
27  inductChange = true;
28}

В консоли получаю:

0
3761
0
4692
0
5410
 
т.е. в функции _InductionOn millis() мне возвращает 0, а в функции _InductionOff работает нормально

 

rene
Offline
Зарегистрирован: 21.01.2014

У меня просто не срабатывает прерывание attachInterrupt(0, _InductionOn, RISING); соответственно потому в переменной inductDuration1 всегда ноль. Почему так?

Удалил attachInterrupt(0, _InductionOff, FALLING);, первая функция заработала, ничего не понимаю

rene
Offline
Зарегистрирован: 21.01.2014

Если написать так:

1attachInterrupt(0, _InductionOff, FALLING);
2attachInterrupt(0, _InductionOn, RISING);

Срабатывает самое нижнее прерывание, первое игнорируется. Пробовал менять местами, так же - работает только нижнее. Почему?

axill
Offline
Зарегистрирован: 05.09.2011

rene пишет:

Если написать так:

1attachInterrupt(0, _InductionOff, FALLING);
2attachInterrupt(0, _InductionOn, RISING);

Срабатывает самое нижнее прерывание, первое игнорируется. Пробовал менять местами, так же - работает только нижнее. Почему?

все правильно работает, второй строчкой вы затираете то, что настроили первой

rene
Offline
Зарегистрирован: 21.01.2014

Значит у меня единственное решение, использовать CHANGE

attachInterrupt(0, _InductionOff, CHANGE);

и отслеживать состояние пина?

Araris
Offline
Зарегистрирован: 09.11.2012

И еще почитайте про volatile здесь: http://arduino.ua/ru/prog/Volatile

mag155
Offline
Зарегистрирован: 21.12.2017

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

mag155
Offline
Зарегистрирован: 21.12.2017

Стабильные .

mag155
Offline
Зарегистрирован: 21.12.2017

Частота импульсов примерно 100 герц.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

mag155 пишет:
как побороть ?
апаратно . Повесте триггеры http://digteh.ru/CVT/trigg/

ПС:От туда Следует отметить, что выпускникам ВУЗов, не знающим принципы работы триггеров, достаточно сложно найти работу.

mag155
Offline
Зарегистрирован: 21.12.2017

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

01#define dimPin 8
02#define dimPin1 9
03#define zeroPin1 3
04#define zeroPin 2
05#include <CyberLib.h>
06volatile int  tic, Dimmer;
07volatile int  tic1, Dimmer1;
08void setup() {
09  Serial.begin(9600);
10  pinMode(dimPin, OUTPUT);
11 pinMode(dimPin1, OUTPUT);
12  digitalWrite(dimPin, 0);
13 digitalWrite(dimPin1, 0);
14  pinMode(zeroPin, INPUT);                
15 pinMode(zeroPin1, INPUT);
16  attachInterrupt(0, detect_up, FALLING);
17attachInterrupt(1, detect_up1, FALLING);
18  StartTimer1(timer_interrupt, 40);       
19  StartTimer1(timer_interrupt1, 40);
20  StopTimer1();                           
21  
22  Serial.println("Start");
23}
24 
25void loop() {
26   
27   Dimmer = map(analogRead(0), 0, 1023, 240, 0);
28 Dimmer1 = map(analogRead(0), 0, 1023, 240, 0);
29 
30}
31 
32void timer_interrupt1() {     
33  tic1++;                     
34  if (tic1 > Dimmer1)           
35    digitalWrite(dimPin1, 1);  
36}
37void  detect_up1() {  
38  tic1 = 0;                                
39  ResumeTimer1();                          
40  attachInterrupt(1,detect_down1,  RISING); 
41}
42 
43void  detect_down1() {
44  tic1 = 0;                                 
45  StopTimer1();                            
46  digitalWrite(dimPin1, 0);                   
47attachInterrupt(1, detect_up1, FALLING); 
48}
49void timer_interrupt() {      
50  tic++;                     
51  if (tic > Dimmer  )    
52  digitalWrite(dimPin, 1 ) ;
53     
54}
55 
56void  detect_up() {  
57  tic = 0;                                
58  ResumeTimer1();                          
59  attachInterrupt(0, detect_down, RISING); 
60}
61 
62void  detect_down() {
63  tic = 0;                                 
64  StopTimer1();                            
65  digitalWrite(dimPin, 0);                   
66attachInterrupt(0, detect_up, FALLING); 
67 
68}

 

andryn
Offline
Зарегистрирован: 08.06.2018

mag155 пишет:

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

А вот это правильно?

1StartTimer1(timer_interrupt, 40);      
2StartTimer1(timer_interrupt1, 40);

Какой обработчик будет у таймера 1?

kalapanga
Offline
Зарегистрирован: 23.10.2016

Как минимум потому, что Вы на один таймер пытаетесь два обработчика повесить (строки 18 и 19).

mag155
Offline
Зарегистрирован: 21.12.2017

Я так и дкмал. Как тогда зделать три отдельных таймера ???

mag155
Offline
Зарегистрирован: 21.12.2017

Думал