#include <LiquidCrystal.h>
#include <FastLED.h>
#include <Servo.h>
// Инициализация LCD (12, 11, 10, 9, 8, 7)
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
// Определение пинов
#define button1Pin 2 // Кнопка 1 (прерывание 0)
#define button2Pin 3 // Кнопка 2 (прерывание 1)
#define PIN_TRIG 13 // Ультразвуковой датчик Trig
#define PIN_ECHO 4 // Ультразвуковой датчик Echo
#define DATA_PIN 5 // NeoPixel лента
#define SERVO_PIN 6 // Сервопривод
#define SHOCK_SENSOR A0 // Ударный датчик
// Настройки NeoPixel
#define NUM_ROWS 4
#define NUM_COLS 1
#define NUM_LEDS (NUM_ROWS * NUM_COLS)
#define BRIGHTNESS 255
CRGB leds[NUM_LEDS];
// Глобальные переменные
Servo servo;
volatile bool resetRequested = false;
volatile int button2Count = 0;
unsigned long resetStartTime = 0;
int totalAmount = 0;
bool coinAccepted = true;
void setup() {
// Настройка пинов
pinMode(PIN_TRIG, OUTPUT);
pinMode(PIN_ECHO, INPUT);
pinMode(button1Pin, INPUT_PULLUP);
pinMode(button2Pin, INPUT_PULLUP);
pinMode(SHOCK_SENSOR, INPUT);
// Настройка прерываний
attachInterrupt(digitalPinToInterrupt(button1Pin), requestReset, FALLING);
attachInterrupt(digitalPinToInterrupt(button2Pin), countButton2Press, FALLING);
// Инициализация LCD
lcd.begin(16, 2);
lcd.print("summa:");
// Инициализация NeoPixel
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS);
// Инициализация сервопривода
servo.attach(SERVO_PIN);
servo.write(0);
updateDisplay();
}
void loop() {
// Проверка наполненности копилки
int fillLevel = checkFillLevel();
updateLEDs(fillLevel);
// Если копилка не полная, принимаем монеты
if(fillLevel < 4 && coinAccepted) {
int coinValue = readCoinValue();
if(coinValue > 0) {
processCoin(coinValue);
}
}
// Обработка запроса сброса
if(resetRequested) {
handleResetProcess();
}
delay(100);
}
int checkFillLevel() {
digitalWrite(PIN_TRIG, LOW);
delayMicroseconds(2);
digitalWrite(PIN_TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(PIN_TRIG, LOW);
long duration = pulseIn(PIN_ECHO, HIGH);
int distance = duration * 0.034 / 2;
// Условные значения для 4 уровней наполненности
if(distance < 5) return 4; // Полная
if(distance < 10) return 3; // 3/4
if(distance < 15) return 2; // 1/2
if(distance < 20) return 1; // 1/4
return 0; // Пустая
}
void updateLEDs(int level) {
for(int i = 0; i < NUM_LEDS; i++) {
if(i < level) {
if(level == 4) leds[i] = CRGB::Red; // Полная - красный
else leds[i] = CRGB::Green; // Есть место - зелёный
} else {
leds[i] = CRGB::Black; // Выключен
}
}
FastLED.show();
}
int readCoinValue() {
int sensorValue = analogRead(SHOCK_SENSOR);
// Калибровочные значения для разных номиналов
if(sensorValue > 800) return 10;
if(sensorValue > 600) return 5;
if(sensorValue > 400) return 2;
if(sensorValue > 200) return 1;
return 0;
}
void processCoin(int value) {
coinAccepted = false;
totalAmount += value;
updateDisplay();
// Анимация сервопривода
servo.write(90);
delay(500);
servo.write(0);
delay(500);
// Ждем, пока датчик успокоится
while(analogRead(SHOCK_SENSOR) > 50) {
delay(100);
}
coinAccepted = true;
}
void updateDisplay() {
lcd.setCursor(0, 1);
lcd.print(" "); // Очистка строки
lcd.setCursor(0, 1);
lcd.print(totalAmount);
lcd.print("rub");
}
void requestReset() {
if(!resetRequested) {
resetRequested = true;
resetStartTime = millis();
button2Count = 0;
}
}
void countButton2Press() {
if(resetRequested) {
button2Count++;
}
}
void handleResetProcess() {
lcd.setCursor(0, 0);
lcd.print("cbrosit? ");
int countdown = 10 - (millis() - resetStartTime) / 1000;
if(countdown < 0) countdown = 0;
lcd.setCursor(0, 1);
lcd.print("najmi 3x ");
lcd.print(countdown);
if(button2Count >= 3) {
totalAmount = 0;
updateDisplay();
resetRequested = false;
return;
}
if(countdown <= 0) {
updateDisplay();
resetRequested = false;
lcd.setCursor(0, 0);
lcd.print("summa:");
}
}