/* Скетч к проекту "Спутниковая Роботорговля" bgp, 2023 */ #define EE_RESET 26 // любое число 0-255. Измени, чтобы сбросить настройки и обновить время #define FEED_SPEED 1500 // задержка между шагами мотора (мкс) #define DIRPIN 2 // d2 направление #define STEPPIN 3 // d3 движение #define BTN_PIN 4 // кнопка выдачи #define BUNKERPIN 5 // d5 датчик наличия корма #define HANDPIN 6 // d6 датчик наличия руки #define TERM_INHIB 8 // d8 посылать "отказ от обслуживания" -upd #define TERM_COIN 7 // d7 считаем монетки - upd #define SLEEP 9 // d9 пока не работаем - двигатель спит #define RELAY 10 // d10 ключ для отключения терминала и двигателя в ночное время #define BTN_PIN2 11 // кнопка настройки // 773 - шаги на один полный круг // 3 - количество выемок в одном круге // 258 = 773/3 #define STEPS_FRW 258 // шаги вперёд #define STEPS_BKW 0 // шаги назад #define STEPPER_SPEED 30 * 2 #define STEPPER_REV 200 * 4 #define STEPPER_DELAY 1000 // ========================================================= #include #include "microDS3231.h" MicroDS3231 rtc; #include "EncButton.h" EncButton btn; EncButton btn_setup; EncButton term_inhib; // EncButton term_coin_put; #include Stepper myStepper(STEPPER_REV, STEPPIN, DIRPIN); int feedAmount = 1; // https://robotchip.ru/podklyuchenie-kupyuropriemnika-cashcode-sm-k-arduino/ int valuePulse = 10; // Стоимость одного импульса int minWidthPulse = 80; // Минимальная ширина одного импульса int maxWidthPulse = 120; // Максимальная ширина одного импульса int debounce = 4; // Защита от помех int pulseCount = 0; // Сколько импульсов получено int receivedRUB = 0; // Сумма unsigned long pulseDuration; // Как давно был последний импульс unsigned long pulseBegin = 0; // Начало импульса unsigned long pulseEnd = 0; // Конец импульса unsigned long curtime; // Время int postPulsePause = 300; // Время ожидания, для завершения подсчета импульсов int pulseState; // Состояние входа "0" или "1" int lastState = 1; // Последние состояние входа "0" или "1" int paymentsCount = 0; int onTime = 6; // время включения int offTime = 20; // время выключения unsigned long sleepTime; // переменная для задания времени сна int monitor_speed = 9600; // GND -- [ R2 ] -- A0 -- [ R1 ] -- VIN #define VREF 3.94 // точное напряжение на пине 5V (в данном случае зависит от стабилизатора на плате Arduino) #define DIV_R1 10000 // точное значение 6.80 кОм резистора #define DIV_R2 4700 // точное значение 1.1 кОм резистора #define VOLT 10.5 #define DEBUG true void setup() { rtc.begin(); if (EEPROM.read(0) != EE_RESET) { // первый запуск EEPROM.write(0, EE_RESET); EEPROM.put(1, feedAmount); rtc.setTime(BUILD_SEC, BUILD_MIN, BUILD_HOUR, BUILD_DAY, BUILD_MONTH, BUILD_YEAR); } EEPROM.get(1, feedAmount); pinMode(STEPPIN, OUTPUT); // пин движения pinMode(DIRPIN, OUTPUT); // пин направления pinMode(HANDPIN, INPUT); // пин ИК датчик руки pinMode(BUNKERPIN, INPUT); // пин ИК датчик бункер pinMode(LED_BUILTIN, OUTPUT); // встроенный LED pinMode(SLEEP, OUTPUT); // пин для отключения двигателя pinMode(TERM_COIN, INPUT); // прием сигнала от терминала pinMode(RELAY, OUTPUT); sleepTime = 60 *60 * 1000; myStepper.setSpeed(STEPPER_SPEED); // Debug if (DEBUG) { Serial.begin(monitor_speed); // debug в serial sleepTime = 10 * 1000; } } void loop() { static uint32_t tmr = 0; float voltage = (float)analogRead(0) * VREF * ((DIV_R1 + DIV_R2) / DIV_R2) / 1024; if (millis() - tmr > 500) { // два раза в секунду static byte prevMin = 0; tmr = millis(); DateTime now = rtc.getTime(); if (DEBUG) { // получаем время Serial.println(String(voltage) + " V"); // debug Serial.println(String(now.hour) + " h"); // debug String str_time = String(rtc.getHours()) + ":" + String(rtc.getMinutes()) + ":" + String(rtc.getSeconds()); String date_time = String(rtc.getDate()) + "-" + String(rtc.getMonth()) + "-" + String(rtc.getYear()); Serial.println(str_time + " " + date_time); } if (voltage < VOLT) { digitalWrite(RELAY, LOW); delay(sleepTime); } if ((now.hour >= onTime && now.hour < offTime && voltage > VOLT)) { //&& voltage > 10.2 digitalWrite(RELAY, HIGH); // работаем если время рабочее И напряжение выше минимума } else { digitalWrite(RELAY, LOW); } } int food_available = digitalRead(HANDPIN); // читать инпут с "датчика рук" digitalWrite(TERM_INHIB, food_available == 0); btn.tick(); btn_setup.tick(); term_inhib.tick(); pulseState = digitalRead(TERM_COIN); // Считываем значение с входа TERM_COIN curtime = millis(); // Записываем значение миллисекунд с момента начала выполнения программы if ((pulseState == 0) && (lastState == 1)) // Ждем начало импульса, логический "0" { pulseBegin = curtime; // Записываем значение милисикунд lastState = 0; // Записываем значение "0" в переменную lastState } else if ((pulseState == 1) && (lastState == 0)) // Ждем окончания импульса, логический "1" { pulseDuration = curtime - pulseBegin; // Расчет длительности импульса в миллисекунд if (pulseDuration > debounce) // Защита от помех, если импульс был небольшой { lastState = 1; // Записываем значение "1" в переменную lastState } if ((pulseDuration > minWidthPulse) && (pulseDuration < maxWidthPulse)) // Проверяем ширину импульса { pulseEnd = curtime; // Сохранить значение милисикунд, окончания импульса pulseCount++; // Инкремент счетчика импульсов } } if ((pulseEnd > 0) && (curtime - pulseEnd > postPulsePause)) // Проверяем, поступают ли еще импульсы { receivedRUB += pulseCount * valuePulse; // Расчет суммы if (receivedRUB > 0) { paymentsCount++; // Надо описать логику, "принимаем платежи сколько угодно раз и кормим сстолько же, как только в кадре появятся руки" Serial.print("Credit: "); // Вывести текст на последовательный порт //Debug Serial.print(receivedRUB); // Вывести значение переменной на пслеовательный порт //Debug Serial.println(" RUB"); // Вывести текст на последовательный порт //Debug Serial.print("Payed: "); Serial.print(paymentsCount); Serial.println(" times"); pulseEnd = 0; // Обнуляем pulseCount = 0; // Обнуляем receivedRUB = 0; // Обнуляем } } if (paymentsCount > 0) // Debug подставляем руки, жмем кнопку - получаем внеочередную кормежку { feed(); paymentsCount--; Serial.print("Payed: "); Serial.print(paymentsCount); } if (btn.click()) { feed(); } if (btn_setup.hold()) { feedAmount = 1; EEPROM.put(1, feedAmount); } if (btn_setup.click()) // Задаем размер порции: { feedAmount += 1; EEPROM.put(1, feedAmount); // записываем количество шагов в постоянную память } } // конец основного цикла // выдача корма void feed() { digitalWrite(SLEEP, HIGH); delayMicroseconds(STEPPER_DELAY); for (int i = 0; i < feedAmount; i++) myStepper.step(STEPPER_REV); delayMicroseconds(STEPPER_DELAY); // oneRev(); disableMotor(); } // кормежка по кнопке void feedByButton() { if (btn.click()) { feed(); } } // выключаем ток на мотор void disableMotor() { digitalWrite(SLEEP, LOW); } // вращение void runMotor() { digitalWrite(SLEEP, HIGH); // Включаем мотор digitalWrite(STEPPIN, HIGH); // по часовой delayMicroseconds(FEED_SPEED); digitalWrite(STEPPIN, LOW); // против часовой delayMicroseconds(FEED_SPEED); } // вращение двигателя в виброрежиме, для непопущения заклинивания void oneRev() { for (int i = 0; i < STEPS_BKW; i++) { digitalWrite(DIRPIN, HIGH); // low обратное вращение runMotor(); } for (int i = 0; i < STEPS_FRW; i++) { digitalWrite(DIRPIN, LOW); runMotor(); } }