#include <Arduino.h> // Biblioteca para funcoes especificas do Arduino (tone, noTone)
// Pinos dos componentes do sistema
const int RED_LED_PIN = 13; // Pino do LED vermelho
const int YELLOW_LED_PIN = 14; // Pino do LED amarelo
const int GREEN_LED_PIN = 15; // Pino do LED verde
const int BUTTON_PIN = 16; // Pino do botao
const int BUZZER_PIN = 17; // Pino do alarme
const int MOTION_SENSOR_PIN = 18; // Pino do sensor de movimento
// Tempos de espera em milissegundos
const unsigned long MAX_WAITING_TIME = 3UL * 60UL * 1000UL; // 3 min
const unsigned long MIN_WAITING_TIME = 10UL * 1000UL; // 10 s
// Tempos de sinal amarelo e vermelho
const unsigned long YELLOW_TIME = 10UL * 1000UL; // 10s
const unsigned long RED_TIME = 30UL * 1000UL; // 30s
// Parametros do sinal sonoro de confirmacao
const unsigned int CONFIRMATION_SOUND_FREQUENCY = 500; // Hz
const unsigned long CONFIRMATION_SOUND_DELAY = 200; // ms
// Parametros do sinal sonoro do sinal vermelho
const unsigned int N = 30; // numero de subintervalos
const unsigned int MIN_FREQUENCY = 500; // Hz
const unsigned int MAX_FREQUENCY = 1500; // Hz
const unsigned int FREQUENCY_STEP = (MAX_FREQUENCY - MIN_FREQUENCY) / N; // Hz
const unsigned long TIME_STEP = RED_TIME / N; // ms
// Estado do sinal
enum {
RED, // 0
YELLOW, // 1
GREEN // 2
} light_status;
// Estado do botao
int button_status;
bool was_pressed;
// Registros do tempo em milissegundos
unsigned long current_time;
unsigned long previous_green_time;
unsigned long previous_red_time;
unsigned long button_pressed_time;
unsigned long last_sound_change_time;
// Tempo de espera em milissegundos
unsigned long waiting_time;
// Frequencia atual do sinal sonoro do sinal vermelho
unsigned int current_frequency;
// Quantidade de multas
unsigned long fine_quantity;
int motion_sensor_status;
bool has_movement;
void setup() {
// Configuracao dos pinos
pinMode(RED_LED_PIN, OUTPUT);
pinMode(YELLOW_LED_PIN, OUTPUT);
pinMode(GREEN_LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(MOTION_SENSOR_PIN, INPUT);
// Inicializacao dos pinos de saida
digitalWrite(RED_LED_PIN, LOW);
digitalWrite(YELLOW_LED_PIN, LOW);
digitalWrite(GREEN_LED_PIN, HIGH);
digitalWrite(BUZZER_PIN, LOW);
// Inicializacao das variaveis
light_status = GREEN;
button_status = HIGH;
was_pressed = false;
current_time = 0;
previous_green_time = 0;
previous_red_time = 0; // irrelevante
button_pressed_time = 0; // irrelevante
last_sound_change_time = 0; // irrelevante
waiting_time = 4294967295UL; // valor maximo de unsigned long
current_frequency = MIN_FREQUENCY; // irrelevante
fine_quantity = 0;
motion_sensor_status = LOW;
has_movement = false;
// Depuracao
Serial.begin(9600);
}
void loop() {
// Obter o tempo atual em milissegundos
current_time = millis();
// Checar se o botao foi pressionado
button_status = digitalRead(BUTTON_PIN); // LOW - pressionado, HIGH - nao pressionado
// Acionar o som se o botao for pressionado e se o sinal nao for vermelho (aberto para pedestres)
if (button_status == LOW && light_status != RED) {
// Tocar o alarme por um periodo de tempo
tone(BUZZER_PIN, CONFIRMATION_SOUND_FREQUENCY);
delay(CONFIRMATION_SOUND_DELAY);
noTone(BUZZER_PIN);
// Calcular o tempo de espera
if (was_pressed == false) {
// Tempo decorrido desde que o sinal verde foi ligado
unsigned long elapsed_time = current_time - previous_green_time;
if (elapsed_time > MAX_WAITING_TIME) {
// Se mais de tres minutos se passaram com o sinal verde
waiting_time = MIN_WAITING_TIME;
} else if (elapsed_time < MIN_WAITING_TIME) {
// Se menos de dez segundos passaram com o sinal verde
waiting_time = MAX_WAITING_TIME - elapsed_time;
} else {
// Caso contrario
if (MAX_WAITING_TIME - elapsed_time < MIN_WAITING_TIME) {
waiting_time = MIN_WAITING_TIME;
} else {
waiting_time = MAX_WAITING_TIME - elapsed_time;
}
}
// TODO: waiting_time = MAX_WAITING_TIME - elapsed_time + MIN_WAITING_TIME - uma outra forma de logica
// Marcar a hora em que o botao foi pressionado
button_pressed_time = current_time;
}
// Registrar como botao pressionado
was_pressed = true;
}
// Se o botao for pressionado
if (was_pressed == true) {
// Tempo decorrido desde que o botao foi pressionado
unsigned long elapsed_time = current_time - button_pressed_time;
// Se o sinal estiver verde e o tempo de espera for inferior a dez segundos
//if (light_status == GREEN && (waiting_time - elapsed_time) < YELLOW_TIME) {
if (light_status == GREEN && (YELLOW_TIME + elapsed_time) > waiting_time) {
// Mudar o sinal para amarelo
light_status = YELLOW;
// Desligar o verde e ligar o amarelo
digitalWrite(GREEN_LED_PIN, LOW);
digitalWrite(YELLOW_LED_PIN, HIGH);
}
// Se o sinal estiver amarelo e o tempo de espera for inferior a zero
if (light_status == YELLOW && elapsed_time > waiting_time) {
// Mudar o sinal para vermelho
light_status = RED;
// Desligar o amarelo e ligar o vermelho
digitalWrite(YELLOW_LED_PIN, LOW);
digitalWrite(RED_LED_PIN, HIGH);
// Tocar o sinal sonoro do sinal vermelho
current_frequency = MIN_FREQUENCY;
tone(BUZZER_PIN, current_frequency);
// Registrar o tempo em que o sinal vermelho foi ligado
previous_red_time = current_time;
last_sound_change_time = current_time;
// Resetar a variavel
was_pressed = false;
}
}
// Se o sinal for vermelho (para o carro)
if (light_status == RED) {
// Tempo decorrido desde que o sinal vermelho foi acionado
unsigned long elapsed_time = current_time - previous_red_time;
// Mudar a frequencia do sinal sonoro
if (current_time - last_sound_change_time > TIME_STEP) {
noTone(BUZZER_PIN);
current_frequency += FREQUENCY_STEP;
tone(BUZZER_PIN, current_frequency);
last_sound_change_time = current_time;
}
// Verificar se o sensor de movimento acionou
motion_sensor_status = digitalRead(MOTION_SENSOR_PIN);
if (motion_sensor_status == HIGH && has_movement == false) {
// Incrementar a multa
fine_quantity += 1;
// Registrar o movimento
has_movement = true;
// Tirar uma foto do carro que passou no sinal vermelho
takePhoto();
} else if (motion_sensor_status == LOW && has_movement == true) { // Checa se o sensor resetou
// Resetar a variavel
has_movement = false;
}
// Mudar para o sinal verde se passarem trinta segundos com o sinal vermelho
if (elapsed_time > RED_TIME) {
// Mudar o sinal para verde
light_status = GREEN;
// Desligar o vermelho e ligar o verde
digitalWrite(RED_LED_PIN, LOW);
digitalWrite(GREEN_LED_PIN, HIGH);
// Parar de tocar o sinal sonoro
noTone(BUZZER_PIN);
// Registrar o tempo em que o sinal verde foi ligado
previous_green_time = millis();
}
}
// Depuracao - debug
debug();
}
void takePhoto() {
// Tirar uma foto do carro que passou no sinal vermelho
}
void debug() {
Serial.print("LIGHT: ");
if (light_status == GREEN) {
Serial.print("GREEN");
} else if (light_status == YELLOW) {
Serial.print("YELLOW");
} else {
Serial.print("RED");
}
Serial.print(", CT: ");
Serial.print(current_time);
Serial.print(", PGT: ");
Serial.print(previous_green_time);
Serial.print(", PRT: ");
Serial.print(previous_red_time);
Serial.print(", BPT: ");
Serial.print(button_pressed_time);
Serial.print(", WP: ");
Serial.print(was_pressed ? "true" : "false");
Serial.print(", WT: ");
Serial.print(waiting_time);
Serial.print(", PQ: ");
Serial.print(fine_quantity);
Serial.print(", MSS: ");
Serial.print(motion_sensor_status ? "HIGH" : "LOW");
Serial.print(", HM: ");
Serial.println(has_movement ? "true" : "false");
}