252 lines
10 KiB
C++
252 lines
10 KiB
C++
/*
|
||
Скетч к проекту "Спутниковая Роботорговля"
|
||
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();
|
||
}
|
||
}
|