#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <AccelStepper.h>
void displayWelcomeScreen();
void displayInputMenu();
void finalizarExecucao();
void displayWaitingScreen();
// Configurações do teclado
const byte numRows = 4;
const byte numCols = 3;
char keys[numRows][numCols] = {
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'*', '0', '#'}
};
byte rowPins[numRows] = {22, 23, 24, 25}; // Pinos conectados às linhas do teclado
byte colPins[numCols] = {26, 27, 28}; // Pinos conectados às colunas do teclado
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, numRows, numCols);
// Configurações do LCD
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Definições dos motores de passo
AccelStepper motorFuso(AccelStepper::FULL4WIRE, 11, 10, 8, 9);
AccelStepper motorPlaca(AccelStepper::FULL4WIRE, 7, 6, 4, 5);
// Definição dos pinos dos potenciômetros
const int potFuso = A0;
const int potPlaca = A1;
const int ledPin = 33; // Led verde
const int ledPinAguardandoEtc = 37; // Led vermelho
const int ledPinEstadoInicialEtc = 35; // Led amarelo
// Definição dos botões start e stop
const int BOTAO_START = 50;
const int BOTAO_STOP = 51;
const int BOTAO_EMERGENCIA = 52;
// Variáveis de controle
String input = ""; // Armazena a entrada do usuário
bool enteringDiameter = true; // Controla se o diâmetro ou a espessura está sendo inserido
bool operationStarted = false; // Indica se a operação foi iniciada
float diametro = 0; // Valor do diâmetro inserido pelo usuário
float espessura = 0; // Valor da espessura inserido pelo usuário
float grausPlacaTotal = 0; // Declare a variável globalmente
const float passeRosca = .5;
const float passeSolda = 8;
enum Estado {
INICIAL,
DIGITANDO_DIAMETRO,
DIGITANDO_ESPESSURA,
AGUARDANDO_INICIO,
EXECUTANDO,
PAUSADO,
FINALIZADO,
EMERGENCIA
};
Estado estadoAtual = INICIAL; // Exemplo de inicialização com o estado INICIAL
// Declarações para controle de debounce
unsigned long lastDebounceTimeStart = 0; // Última vez que o botão start foi pressionado
unsigned long lastDebounceTimeStop = 0; // Última vez que o botão stop foi pressionado
const long debounceDelay = 50; // ms para debounce
void setup() {
// Inicializa a comunicação Serial
Serial.begin(9600);
// Inicializa o LCD
lcd.init();
lcd.backlight();
// Define os pinos dos botões como entrada
pinMode(BOTAO_START, INPUT_PULLUP);
pinMode(BOTAO_STOP, INPUT_PULLUP);
pinMode(BOTAO_EMERGENCIA, INPUT_PULLUP);
// Define o pino do relé como saída e inicialmente desligado
pinMode(53, OUTPUT);
digitalWrite(53, LOW);
//Definie os LEDs
pinMode(ledPin, OUTPUT);
pinMode(ledPinEstadoInicialEtc, OUTPUT);
pinMode(ledPinAguardandoEtc, OUTPUT);
// Configurações iniciais dos motores de passo
motorFuso.setMaxSpeed(1000); // Exemplo, ajuste conforme necessário
motorFuso.setAcceleration(1000); // Exemplo, ajuste conforme necessário
motorPlaca.setMaxSpeed(1000); // Exemplo, ajuste conforme necessário
motorPlaca.setAcceleration(1000); // Exemplo, ajuste conforme necessário
// Exibe a tela de boas-vindas
displayWelcomeScreen();
// Após a tela de boas-vindas, o programa deve automaticamente pedir o diâmetro
estadoAtual = DIGITANDO_DIAMETRO;
displayInputMenu(); // Exibe o menu para entrada do diâmetro
}
void loop() {
Serial.print("Estado Atual: ");
Serial.println(estadoAtual);
// Verificação do botão de emergência
if (digitalRead(BOTAO_EMERGENCIA) == LOW) {
estadoAtual = EMERGENCIA;
digitalWrite(53, LOW); // Desliga o relé
motorFuso.stop();
motorPlaca.stop();
emergencyBlink();
lcd.setCursor(0, 0);
lcd.print("Emergencia");
lcd.setCursor(0, 1);
lcd.print("Pressione Reset");
return;
}
// Verificação do estado pausado
if (estadoAtual == PAUSADO) {
lcd.setCursor(0, 0);
lcd.print("Pausado");
lcd.setCursor(0, 1);
lcd.print("Aguardando");
// Verificação do botão start para retomar a execução
if (digitalRead(BOTAO_START) == LOW) {
estadoAtual = EXECUTANDO;
displayWaitingScreen(); // Mostra a tela de espera
}
return;
}
// Verificação do botão stop
if (digitalRead(BOTAO_STOP) == LOW && (estadoAtual == EXECUTANDO || estadoAtual == AGUARDANDO_INICIO)) {
estadoAtual = PAUSADO;
displayWaitingScreen(); // Mostra a tela de espera
return;
}
if (estadoAtual == INICIAL || estadoAtual == DIGITANDO_DIAMETRO || estadoAtual == DIGITANDO_ESPESSURA) {
digitalWrite(ledPinEstadoInicialEtc, HIGH); // Acende o LED
} else {
digitalWrite(ledPinEstadoInicialEtc, LOW); // Apaga o LED
}
// Controle do LED para os estados Aguardando Início, Executando e Pausado
if (estadoAtual == AGUARDANDO_INICIO || estadoAtual == EXECUTANDO || estadoAtual == PAUSADO) {
digitalWrite(ledPinAguardandoEtc, HIGH); // Acende o LED
} else {
digitalWrite(ledPinAguardandoEtc, LOW); // Apaga o LED
}
if (estadoAtual == FINALIZADO) {
return; // Sai do loop, não executa mais nada
}
unsigned long currentMillis = millis();
// Leitura e tratamento do teclado
if (estadoAtual == DIGITANDO_DIAMETRO || estadoAtual == DIGITANDO_ESPESSURA) {
char key = keypad.getKey();
if (key) {
processKeyInput(key);
}
}
// Debounce e leitura do botão start
bool startPressed = digitalRead(BOTAO_START) == LOW;
if (startPressed && (currentMillis - lastDebounceTimeStart) > debounceDelay) {
lastDebounceTimeStart = currentMillis;
if (estadoAtual == AGUARDANDO_INICIO) {
estadoAtual = EXECUTANDO; // Mudança para estado EXECUTANDO antes de iniciar
iniciarExecucao(); // Ajuste para iniciar a execução
}
}
// Chamadas contínuas para atualização dos motores no estado EXECUTANDO
if (estadoAtual == EXECUTANDO) {
motorFuso.run();
motorPlaca.run();
}
// Verificação do movimento dos motores para decidir sobre a finalização
if (estadoAtual == EXECUTANDO && !executandoMovimentoDosMotores()) {
finalizarExecucao();
}
}
bool executandoMovimentoDosMotores() {
// Verifica se algum dos motores ainda tem passos a percorrer.
if (motorFuso.distanceToGo() != 0 || motorPlaca.distanceToGo() != 0) {
return true; // Movimento em andamento.
}
return false; // Nenhum movimento em andamento.
}
void iniciarExecucao() {
digitalWrite(53, HIGH); // Ativa o relé para indicar o início da operação
operationStarted = true; // Flag que indica que a operação foi iniciada
// Executa a sequência dos motores
executarSequencia();
}
void processKeyInput(char key) {
if (key == '#') { // Confirmação da entrada
if (estadoAtual == DIGITANDO_DIAMETRO) {
// Converte a entrada atual para o diâmetro e limpa a entrada
diametro = input.toFloat();
input = "";
// Muda o estado para a entrada da espessura e atualiza o display
estadoAtual = DIGITANDO_ESPESSURA;
enteringDiameter = false; // Pronto para a próxima entrada
displayInputMenu(); // Atualiza o menu de entrada para espessura
} else if (estadoAtual == DIGITANDO_ESPESSURA) {
// Converte a entrada atual para a espessura e limpa a entrada
espessura = input.toFloat();
input = "";
// Muda o estado para aguardar o início da operação
estadoAtual = AGUARDANDO_INICIO;
displayWaitingScreen(); // Mostra a tela de espera
}
} else if (key == '*') { // Apaga o último dígito
if (input.length() > 0) {
input.remove(input.length() - 1);
displayInputMenu(); // Atualiza o display com a entrada atualizada
}
} else if (key >= '0' && key <= '9') { // Adiciona o dígito à entrada
input += key;
displayInputMenu(); // Atualiza o display com a nova entrada
}
}
// Supondo que PASSOS_POR_VOLTA_COMPLETA esteja definido de acordo com seu motor
const int PASSOS_POR_VOLTA_COMPLETA = 200; // Exemplo hipotético
float passosPorGrau = PASSOS_POR_VOLTA_COMPLETA / 360.0;
void atualizarProgresso(float graus) {
float porcentagem = (graus / 361.0) * 100;
porcentagem = min(porcentagem, 100.0); // Garante que a porcentagem não exceda 100%
lcd.clear(); // Limpa a tela para a nova mensagem
lcd.setCursor(0, 0); // Define a posição do cursor
lcd.print("Progresso: ");
lcd.setCursor(0, 1); // Define a posição do cursor
lcd.print(porcentagem, 1); // Mostra a porcentagem com 0 casas decimais
lcd.print("%");
}
void executarSequencia() {
const unsigned long debounceDelay = 50; // ms para debounce
unsigned long lastDebounceTime = 0; // Último timestamp de mudança de estado do botão
bool pausado = false; // Flag para indicar se a execução está pausada
if (!operationStarted) return; // Continua somente se a operação foi iniciada
int direcaoFuso = 1; // Inicializa a direção como positiva para o primeiro movimento
while(true) { // Altera para um loop infinito, a condição de saída será verificada internamente
// Se grausPlacaTotal já atingiu ou ultrapassou 360 graus, conclui a execução
if (grausPlacaTotal >= 360) {
Serial.println("Motor placa atingiu 360 graus. Finalizando...");
break; // Sai do loop
}
digitalWrite(53, HIGH); // Ativa o relé
// Calcula os passos necessários para o motor do Fuso baseados nas entradas do usuário
float passosFuso = (espessura / passeRosca) * PASSOS_POR_VOLTA_COMPLETA * direcaoFuso;
// Realiza os cálculos para o movimento do motor Placa
float perimetro = PI * diametro;
float mmPorGrau = perimetro / 360.0;
float grausNecessarios = passeSolda / mmPorGrau;
if (grausPlacaTotal + grausNecessarios > 360) {
grausNecessarios = 360 - grausPlacaTotal;
}
float passosPlaca = grausNecessarios * passosPorGrau;
Serial.print("Movendo motor placa por graus: ");
Serial.println(grausPlacaTotal);
// Executa movimento do motor Fuso
motorFuso.move(passosFuso);
while (motorFuso.distanceToGo() != 0) {
motorFuso.run();
// Verifica se o botão Stop foi pressionado para pausar a execução
if (digitalRead(BOTAO_STOP) == LOW) {
estadoAtual = PAUSADO; // Altera o estado para pausado
displayWaitingScreen(); // Exibe a tela de pausa
pausado = true; // Ativa a flag de pausa
return; // Sai da função
}
}
// Executa movimento do motor Placa
motorPlaca.move(passosPlaca);
while (motorPlaca.distanceToGo() != 0) {
motorPlaca.run();
// Verifica se o botão Stop foi pressionado para pausar a execução
if (digitalRead(BOTAO_STOP) == LOW) {
estadoAtual = PAUSADO; // Altera o estado para pausado
displayWaitingScreen(); // Exibe a tela de pausa
pausado = true; // Ativa a flag de pausa
return; // Sai da função
}
}
// Atualiza o progresso após o movimento dos motores
grausPlacaTotal += grausNecessarios;
atualizarProgresso(grausPlacaTotal); // Chama a função para atualizar o LCD com o progresso
// Alterna a direção do motor Fuso para o próximo ciclo
direcaoFuso *= -1;
if (grausPlacaTotal >= 360.0) {
Serial.println("Processo concluído.");
break;
}
}
// Se a execução estiver pausada, aguarda o pressionamento do botão Start para retomar
if (pausado) {
while (digitalRead(BOTAO_START) == HIGH) {
// Aguarda o pressionamento do botão Start
}
// Reinicia a execução após o botão Start ser pressionado
pausado = false; // Desativa a flag de pausa
displayInputMenu(); // Volta a exibir o menu de entrada
estadoAtual = AGUARDANDO_INICIO; // Altera o estado para aguardando início
}
// Após concluir a execução, mostra a tela final
displayFinishedScreen(); // Chama a função para mostrar a tela de conclusão no LCD
// Finaliza a execução
digitalWrite(53, LOW); // Desativa o relé
digitalWrite(ledPin, HIGH); // Aciona o LED indicando o fim do processo
operationStarted = false; // Marca a operação como concluída
estadoAtual = FINALIZADO; // Muda o estado para finalizado
}
void finalizarExecucao() {
Serial.println("Finalizando Execução");
digitalWrite(53, LOW); // Desativa o relé indicando o fim da operação
displayFinishedScreen(); // Exibe mensagem de conclusão
estadoAtual = FINALIZADO; // Muda o estado para FINALIZADO
Serial.println("Estado definido para FINALIZADO");
}
void emergencyBlink() {
static unsigned long previousMillis = 0;
static bool ledState = HIGH;
const unsigned long interval = 500; // Intervalo de piscar em milissegundos
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// Inverte o estado do LED a cada intervalo
ledState = !ledState;
digitalWrite(ledPinAguardandoEtc, ledState);
previousMillis = currentMillis;
}
}
void displayWelcomeScreen() {
if (estadoAtual == FINALIZADO) {
return; // Impede a execução se o programa já foi finalizado
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Fibertech");
lcd.setCursor(0, 1);
lcd.print("Cintador LSB");
delay(5000);
estadoAtual = DIGITANDO_DIAMETRO; // Mudança de estado após a tela de boas-vindas
displayInputMenu(); // Mostra o menu de entrada para iniciar a digitação do diâmetro
}
void displayInputMenu() {
lcd.clear();
lcd.setCursor(0, 0);
if (enteringDiameter) {
lcd.print("Diametro:");
} else {
lcd.print("Espessura:");
}
lcd.setCursor(0, 1);
lcd.print(input + "mm");
}
void displayWaitingScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Aguardando");
lcd.setCursor(0, 1);
lcd.print("inicio");
}
void displayFinishedScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Concluido");
lcd.setCursor(0, 1);
lcd.print("Aguardando reset");
}