/*
parking-access-s01 is demo application of parking access.
https://programmersqtcpp.blogspot.com/2022/03/applicazione-accesso-parcheggio-entry.html
Copyright (C) 2023 Maurilio Pizzurro
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/*
Pulsante verde per simulare la barriera IR
Pulsante giallo per simulare il contatto chiave
*/
#include <IRremote.h>
#include <LiquidCrystal.h>
#include <Servo.h>
#define PIN_RECEIVER 2 // Signal Pin of IR receiver
IRrecv receiver(PIN_RECEIVER);
Servo RCservo;
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
/* SERVO_UP servo in posizione verticale */
#define SERVO_UP 180
/* SERVO_DOWN servo in posizione orizzontale */
#define SERVO_DOWN 90
/* S_XXX stati della macchina a stati g_state */
#define S_START 0
#define S_INOPENING 1
#define S_ISUP 2
#define S_INCLOSING 3
#define IRCMD_PLAY 168
// g_state è la variabile di stato
uint8_t g_state = S_START;
uint8_t g_oldState = 255;
uint8_t g_servoPos = SERVO_DOWN;
uint32_t g_saveMillis = 0;
bool g_onEntryState = false;
/* PIN_IR_BARRIER contatto pulito relay IR RX */
const byte PIN_IR_BARRIER = 4;
/* PIN_KEY contatto pulito comando chiave */
const byte PIN_KEY = 6;
void setup()
{
Serial.begin(115200);
pinMode(PIN_IR_BARRIER, INPUT_PULLUP);
pinMode(PIN_KEY, INPUT_PULLUP);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(A0, OUTPUT);
receiver.enableIRIn(); // Start the receiver
lcd.begin(16, 2);
lcd.setCursor(0, 1);
lcd.print((char)223);
lcd.setCursor(6,1);
lcd.print("Tms: ");
Serial.print("Press play or\nyellow button\n");
RCservo.attach(5);
RCservo.write(g_servoPos);
lcdPrintPos(g_servoPos);
lcdPrintTimeout(0);
}
/* lcdPrintPos() visualizza su lcd la posizione angolare del servo*/
void lcdPrintPos(uint8_t pos) {
char posBuff[4];
posBuff[ 4 - 1 ] = '\0';
sprintf(posBuff, "%#3u", pos);
lcd.setCursor(1, 1);
lcd.print(posBuff);
}
/* lcdPrintState() visualizza su lcd lo stato corrente */
void lcdPrintState(uint8_t n) {
char *s[] = {"S_START "
, "S_INOPENING"
, "S_ISUP "
, "S_INCLOSING"};
lcd.setCursor(0, 0);
lcd.print("RUN ");
lcd.setCursor(5, 0);
lcd.print(s[n]);
}
/* flashingLight() accendo/spegne il lampeggiante */
void flashingLight(bool tf) {
#define FL_TIMING 200
static uint32_t timer = 0;
static uint8_t timing = 0;
if (!tf) {
digitalWrite(LED_BUILTIN, LOW);
digitalWrite(A0, LOW);
timer = 0;
timing = 0;
return;
}
if (millis() - timer > timing) {
bool yelIsOn = !digitalRead(A0);
timer = millis();
timing = FL_TIMING;
digitalWrite(LED_BUILTIN, !yelIsOn);
digitalWrite(A0, yelIsOn);
}
}
/* lcdPrintTimeout() visualizza su lcd il timeout residuo */
void lcdPrintTimeout(uint16_t t) {
char timeBuff[5];
timeBuff[ 5 - 1 ] = '\0';
sprintf(timeBuff, "%#4u", t);
lcd.setCursor(11, 1);
lcd.print(timeBuff);
}
void loop() {
flashingLight(g_state);
uint8_t command = 0;
if (receiver.decode()) {
command = receiver.decodedIRData.command;
receiver.resume(); // Receive the next value
} else if (digitalRead(PIN_KEY) == LOW) {
command = IRCMD_PLAY;
}
/* Gestione automatica degli entry state */
if (g_oldState != g_state) {
g_oldState = g_state;
g_onEntryState = true;
// visualizza lo stato corrente sul display
lcdPrintState(g_state);
} else {
g_onEntryState = false;
}
switch (g_state) {
case S_START:
/* ENTRY STATE */
if (g_onEntryState) {
Serial.println(F("Enter to S_START"));
}
/* RUN STATE */
if (command == IRCMD_PLAY) {
g_state = S_INOPENING;
}
/* EXIT STATE */
if (g_state != g_oldState) {
Serial.println(F("Exit from S_START"));
}
break;
case S_INOPENING:
/* ENTRY STATE */
if (g_onEntryState) {
Serial.println(F("Enter to S_INOPENING"));
}
/* RUN STATE */
if (millis() - g_saveMillis > 25) {
g_saveMillis = millis();
if (g_servoPos <= SERVO_UP) {
g_servoPos++;
RCservo.write(g_servoPos);
lcdPrintPos(g_servoPos);
}
if (g_servoPos == SERVO_UP) {
/* CHANGE STATE */
g_state = S_ISUP;
g_saveMillis = millis();
}
}
/* EXIT STATE */
if (g_state != g_oldState) {
Serial.println(F("Exit from S_INOPENING"));
}
break;
case S_ISUP:
/* ENTRY STATE */
if (g_onEntryState) {
Serial.println(F("Enter to S_ISUP"));
}
/* RUN STATE */
if (millis() - g_saveMillis > 2000) {
/* CHANGE STATE */
g_state = S_INCLOSING;
lcdPrintTimeout(0);
} else {
uint32_t dt = millis() - g_saveMillis;
lcdPrintTimeout(2000 - dt);
}
/* CHECK IR BARRIER */
if (digitalRead(PIN_IR_BARRIER) == LOW) {
/* RESTART TIMER */
g_saveMillis = millis();
}
/* EXIT STATE */
if (g_state != g_oldState) {
Serial.println(F("Exit from S_ISUP"));
}
break;
case S_INCLOSING:
/* ENTRY STATE */
if (g_onEntryState) {
Serial.println(F("Enter to S_INCLOSING"));
}
/* RUN STATE */
if (millis() - g_saveMillis > 35) {
g_saveMillis = millis();
if (g_servoPos >= SERVO_DOWN) {
g_servoPos--;
RCservo.write(g_servoPos);
lcdPrintPos(g_servoPos);
}
if (g_servoPos == SERVO_DOWN) {
/* CHANGE STATE */
g_state = S_START;
}
}
/* CHECK IR BARRIER */
if (digitalRead(PIN_IR_BARRIER) == LOW) {
/* CHANGE STATE */
g_state = S_INOPENING;
}
/* EXIT STATE */
if (g_state != g_oldState) {
Serial.println(F("Exit from S_INCLOSING"));
}
break;
} // end switch
} // end loop()
nano:12
nano:11
nano:10
nano:9
nano:8
nano:7
nano:6
nano:5
nano:4
nano:3
nano:2
nano:GND.2
nano:RESET.2
nano:0
nano:1
nano:13
nano:3.3V
nano:AREF
nano:A0
nano:A1
nano:A2
nano:A3
nano:A4
nano:A5
nano:A6
nano:A7
nano:5V
nano:RESET
nano:GND.1
nano:VIN
nano:12.2
nano:5V.2
nano:13.2
nano:11.2
nano:RESET.3
nano:GND.3
lcd:VSS
lcd:VDD
lcd:V0
lcd:RS
lcd:RW
lcd:E
lcd:D0
lcd:D1
lcd:D2
lcd:D3
lcd:D4
lcd:D5
lcd:D6
lcd:D7
lcd:A
lcd:K
r1:1
r1:2
ir:GND
ir:VCC
ir:DAT
servo1:GND
servo1:V+
servo1:PWM
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r
led1:A
led1:C
led2:A
led2:C
r2:1
r2:2
r3:1
r3:2