feeder/feeder_v2.1.ino

268 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Скетч к проекту "Спутниковая Роботорговля"
bgp, 2023
*/
#define EE_RESET 15 // любое число 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 // кнопка настройки
#define STEPS_FRW 19 // шаги вперёд
#define STEPS_BKW 12 // шаги назад
// =========================================================
#include <EEPROM.h>
#include "microDS3231.h"
MicroDS3231 rtc;
#include "EncButton.h"
// #include <Sleep_n0m1.h> //подключение библиотеки для режимов сна
// #include <Wire.h>
#include <GyverPower.h>
// #include <I2C_RTC.h>
EncButton<EB_TICK, BTN_PIN> btn;
EncButton<EB_TICK, BTN_PIN2> btn2;
EncButton<EB_TICK, BUNKERPIN> term_inhib;
// EncButton<EB_TICK, TERM_COIN> term_coin_put;
int feedAmount = 100;
// 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; // время выключения
// Sleep sleep; //объект для работы с режимами сна
unsigned long sleepTime; //переменная для задания времени сна
// GND -- [ R2 ] -- A0 -- [ R1 ] -- VIN
#define VREF 4.25 // точное напряжение на пине 5V (в данном случае зависит от стабилизатора на плате Arduino)
#define DIV_R1 10025 // точное значение 10 кОм резистора
#define DIV_R2 3285 // точное значение 3.3 кОм резистора
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);
power.autoCalibrate(); // автоматическая калибровка ~ 2 секунды , средняя но достаточная точность
// отключение ненужной периферии
power.hardwareDisable(PWR_ADC | PWR_TIMER1); // см раздел константы в GyverPower.h, разделяющий знак " | "
// управление системной частотой
power.setSystemPrescaler(PRESCALER_2); // см константы в GyverPower.h
// настройка параметров сна
power.setSleepMode(STANDBY_SLEEP); // если нужен другой режим сна, см константы в GyverPower.h (по умолчанию POWERDOWN_SLEEP)
power.bodInSleep(false); // рекомендуется выключить bod во сне для сохранения энергии (по умолчанию false - выключен!!)
sleepTime = 60 * 60 * 1000;
//Debug
// Serial.begin(9600); // debug в serial
}
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();
// получаем время
// Serial.print(voltage); // debug
// Serial.println(" V"); // debug
// Serial.print(now.hour); // debug
// Serial.println(" h"); // debug
// Serial.print(rtc.getHours());
// Serial.print(":");
// Serial.print(rtc.getMinutes());
// Serial.print(":");
// Serial.print(rtc.getSeconds());
// Serial.print(" ");
// Serial.print(rtc.getDay());
// Serial.print(" ");
// Serial.print(rtc.getDate());
// Serial.print("/");
// Serial.print(rtc.getMonth());
// Serial.print("/");
// Serial.println(rtc.getYear());
if (voltage < 13.2) {
digitalWrite(RELAY, LOW);
// sleep.pwrDownMode(); //установка режима сна PWR_DOWN
power.sleep(sleepTime); //заснуть на указанное время
}
if ((now.hour >= onTime && now.hour < offTime && voltage > 13.2)) { //&& voltage > 10.2
digitalWrite(RELAY, HIGH); // работаем если время рабочее И напряжение выше минимума
// digitalWrite(TERM_INHIB, LOW);
} else {
digitalWrite(RELAY, LOW);
}
}
// состояние датчика рук
int hand = digitalRead(HANDPIN); //читать инпут с "датчика рук"
digitalWrite(TERM_INHIB, term_inhib.isHold() == 0);
btn.tick();
btn2.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 (hand == LOW)
// {
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 (hand == LOW) // Debug подставляем руки, жмем кнопку - получаем внеочередную кормежку
// {
// feedByButton();
// }
if (btn.click()) {
feed();
}
if (btn2.hold()) // Задаем размер порции:
{
int newAmount = 0;
while (btn2.isHold()) // пока кнопка зажата
{
btn2.tick();
oneRev(); // крутим мотор
newAmount++; // считаем шаги
}
feedAmount = newAmount;
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, LOW);
runMotor();
}
for (int i = 0; i < STEPS_FRW; i++) {
digitalWrite(DIRPIN, HIGH);
runMotor();
}
}