diff --git a/microDS3231.h b/microDS3231.h index b93f79c..c006020 100644 --- a/microDS3231.h +++ b/microDS3231.h @@ -1,82 +1,247 @@ /* - Лёгкая библиотека для работы с RTC DS3231 для Arduino - Документация: - GitHub: https://github.com/GyverLibs/microDS3231 - Возможности: - - Чтение и запись времени - - Вывод в char* и String - - Чтение температуры датчика - - Egor 'Nich1con' Zakharov & AlexGyver, alex@alexgyver.ru - https://alexgyver.ru/ - MIT License - - Версии: - v1.2 - добавлены ограничения на вводимые в setTime числа. Также нельзя ввести 29 февраля увы =) - v1.3 - пофикшено зависание, когда модуль отключен но опрашивается - v1.4 - незначительный фикс - v2.0 - новые возможности, оптимизация и облегчение - v2.1 - добавил вывод температуры, вывод в String и char - v2.2 - исправлены дни недели (пн-вс 1-7) - v2.3 - небольшие исправления, оптимизация, изменён порядок вывода даты - v2.4 - исправлена установка времени компиляции - v2.5 - добавлен begin для проверки наличия модуля на линии - v2.6 - исправлены отрицательные температуры + Скетч к проекту "Спутниковая Роботорговля" +bgp, 2023 */ -#ifndef microDS3231_h -#define microDS3231_h -//#include // выбор между библиотеками Wire и microWire -#include -#include "buildTime.h" +#define EE_RESET 26 // любое число 0-255. Измени, чтобы сбросить настройки и обновить время +#define FEED_SPEED 2500 // задержка между шагами мотора (мкс) +#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 // шаги назад -#include -#define COMPILE_TIME F(__TIMESTAMP__) +// ========================================================= +#include +#include "microDS3231.h" +MicroDS3231 rtc; +#include "EncButton.h" -struct DateTime { - uint8_t second; - uint8_t minute; - uint8_t hour; - uint8_t day; - uint8_t date; - uint8_t month; - uint16_t year; -}; +EncButton btn; +EncButton btn_setup; +EncButton term_inhib; +// EncButton term_coin_put; +int feedAmount = 1; -class MicroDS3231 { -public: - MicroDS3231(uint8_t addr = 0x68); // конструктор. Можно передать адрес - bool begin(void); // инициализация, вернет true, если RTC найден - void setTime(const __FlashStringHelper* stamp); // установка времени == времени компиляции - void setTime(DateTime time); // установить из структуры DateTime - void setTime(int8_t seconds, int8_t minutes, int8_t hours, int8_t date, int8_t month, int16_t year); // установка времени - void setHMSDMY(int8_t hours, int8_t minutes, int8_t seconds, int8_t date, int8_t month, int16_t year); // установка времени тип 2 - - DateTime getTime(void); // получить в структуру DateTime - uint8_t getSeconds(void); // получить секунды - uint8_t getMinutes(void); // получить минуты - uint8_t getHours(void); // получить часы - uint8_t getDay(void); // получить день недели - uint8_t getDate(void); // получить число - uint16_t getYear(void); // получить год - uint8_t getMonth(void); // получить месяц - - String getTimeString(); // получить время как строку вида HH:MM:SS - String getDateString(); // получить дату как строку вида DD.MM.YYYY - void getTimeChar(char* array); // получить время как char array [8] вида HH:MM:SS - void getDateChar(char* array); // получить дату как char array [10] вида DD.MM.YYYY - - bool lostPower(void); // проверка на сброс питания - float getTemperatureFloat(void);// получить температуру float - int getTemperature(void); // получить температуру int - -private: - uint8_t encodeRegister(int8_t data); - int getTemperatureRaw(void); - uint8_t readRegister(uint8_t addr); - uint8_t unpackRegister(uint8_t data); - uint8_t unpackHours(uint8_t data); - const uint8_t _addr; -}; +// https://robotchip.ru/podklyuchenie-kupyuropriemnika-cashcode-sm-k-arduino/ -#endif \ No newline at end of file +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 4.5 // точное напряжение на пине 5V (в данном случае зависит от стабилизатора на плате Arduino) +#define DIV_R1 6800 // точное значение 6.80 кОм резистора +#define DIV_R2 1100 // точное значение 1.1 кОм резистора + +#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; + // 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 < 31) + { + digitalWrite(RELAY, LOW); + delay(sleepTime); + } + if ((now.hour >= onTime && now.hour < offTime && voltage > 31)) + { //&& voltage > 10.2 + digitalWrite(RELAY, HIGH); // работаем если время рабочее И напряжение выше минимума + } + else + { + digitalWrite(RELAY, LOW); + } + } + + digitalWrite(TERM_INHIB, term_inhib.isHold() == 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); + Serial.println(" times"); + } + + 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() +{ + for (int i = 0; i < feedAmount; i++) + 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(); + } +}