feeder/feeder.ino

236 lines
9.7 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 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 // кнопка настройки
#define STEPPER_SPEED 150
#define STEPPER_REV 800
#define STEPPER_DELAY 1000
#define GROOVE_COUNT 3
#define GEAR 4*3.857 // 3.857 - это соотношение зубцов внцтреннее шестеренки и белого круга с орехами
// =========================================================
#include <EEPROM.h>
#include "microDS3231.h"
MicroDS3231 rtc;
#include "EncButton.h"
EncButton<EB_TICK, BTN_PIN> btn;
EncButton<EB_TICK, BTN_PIN2> btn_setup;
EncButton<EB_TICK, BUNKERPIN> term_inhib;
// EncButton<EB_TICK, TERM_COIN> term_coin_put;
#include <Stepper.h>
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 * GEAR) / GROOVE_COUNT);
delayMicroseconds(STEPPER_DELAY);
// oneRev();
disableMotor();
}
// кормежка по кнопке
void feedByButton()
{
if (btn.click())
{
feed();
}
}
// выключаем ток на мотор
void disableMotor()
{
digitalWrite(SLEEP, LOW);
}