Как обработать сигнал с компаратора

DmitryR
Offline
Зарегистрирован: 12.05.2017

Здравствуйте, подскажите пожалуйста, какой код использовать для фиксации сигнала с компаратора:

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А частота ШИМ

А) известна?

Б) постоянна?

DmitryR
Offline
Зарегистрирован: 12.05.2017

Не известна
Не постоянна
Сигнал на компаратор идёт в виде затухающей синусоиды, ввиду этого, компаратор срабатывает с изменяющейся частотой, и в какой-то момент он сработает последний раз, необходимо зафиксировать время до наступления этого момента

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, тогда Вам придётся смириться с тем фактом, что стопудово-достоверно Вы никогда не узнаете установился у Вас уже постоянный высокий сигнал или ещё будет низкий. Если бы Вы хотя бы значит частоту, то можно было бы выждать период и, если за время периода низкий сигнал не появился ни разу, то считать, что всё, - высокий сигнал установился и «дальше только тишина», как писал Шекспир.

Можно, выбрать произвольно некий период времени P и считать, сигнал установился, если за время P ни разу не появился низкий уровень. При таком подходе Вы соможете точно определить время «установления» высокого уровня, но определить его Вы сможете только по прошествии времени P – не раньше. Такой подход устраивает? 

DmitryR
Offline
Зарегистрирован: 12.05.2017

Да, полностью. Только вот теперь не знаю, как написать необходимый код, можете подсказать?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну. тогда конкретизируйте:

1. Что на пине "в начале времён", до появления ШИМ? Или он сразу при включени питания появляется?

2. Что делать, когда высокий уровень отловлен? Забить или ждать появления нового ШИМ?

DmitryR
Offline
Зарегистрирован: 12.05.2017

ШИМ появляется сразу после появления сигнала (начале на пине убдет либо 1, либо 0 в зависимости от инвентирующего или нет включения компаратора,что для меня будет непринципиально). В качестве сигнала случит сигнал с колебательного контура (затухающая выпрямленная синусоида). 
Когда высокий уровень установлен (не происходит изменения после последнего срабатывания компаратоа в течении периода P) не надо ждать. Главное зафиксировать время, от появления сигнала, до последнего срабатывания. Сигнал появляется после замыкания ключа (кнопки).

DmitryR
Offline
Зарегистрирован: 12.05.2017

Два графика, в зависимости от схемы включения компаратора
Зелёный - выпряжленный сигнал
Красный - сигнал с колебательного контура
Фиолетовый - сигнал с компаратора

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

DmitryR пишет:

ШИМ появляется сразу после появления сигнала (начале на пине убдет либо 1, либо 0 в зависимости от инвентирующего или нет включения компаратора,что для меня будет непринципиально). В качестве сигнала случит сигнал с колебательного контура (затухающая выпрямленная синусоида). 
Когда высокий уровень установлен (не происходит изменения после последнего срабатывания компаратоа в течении периода P) не надо ждать. Главное зафиксировать время, от появления сигнала, до последнего срабатывания. Сигнал появляется после замыкания ключа (кнопки).

Ага, т.е. факт появления сигнала мы опреляем по нажатию кнопки? Так? Кнопка притянута к питанию? По нажатию на ней LOW вылазит? 

И Вы на второй вопрос не ответили, что делать после завершения? 

DmitryR
Offline
Зарегистрирован: 12.05.2017

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Похоже, Вы вообще никогда с программированием не имели дела? Вы просто не понимаете о чём Вас спрашивают, а я не получаю ответов на вопросы без которых не могу работать. Вместо ответов Вы пишете "не принципиально". Давайте так не будем. Не рассказывайте мне про конденсаторы и компараторы. Просто коротко отвечайте на вопросы.

1. Как я узнаю, что пора начинать измерение? На пине кнопки появится LOW? Или HIGH? Просто скажить чего мне ждать.

2. Нужно ли после завершения первого измерения ждать нового нажатия кнопки (и нового измерения) или не нужно?

DmitryR
Offline
Зарегистрирован: 12.05.2017

Извиняюсь, с программированием действительно практические не сталкивался, возможно мы друг друга не поняли.
1. Кнопка играет роль механического ключа. Т.е. она не сигнализирует о начале измерения, при её нажатии она "залипает" и становится просто проводником, соответственно в этот самый момент начнёт поступать сигнал на схему и далее на компаратор. Начинать измерение надо непосредственно сразу при замыкании кнопки, что происходит практически одновременно с первым срабатыванием копаратора.

2. После первого измерения (когда энергия сигнала полностью расходуется и синусоида погасится), кнопку необходимо разомкнуть, что вызовет замыкание другой цепи и новый заряд конденсатора, и при повторном нажатии повторяется измерение.

Извиняюсь за подробное оприсание, стараюсь изложить всё более подробно, для лучшего понимания

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

DmitryR,  ну, поймите же Вы, ... вот Вы знаете, что кнопки иногда притягивают к земле, а иногда к питанию? ... так вот, я же Вам задал простой вопрос - что на кнопке должно появитсья, чтобы это было сигналом к началу измерений? Я ожидал от Вас просто "HIGH" или "LOW" - но именно этого Вы мне опять не сказали! Если Вам непринципиально куда её притягивать, то мне - тем более. Уж определитесь и скажите мне что-нибудь.

Давайте всё-таки Вы будете чётко отвечать на мои вопросы. Если Вам трудно, я их перефомулирую, чтобы Вы могли отвечать "да" или "нет". И если В ваших ответах будет что-то ещё, то простите, я прекращаю работу с Вами.

Итак, вопросы. Отвечать ТОЛЬКО "да" или "нет"

1. Измерение следует начинать, когда на пине кнопки уровень сменится с HIGH на LOW?

2. Измерение следует начинать, когда на пине кнопки уровень сменится с LOW на HIGH?

3. После завершения измерения программа должна снова перейти в режим ожидания нажатия кнопки и когда это произойдёт, начать новое измерение?

4. После завершения измерения программа вообще не должна обращать какого либо внимания ни на кпопку, ни на сигнал?

 

 

DmitryR
Offline
Зарегистрирован: 12.05.2017

Хорошо, понял, извиняюсь
1. нет

2. да

3. нет

4. да

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, вот, совсем другое дело. 

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

ЕвгенийП, вот интересно, а по какому принципу вы разделяете людей на тех, кого сразу отправить в раздел "ищу исполнителя", и на тех у кого выпытать все нюансы задачи ..и потом всё написать ему? :)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Так, ну, проверять мне сейчас не на чем, примерно так должно работать. Попробуйте, если что пойдёт не так, постарайтесь внятно описать проблему. Идейно-то работать должно.

///////////////////////////////////
//
//	Пины копки и сигнала
// должны быть 2 и 3 в любом порядке
//
#define	BUTTON_PIN	2
#define	SIGNAL_PIN	3

///////////////////////////////////
//
//	Время ожидания продолжения сигнала в миллисекундах
// Если за это время уровень ни разу не стал LOW, 
// то считаем, что сигнал прекратился
//
#define	CONTROL_PERIOD	50ul

///////////////////////////////////
//
// Возможные состояния измерителя
//
enum METER_STATES {
	WAITING_FOR_SIGNAL = 0,	// Ждём нажатия кнопки
	MEASURING,	// Измеряем
	READY	// Закончили, результат готов
};

//////////////////////////////////
//
//	Переменная для хранени текущего состояния измерителя
// Изначальное состояние - ожидание нажатия кнопки
//
static volatile METER_STATES meterState = WAITING_FOR_SIGNAL;

//////////////////////////////////
//
// Переменные для хранения времени начала отсчёта
// и времени окончания отсчёта (пропадания сигнала)
//
static volatile unsigned long startSignalTime = 0, endSignalTime = 0;

//////////////////////////////////
//
// Функция - обработчик поступающего во 
// время измерения сигнала. Выполняется,
// когда на сигнальном пине появляется LOW
//
void measureISR(void) {
	endSignalTime = millis(); // просто запоминем время
}

//////////////////////////////////
//
// Функция - обработчик нажатия на кнопку
//
void waitingISR(void) {
	startSignalTime = endSignalTime = millis(); // запоминаем время
	detachInterrupt(BUTTON_PIN - 2);
	pinMode(SIGNAL_PIN, INPUT);
	attachInterrupt(SIGNAL_PIN - 2, measureISR, RISING);
	meterState = MEASURING;	// Изменяем состояние на "измеряем"
}

void setup(void) {
	Serial.begin(115200);
	pinMode(BUTTON_PIN, INPUT);
	attachInterrupt(BUTTON_PIN - 2, waitingISR, RISING);
}

void loop(void) {
  if (meterState == MEASURING) {
  		//
  		// Проверяем, что с момент последнего LOW 
  		// прошло >= CONTROL_PERIOD миллисекунд
  		//
  		if (millis() - endSignalTime >= CONTROL_PERIOD) {
  			//
  			// если прошло, то заканчиваем измерения
  			//
  			detachInterrupt(SIGNAL_PIN - 2);
			meterState = READY;	// закончили
			Serial.print("Result is: ");
			Serial.print(endSignalTime - startSignalTime);
			Serial.println(" milliseconds");
  		}
  }
}

Значит, кнопку вешаем на пин 2, а сигнал на пин 3 (можно поменять местами, но тогда надо соответсвенно поменять в строках 6 и 7.

1.
Программа сначала ждёт появления HIGH на кнопке.

2.
Как дождётся, перестаёт обращать внимания на кнопку и начинает ждать одного зи двух событий (что наступит раньше) истечения интервала времени CONTROL_PERIOD (задаётся в строке 15) или появления HIGH на пине сигнала. Если раньше появляется HIGH, она опять уже с этого момента начинает ждать одного зи двух событий (что наступит раньше) истечения интервала времени CONTROL_PERIOD или появления HIGH на пине сигнала. И так повторяется пока, наконец, не дождётся истечения интервала времени.

3.
Когда таки дождётся, печатает разность между временим последнего появления HIGH и временем нажатия кнопки.

4.
после этого программа никак не реагирует на изменения на пине кнопки или пине сигнала.

Я там старался комментировать - разбирайтесь

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

dimax пишет:

ЕвгенийП, вот интересно, а по какому принципу вы разделяете людей на тех, кого сразу отправить в раздел "ищу исполнителя", и на тех у кого выпытать все нюансы задачи ..и потом всё написать ему? :)

Хрен его знает. Ну, там ... хрен его знает ... по настроению левой пятки, наверное :)

DmitryR
Offline
Зарегистрирован: 12.05.2017

Спасибо бьльшое, прочитал, конечно не всё понял, но разберусь и в ближайшее время протестирую на "железе".
Обязательно сообщу о результатах
 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

В комментариях в строках 45 и 72 опечатка  - должно быть не LOW, а HIGH.

DmitryR
Offline
Зарегистрирован: 12.05.2017

Спасибо, учёл 

Гриша
Offline
Зарегистрирован: 27.04.2014

спортивный интерес...

ЕвгенийП пишет:

1.
Программа сначала ждёт появления HIGH на кнопке.

3.
Когда таки дождётся, печатает разность между временим последнего появления HIGH и временем нажатия кнопки.

4.
после этого программа никак не реагирует на изменения на пине кнопки или пине сигнала.

как я понял по тексту топика, кнопка нужна для ввода контроллера в режим измерения, само измерение начинается после первого изменения сигнала с компаратора. И интервал интересует между первым и последним переходом (без учета момента нажатия кнопки)... и ничего про ширину ШИМ не скзали, может там МГц... 

не совсем понятно, как делать следующее измерения...

ИМХО кнопка нафиг не нужна, ждем первое прерывание - запоминаем, ждем что новое прерывание не поступило в интервале определения, считаем разницу времени между первым и последним полученым прерыванием - выводим результат и снова ждем прерывание для нового измерения.

ЗЫ. увы, сам не силен код поправить...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Гриша пишет:

ИМХО кнопка нафиг не нужна, ждем первое прерывани

Я тоже так думал и пытался выжать из ТС, что же там на пине сигнала до первого прерывания - какой уровень (пост №5). Но ТС сказал "по кнопке".

Гриша пишет:

ЗЫ. увы, сам не силен код поправить...

И не надо. Судя по всему, ТС пока толком не понимает что ему нужно. Вернее понимает, но "с другой колокольни". Вот поэкспериментирует, поймёт, и тогда будет в востоянии внятно сказать что именно нужно править. А пока не надо.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

dimax пишет:

ЕвгенийП, вот интересно, а по какому принципу вы разделяете людей на тех, кого сразу отправить в раздел "ищу исполнителя", и на тех у кого выпытать все нюансы задачи ..и потом всё написать ему? :)

Хрен его знает. Ну, там ... хрен его знает ... по настроению левой пятки, наверное :)

И Астрология, зная дату. время и место рождения можно глянуть графики и, они не врут более чем на 80% )))

DmitryR
Offline
Зарегистрирован: 12.05.2017

Тут наврено моя ошибка в том, что не выложил схему
Под кнопкой я подразумевал ключ в контуре, при замыкании которого конденсатор разряжается на катушку и сигнал поступает  на схему и с компаратора на Arduino (вместо которой сейчас стоит осциллограф) 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Так постоянная времени LC цепи (частота) неизменна жеж - 3.355 килогерца!
Сейчас Вам Евгений Петрович классный скетч выдаст - измерение с синхронизацией по фронту первого импульса

DmitryR
Offline
Зарегистрирован: 12.05.2017

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

ssss
Offline
Зарегистрирован: 01.07.2016

DmitryR пишет:

Необходимо зафиксировать время, когда установится эта единица с момента начала сигнала.

На СТМ32 - легко! Запускаем таймер по спаду входного, по фронту делаем захват. Последний захват и будет нужным временем.

DmitryR
Offline
Зарегистрирован: 12.05.2017

К сожалению не силён в программировании, единственное, что приходилось делать - это простые девайсы на ардуино с полуготовым кодом.
Буду благодарен, если набросаете код программы на stm32

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ssss пишет:

На СТМ32 - легко! 

А здесь Вам трудно? Сочувствую.

Logik
Offline
Зарегистрирован: 05.08.2014

Началось... тривиальная задача, которую ТС в силу неумения подумать не может решить станет основой срача. 

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

//К сожалению не силён в программировании, 

так вали и заказывай работу другим.

DmitryR
Offline
Зарегистрирован: 12.05.2017

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

Про неумение подумать ещё поспорить можно, доказательства Ваших умственных способностей у нас тоже нету 

Logik
Offline
Зарегистрирован: 05.08.2014

//доказательства Ваших умственных

Да пожалуста. Настраиваем прерывание по изменению состояния пина, в обработчике при первом проходе фиксируем из таймера время в Т1, при каждом непервом - в Т2. Если Т2-Т1 на протяжении времени, заведомо превышающего период входного сигнал, не изменилось, то Т2-Т1 и есть результат требуемый в стартовом топике, т.е. длительность затухания. А в Т2 понятно абсолютное время завершения по системному таймеру.

ПС. DmitryR, займитесь вышиванием, макраме или плетением из лозы. Програмирование не для Вас.

ssss
Offline
Зарегистрирован: 01.07.2016

Logik пишет:

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

"Сам дурак!"(с)

Цитата:

Настраиваем прерывание по изменению состояния пина, в обработчике при первом проходе фиксируем из таймера время в Т1, при каждом непервом - в Т2. Если Т2-Т1 на протяжении времени, заведомо превышающего период входного сигнал, не изменилось, то Т2-Т1 и есть результат требуемый в стартовом топике, т.е. длительность затухания. А в Т2 понятно абсолютное время завершения по системному таймеру.

Пфффффф... ))))))))

Настраиваем таймер СТМ32 как слэйв и запуск по спаду, захват по нарастанию тоже тривиален. Всё хардварно и никаких "если".

 

Logik
Offline
Зарегистрирован: 05.08.2014

ssss пишет:

Logik пишет:

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

"Сам дурак!"(с)

 
Отличный уровень!

ssss пишет:

Пфффффф... ))))))))

Вот так сразу в истерику?! А поговорить?

ssss пишет:

Настраиваем таймер СТМ32 как слэйв и запуск по спаду

Картинку видим? Спады на ней тоже? Запускайте по каждому ;)

1.png

DmitryR
Offline
Зарегистрирован: 12.05.2017

// Програмирование не для Вас
Я это и не отрицал, но бывают случае, когда надо сделать то, что не умеешь в короткие сроки
Логику кода и способов как сделать измерение я и сам с десяток написать могу, совсем другое дело написать конкретный рабочий код на какой-либо МК, для чего надо как минимум знать язык программирования

DmitryR
Offline
Зарегистрирован: 12.05.2017

Я благодарен ЕвгениюП. Человек узнал необходимую информацию, хоть это не сразу получилось, составил код, в котором я сейчас разбираюсь и после выходных попробую отработаю на железе. Это называется помощь 

Logik
Offline
Зарегистрирован: 05.08.2014

///когда надо сделать то, что не умеешь в короткие сроки

Бывают. Вот у меня оббивка двана подралась, вчера приехали умеющие в короткий срок сделать а я им заплатил. Это цивилизация, разделение труда, что не умею сделать сам - покупаю. Сам умею очень многое, даже корпусную мебель, а мягкую - нет. Все 100% делать сам никто не умеет.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DmitryR пишет:

Я благодарен ЕвгениюП. Человек узнал необходимую информацию, хоть это не сразу получилось, составил код, в котором я сейчас разбираюсь и после выходных попробую отработаю на железе. Это называется помощь 

Да не переживайте Вы так!
Просто LOGIK с ЕвгениемП живут на разных волнах
Даже такого выдержанного и ровного как DIMAX это заинтересовало )))

DmitryR
Offline
Зарегистрирован: 12.05.2017

//Сам умею очень многое, даже корпусную мебель, а мягкую - нет. Все 100% делать сам никто не умеет.

Хорошо, если мне вдруг понадобится корпусная мебель, я Вам напишу

Logik
Offline
Зарегистрирован: 05.08.2014

Мелкие заказы по всему что умею не принимаю. Только хороше оплачиваемое, а это разработка ПО и по контрактам на пару лет. Так что по пустякам  - не беспокойте, то все лично для себя т.к. с нынешними халтурщиками связыватся не охота, что умею - сам делаю.

ssss
Offline
Зарегистрирован: 01.07.2016

Logik пишет:

Картинку видим? Спады на ней тоже? Запускайте по каждому ;)

И что? Можно по спаду таймер запустить, можно по фронту. Можно по фронту делать захват, можно по спаду. И в чём здесь трудности?

Logik
Offline
Зарегистрирован: 05.08.2014

Трудность в том что запускать надо только один раз по первому, и останавливать один раз по последнему, причем какой именно последний окажется неизвестно. Но не понимаете, так проехали, забейте, задача уже ж решена.

ssss
Offline
Зарегистрирован: 01.07.2016

Вот же ты чукча нечитатель, как а5021! Да хоть 171659765 раз запусти, толку с этого, если оно уже будет запущено после первого. Оно один раз и запустится - ХАРДВАРНО.

Trigger Mode - The counter starts at a rising edge of the trigger TRGI (but it is not
reset). Only the start of the counter is controlled.

И останавливать не надо, последний захват (тоже хардварно) и будет истиной. А даже если и надо остановить, есть режим ОРМ (тоже хардварно). Короче... "Учи матчасть!"(с).

Гриша
Offline
Зарегистрирован: 27.04.2014

мляяяя, один про Фому другой про Ерему... пост 42 про алгоритм вычисление времени, пост 43 про запуск и останов по условию.

ЗЫ. на мой взгляд, задача не решена, код нужно поправить... посты №№ 7, 22, 24

И хватит повторять боевые действия  intel vs amd... если так не ровнодушны, выкеньте кнопку из кода, алгоритм в посте 21

 

DmitryR
Offline
Зарегистрирован: 12.05.2017

Подразобрался с кодом, в общем да, кнопка надо убрать, начинать измерение надо по первому спаду импульса, заканчивать по последнему нарастанию, после выжидания периода времени, заканчивать измерение

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

DmitryR пишет:

Подразобрался с кодом, в общем да, кнопка надо убрать, начинать измерение надо по первому спаду импульса, заканчивать по последнему нарастанию, после выжидания периода времени, заканчивать измерение

Сумеете сами поменять? Там буквально пара строк изменится (и пара выбросится) и всё станет на самом деле ещё проще (кнопка с возу - одной сущностью меньше).

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

DmitryR
Offline
Зарегистрирован: 12.05.2017

Хорошо, сейчас попробую
 

DmitryR
Offline
Зарегистрирован: 12.05.2017

Попробовал, такой вопрос появился: как в коде отражено условие:

// Время ожидания продолжения сигнала в миллисекундах

// Если за это время уровень ни разу не стал LOW, 

// то считаем, что сигнал прекратился 

 

 // Проверяем, что с момент последнего HIGH 
      // прошло >= CONTROL_PERIOD миллисекунд
      //
      if (millis() - endSignalTime >= CONTROL_PERIOD) {
Про сравнение времени с контрольным периодом есть, а про уровень нет
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, это же автомат. Для того, чтобы вообще сюда попасть, он должен находится в состоянии MEASURING (проверка в строке 70). Само состояние устанавливается после нажатия кнопки в строке 60. А время последнего появления высокого уровня (при условии, что состояние MEASURING) устанавливается в обработчике прерывания по появлению этого самого уровня - строка 48

DmitryR
Offline
Зарегистрирован: 12.05.2017


Результат моих издевательств над кодом. Проверку проходит, но мне кажется не правильный код.
///////////////////////////////////
//
//  Пины копки и сигнала
//
//////////////////////#define BUTTON_PIN  2   // Определяем пин 2 как кнопку
#define SIGNAL_PIN  3   // Определяем пин 3 как сигнальный

///////////////////////////////////
//
// Время ожидания продолжения сигнала в миллисекундах
// Если за это время уровень ни разу не стал LOW, 
// то считаем, что сигнал прекратился
//
#define CONTROL_PERIOD  50ul // Определяем период ожидания сигнала

///////////////////////////////////
//
// Возможные состояния измерителя
//
enum METER_STATES {              // enum перечисляет возможные состояния устройства
  WAITING_FOR_SIGNAL = 0,        ///////// Ждём появления LOW на сигнальном пине
  MEASURING,                     // Измеряем
  READY                          // Закончили, результат готов
};

//////////////////////////////////
//
// Переменная для хранени текущего состояния измерителя
// Изначальное состояние - ожидание нажатия кнопки
//
static volatile METER_STATES meterState = WAITING_FOR_SIGNAL; // static используется для создания переменной, которая видна только одной функции; 
                                                              // volatile, используется перед типом переменной, чтобы изменить способ интерпретации и доступа к переменной компилятором и в дальнейшем программой
                                                              // Переменная должна быть объявлена volatile, когда её значение может быть изменено чем-либо за пределами того участка программы, где она объявлена

//////////////////////////////////
//
// Переменные для хранения времени начала отсчёта
// и времени окончания отсчёта (пропадания сигнала)
//
static volatile unsigned long startSignalTime = 0, endSignalTime = 0; // Unsigned long используется для хранения положительных целых чисел в диапазоне от 0 до 4,294,967,295 (2^32 - 1)
                                                                      // unsigned long var = val;
                                                                      // var - имя переменной
                                                                      // val  - присваиваемое значение

//////////////////////////////////
//
// Функция - обработчик поступающего во время измерения сигнала. 
// Выполняется,когда на сигнальном пине появляется HICH
//
void measureISR(void) {                      // void используется при объявлении функций, если функция не возвращает никакого значение при ее вызове 
  endSignalTime = millis();                  // Запоминем время
}

//////////////////////////////////
//
// Функция - обработчик нажатия на кнопку - заменяем на функцию, ожидающую первого появления LOW на пине 3 
//
void waitingISR(void) {
  startSignalTime = endSignalTime = millis(); // Запоминаем время
//////////////////////  detachInterrupt(BUTTON_PIN - 3);            // detachInterrupt(interrupt)выключает обработку внешнего прерывания.


  pinMode(SIGNAL_PIN, INPUT);                 // Устанавливает режим работы сигнального пина как входа. 
                                              // pinMode(pin, mode); 
                                              // pin: номер вход/выхода(pin)

             // mode: режим одно из двух значение - INPUT или OUTPUT,
//detachInterrupt(SIGNAL_PIN - 3)  ???????????? 
attachInterrupt(SIGNAL_PIN - 3, measureISR, RISING); // Задает функцию обработки внешнего прерывания, то есть функция, которая будет вызвана по внешнему прерыванию.
                                                       // Синтексис: attachInterrupt(interrupt, function, mode)
                                                       // interrupt: номер прерывания
                                                       // function: функция, вызваемая прерыванием
                                                       // mode задает режим обработки прерывания
                                                       // RISING прерывание вызывается только при смене значения на порту с LOW на HIGH
  meterState = MEASURING;                     // Изменяем состояние на "измеряем"
}

void setup(void) {                            // void используется при объявлении функций, если функция не возвращает никакого значение при ее вызове 
                                              // Функция setup() вызывается, когда стартует скетч
  Serial.begin(115200);                       // Набор функций Serial служит для связи устройства Ардуино с компьютером или другими устройствами, поддерживающими последовательный интерфейс обмена данными.
                                              // Serial.begin(speed); speed: скорость в бит/c
                                              // Serial.begin инициирует последовательное соединение и задает скорость передачи данных в бит/c (бод). 
                                              // Для обмена данными с компьютером используются следующие значения: 300, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600 или 115200
  
  ///////////////////////////pinMode(BUTTON_PIN, INPUT);                 // Устанавливает режим работы кнопки на вход. 
  ///////////////////////////attachInterrupt(BUTTON_PIN - 3, waitingISR, RISING);     // Задает функцию обработки внешнего прерывания, то есть функция, которая будет вызвана по внешнему прерыванию.
                                                           // Синтексис: attachInterrupt(interrupt, function, mode)
                                                           // interrupt: номер прерывания
                                                           // function: функция, вызваемая прерыванием
}

void loop(void) {                             // Измерительный цикл
  if (meterState == MEASURING) {              // if (условие) и ==, !=, <, > (операторы сравнения)
                                              // if, используется в сочетании с операторами сравнения, проверяет, достигнута ли истинность условия
                                              // Программа проверяет, значение someVariable. Если условие выполняется, то выполняются определенные действия

      //
      // Проверяем, что с момент последнего HIGH 
      // прошло >= CONTROL_PERIOD миллисекунд
      //
      if (millis() - endSignalTime >= CONTROL_PERIOD) {
        //
        // если прошло, то заканчиваем измерения
        //
        detachInterrupt(SIGNAL_PIN - 3);             // detachInterrupt(interrupt)выключает обработку внешнего прерывания.
      meterState = READY;                            // Измеряемое состояние - конец программы
      Serial.print("Result is: ");                   // Serial.print()передает данные через последовательный порт как ASCII текст
      Serial.print(endSignalTime - startSignalTime); // Отоюразить разность между двумя операндами
      Serial.println(" milliseconds");               
      }
  }
}