@adruzh , ага, я уже тоже начитался))) И даже осознал, что функцию delay() в бесконечных циклах использовать нежелательно, чтобы не пропустить нужные события. Надо делать все непрерывно, но делать защиту от дребезга.
Пока у меня получается так:
Код:
boolean DPPA = 0, dppa_tmp = 0; //Флаги педали газа: 0 - педаль не нажата, 1 - педаль нажата
boolean DS = 0, ds_tmp = 0; //Флаги датчика скорости: 0 - скорость недостаточна, 1 - скорость в норме
boolean ESW = 0, esw_tmp = 0; //Флаги состояние коцевика дверей: 1 - двери закрыты, 0 - открыты
boolean LOCK = 0; //Флаг запертых дверей: 1 - двери заперты, 0 - незаперты
boolean bnc_esw = 0; //Флаг дребезга дверей: 1 - дребезг, 0 - дребезга нет
volatile unsigned long TM = 0; //Время предудущего прерывания датчика скорости
volatile unsigned int HZ = 0; //Частота датчика скорости
unsigned long time_esw = 0, time_dppa = 0, time_ds = 0, time_zakr = 0; //Засечки времени
void setup() { //Вход педали газа на аналоговом входе 5
pinMode(7, INPUT); //Вход концевика дверей: 1 - двери закрыты, 0 - открыты
pinMode(13, OUTPUT); //Выходной сигнал на закрытие
attachInterrupt(1, Speed, RISING); //Прерывание по датчику скорости, пин 3
}
/***Мониторит концевик в реальном времени***/
void loop() {
Bounce_ESW(digitalRead(7)); //Считываем концевик и проверяем на дребезг
if(!ESW) LOCK = DPPA = DS = 0; //Если двери открыты, то они не заперты, флаги сброшены
if(ESW && !LOCK) LOCK = Zakrdv(); //Если двери закрыты и не заперты, попытаться запереть
}
/***Пытается запереть двери при благоприятных условиях***/
boolean Zakrdv() {
Bounce_DPPA(analogRead(5) > 230); //Проверка педали газа с установка флага (U*204.8)
Bounce_DS(HZ > 15*6/3.6); //Проверка датчика скорости на 15 км/ч с установка флага (HZ = V*6/3.6)
if(DPPA && DS){ //Процесс запирание если флаги выставлены
time_zakr = millis(); //Поставить засечку времени.
while(ESW && millis()-time_zakr < 1000){ //Секундная задержка на полное защелкивание замков (если двери закрылись на ходу)
Bounce_ESW(digitalRead(7)); //Продолжаем мониторить концевик
if(!ESW) DPPA = DS = 0; //Резет, если двери открылись внезапкно
return 0;
}
digitalWrite(13, 1); //Подать импульс 0,5 сек. на запирание
delay(500);
digitalWrite(13, 0);
DPPA = 0; DS = 0; //Сброс флагов
delay(2000); //Подождать запирание дверей (из-за ступенчатой работы активаторов)
return 1;
}
return 0;
}
/***Мониторит скорость в реальном времени***/
void Speed() {
HZ = 1000000/(micros() - TM); //Определение частоты датчика скорости
TM = micros();
}
/***Проверка дребезга двери двухстороняя***/
void Bounce_ESW(boolean tmp) { //Проверка дребезга концевика в течении 1/4 сек
if (esw_tmp != tmp){ //Если прошла инвертация, то
bnc_esw = 1; //поднять флаг дребезга,
esw_tmp = tmp; //запомнить текущее состояние (временный флаг),
time_esw = millis(); //поставить засечку времени.
}
else
if (bnc_esw && millis()-time_esw > 250){ //Если прошло больше четверти секунды без инвертаций, то
bnc_esw = 0; //сбросить флаг дребезга,
ESW = esw_tmp = tmp; //записать значение флага концевика (основное и временное).
}
}
/***Проверка дребезга педали газана на стабильный положительный отклик***/
void Bounce_DPPA (boolean tmp) { //Проверка педали газа в течении 1/4 сек.
if(!tmp){ //При отрицательном отклике,
dppa_tmp = 0; //обнулить временный флаг,
return; //и выйти.
}
if (tmp > dppa_tmp){ //Если прошел положительный фронт,
dppa_tmp = 1; //поднять временный флаг,
time_dppa = millis(); //поставить засечку времени.
}
else //Если идут непрерывные положительные отклики,
if (millis()-time_dppa > 250) DPPA = 1; //и, если прошло больше четверти секунды, поднять основной флаг.
}
/***Проверка дребезга датчика скорости на стабильный положительный отклик***/
void Bounce_DS (boolean tmp) { //Проверка стабильности ДС в течении 1/2 сек.
if(!tmp){ //При отрицательном отклике,
ds_tmp = 0; //обнулить временный флаг,
return; //и выйти.
}
if (tmp > ds_tmp){ //Если прошел положительный фронт,
ds_tmp = 1; //поднять временный флаг,
time_ds = millis(); //поставить засечку времени.
}
else //Если идут непрерывные положительные отклики,
if (millis()-time_ds > 500) DS = 1; //и, если прошло больше пол секунды, поднять основной флаг.
}
Получилось конечно длинновато, зато читаемо.
Классами и объектно-ориентированным программированием пользоваться так и не научился. Да и не нужно оно имхо тут. В этом коде только две функции (проверка педали газа и проверка ДС) которые проверяют по одному и тому же алгоритму.
В принципе, логика весьма проста получилась, не смотря на длину.
В loop() непрерывно ведется мониторинг концевика и вызывается функция закрытия.
В функции закрытия непрерывно ведется мониторинг датчиков. И при положительном исходе дает импульс закрытия. И только при импульсе закрытия есть задержи delay() которые останавливают программу на время механических действий.
Самый "мутные" функции - это функция проверки дребезга на концевике, и функции проверки датчиков.
Дребезг концевика отслеживается в обе стороны, т.к. на концевике важно отслеживать оба состояния - как "закрыто", так и "открыто". То есть, если в течении определенного времени не было инвертаций (дребезга), то выставляется соответствующее состояние флага. Если произошел дребезг в незначительное время (не важно в каком состоянии), то состояние флага не меняется.
С отслеживанием обоих датчиков (датчик педали газа и датчик скорости) я поступил немного иначе. Флаг датчика выставляется только если в течении определенного времени были только положительные сигналы без дребезга. Если произошел дребезг (хотя бы единичный), то флаг не выставляется. Т.е. если вдруг датчик неисправный и/или "шумит", то он не учитывается, и команды на закрытия давать не будет. Этот алгоритм решил применить больше для перестраховки, чем как логически верный. Пусть лучше двери перестанут автоматически запираться, чем останется вероятность ложного закрытия по неверным сигналам.