Хитрое реле задержки

johnnie
Offline
Зарегистрирован: 06.01.2019

ВН пишет:

не вполне понимаю логический смысл всего действа

ведь понятно, что в N секенду может при разном потоке вписаться разный объем.

т.е. зачем здесь вообще фигурирует время, не проще ли и логичней пропускать ХХ импульсов вначале.

какой объем воды прошел не интересно, важно время открытия крана, на которое не должен реагировать котёл.

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

johnnie пишет:

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

Так я и спрашиваю нахера такие сложности!

Чего Вам так неймётся через жопу-то всё делать? ну, сядьте подумайте. СЛОВАМИ напишите, а не непонятными Вам значками! Оно ж делается тривиально, причём контроллер спит ВСЁ ВРЕМЯ, просыпаясь только для когда приходим импульс на несколько микросекунд. Проснулся, порабоал 2-3 микросекунды и снова спать завалися и делать-то ничего не надо. Там всё как два пальца!

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

johnnie пишет:

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

Из заменяют в разделе "Ищу исполнителя", я Вам с самого начала про это талдычу.

johnnie
Offline
Зарегистрирован: 06.01.2019

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

Я могу Вам алгоритм написать, мне не трудно

Напишите, я сам переведу в программу

johnnie
Offline
Зарегистрирован: 06.01.2019

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

только Вы ведь не отстанете пока Вам готовую программу не дадут

С чего вы взяли? Мне вспоминать ATMEL один день. А уж с ассемблера на С++ я как-нибудь перестроюсь.

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

johnnie пишет:

Напишите, я сам переведу в программу

Хорошо, только уговор, Вы не вяжетесь здесь с кусками программы после этого.

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

johnnie пишет:

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

только Вы ведь не отстанете пока Вам готовую программу не дадут

С чего вы взяли? 

С того, что Вы уже требуете Вам "вопросики" заменять.

johnnie
Offline
Зарегистрирован: 06.01.2019

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

Чего Вам так неймётся через жопу-то всё делать? ну, сядьте подумайте...

...в разделе "Ищу исполнителя"

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

Сяду подумать, когда новогодний марафон закончится :)

хватит намекать мне про бабло, всегда сам делал и сейчас сам сделаю, приехала бы поскорее ARDUINа

johnnie
Offline
Зарегистрирован: 06.01.2019

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

С того, что Вы уже требуете Вам "вопросики" заменять.

Я прошу помощи, а не требую, потому что вашу ардуину я второй день "вижу". Вопросики я и сам заменю, там делов то в коде осталось, пшик. Тока не в форме я пока...рождество.

johnnie
Offline
Зарегистрирован: 06.01.2019

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

Хорошо, только уговор, Вы не вяжетесь здесь с кусками программы после этого.

В 4-м сообщении так и сказал.

Давай

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

Для начала, давайте определимся. Надо воспользоваться тем фактом, что таймер №2 работает в POWER_SAFE режиме, сделать на нём самогонный миллис и при помощи его считать время. Самый дешёвый (в смысле необходимости просыпаться) способ сделать это – это считать время не в миллисекундах, а в неких попугаях. Попугай равен 16,384 миллисекунды. Надеюсь, что такой точности Вам хватит. Это как раз время переполнения этого таймера при макимальном делителе частоты (256 * 1024 / 16000 = 16,384)

Итак, мы сделали собственную функцию _millis(), которая возвращает количество переполнений таймера №2 (т.е. количество интервалов в 16,384 мс) с момента старта программы.

При этом таймер сконфигурирован так, что он считает количество переполнений. Собственно _millis() именно это посчитанное количество и возвращает. Контроллер просыпается по переполнению, увеличивает счётчик переполнений на 1, и тут же засыпает снова. Получается, что ради подсчёта времени, мы просыпаемся на "менее, чем 1 микросекунду" каждые 16384 микросекунды). Мне кажетсся. приемлемо

Если у нас уже есть такая _millis() , нам осталось описать переменные, сконфигурировать прерывание по поступившему импульсу и заснуть. Вся работа будет делаться в обработчике прерывания по импульсу.

Для сна используем режим POWER_SAVE – это самый экономный режим при котором таймер 2 ещё работает.

Пока всё понятно? Продолжу завтра.

Теперь заводим вде константы и две переменные

//
// время (в попугаях) между импульсами, после которого мы считаем,
// что это уже новая пачка сигналов, если меньше равно, то это новый 
//	сигнал текущей пачки
static const uint32_t sessionBreak = 1000; 
//
// время (в попугаях) на которое нужно задерживать начало сессии
static const uint32_t delayTime = 5000; 
//
//	время (в попугаях) начала текущей пачки сигналов
static uint32_t startSession = 0;
//
//	время (в попугаях) последнего зафиксированного сигнала
static uint32_t lastSignal = 0;

Надеюсь, они понятны.

Сейчас можно сделать важное уточнение. При создании механизма _millis о котором шла речь выше, необходимо начальное значение (которое бы выдавалось точно при старте программы) сделать не 0, а sessionBreak+1 !!! Это позволит понять, что самый первый сигнал, который мы получили - есть начало "пачки сигналов" без дополнительных проверок и бубнов.

Ну, собственно всё. Осталось написать обработчик прерывания по поступившему сигналу. Итак, когда поступил сигнал и мы проснулись, необходимо выполнить несколько простейших действий

if (digitalRead(IN_PIN)) { // если это начало сигнала, то провреям
	if (_millis() - lastSignal > sessionBreak) { // если с последнего сигнала прошло много времени (это начало новой пачки)
		startSession = _millis();  // фиксируем начало новой сессии
	} else if (_millis() - startSession >= delayTime) {  // Нет,это сигнал из текущей пачки. (тогда проверяем не истекло ли время задержки)
		digitalWrite(OUT_PIN, HIGH); // если истекло, то дублируем сигнал
	}
	lastSignal = _millis();		// по-любому запоминаем время последнего сигнала
} else { // нет - это конец сигнала
	digitalWrite(OUT_PIN, LOW); // тогда тупо дублируем его в линию (даже, если мы не дублировали начало - хуже не будет)
}

а потом смело ложиться спать дальше.

надеюсь, комментарии достаточно поясняют суть дела?

Вот и всего делов. Котроллер спит практиески всё время, а не рисует лазером по целой секунде.

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

johnnie пишет:

MK свободен, хоть на стене лазером рисуй.

Так спать надо или лазером на стене рисовать? Не понял задачи! Вы уж в показаниях-то не путайтесь!

johnnie
Offline
Зарегистрирован: 06.01.2019

Понятно, а алгоритм где?

Мы не капиталисты и МК не эксплуатируем, пусть спит.

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

sadman41 пишет:

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

я бы так и сдел, там тогда кода на десяток-другой строк, и прерываний не надо

johnnie
Offline
Зарегистрирован: 06.01.2019

ua6em пишет:

я бы так и сдел, там тогда кода на десяток-другой строк, и прерываний не надо

там сложнее, чем секунда после "подлова фронта"

предложите алгоритм?

nik182
Offline
Зарегистрирован: 04.05.2015

А вам моего не хватает? Или обязательно надо через прерывания?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

А можно спросить, у тебя Ардуино, или самодельная плата?  А то тебе сейчас наговорят про энергосбережение, а оно тебе нафиг не нужно. 

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

johnnie пишет:

Понятно, а алгоритм где?

А что, моя фраза 

ЕвгенийП пишет:
Продолжу завтра.
По каким-то причнам не понятна? Я по ошибке по-китайски написал?

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

johnnie пишет:

там сложнее, чем секунда после "подлова фронта"

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

johnnie
Offline
Зарегистрирован: 06.01.2019

Извините, а алгоритм, обещанный, где?

Это?:

Для начала, давайте определимся. Надо воспользоваться тем фактом, что таймер №2 работает в POWER_SAFE режиме, сделать на нём самогонный миллис и при помощи его считать время. Самый дешёвый (в смысле необходимости просыпаться) способ сделать это – это считать время не в миллисекундах, а в неких попугаях. Попугай равен 16,384 миллисекунды. Надеюсь, что такой точности Вам хватит. Это как раз время переполнения этого таймера при макимальном делителе частоты (256 * 1024 / 16000 = 16,384)

Итак, мы сделали собственную функцию _millis(), которая возвращает количество переполнений таймера №2 (т.е. количество интервалов в 16,384 мс) с момента старта программы.

При этом таймер сконфигурирован так, что он считает количество переполнений. Собственно _millis() именно это посчитанное количество и возвращает. Контроллер просыпается по переполнению, увеличивает счётчик переполнений на 1, и тут же засыпает снова. Получается, что ради подсчёта времени, мы просыпаемся на "менее, чем 1 микросекунду" каждые 16384 микросекунды). Мне кажетсся. приемлемо

Если у нас уже есть такая _millis() , нам осталось описать переменные, сконфигурировать прерывание по поступившему импульсу и заснуть. Вся работа будет делаться в обработчике прерывания по импульсу.

Для сна используем режим POWER_SAVE – это самый экономный режим при котором таймер 2 ещё работает.

Пока всё понятно? Продолжу завтра.

Теперь заводим вде константы и две переменные

01 //
02 // время (в попугаях) между импульсами, после которого мы считаем,
03 // что это уже новая пачка сигналов, если меньше равно, то это новый
04 //  сигнал текущей пачки
05 static const uint32_t sessionBreak = 1000;
06 //
07 // время (в попугаях) на которое нужно задерживать начало сессии
08 static const uint32_t delayTime = 5000;
09 //
10 //  время (в попугаях) начала текущей пачки сигналов
11 static uint32_t startSession = 0;
12 //
13 //  время (в попугаях) последнего зафиксированного сигнала
14 static uint32_t lastSignal = 0;

Надеюсь, они понятны.

Сейчас можно сделать важное уточнение. При создании механизма _millis о котором шла речь выше, необходимо начальное значение (которое бы выдавалось точно при старте программы) сделать не 0, а sessionBreak+1 !!! Это позволит понять, что самый первый сигнал, который мы получили - есть начало "пачки сигналов" без дополнительных проверок и бубнов.

Ну, собственно всё. Осталось написать обработчик прерывания по поступившему сигналу. Итак, когда поступил сигнал и мы проснулись, необходимо выполнить несколько простейших действий

01 if (digitalRead(IN_PIN)) { // если это начало сигнала, то провреям
02     if (_millis() - lastSignal > sessionBreak) { // если с последнего сигнала прошло много времени (это начало новой пачки)
03         startSession = _millis();  // фиксируем начало новой сессии
04     } else if (_millis() - startSession >= delayTime) {  // Нет,это сигнал из текущей пачки. (тогда проверяем не истекло ли время задержки)
05         digitalWrite(OUT_PIN, HIGH); // если истекло, то дублируем сигнал
06     }
07     lastSignal = _millis();     // по-любому запоминаем время последнего сигнала
08 } else { // нет - это конец сигнала
09     digitalWrite(OUT_PIN, LOW); // тогда тупо дублируем его в линию (даже, если мы не дублировали начало - хуже не будет)
10 }

а потом смело ложиться спать дальше.

надеюсь, комментарии достаточно поясняют суть дела?

Вот и всего делов. Котроллер спит практиески всё время, а не рисует лазером по целой секунде.

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

johnnie пишет:

Извините, а алгоритм, обещанный, где?

А что, там не описано чётко и однозначно, словами что и зачем надо делать? Или Вам непоянтно? Больше того, я даже псевдокод программы добавил для однозначности и понятности.

Это и всё, больше ничего не надо. Ваша задача решена полностью. нужно написать свой _millis (строк 10 - не более) и ту программу, что я привёл с подробнейшим описанием. Больше ничего делать не надо. Я же говорил, что там как "два пальца". Читайте комментарии в программе и текст топика - разбирайтесь.

Вас что-то не устраивает?

gena
Offline
Зарегистрирован: 04.11.2012

  

gena
Offline
Зарегистрирован: 04.11.2012

  Можно пытаться решить задачу чисто аппаратными средствами, используя например К561АГ1.

nik182
Offline
Зарегистрирован: 04.05.2015

Скажите, а под алгоритмом вы понимаете текст программы или что-то другое? 

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

К кому вопрос? Ко мне? В контексте данного форума, под алгоритмом я понимаю ясное и однозначное описание последовательности действий.

nik182
Offline
Зарегистрирован: 04.05.2015

Что Вы, Евгений! Этот вопрос исключительно ТС. Он так настойчиво требует алгоритм, что я начинаю сомневаться, что же это такое в понимании ТС. Особено в свете замены вопросиков строчками кода. 

johnnie
Offline
Зарегистрирован: 06.01.2019

ЕвгенийП пишет:
ради подсчёта времени, мы просыпаемся на "менее, чем 1 микросекунду" каждые 16384 микросекунды)

Зачем постоянно просыпаться и засыпать? Надо спать пока юзер не открыл кран, пока кран открыт не спать, когда кран закрыли уснуть.

Чего вы добились своей функцией? В моем варианте время считается когда это нужно, а не всё время, и в секундах.

Какое максимальное время в секундах поместится в ваш милис? И что произойдет как он перейдет через ноль?

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

johnnie пишет:

Зачем постоянно просыпаться и засыпать? Надо спать пока юзер не открыл кран, пока кран открыт не спать, когда кран закрыли уснуть.

Чего вы добились своей функцией?

Я добился того, что устройство "не спит" всего две с половиной секунды в сутки + по полмикросекунды на кажды импуьс. А сколько в Вашем варианте, скажем при 10 открытиях крана в сутки (а реально открывают больше)? В среднем кран открывается минут на пять  (если зубы чистить или руки мыть, то на две минуты, а если душ принимать или посуду мыть, так и на все десять-двадцать). Т.е. в Вашем варианте устройство не спит примерно час в сутки, а реально больше, если три человека принимаю душ - уже минимум час только на это.

Вот этого я и добился.

johnnie пишет:

Какое максимальное время в секундах поместится в ваш милис?

Такое, как и в штатный. т.е. любое (с переходами). А если без переходов, в 16384 раза больше, чем в штатный.

johnnie пишет:
И что произойдет как он перейдет через ноль?

Ничего, будет работать дальше.

Впрочем, я Вам ничего не навязываю, делайте как хотите.

johnnie
Offline
Зарегистрирован: 06.01.2019

nik182 пишет:

Скажите, а под алгоритмом вы понимаете текст программы или что-то другое? 

Под словом алгоритм, я понимаю тоже что и все:

АЛГОРИ́ТМ
Мужской род
  1. 1.
    специальное
    Система последовательных операций (в соответствии с определёнными правилами) для решения какой-н. задачи.
    "Теория алгоритмов"
  2. 2.
    книжное
    Совокупность последовательных шагов, схема действий, приводящих к желаемому результату.
    "А. поиска"

 

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

johnnie пишет:

Под словом алгоритм, я понимаю тоже что и все:

Ну, во-первых - это копипаста, а не понимание. А во-вторых, Вы за всех-то не расписывайтесь. Специалисты по алгоритмам используют определения Чёрча, Клини и Тьюринга на основе частично-рекурсивных функций. Позже Россер доказал, что все три подхода математически эквиваленты, и потому пофиг, что использовать.

johnnie
Offline
Зарегистрирован: 06.01.2019

Алгоритм программы в 32-м посте, которая, кстати, почти готова:

Основная программа:

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

При изменении на входе:

Если передача разрешена, то передать вход на выход, иначе Если это начало серии импульсов, то обнулить счетчик импульсов и запустить таймер с интервалом в 1 секунду, на изменения на входе не реагировать, только считать.

С интервалом в одну секунду:

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

Если кол-во секунд равно заданной юзером паузе, то разрешить передачу и ждать изменений на входе.

 

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

Это не алгоритм, ему не хватает ясности и однозначности.

Читаю последние две фразы и сравниваю их с первой фразой "Если МК не занят передачей ..." и никак не могу въехать, когда же ему можно обратно на боковую? Обе последние фразы заканчиваются "начать реалировать ..." ... а спать-то когда? В этих фразах (первой и двух последних)  используются разные слова (возможно,для одинаковых понятий), а потому ясности и однозначности у описания нет.

johnnie
Offline
Зарегистрирован: 06.01.2019

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

johnnie
Offline
Зарегистрирован: 06.01.2019

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

не хватает ясности и однозначности.

Исправил

johnnie
Offline
Зарегистрирован: 06.01.2019

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

Специалисты по алгоритмам используют определения Чёрча, Клини и Тьюринга на основе частично-рекурсивных функций. Позже Россер доказал, что все три подхода математически эквиваленты, и потому пофиг, что использовать.

Можно умничать как угодно, алгоритм - последовательность действий.

johnnie
Offline
Зарегистрирован: 06.01.2019

johnnie пишет:

01 if (digitalRead(IN_PIN)) { // если это начало сигнала, то провреям
02     if (_millis() - lastSignal > sessionBreak) { // если с последнего сигнала прошло много времени (это начало новой пачки)
03         startSession = _millis();  // фиксируем начало новой сессии
04     } else if (_millis() - startSession >= delayTime) {  // Нет,это сигнал из текущей пачки. (тогда проверяем не истекло ли время задержки)
05         digitalWrite(OUT_PIN, HIGH); // если истекло, то дублируем сигнал
06     }
07     lastSignal = _millis();     // по-любому запоминаем время последнего сигнала
08 } else { // нет - это конец сигнала
09     digitalWrite(OUT_PIN, LOW); // тогда тупо дублируем его в линию (даже, если мы не дублировали начало - хуже не будет)
10 }

Нигде не уточнялось, что импульсы всегда начинаются с 1. Там датчик Холла, на каком уровне остановится - тот и будет полдня висеть. :))

ну а фраза "тупо дублируем его в линию (даже, если мы не дублировали начало - хуже не будет)" идиотская, как и постоянно выполняющаяся ненужная команда

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

johnnie пишет:

Можно умничать как угодно, алгоритм - последовательность действий.

Для каждого своё определение. Для Вас одно,для меня - другое, для специалистов по алгоритмам - третье. так же как язык программирования. Уверен. что Вы понимаете под этим свосем не то. что я.

nik182
Offline
Зарегистрирован: 04.05.2015

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

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

johnnie пишет:

Нигде не уточнялось, что импульсы всегда начинаются с 1. 

А это не нужно. Всё работает без счётчика мипульсов,там же время считается.  Зачем подить сущности без необходимости?

johnnie пишет:

ну а фраза "тупо дублируем его в линию (даже, если мы не дублировали начало - хуже не будет)" идиотская, как и постоянно выполняющаяся ненужная команда

Это одна команда. А если поставить проверку, то будет две. Что лучше всегда выполнять одну? Или две?