#include <Arduino.h>
// Entradas conforme solicitado:
// IN1: pulso trava/destrava (normalmente 0)
// IN2: pulso seta (normalmente 0)
// IN3: porta (0 aberta, 1 fechada)
// IN4: ignicao (1 ligada, 0 desligada)
#define IN_LOCK_UNLOCK 2 // PB0
#define IN_TURN_SIGNAL 3 // PB1
#define IN_DOOR 4 // PB2
#define IN_IGNITION 5 // PB3
#define OUT_HEADLIGHT 6 // PB4
#define DEBOUNCE_MS 30UL
#define OUTPUT_40S_MS 40000UL
#define DELAY_20S_MS 20000UL
struct DebouncedInput {
uint8_t pin;
uint8_t stable;
uint8_t rawPrev;
unsigned long changedAt;
};
enum ControlState {
STATE_IDLE = 0,
STATE_TIMER_40S,
STATE_WAIT_20S_AFTER_DOOR_CYCLE,
STATE_ON_UNTIL_IGN_OFF_DOOR_CYCLE,
STATE_TIMER_40S_AFTER_IGN_OFF_DOOR_CYCLE
};
DebouncedInput in1 = {IN_LOCK_UNLOCK, LOW, LOW, 0};
DebouncedInput in2 = {IN_TURN_SIGNAL, LOW, LOW, 0};
DebouncedInput in3 = {IN_DOOR, HIGH, HIGH, 0};
DebouncedInput in4 = {IN_IGNITION, LOW, LOW, 0};
ControlState state = STATE_IDLE;
unsigned long stateStartedAt = 0;
bool doorOpenedWhileIgnOn = false;
bool doorOpenedWhileIgnOff = false;
bool pulseIn1Rise = false;
bool pulseIn2Rise = false;
bool doorOpenEvent = false;
bool doorCloseEvent = false;
bool updateInput(DebouncedInput &input, unsigned long now) {
const uint8_t raw = digitalRead(input.pin);
if (raw != input.rawPrev) {
input.rawPrev = raw;
input.changedAt = now;
}
if ((now - input.changedAt) >= DEBOUNCE_MS && input.stable != input.rawPrev) {
input.stable = input.rawPrev;
return true;
}
return false;
}
void setState(ControlState newState, unsigned long now) {
state = newState;
stateStartedAt = now;
}
void readInputsAndEvents(unsigned long now) {
pulseIn1Rise = false;
pulseIn2Rise = false;
doorOpenEvent = false;
doorCloseEvent = false;
if (updateInput(in1, now) && in1.stable == HIGH) {
pulseIn1Rise = true;
}
if (updateInput(in2, now) && in2.stable == HIGH) {
pulseIn2Rise = true;
}
if (updateInput(in3, now)) {
if (in3.stable == LOW) {
doorOpenEvent = true;
} else {
doorCloseEvent = true;
}
}
updateInput(in4, now);
}
void processDoorCycleFlags() {
if (in4.stable == HIGH) {
if (doorOpenEvent) {
doorOpenedWhileIgnOn = true;
}
} else {
if (doorOpenEvent) {
doorOpenedWhileIgnOff = true;
}
}
}
void processLogic(unsigned long now) {
const bool ignitionOn = (in4.stable == HIGH);
const bool ignitionOff = !ignitionOn;
const bool anyPulse = pulseIn1Rise || pulseIn2Rise;
processDoorCycleFlags();
// Regra 1: pulso em IN1 ou IN2 com ignicao desligada aciona por 40s.
if (ignitionOff && anyPulse) {
setState(STATE_TIMER_40S, now);
}
// Regra 2 (inicio): porta abriu e fechou com ignicao ligada -> esperar 20s.
if (ignitionOn && doorOpenedWhileIgnOn && doorCloseEvent) {
doorOpenedWhileIgnOn = false;
setState(STATE_WAIT_20S_AFTER_DOOR_CYCLE, now);
}
switch (state) {
case STATE_IDLE:
break;
case STATE_TIMER_40S:
if ((now - stateStartedAt) >= OUTPUT_40S_MS) {
setState(STATE_IDLE, now);
}
break;
case STATE_WAIT_20S_AFTER_DOOR_CYCLE:
// Se ignicao desligar antes dos 20s, cancela.
if (ignitionOff) {
setState(STATE_IDLE, now);
} else if ((now - stateStartedAt) >= DELAY_20S_MS) {
setState(STATE_ON_UNTIL_IGN_OFF_DOOR_CYCLE, now);
}
break;
case STATE_ON_UNTIL_IGN_OFF_DOOR_CYCLE:
// Mantem ligado ate ignicao = 0 e ocorrer ciclo de porta (abre e fecha).
if (ignitionOff && doorOpenedWhileIgnOff && doorCloseEvent) {
doorOpenedWhileIgnOff = false;
setState(STATE_TIMER_40S_AFTER_IGN_OFF_DOOR_CYCLE, now);
}
break;
case STATE_TIMER_40S_AFTER_IGN_OFF_DOOR_CYCLE:
if ((now - stateStartedAt) >= OUTPUT_40S_MS) {
setState(STATE_IDLE, now);
}
break;
}
}
void updateOutput() {
const bool outputOn =
state == STATE_TIMER_40S ||
state == STATE_ON_UNTIL_IGN_OFF_DOOR_CYCLE ||
state == STATE_TIMER_40S_AFTER_IGN_OFF_DOOR_CYCLE;
digitalWrite(OUT_HEADLIGHT, outputOn ? HIGH : LOW);
}
void setup() {
Serial.begin(115200);
// Entradas com nivel logico direto (normalmente 0): usar pull-down externo no hardware.
pinMode(IN_LOCK_UNLOCK, INPUT);
pinMode(IN_TURN_SIGNAL, INPUT);
pinMode(IN_DOOR, INPUT);
pinMode(IN_IGNITION, INPUT);
pinMode(OUT_HEADLIGHT, OUTPUT);
digitalWrite(OUT_HEADLIGHT, LOW);
const unsigned long now = millis();
in1.stable = digitalRead(IN_LOCK_UNLOCK);
in1.rawPrev = in1.stable;
in1.changedAt = now;
in2.stable = digitalRead(IN_TURN_SIGNAL);
in2.rawPrev = in2.stable;
in2.changedAt = now;
in3.stable = digitalRead(IN_DOOR);
in3.rawPrev = in3.stable;
in3.changedAt = now;
in4.stable = digitalRead(IN_IGNITION);
in4.rawPrev = in4.stable;
in4.changedAt = now;
setState(STATE_IDLE, now);
}
void loop() {
const unsigned long now = millis();
readInputsAndEvents(now);
processLogic(now);
updateOutput();
delay(30);
}