#include <LiquidCrystal_74HC595.h>
#include <TimerOne.h>
// LCD via 74HC595: (DS, clock, latch, RS, E, D4, D5, D6, D7)
LiquidCrystal_74HC595 lcd(11, 13, 12, 1, 2, 4, 5, 6, 7);
#define MOTOR1 3 // Pulso STEP (esteira, via driver A4988)
const int PINO_POTENCIOMETRO = A0;
const int fotoeletrico = A4;
const int capacitivo = A5;
const int botao_liga = A1;
const int botao_desliga = A2;
const int botao_reset = A3;
// Catraca: 7=A-, 6=A+, 5=B+, 4=B-
const int MOTOR2_AM = 7;
const int MOTOR2_AP = 6;
const int MOTOR2_BP = 5;
const int MOTOR2_BM = 4;
// Ultrassonico (tamanho)
const int PINO_TRIG = 10;
const int PINO_ECHO = 9;
// LEDs via transistor: HIGH=amarelo(nao-metal), LOW=verde(metal)
const int PINO_LEDS = 8;
const int PASSOS_45_GRAUS = 25;
int faseMotor2 = 0;
// --- ESTEIRA via Timer1 (pulsos por interrupcao) ---
volatile bool nivelStep = LOW;
volatile bool esteiraLigada = false;
// faixa de meio-periodo do pulso, em microssegundos:
// pot baixo = periodo longo (lento), pot alto = periodo curto (rapido)
const long ESTEIRA_LENTO_US = 2500; // bem lento
const long ESTEIRA_RAPIDO_US = 300; // bem rapido
unsigned long ultimoPot = 0;
const long intervaloPot = 100; // le o pot a cada 100ms
bool estado_sistema = false;
// --- Classificacao ---
bool pecaEmAnalise = false;
bool detectouMetal = false;
bool jaClassificou = false;
unsigned long tempoDeteccao = 0;
const long tempoAnalise = 3000;
int contadorMetal = 0;
int contadorNaoMetal = 0;
bool desviarPeca = false;
bool pedidoDesligar = false;
bool mostrarTotalFinal = false;
// Mensagem de reset
bool mostrarReset = false;
unsigned long tempoReset = 0;
const long duracaoReset = 1000;
// --- Tamanho (ultrassonico) ---
float distancia = 0;
const float LIMITE_TAMANHO_CM = 8.0;
char tamanhoPeca[8] = "?";
int passosAtuaisMotor2 = 0;
unsigned long ultimoPassoMotor2 = 0;
const unsigned long INTERVALO_PASSO_MOTOR2_MS = 15;
int telaAtual = 0;
unsigned long tempoTela = 0;
const long intervaloTela = 3000;
char ultimoStatus[17] = "AGUARDANDO";
unsigned long tempoStatus = 0;
const long duracaoStatus = 2500;
const unsigned long DEBOUNCE_MS = 40;
bool estLiga = HIGH, ultLiga = HIGH;
bool estDeslig = HIGH, ultDeslig = HIGH;
bool estReset = HIGH, ultReset = HIGH;
unsigned long tDebLiga = 0, tDebDeslig = 0, tDebReset = 0;
const int LEITURAS_CONFIRMA = 3;
int contFoto = 0, contCap = 0;
bool fotoEstavel = false, capEstavel = false;
// --- ISR da esteira: so alterna o pino STEP, nada mais ---
void esteiraISR() {
if (esteiraLigada) {
nivelStep = !nivelStep;
digitalWrite(MOTOR1, nivelStep);
} else {
digitalWrite(MOTOR1, LOW);
}
}
void setup() {
Serial.begin(9600);
pinMode(PINO_POTENCIOMETRO, INPUT);
pinMode(fotoeletrico, INPUT);
pinMode(capacitivo, INPUT);
pinMode(MOTOR1, OUTPUT);
pinMode(MOTOR2_AP, OUTPUT);
pinMode(MOTOR2_AM, OUTPUT);
pinMode(MOTOR2_BP, OUTPUT);
pinMode(MOTOR2_BM, OUTPUT);
pinMode(PINO_TRIG, OUTPUT);
pinMode(PINO_ECHO, INPUT);
pinMode(PINO_LEDS, OUTPUT);
pinMode(botao_liga, INPUT_PULLUP);
pinMode(botao_desliga, INPUT_PULLUP);
pinMode(botao_reset, INPUT_PULLUP);
digitalWrite(MOTOR1, LOW);
digitalWrite(PINO_LEDS, LOW);
// Inicializa o Timer1 com a velocidade mais lenta por padrao
Timer1.initialize(ESTEIRA_LENTO_US);
Timer1.attachInterrupt(esteiraISR);
lcd.begin(16, 2);
mostrarLogo();
lcd.clear();
}
void mostrarLogo() {
lcd.clear();
lcd.setCursor(5, 0); lcd.print("HORSCH");
lcd.setCursor(4, 1); lcd.print("NEXT GEN");
delay(2000);
}
// Le o pot e ajusta a frequencia do Timer1 (velocidade da esteira)
void atualizarVelocidadeEsteira() {
if (millis() - ultimoPot < intervaloPot) return;
ultimoPot = millis();
int leitura = analogRead(PINO_POTENCIOMETRO);
// pot baixo -> periodo longo (lento); pot alto -> periodo curto (rapido)
long meioPeriodo = map(leitura, 0, 1023, ESTEIRA_LENTO_US, ESTEIRA_RAPIDO_US);
noInterrupts();
Timer1.setPeriod(meioPeriodo);
interrupts();
}
// --- Ultrassonico: medicao pontual com timeout curto ---
void medirUltra() {
digitalWrite(PINO_TRIG, LOW);
delayMicroseconds(2);
digitalWrite(PINO_TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(PINO_TRIG, LOW);
long duracao = pulseIn(PINO_ECHO, HIGH, 12000); // timeout 12ms (~2m)
if (duracao > 0) distancia = duracao / 58.0;
}
void ligar_FaseMotor2(int fase) {
digitalWrite(MOTOR2_AP, LOW);
digitalWrite(MOTOR2_BP, LOW);
digitalWrite(MOTOR2_AM, LOW);
digitalWrite(MOTOR2_BM, LOW);
switch (fase) {
case 0: digitalWrite(MOTOR2_AP, HIGH); break;
case 1: digitalWrite(MOTOR2_BP, HIGH); break;
case 2: digitalWrite(MOTOR2_AM, HIGH); break;
case 3: digitalWrite(MOTOR2_BM, HIGH); break;
}
}
void passoMotor2(bool sentidoHorario) {
faseMotor2 = sentidoHorario ? (faseMotor2 + 1) % 4 : (faseMotor2 + 3) % 4;
ligar_FaseMotor2(faseMotor2);
}
void atualizarMotor2() {
int alvoPassos = desviarPeca ? PASSOS_45_GRAUS : 0;
if (passosAtuaisMotor2 == alvoPassos) return;
if (millis() - ultimoPassoMotor2 < INTERVALO_PASSO_MOTOR2_MS) return;
ultimoPassoMotor2 = millis();
if (passosAtuaisMotor2 < alvoPassos) {
passoMotor2(true);
passosAtuaisMotor2++;
} else {
passoMotor2(false);
passosAtuaisMotor2--;
}
}
bool clicou(int pino, bool &estado, bool &ultimo, unsigned long &tDeb) {
bool leitura = digitalRead(pino);
bool flanco = false;
if (leitura != ultimo) tDeb = millis();
if (millis() - tDeb > DEBOUNCE_MS) {
if (leitura != estado) {
estado = leitura;
if (estado == LOW) flanco = true;
}
}
ultimo = leitura;
return flanco;
}
bool sensorConfirmado(int pino, int &contador, bool &estavel) {
bool leitura = (digitalRead(pino) == HIGH);
if (leitura == estavel) {
contador = 0;
} else {
contador++;
if (contador >= LEITURAS_CONFIRMA) {
estavel = leitura;
contador = 0;
}
}
return estavel;
}
void telaContadores() {
lcd.setCursor(0, 0);
lcd.print("METAL: ");
lcd.print(contadorMetal);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print("N-METAL: ");
lcd.print(contadorNaoMetal);
lcd.print(" ");
}
void telaStatus() {
lcd.setCursor(0, 0);
lcd.print("STATUS: ");
lcd.setCursor(0, 1);
lcd.print(ultimoStatus);
int n = strlen(ultimoStatus);
for (int i = n; i < 16; i++) lcd.print(" ");
}
void telaTotalFinal() {
int total = contadorMetal + contadorNaoMetal;
lcd.setCursor(0, 0);
lcd.print("M:");
lcd.print(contadorMetal);
lcd.print(" NM:");
lcd.print(contadorNaoMetal);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print("TOTAL: ");
lcd.print(total);
lcd.print(" ");
}
void telaReset() {
lcd.setCursor(0, 0);
lcd.print(" RESETADO! ");
lcd.setCursor(0, 1);
lcd.print(" contadores=0 ");
}
void atualizarLCD() {
if (mostrarReset) { telaReset(); return; }
if (mostrarTotalFinal) { telaTotalFinal(); return; }
if (pecaEmAnalise || (millis() - tempoStatus < duracaoStatus)) { telaStatus(); return; }
switch (telaAtual) {
case 0: telaContadores(); break;
case 1: telaContadores(); break;
}
}
void classificar(bool metal) {
jaClassificou = true;
// tamanho pela distancia medida no momento
if (distancia > 0 && distancia < LIMITE_TAMANHO_CM) strcpy(tamanhoPeca, "GRANDE");
else strcpy(tamanhoPeca, "PEQUENA");
if (metal) {
contadorMetal++;
snprintf(ultimoStatus, sizeof(ultimoStatus), "METAL %s", tamanhoPeca);
desviarPeca = false;
digitalWrite(PINO_LEDS, LOW); // verde
Serial.print("METAL ("); Serial.print(tamanhoPeca);
Serial.print(") dist="); Serial.println(distancia);
} else {
contadorNaoMetal++;
snprintf(ultimoStatus, sizeof(ultimoStatus), "N-METAL %s", tamanhoPeca);
desviarPeca = true;
digitalWrite(PINO_LEDS, HIGH); // amarelo
Serial.print("NAO-METAL ("); Serial.print(tamanhoPeca);
Serial.print(") dist="); Serial.println(distancia);
}
tempoStatus = millis();
}
void loop() {
// --- BOTOES ---
if (clicou(botao_liga, estLiga, ultLiga, tDebLiga)) {
estado_sistema = true;
esteiraLigada = true;
pedidoDesligar = false;
mostrarTotalFinal = false;
}
if (clicou(botao_desliga, estDeslig, ultDeslig, tDebDeslig)) {
pedidoDesligar = true;
}
if (clicou(botao_reset, estReset, ultReset, tDebReset)) {
contadorMetal = 0;
contadorNaoMetal = 0;
mostrarReset = true;
tempoReset = millis();
mostrarTotalFinal = false;
lcd.clear();
Serial.println("CONTADORES ZERADOS");
}
if (mostrarReset && (millis() - tempoReset >= duracaoReset)) {
mostrarReset = false;
lcd.clear();
}
// --- VELOCIDADE DA ESTEIRA (le pot e ajusta Timer1) ---
atualizarVelocidadeEsteira();
// --- SENSORES ---
bool pecaPresente = sensorConfirmado(fotoeletrico, contFoto, fotoEstavel);
bool capacitivoAtivo = sensorConfirmado(capacitivo, contCap, capEstavel);
// --- CLASSIFICACAO ---
if (estado_sistema) {
if (pecaPresente) {
if (!pecaEmAnalise) {
pecaEmAnalise = true;
detectouMetal = false;
jaClassificou = false;
tempoDeteccao = millis();
strcpy(ultimoStatus, "ANALISANDO...");
tempoStatus = millis();
Serial.println("PECA AVISTADA - analisando...");
medirUltra(); // mede o tamanho so quando a peca aparece
}
if (capacitivoAtivo && !jaClassificou) classificar(true);
if (!jaClassificou && (millis() - tempoDeteccao >= tempoAnalise)) classificar(false);
}
if (!pecaPresente && pecaEmAnalise) {
pecaEmAnalise = false;
desviarPeca = false;
digitalWrite(PINO_LEDS, LOW);
Serial.println("PECA PASSOU");
}
}
// --- CATRACA ---
atualizarMotor2();
// Esteira so para de vez quando a catraca voltou a 0 graus
if (pedidoDesligar && passosAtuaisMotor2 == 0) {
estado_sistema = false;
esteiraLigada = false;
pedidoDesligar = false;
mostrarTotalFinal = true;
Serial.println("ESTEIRA PARADA - mostrando total");
}
// --- TELAS ---
if (millis() - tempoTela >= intervaloTela) {
tempoTela = millis();
telaAtual = (telaAtual + 1) % 2;
lcd.clear();
}
atualizarLCD();
}LEDS
FIM DE CURSO