#include <Wire.h> // Biblioteca para comunicação I2C
#include <LiquidCrystal_I2C.h> // Biblioteca para display LCD I2C
#include <Keypad.h> // Biblioteca para teclado matricial
// ================= TECLADO 4x4 =================
const byte ROWS = 4; // número de linhas
const byte COLS = 4; // número de colunas
// Mapeamento das teclas do teclado 4x4
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'.','0','#','D'}
};
// Definição dos pinos conectados ao teclado
byte rowPINS[ROWS] = {11,10,9,8}; // linhas
byte colPINS[COLS] = {7,6,5,4}; // colunas
// Criação do objeto teclado
Keypad kpd = Keypad(makeKeymap(keys),rowPINS,colPINS, ROWS, COLS);
// Criação do objeto LCD I2C (endereço 0x27, 20 colunas x 4 linhas)
LiquidCrystal_I2C lcd(0x27,20,4);
// ================= MOTOR DE PASSO =================
const int stp = 2; // pino de passo do driver
const int dir = 3; // pino de direção do driver
const int StepsPerRotation = 400; // passos por volta do motor (depende do motor/driver)
const int TableRatio = 45; // relação da mesa divisor
const int Multiplier = (StepsPerRotation * TableRatio)/360;
// fator de conversão de graus para passos
// ================= POTENCIÔMETRO =================
const int potPin = A0; // pino analógico ligado ao potenciômetro
int stepdelay = 500; // atraso inicial em microssegundos entre passos
// ================= VARIÁVEIS GLOBAIS =================
float Degrees = 0; // ângulo a ser movido
float ToMove = 0; // quantidade de passos para mover
float bob = 0; // total acumulado de movimento
int cho = 0; // escolha do menu
// ================= SETUP =================
void setup()
{
lcd.init(); // inicializa LCD
pinMode(stp, OUTPUT); // define pino de passo como saída
pinMode(dir, OUTPUT); // define pino de direção como saída
pinMode(potPin, INPUT); // define pino do potenciômetro como entrada
lcd.backlight(); // liga a luz de fundo do LCD
lcd.print("**Divisor Digital**");
lcd.setCursor(3,3);
lcd.print("Wagner Koller"); // mensagem de boas-vindas
delay(2000); // espera 2 segundos
lcd.init(); // limpa a tela
cho = 0; // zera escolha de menu
char key = kpd.getKey(); // lê tecla
// Mostra menu principal
lcd.print(" MENU");
lcd.setCursor(0,1);
lcd.print("Graus ------ Tecla A");
lcd.setCursor(0,2);
lcd.print("Divisao ---- Tecla B");
lcd.setCursor(0,3);
lcd.print("Livre ------ Tecla C");
// Aguarda escolha do usuário
while(cho == 0)
{
key = kpd.getKey();
switch (key)
{
case NO_KEY: break; // nenhuma tecla
case 'A': // modo Graus
Degrees=getdegrees();
lcd.clear();
cho = 1;
break;
case 'B': // modo Divisão
Degrees=getdivisions();
cho=2;
break;
case 'C': // modo Livre
Degrees=getjog();
lcd.clear();
cho=3;
break;
}
}
}
// ================= LOOP PRINCIPAL =================
void loop()
{
lcd.clear();
char key = kpd.getKey();
bob = 0; // zera total acumulado
// Mostra total acumulado na tela
lcd.setCursor(7,0);lcd.print("Total: ");lcd.print(bob,2);
lcd.setCursor(0,3);lcd.print("Vai=A Volta=B sair=C");
// Enquanto não apertar "C" (sair)
while(key != 'C')
{
// Mostra ângulo configurado
lcd.setCursor(0,0);lcd.print(abs(Degrees),2);lcd.print((char)223);
// Lê potenciômetro e converte em delay
int potValue = analogRead(potPin);
stepdelay = map(potValue, 0, 1023, 2000, 200);
float delayMs = stepdelay / 1000.0; // converte µs → ms
// Mostra ajuste de delay em ms
lcd.setCursor(0,1);
lcd.print("Delay: ");
lcd.print(delayMs,2);
lcd.print(" ms ");
key = kpd.getKey();
if(key == 'A') // giro positivo
{
bob = bob + Degrees; // soma ao total
ToMove = (Degrees*Multiplier); // calcula passos
digitalWrite(dir, LOW); // define direção
printadvance(); // executa movimento
}
if(key=='B') // giro negativo
{
bob = bob - Degrees;
ToMove = (Degrees*Multiplier);
digitalWrite(dir, HIGH);
printadvance();
}
}
lcd.init(); // reinicia LCD
setup(); // volta ao menu inicial
}
// ================= MODO LIVRE =================
float getjog()
{
float Degrees = 0;
float num = 0.00;
char key = kpd.getKey();
lcd.clear();
lcd.setCursor(6,0);lcd.print("Livre");
lcd.setCursor(0,1);lcd.print("A=1 B=10 C=100 Pasos");
lcd.setCursor(0,2);lcd.print("Entre Graus:");
lcd.setCursor(0,3);lcd.print("OK = # ");lcd.print((char)60);lcd.print((char)45);lcd.print(" D");
while(key != '#')
{
switch (key)
{
case NO_KEY: break;
case 'A': Degrees = 1; lcd.setCursor(14,2);lcd.print(Degrees); break;
case 'B': Degrees = 10; lcd.setCursor(14,2);lcd.print(Degrees); break;
case 'C': Degrees = 100; lcd.setCursor(14,2);lcd.print(Degrees); break;
case 'D': num=0.00; lcd.setCursor(14,2);lcd.print(" "); lcd.setCursor(14,2); break;
}
key = kpd.getKey();
}
return Degrees;
}
// ================= MODO DIVISÕES =================
float getdivisions()
{
float Degrees = 0;
float num = 0.00;
char key = kpd.getKey();
lcd.clear();
lcd.setCursor(0,1);lcd.print("Entre Divisao:");
lcd.setCursor(0,3);lcd.print("OK = # ");lcd.print((char)60);lcd.print((char)45);lcd.print(" D");
lcd.setCursor(16,1);
while(key != '#')
{
switch (key)
{
case NO_KEY: break;
case '0'...'9': num = num * 10 + (key - '0'); lcd.print(key); break;
case 'D': num=0.00; lcd.setCursor(16,1);lcd.print(" "); lcd.setCursor(16,1); break;
}
Degrees = 360/num; // converte número de divisões em graus
key = kpd.getKey();
}
return Degrees;
}
// ================= MODO GRAUS DIRETO =================
float getdegrees()
{
float num = 0.00;
float decnum = 0.00;
int counter = 0;
lcd.clear();
char key = kpd.getKey();
lcd.setCursor(0,1);lcd.print("Entre Graus:");
lcd.setCursor(0,3);lcd.print("OK = # ");lcd.print((char)60);lcd.print((char)45);lcd.print(" D");
lcd.setCursor(15,1);
bool decOffset = false;
while(key != '#')
{
switch (key)
{
case NO_KEY: break;
case '.': if(!decOffset){ decOffset = true; } lcd.print(key); break;
case 'D': num=0.00; lcd.setCursor(15,1);lcd.print(" "); lcd.setCursor(15,1); break;
case '0'...'9':
if(!decOffset){ num = num * 10 + (key - '0'); lcd.print(key); }
else if((decOffset) && (counter <= 1)){ num = num * 10 + (key - '0'); lcd.print(key); counter++; }
break;
}
decnum = num / pow(10, counter); // ajusta número com decimal
key = kpd.getKey();
}
return decnum;
}
// ================= MOSTRA E AVANÇA =================
void printadvance()
{
lcd.setCursor(4,2);lcd.print("pasos ");lcd.print(ToMove,0);
lcd.setCursor(13,0);lcd.print(bob,2);
rotation(ToMove,0); // executa movimento
}
// ================= MOVIMENTO DO MOTOR =================
void rotation(float tm, int d)
{
long steps = round(tm); // arredonda quantidade de passos
for(long i = 0; i < steps; i++)
{
// lê potenciômetro e ajusta delay dinamicamente
int potValue = analogRead(potPin);
stepdelay = map(potValue, 0, 1023, 2000, 200);
// gera pulso no pino do driver
digitalWrite(stp, HIGH);
delayMicroseconds(stepdelay);
digitalWrite(stp, LOW);
delayMicroseconds(stepdelay);
}
}
// ================= RESET DE SOFTWARE =================
void software_Reset()
{
asm volatile (" jmp 0"); // reinicia o programa
}