/* Bobinatrice.ino
Created: Gennaio 2025
Processor: Arduino Uno
Compiler: Arduino AVR
*/
#include <LiquidCrystal_I2C.h>
//#include <wire.h> da inserire listato finale
#include <EEPROM.h>
#include <Keypad.h>
#include <AccelStepper.h>
// Definizione display I2C
LiquidCrystal_I2C lcd(0x27, 20, 4);
byte frecciaSu[8] = { 0x04, 0x0E, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E }; // Definizione carattere freccia in su
byte frecciaGiu[8] = { 0x0E, 0x0E, 0x0E, 0x0E, 0x1F, 0x0E, 0x04, 0x00 }; // Definizione carattere freccia in ggiu
byte frecciaDx[8] = { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00 }; // Definizione carattere freccia a sinistra
byte frecciaSx[8] = { 0x03, 0x06, 0x0C, 0x18, 0x0C, 0x06, 0x03, 0x00 }; // Definizione carattere freccia a destra
// definizione tastiera 4X4
const byte ROWS = 4; // Quattro linee per...
const byte COLS = 4; // Quattro colonne.
char keys[ROWS][COLS] = {
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', '.' },
{ '*', '0', '#', 'D' }
};
byte rowPins[ROWS] = { 9, 8, 7, 6 };
byte colPins[COLS] = { 5, 4, 3, 2 };
Keypad kpd = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
char key = kpd.getKey();
char kpadState;
char oldKey;
String Texto = "";
// Definizione pins stepper Carrello
#define STEPPER_C_DIR_PIN 12
#define STEPPER_C_STEP_PIN 13
// Definizione pins stepper Rocchetto
#define STEPPER_R_DIR_PIN 10
#define STEPPER_R_STEP_PIN 11
// Definizione degli stepper e dei pin utilizzati
AccelStepper stepper_R(AccelStepper::DRIVER, STEPPER_R_STEP_PIN, STEPPER_R_DIR_PIN);
AccelStepper stepper_C(AccelStepper::DRIVER, STEPPER_C_STEP_PIN, STEPPER_C_DIR_PIN);
int NumSpi; // Numero delle spire previste
int NumSpiOld;
float DiaFil; // Diametro del filo
float LunRoc; // Lunghezza del rocchetto
bool Isolan = false; // Flag isolante 1=Si 0=No
int menu = 0; // Indice dei menu
int Direzione; // Direzione spostamento Carrello 1 = DX -1 = SX
const int StepGiro = 200; // numero di step per spira
int Vel = 0; // Velocità motore rocchetto
int VelMax = 1000; // Velocità massima motore rocchetto
int Valore = 0; // Variabile temporanea
bool Start = false; // Flag inizio lavoro
bool Pausa = false; // Flag pausa attiva
int SpireStrato; // Numero di spire per strato
int AvvCarr; // Passi di avanzamento carrello
int Target_R; // Variabile passi rocchetto
int Target_C; // Variabile passi carrello
int Target_T; // Variabile passi Agg. zero
int SpireAtt; // Numero spire fatte
int StratoAtt; // Numero strati fatti
/******************************************************************
SETUP
******************************************************************/
void setup() {
lcd.init(); // Inizializza LCD
lcd.createChar(0, frecciaSu);
lcd.createChar(1, frecciaGiu);
lcd.createChar(2, frecciaDx);
lcd.createChar(3, frecciaSx);
lcd.backlight();
EEPROM.begin(); // Inizializzazione EEPROM
//le seguenti righe servono solo nella sinulazione
EEPROM.put(100, 20);
EEPROM.put(110, 1.00);
EEPROM.put(120, 10.00);
// lettuta parametri dalla EEPROM
EEPROM.get(100, NumSpi); // NumSpi
EEPROM.get(110, DiaFil); // DiaFil
EEPROM.get(120, LunRoc); // LunRoc
// Inizializzazione motori passo-passo
stepper_R.setMaxSpeed(Vel);
stepper_R.setAcceleration(50.0);
stepper_R.disableOutputs(); //Disabilita output
stepper_C.setMaxSpeed(200.0);
stepper_C.setAcceleration(50.0);
stepper_R.disableOutputs(); //Disabilita output
}
/******************************************************************
LOOP
******************************************************************/
void loop() {
Menu();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Spire Totali: ");
lcd.print(NumSpi);
lcd.setCursor(0, 1);
lcd.print("Spire attuali: ");
lcd.setCursor(0, 2);
lcd.print("Strati attuali: ");
SpireStrato = LunRoc / DiaFil; // numero di spire per strato
AvvCarr = StepGiro * DiaFil / 2; // Calcola numero passi per avanzamento carrello
SpireAtt = 1; // Imposta per prima spira
StratoAtt = 1; // Imposta per primo strato
Target_R = StepGiro; // Imposta spira uguale a un giro
Target_C = 0; // Imposta avanzamento carrello uguale a 0
while (Start) { // Se avviata lavorazione.......
lcd.setCursor(16, 1); // Stampa sul display
lcd.print(int(SpireAtt)); // le informazioni correnti
lcd.setCursor(16, 2); // di spire e strati
lcd.print(int(StratoAtt)); // correnti
Valore = analogRead(A0); // Leggi potenziometro della velocità
if (Valore < 10) { // Se valore letto è inferiore a 10.....
while (Valore < 10) { // Fintanto che valore è inferiore a 10.....
Valore = analogRead(A0); // Leggi potenziometro della velocità
lcd.setCursor(0, 3); // Stampa su display
lcd.print("PAUSA "); // stato di PAUSA
}
lcd.setCursor(0, 3);
lcd.print(" ");
} else { // Se valore superiore a 10.....
Vel = map(Valore, 0, 1023, 0, VelMax); // conferti valore in velocità
}
A_Rocchetto(Target_R, Vel); // Avvia motore rocchetto
Target_R = Target_R + StepGiro; // imposta per spira successiva
if (SpireAtt == StratoAtt * SpireStrato) { // se fine strato....
StratoAtt++; // Incrementa strato corrente
SpireAtt++; // Incrementa spira corrente
Direzione = -Direzione; // Inverti direzione carrello
if (Isolan) { // Se richiesto isolante....
Pausa = true;
while (Pausa) {
lcd.setCursor(0, 3); // Stampa su display
lcd.print("Premi ENT per con."); // stato di PAUSA
if (kpd.getKey() == 'D') {
Pausa = false;
}
}
lcd.setCursor(0, 3);
lcd.print(" ");
}
} else { // Altrimenti....
SpireAtt++; // Incrementa spira corrente
Target_C = Target_C + (Direzione * AvvCarr); // Imposta posizione carrello per spira successiva
A_Carrello(Target_C); // Sposta carrello
}
if (SpireAtt == NumSpi + 1) {
Fine(); // Se lavoro completato finisci
}
}
}
/******************************************************************
Avanzamento rocchetto
******************************************************************/
void A_Rocchetto(int Target, int Vel) {
stepper_R.setMaxSpeed(Vel); //Imposta la velocità
stepper_R.runToNewPosition(Target); //Imposta distanza e direzione relative
stepper_R.enableOutputs(); //Abilita PIN
stepper_R.run(); //passo il motore (questo farà un passo del motore di 1 passo ad ogni ciclo)
}
/******************************************************************
Avanzamento carrello
******************************************************************/
void A_Carrello(int Target) {
stepper_C.setMaxSpeed(200); //Imposta la velocità
stepper_C.runToNewPosition(Target); //Imposta distanza e direzione relative
stepper_C.enableOutputs(); //Abilita PIN
stepper_C.run(); //passo il motore (questo farà un passo del motore di 1 passo ad ogni ciclo)
}
/******************************************************************
Fine Bobina
******************************************************************/
void Fine() {
lcd.clear();
lcd.setCursor(2, 0);
lcd.print("Bobina completata");
lcd.setCursor(5, 1);
lcd.print("premere Ent");
lcd.setCursor(5, 2);
lcd.print("per iniziare");
Pausa = true;
menu = 0;
Start = false;
while (Pausa) {
if (kpd.getKey() == 'D') {
Pausa = false;
}
}
}
/******************************************************************
Menu
******************************************************************/
void Menu() {
if (menu == 0) { // Verifica parametri
lcd.clear();
lcd.setCursor(2, 0);
lcd.print("Parametros atuais");
lcd.setCursor(0, 1);
lcd.print("Espra Filo L. Rocc.");
lcd.setCursor(0, 2);
lcd.print(NumSpi);
lcd.setCursor(6, 2);
lcd.print(DiaFil);
lcd.setCursor(12, 2);
lcd.print(LunRoc);
lcd.setCursor(18, 2);
lcd.print("mm");
lcd.setCursor(0, 3);
lcd.print("Certo? A=No Ent=Si");
}
while (menu == 0) {
key = kpd.waitForKey();
switch (key) {
case 'D':
menu = 2; // Presenza Isolamento
break;
case 'A':
menu = 1; // Correzione Parametri
break;
}
}
if (menu == 1) { // Correzione parametri
lcd.clear();
lcd.noBlink();
lcd.setCursor(0, 0);
lcd.print("Spire Fio L. Rocc.");
lcd.setCursor(0, 1);
lcd.print(NumSpi);
lcd.setCursor(6, 1);
lcd.print(DiaFil);
lcd.setCursor(12, 1);
lcd.print(LunRoc);
lcd.setCursor(18, 1);
lcd.print("mm");
lcd.setCursor(2, 2);
lcd.write(byte(0));
lcd.setCursor(8, 2);
lcd.write(byte(0));
lcd.setCursor(14, 2);
lcd.write(byte(0));
lcd.setCursor(17, 2);
lcd.print("Esc");
lcd.setCursor(2, 3);
lcd.print("1 2 3 0");
}
while (menu == 1) {
key = kpd.waitForKey();
switch (key) {
case '1':
menu = 12; // Correzione Numero di spire
break;
case '2':
menu = 13; // Correzione diametro filo
break;
case '3':
menu = 14; // Correzione lunghezza rocchetto
break;
case '0':
menu = 0; // RitornO
break;
}
}
lcd.setCursor(0, 2);
lcd.print(" Inserire valore e ");
lcd.setCursor(0, 3);
lcd.print("A = ESC Or Ent = OK");
if (menu == 12) { // Numero di spire
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.blink();
}
if (menu == 12) {
LeggiKey();
if (Texto != "") {
NumSpi = Texto.toInt(); // Converti il testo in numero intero
Texto = ""; // Azzera il Texto
EEPROM.put(100, NumSpi);
}
}
if (menu == 13) { // Correzione diametro filo
lcd.setCursor(6, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(NumSpi);
lcd.setCursor(6, 1);
lcd.blink();
}
if (menu == 13) {
LeggiKey();
if (Texto != "") {
DiaFil = Texto.toFloat(); // Converti il testo in numero float
Texto = ""; // Azzera il Texto
EEPROM.put(110, DiaFil);
}
}
if (menu == 14) { // Correzione lunghezza rocchetto
lcd.setCursor(12, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(NumSpi);
lcd.setCursor(12, 1);
lcd.blink();
}
if (menu == 14) {
LeggiKey();
if (Texto != "") {
LunRoc = Texto.toFloat(); // Converti il testo in numero float
Texto = ""; // Azzera il Texto
EEPROM.put(120, LunRoc);
}
}
if (menu == 2) { // Isolamento
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Si desidera inserire");
lcd.setCursor(4, 1);
lcd.print("isolante tra");
lcd.setCursor(4, 2);
lcd.print("gli strati?");
lcd.setCursor(1, 3);
lcd.print("A = No Ent = Si");
}
while (menu == 2) {
key = kpd.waitForKey();
switch (key) {
case 'D':
Isolan = true;
menu = 3; // Riepilogo con isolamento
break;
case 'A':
Isolan = false;
menu = 3; // Riepilogo senza isolamneto
break;
}
}
if (menu == 3) { // Riepilogo
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Spire:");
lcd.print(NumSpi);
lcd.setCursor(10, 0);
lcd.print("Filo:");
lcd.print(DiaFil);
lcd.setCursor(0, 1);
lcd.print("Lunghezza: ");
lcd.print(LunRoc);
lcd.print(" mm");
lcd.setCursor(0, 2);
lcd.print("Isolamento: ");
if (Isolan) {
lcd.print("Si");
} else {
lcd.print("No");
}
lcd.setCursor(0, 3);
lcd.print("A = Ret Ent = Avvia");
}
while (menu == 3) {
key = kpd.waitForKey();
switch (key) {
case 'D':
menu = 4; // Posizione zero
break;
case 'A':
menu = 0; // Ritorna
break;
}
}
if (menu == 4) { // Posizione zero
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("Regolare Punto Zero");
lcd.setCursor(2, 1);
lcd.print("1=");
lcd.print(char(0));
lcd.print(char(0));
lcd.print(" 2=");
lcd.print(char(0));
lcd.print(" 3=");
lcd.print(char(1));
lcd.print(" 4=");
lcd.print(char(1));
lcd.print(char(1));
lcd.setCursor(2, 2);
lcd.print("5=");
lcd.print(char(3));
lcd.print(char(3));
lcd.print(" 6=");
lcd.print(char(3));
lcd.print(" 7=");
lcd.print(char(2));
lcd.print(" 8=");
lcd.print(char(2));
lcd.print(char(2));
lcd.setCursor(0, 3);
lcd.print("A=Ret B=0 Ent=Avvia");
}
while (menu == 4) {
key = kpd.waitForKey();
switch (key) {
case '1':
{
Motore(1, StepGiro / 2);
}
break; // Avanti 1 mm Rocchetto
case '2':
{
Motore(1, StepGiro / 20);
}
break; // Avanti 0.1 mm Rocchetto
case '3':
{
Motore(1, -StepGiro / 20);
}
break; // Indietro 0.1 mm Rocchetto
case '4':
{
Motore(1, -StepGiro / 2);
}
break; // Indietro 1 mm Rocchetto
case '5':
{
Motore(0, StepGiro / 2);
}
break; // Avanti 1 mm Carrello
case '6':
{
Motore(0, StepGiro / 20);
}
break; // Avanti 0.1 mm Carrello
case '7':
{
Motore(0, -StepGiro / 20);
}
break; // Indietro 0.1 mm Carrello
case '8':
{
Motore(0, -StepGiro / 2);
}
break; // Indietro 1 mm Carrello
case 'D':
stepper_R.setCurrentPosition(0); //Ripristina la posizione corrente. "di zero"
stepper_C.setCurrentPosition(0); //Ripristina la posizione corrente. "di zero"
menu = 5; // Avviamento
break;
case 'A':
menu = 3; // Ritorna
break;
case 'B':
A_Rocchetto(0, 200);
A_Carrello(0);
break;
}
}
if (menu == 5) { // Posizione zero
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("Selezionare la");
lcd.setCursor(4, 1);
lcd.print("direzione di");
lcd.setCursor(7, 2);
lcd.print("avvio");
lcd.setCursor(2, 3);
lcd.print(char(3));
lcd.print(char(3));
lcd.print(" = Sx ");
lcd.print(char(2));
lcd.print(char(2));
lcd.print(" = Dx");
}
while (menu == 5) {
key = kpd.waitForKey();
switch (key) {
case '*':
{
Direzione = -1;
Start = true;
menu = 0;
}
break; // Avvia verso SX
case '#':
{
Direzione = 1;
Start = true;
menu = 0;
}
break; // Avvia verso DX
case 'A':
menu = 3; // Ritorna
break;
}
}
}
/******************************************************************
Motore
******************************************************************/
void Motore(int Tipo, int Step) {
if (Tipo == 1) {
Target_T = stepper_R.currentPosition();
A_Rocchetto(Target_T + Step, 200);
}
if (Tipo == 0) {
Target_T = stepper_C.currentPosition();
A_Carrello(Target_T + Step);
}
}
/******************************************************************
Leggi tastiera
******************************************************************/
void LeggiKey() {
while (menu != 1) {
key = kpd.waitForKey();
switch (key) {
case '0':
if (Texto.length() < 4) {
Texto += "0";
lcd.print(key);
}
break;
case '1':
if (Texto.length() < 4) {
Texto += "1";
lcd.print(key);
}
break;
case '2':
if (Texto.length() < 4) {
Texto += "2";
lcd.print(key);
}
break;
case '3':
if (Texto.length() < 4) {
Texto += "3";
lcd.print(key);
}
break;
case '4':
if (Texto.length() < 4) {
Texto += "4";
lcd.print(key);
}
break;
case '5':
if (Texto.length() < 4) {
Texto += "5";
lcd.print(key);
}
break;
case '6':
if (Texto.length() < 4) {
Texto += "6";
lcd.print(key);
}
break;
case '7':
if (Texto.length() < 4) {
Texto += "7";
lcd.print(key);
}
break;
case '8':
if (Texto.length() < 4) {
Texto += "8";
lcd.print(key);
}
break;
case '9':
if (Texto.length() < 4) {
Texto += "9";
lcd.print(key);
}
break;
case '.':
if (Texto.length() < 4) {
Texto += ".";
lcd.print(key);
}
break;
case 'A':
Texto = "";
menu = 1;
break; //A: cancella il testo e ritorna
case 'D':
menu = 1; // Passa al menu 3 Calibro filo
break;
}
}
}CARRELLO
ROCCHETTO