проблема с счетчиком?
- Войдите на сайт для отправки комментариев
Доброго времени суток всем форумчанам.
Огромная просьба подтолкнуть в нужном направлении человека который дуб в программировании, но очень хочет научится. В общем суть вопроса такова:
Имеется ардуино мини про(точнее только жду с китая), автомобиль, и огромное желание сделать на нем автозапуск от штатной противоугонной системы. Логика работы в моем понимании такова - при нажатии кнопки брелока открытия автомобиля, на актюатор центрального замка приходит импульс не зависимо от того открыт автомобиль или нет. Трижды нажали - трижды сигнал. Так вот хотелось бы чтоб при троекратном нажатии в течении 10 секунд автомобиль заводился. Код автоматического закрытия уже заведенного авто добавлю позже. Сейчас больше интересует где я накосячил, что в протеусе ничего не работает. Код взят с сайтов этого и этого.
код выглядит вот так.
//v 22 //Настройки unsigned long ENGINE_WARM_TIME = 1200000; //В миллисекундах время работы мотора после запуска 1200000 миллисекунд = 20 минут int ENGINE_START_MAX_TIME = 5; //В секундах масимальное время работы стартера типично 3 -10 сек const int aktuatorPin = 4; // контакт, к которому подсоединена кнопка // Тут вписываем переменные – это меняющиеся значения: int schetchiksignala = 0; // счетчик количества срабатываний актюатора int aktuatorState = 0; // текущее состояние актюатора int lastaktuatorState = 0; // предыдущее состояние актюатора // select pins for input const int hand_brake_in = 3; //d3 adruino Контакт стояночного тормоза "-" const int sharging_in = 5; //d5 adruino const int sharging_on = 1; // 0 когда во время работы генератора или от датчика давления масла на этом входе низкое состояние , 1 когда на лампе генератора при работе генератора высокое состояние const int hand_brake_on = 0; // 0= поднятый датчик ручника замыкает на массу тормоз активен (жигули), 1= датчик ручника в поднятом состоянии выдает высокий уровень напряжения // select pins for output const int starter_out = 6; //d6 adruino реле стартера const int engine_out = 7; //d7 adruino зажигание const int secpower_out = 8; //d8 цепи вторичного питания печка, фары итд const int status_out = 9; //d9 светодиод статуса системы горит = система готова к работе(включена, ручник стоит). одно мигание запущен с первой попытки 2 со второй 3 с третьей //светодиод подключать с этого пина на массу через резистор // variable for actual mode int actual_mode = 0; // 2 engine started int left_start_try = 0; // переменная для хранения остатка числа попыток запуска int start_in = 0; // переменная разрешения запуска unsigned long last_start_time = 0; //время в тысячных секунды когда был запущен движок unsigned long start_timer = 0; void setup() { pinMode(aktuatorPin, INPUT); //---- настройка входов и выходов контроллера -------------- // init selected pins pinMode(hand_brake_in, INPUT); // enable input // digitalWrite(hand_brake_in, HIGH); //если подтяжка реализована аппаратно то тут ненадо pinMode(sharging_in, INPUT); // enable input // digitalWrite(sharging_in, LOW); //generator LOW normaly // init outputs pinMode(starter_out, OUTPUT); // enable output digitalWrite(starter_out, LOW); //set digital 0 pinMode(engine_out, OUTPUT); // enable output digitalWrite(engine_out, LOW); //set digital 0 pinMode(secpower_out, OUTPUT); // enable output digitalWrite(secpower_out, LOW); //set digital 0 pinMode(status_out, OUTPUT); // enable output digitalWrite(status_out, LOW); //set digital 0 //---- конец настройки входов и выходов контроллера -------------- } void loop() { // считываем данные с входного «актюаторного» контакта: aktuatorState = digitalRead(aktuatorPin); // сравниваем текущее состояние (aktuatorState) с предыдущим: if (aktuatorState != lastaktuatorState) { // если состояние изменилось, увеличиваем значение счетчика: if (aktuatorState == HIGH) { schetchiksignala++; start_timer = millis(); //запоминаем время } } // для прогона через следующий цикл // делаем текущее состояние предыдущим lastaktuatorState = aktuatorState; // if (millis() > start_timer + 10 * 1000) // если текущее время больше чем первое нажатие + 10 секунд то обнуляем счетчик //{ //schetchiksignala = 0; //} if (schetchiksignala % 3 == 0) { start_in = 1; } else { start_in = 0; } //---- собственно это и есть весь код программы -------------- if (actual_mode < 2 ) //если двигатель не запущен check_start(); //Управляем режимом запуска //код условия обязательно включать в фигурные скобки если должно быть выполнено несколько инструкций, в данном случае одна, поэтому скобки опущены else // иначе { check_for_shutdown(); //Управляем режимом ожидания окончания прогрева } //но хорошая привычка фигурные скобки ставить всегда set_status_led(); //независимо от режима Управляем светодиодом статуса //------------------конец основного кода ----------------- } //---- а дальше идут используемые функции и подфункции -------------- void check_start() { if (start_in == 1 && left_start_try == 0) // 1 is command for start - 1 значит импульс старта пришел с дистанционного управления <--- тут определяется полярность импульса запуска { left_start_try = 3; // указываем что нужно попытаться трижды запустить движок } if ( left_start_try > 0 ) { digitalWrite(engine_out, HIGH); //включаем зажигание digitalWrite(secpower_out, HIGH); //включаем печку фары итд delay(3000); // останавливаем код на 3 секунды чтобы бензонасос набрал давление, все датчики включились if (digitalRead(hand_brake_in) != hand_brake_on) //без ручника не делаем запуск { actual_mode = 2; // заканчиваем попытки запустить движок left_start_try = 0; //без ручника другие попытки бесполезны return; } if (digitalRead(sharging_in) != sharging_on ) // проверяем что генератор не работает { do_start(); // пытаемся запустить движок left_start_try = left_start_try - 1 ; //уменьшаем число попыток if (left_start_try == 0 ) actual_mode = 2; // заканчиваем попытки запустить движок } // конец проверки что ручник стоит а генератор не работает } } // конец процедуры старта void do_start() { //тут будет запуск движка // digitalWrite(engine_out, HIGH); //включаем зажигание // digitalWrite(secpower_out, HIGH); //включаем печку фары итд // delay(3000); // останавливаем код на 3 секунды чтобы бензонасос набрал давление digitalWrite(secpower_out, LOW); //выключаем печку фары итд //----------------------------------------------------------------------------------- цикл стартера digitalWrite(starter_out, HIGH); //включаем стартер for (int secs = 0; secs <= ENGINE_START_MAX_TIME ; secs++) // { delay(1000); // и продолжаем его держать включенным 1 секунду if (digitalRead(sharging_in) == sharging_on) //если зарядка пошла то break; // прерываем цикл } //----------------------------------------------------------------------------------- digitalWrite(starter_out, LOW); //отключаем стартер if (digitalRead(sharging_in) == sharging_on) //еще раз смотрим что зарядка пошла { actual_mode = 2; //Запоминаем что движок запущен last_start_time = millis(); // запоминаем время запуска движка } else { digitalWrite(engine_out, LOW); //выключаем зажигание чтбы разблокировать реле стартера digitalWrite(secpower_out, LOW); //выключаем печку фары итд delay(5000); // останавливаем код на 3 секунды чтобы бензонасос набрал давление } } void check_for_shutdown() { //сюда мы попадаем когда контроллер считает что движок работает if (digitalRead(sharging_in) != sharging_on ) //проверяем что движок случайно не заглох do_shutdown(); else digitalWrite(secpower_out, HIGH); //включаем печку фары итд if (digitalRead(hand_brake_in) != hand_brake_on ) //проверяем что если злодеи сняли с ручника то глушим мотор { do_shutdown(); left_start_try = 0; // и больше не заводим } //тут будем контролировать чтоб если забыли машинку заведенной она не молотила до скончания бензобака а выключалась через какоето время if (actual_mode != 0 ) //значит не выключили заглохший двигатель только что { // милисекунды в ардуино обнуляются каждые 49 суток // для того чтобы в случае если запуск произошел в течении последних 20 минут до обнуления мотор не молотил еще 49 суток // нужно обнулить и время старта, при этом мотор максимум будет прогреваться вдвое больше обычного if (millis() < last_start_time) { last_start_time = 0; } if (millis() > last_start_time + ENGINE_WARM_TIME) // если текущее время больше чем время старта + время прогрева { do_shutdown(); left_start_try = 0; // и больше не заводим } } } void do_shutdown() { digitalWrite(secpower_out, LOW); //выключаем печку фары итд digitalWrite(engine_out, LOW); //вырубаем зажигание actual_mode = 0; // движок выключили запомним это last_start_time = 0; // ну и забудем о том что он был включен } void set_status_led() { if (digitalRead(hand_brake_in) != hand_brake_on ) //Если ручник не стоит то выкл светодиод нечего ему в пути мигать попусту { digitalWrite(status_out, LOW); return; //прерываем выполнение функции } if (actual_mode == 2) //Движок запущен status_led_flash(); // показываем с какой попытки был прошлый запуск else digitalWrite(status_out, HIGH); // постоянное свечение - показываем что готов к следующему запуску } void status_led_flash() { static unsigned long big_interval = 0; static unsigned long flash_interval = 0; unsigned long flash_count = 0; flash_count = 3 - left_start_try; //сколько раз мигать //1 секндный интервал if (millis() > flash_interval + 1000L) flash_interval = millis() ; //задаем счетчие от 0 до 1 секунды //задаем 6 секунд if (millis() > big_interval + 6000L) { big_interval = millis() ; //задаем счетчие от 0 до 10секунд flash_interval = big_interval; } if (millis() < big_interval + flash_count * 1000L) // делим 6 секндный интервал на два периода, в первый мигаем количество раз соответствующее числу израсходованных попыток { //мигает if (millis() > flash_interval + 500L) digitalWrite(status_out, HIGH); else digitalWrite(status_out, LOW); } else { // негорит digitalWrite(status_out, LOW); //set digital 0 } }
Это мое первое знакомство с ардуино и с програмированием (разве что basic немного помню со школы :-)). Учится и читать готов. просьба толкнуть в нужном направлении.
предполагаю что косяк со счетчиком в строках с 70 по 95. Или его применением в дальнейшем. Проблема еще и в том что самой ардуинки еще нет и мог накосячить в протеусе. Проект протеуса тут.
Я не разбираюсь в логике запуска автомобиля, потому по сути сказать ничего не могу, но хочу предостеречь от очень неаккуратного кода. Он у Вас повторяется много раз (строки 264, 268, 278 и может ещё где). Вы пишете
так нельзя!
Если Вам нужно отработать задержку, то писать нужно:
Иначе у Вас будет много головной боли в случаях, когда скетч работает очень долго без перезагрузки..
Даже если конкретно-данный скетч и не предполагается к работе месяцами без остановки, просто привыкайте писать правильно. Это должно быть на рефлексах. А то когда-нибудь напишете так не задумываясь, а оно подведёт.
признаться пока не понял в чем принципиальное отличие, но обязательно исправлю и попробую разобраться. Спасибо.
признаться пока не понял в чем принципиальное отличие
Так, как у Вас написано, отсчёт интервала будет сбиваться при переполнении millis(), т.е. когда она достигнет максимального значения и станет снова нулём. А так, как я написал - пофиг, пусть переполняется, всё отработает нормально.
да и попробую описать логику запуска авто.
приходит три сигнала (+12v приведу к 5v через делитель) в течении 10с на actuator_pin (если интервал больше 10с то счетчик schetchiksignala обнуляется). Контроллер проверяет наличие 0v на пине hand_brake_in( ручник натянут) и наличие 0v на пине sharging_in (нет зарядки - двигатель заглушен). если условия выполненны то подается +5 на engine_out (зажигание), +5 на secpower_out (доп оборудование) и после паузы +5 на starter_out (стартер). стартер крутит секунду - мониторит наличие зарядки, и если она появляется то прокрутка стартером прекращается. если не появляется то крутим три секунды и останов. затем еще две попытки и если запуск не прошел то окончательно отключаемся. это вкратце. но при симулировании на протеусе ничего не происходит. сечас читаю как прикрутить в протеусе терминал к ардуине, внести в код принты на терминал и может тогда разберусь что к чему... В общем буду благодарен любой подсказке.
Так, как у Вас написано, отсчёт интервала будет сбиваться при переполнении millis(), т.е. когда она достигнет максимального значения и станет снова нулём. А так, как я написал - пофиг, пусть переполняется, всё отработает нормально.
ТОЧНО! Огромное спасибо! уже переделываю!
Даю кстати, если уж у нас сравнение беззнаковых чисел, то и константу надо писать беззнаковую. т.е. не
а
в данном случае "на скорость не влияет", но тоже - лучше привыкать делать правильно потому, что когда-нибудь подведёт.
в общем не верные настройки были в протеусе. Сейчас схема начала отрабатывать, но пока не совсем адекватно. Как говорится с таким кодом авто не заглушишь. отпустил ручник - заглохла, поднял - опять заводится. Буду дальше разбираться. Как разберусь выложу результат.
УРА!!! Заработало!!! Пока правда в протеусе. Исправил пару опечаток и добавил терминал чтобы вкурить где косяки. По сути код терминала можно снести это одна из попыток анализа осталась. (хотя и рабочая). Итог можно поставить практически на любой авто со штатной сигналкой автозапуск. Нужны сигнал зарядки, ручника, и актюатора центрального замка. осталось придумать как переделать проводку для замыкания авто после запуска и разрешение для запуска хочу переделать на тахометр (подсчет кол-ва оборотов и если выше 500 то запуск). В общем работы еще много.