feeder/feeder_v2.1.ino

252 lines
10 KiB
C++
Raw Permalink 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"
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; // время выключения
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);
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);
delay(sleepTime);
}
if ((now.hour >= onTime && now.hour < offTime && voltage > 13.2)) { //&& voltage > 10.2
digitalWrite(RELAY, HIGH); // работаем если время рабочее И напряжение выше минимума
} 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();
}
}