Bobinadeira para transformadores

Bom dia amigos participantes do forum, eu encontei um código de uma bobinadeira para enrolamento de transformadores, já fiz alguns testes e está funcionando, achei bem legal o funcionamento, porém, precisa de alguns ajustes na programação do enrolamento, tipo, a programação é assim, numero de espiras, numero de camadas e o diamentro do fio, tem outras configurações que não vem ao caso, funciona assim, se eu colocar 50 espiras, 5 camadas e diametro de 1mm, a guia vai avanças 50mm e retorna fazendo outra camada até completar as 5 camadas, se o diametro do fio for de 0,5mm a guia vai avançar 25mm, e isso vai complicar na hora de fazer um enrolamento em um determinado tamanho de carretel, a programação correta seria assim, ex. numero de espiras 270, comprimento do carretel 37mm, diametro do fio 0,65mm, o funcionamento ficaria assim, ao iniciar o processo, a guia vai avançar até atingir o comprimento do carretel, (37mm) e depois retornando fazendo outra camada até atingir o numero total de espiras.
estou anexando o arquivo com suas dependencias, e para executar o codigo, precisa instalar as bibliotecas nas versões indicadas no README, desde já, agradeço a quem poder ajudar.
ArduinoWindingMachine.zip (318.5 KB)`

/* Name: Winding machine
   Description: Arduino ATmega 328P + Stepper motor control CNC Shield v3 + 2004 LCD + Encoder KY-040

       Arduino pinout diagram:
          _______________
         |      USB      |
         |           AREF|
         |            GND|
         |             13| DIR A
         |RESET        12| STEP A
         |3V3         #11| STOP BT
         |5V          #10| DIR Z
         |GND          #9| STEP Z
         |VIN           8| EN STEP
         |               |
         |              7| BUZZER OUT
         |             #6|
  LCD RS |A0 14        #5| 
  LCD EN |A1 15         4| ENCODER SW
  LCD D4 |A2 16   INT1 #3| ENCODER CLK
  LCD D5 |A3 17   INT0  2| ENCODER DT
  LCD D6 |A4 18      TX 1|
  LCD D7 |A5 19      RX 0|
         |__A6_A7________|


  https://cxem.net/arduino/arduino235.php
  https://cxem.net/arduino/arduino245.php

*/

#include "config.h"  // todas as configurações de hardware estão aqui
#include "debug.h"

#define FPSTR(pstr) (const __FlashStringHelper *)(pstr)
#define LENGTH(a) (sizeof(a) / sizeof(*a))

#if DISPLAY_I2C == 1
#include <LiquidCrystal_I2C.h>
#else
#include <LiquidCrystal.h>
#endif
#include <EncButton.h>
#include <AnalogKey.h>
#include <GyverPlanner.h>
#include <GyverStepper2.h>
#include "LiquidCrystalCyr.h"
#include "Menu.h"
#include "timer.h"
#include "buzzer.h"

#include "Screen.h"
#include "Winding.h"
#include "strings.h"

#ifndef STEPPER_A_STEPS
#define STEPPER_A_STEPS STEPPER_STEPS
#endif
#ifndef STEPPER_Z_STEPS
#define STEPPER_Z_STEPS STEPPER_STEPS
#endif
#ifndef STEPPER_A_MICROSTEPS
#define STEPPER_A_MICROSTEPS STEPPER_MICROSTEPS
#endif
#ifndef STEPPER_Z_MICROSTEPS
#define STEPPER_Z_MICROSTEPS STEPPER_MICROSTEPS
#endif
#ifndef STEPPER_Z_REVERSE
#define STEPPER_Z_REVERSE 0
#endif
#ifndef STEPPER_A_REVERSE
#define STEPPER_A_REVERSE 0
#endif
#ifndef TRANSFORMER_COUNT
#define TRANSFORMER_COUNT 3
#endif

#define STEPPER_Z_STEPS_COUNT (float(STEPPER_Z_STEPS) * STEPPER_Z_MICROSTEPS)
#define STEPPER_A_STEPS_COUNT (float(STEPPER_A_STEPS) * STEPPER_A_MICROSTEPS)
#define STEPPER_SPEED_LIMIT 18000
#ifdef GS_FAST_PROFILE
#define PLANNER_SPEED_LIMIT 37000
#else
#define PLANNER_SPEED_LIMIT 14000
#endif
#define SPEED_LIMIT (int32_t(PLANNER_SPEED_LIMIT) * 60 / STEPPER_Z_STEPS_COUNT)
#define SPEED_INC 10
#define STEPPER_Z_MANUAL_SPEED 360
#define STEPPER_A_MANUAL_SPEED ((int)(360L * 1000 / PASSO_DO_FUSO))  // Defina o passo do fuso em config.h

#define EEPROM_SETTINGS_VERSION 2
#define EEPROM_WINDINGS_VERSION 2
#define EEPROM_SETTINGS_ADDR 0x00
#define EEPROM_WINDINGS_ADDR 0x10
#define EEPROM_WINDINGS_CLASTER (sizeof(Winding) * WINDING_COUNT + 1)

#define WINDING_COUNT 3


Winding params[WINDING_COUNT];

int8_t currentWinding = 0;

Settings settings;

enum menu_states {
  Autowinding1,
  CurrentTrans,
  PosControl,
  miSettings,
  Winding1,
  Winding2,
  Winding3,
  StartAll,
  WindingBack,
  TurnsSet,
  LaySet,
  StepSet,
  SpeedSet,
  Direction,
  Start,
  Cancel,
  ShaftPos,
  ShaftStepMul,
  LayerPos,
  LayerStepMul,
  PosCancel,
  miSettingsStopPerLevel,
  AccelSet,
  miSettingsBack
};  // Lista numerada de linhas de tela

const char *boolSet[] = { STRING_OFF, STRING_ON };
const char *dirSet[] = { "<<<", ">>>" };
const uint8_t stepSet[] = { 1, 10, 100 };

MenuItem *menuItems[] = {
  new MenuItem(0, 0, MENU_01),
  new ByteMenuItem(0, 1, MENU_02, MENU_FORMAT_02, &settings.currentTransformer, 1, TRANSFORMER_COUNT),
  new MenuItem(0, 2, MENU_04),
  new MenuItem(0, 3, MENU_05),

  new ValMenuItem(1, 0, MENU_06, MENU_FORMAT_06),
  new ValMenuItem(1, 1, MENU_07, MENU_FORMAT_06),
  new ValMenuItem(1, 2, MENU_08, MENU_FORMAT_06),
  new MenuItem(1, 3, MENU_15),
  new MenuItem(1, 4, MENU_09),

  new IntMenuItem(2, 0, MENU_10, MENU_FORMAT_10, NULL, 0, 5000),
  new IntMenuItem(2, 1, MENU_13, MENU_FORMAT_13, NULL, 1, 99),
  new FloatMenuItem(2, 2, MENU_11, MENU_FORMAT_11, NULL, 10, 9995, 10),
  new IntMenuItem(2, 3, MENU_12, MENU_FORMAT_10, NULL, SPEED_INC, SPEED_LIMIT, SPEED_INC),
  new BoolMenuItem(2, 4, MENU_14, NULL, dirSet),
  new MenuItem(2, 5, MENU_15),
  new MenuItem(2, 6, MENU_09),

  new IntMenuItem(10, 0, MENU_17, MENU_FORMAT_17, &settings.shaftPos, -2000, 2000),
  new SetMenuItem(10, 1, MENU_18, MENU_FORMAT_10, &settings.shaftStep, stepSet, 3),
  new IntMenuItem(10, 2, MENU_19, MENU_FORMAT_17, &settings.layerPos, -2000, 2000),
  new SetMenuItem(10, 3, MENU_18, MENU_FORMAT_10, &settings.layerStep, stepSet, 3),
  new MenuItem(10, 4, MENU_09),

  new BoolMenuItem(11, 0, MENU_22, &settings.stopPerLayer, boolSet),
  new IntMenuItem(11, 1, MENU_23, MENU_FORMAT_10, &settings.acceleration, 0, 600, 1),
  new MenuItem(11, 2, MENU_09),
};

byte up[8] = { 0b00100, 0b01110, 0b11111, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000 };    // Создаем свой символ ⯅ для LCD
byte down[8] = { 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b01110, 0b00100 };  // Создаем свой символ ⯆ для LCD

#if DISPLAY_I2C == 0
LiquidCrystalCyr lcd(DISPLAY_RS, DISPLAY_EN, DISPLAY_D4, DISPLAY_D5, DISPLAY_D6, DISPLAY_D7);  // Atribuir pinos para controlar o LCD
#else
LiquidCrystalCyr lcd(DISPLAY_ADDRESS, DISPLAY_NCOL, DISPLAY_NROW);
#endif

MainMenu menu(menuItems, LENGTH(menuItems), lcd);
MainScreen screen(lcd);


GStepper2<STEPPER2WIRE> shaftStepper(STEPPER_Z_STEPS_COUNT, STEPPER_STEP_Z, STEPPER_DIR_Z, ENBLE);
GStepper2<STEPPER2WIRE> layerStepper(STEPPER_A_STEPS_COUNT, STEPPER_STEP_A, STEPPER_DIR_A, ENBLE);
GPlanner<STEPPER2WIRE, 2> planner;

EncButton<EB_TICK, ENCODER_CLK, ENCODER_DT, ENCODER_SW> encoder(ENCODER_INPUT);
EncButton<EB_TICK, BUTTON_STOP> pedal;

Buzzer buzzer(BUZZER);

enum { ButtonLEFT,
       ButtonUP,
       ButtonDOWN,
       ButtonRIGHT,
       ButtonSELECT
};
int16_t key_signals[] = { KEYBOARD_LEFT, KEYBOARD_UP, KEYBOARD_DOWN, KEYBOARD_RIGHT, KEYBOARD_SELECT };
AnalogKey<KEYBOARD_PIN, LENGTH(key_signals), key_signals> keyboard;


void setup() {
  Serial.begin(9600);
  LoadSettings();

  layerStepper.disable();
  shaftStepper.disable();
  layerStepper.reverse(!STEPPER_Z_REVERSE);
  shaftStepper.reverse(!STEPPER_A_REVERSE);
  planner.addStepper(0, shaftStepper);
  planner.addStepper(1, layerStepper);

  lcd.createChar(0, up);                  // Записываем символ ⯅ в память LCD
  lcd.createChar(1, down);                // Записываем символ ⯆ в память LCD
  lcd.begin(DISPLAY_NCOL, DISPLAY_NROW);  // Inicialização do display LCD
  menu.Draw();

  encoder.setEncType(ENCODER_TYPE);
}

void loop() {
  encoder.tick();
  KeyboardRead();

  if (encoder.turn()) {
    menu.IncIndex(encoder.dir());  // Se a posição do codificador for alterada, então alteramos menu.index e exibimos a tela
    menu.Draw();
  }

  if (encoder.click()) {
    switch (menu.index)  // Se houver uma pressão, então realizamos a ação correspondente à posição atual do cursor
    {
      case Autowinding1:
        SaveSettings();
        LoadWindings();
        menu.index = Winding1;

        UpdateMenuItemText(0);
        UpdateMenuItemText(1);
        UpdateMenuItemText(2);
        break;

      case Winding1:
      case Winding2:
      case Winding3:
        currentWinding = menu.index - Winding1;
        menu.index = TurnsSet;
        ((IntMenuItem *)menu[TurnsSet])->value = &params[currentWinding].espiras;
        ((IntMenuItem *)menu[StepSet])->value = &params[currentWinding].bitFio;
        ((IntMenuItem *)menu[SpeedSet])->value = &params[currentWinding].speed;
        ((IntMenuItem *)menu[LaySet])->value = &params[currentWinding].camadas;
        ((BoolMenuItem *)menu[Direction])->value = &params[currentWinding].dir;
        break;
      case WindingBack:
        menu.index = Autowinding1;
        break;
      case PosControl:
        menu.index = ShaftPos;
        break;
      case TurnsSet:
      case StepSet:
      case SpeedSet:
      case LaySet:
      case AccelSet:
        ValueEdit();
        break;
      case CurrentTrans:
      case miSettingsStopPerLevel:
      case Direction:
        menu.IncCurrent(1, true);
        break;
      case StartAll:
        AutoWindingAll(params, WINDING_COUNT);
        menu.Draw(true);
        break;
      case Start:
        SaveWindings();
        AutoWindingAll(params + currentWinding, 1);
        menu.index = Winding1 + currentWinding;
        UpdateMenuItemText(currentWinding);
        break;
      case Cancel:
        SaveWindings();
        menu.index = Winding1 + currentWinding;
        UpdateMenuItemText(currentWinding);
        break;

      case ShaftPos:
      case LayerPos:
        MoveTo((menu.index == LayerPos) ? layerStepper : shaftStepper, *((IntMenuItem *)menu[menu.index])->value);
        break;

      case ShaftStepMul:
      case LayerStepMul:
        menu.IncCurrent(1, true);
        ((IntMenuItem *)menu[menu.index - 1])->increment = *((SetMenuItem *)menu[menu.index])->value;
        break;
      case PosCancel:
        menu.index = PosControl;
        settings.shaftPos = 0;
        settings.layerPos = 0;
        break;

      case miSettings:
        menu.index = miSettingsStopPerLevel;
        break;

      case miSettingsBack:
        SaveSettings();
        menu.index = miSettings;
        break;
    }
    menu.Draw();
  }
}

void UpdateMenuItemText(byte i) {
  ((ValMenuItem *)menu[Winding1 + i])->value = params[i].espiras * params[i].camadas;
}

void ValueEdit() {
  menu.DrawQuotes(1);
  do {
    encoder.tick();

    if (encoder.turn() || encoder.turnH())
      menu.IncCurrent(encoder.dir() * (encoder.state() ? 10 : 1));

  } while (!encoder.click());
  menu.DrawQuotes(0);
}

void MoveTo(GStepper2<STEPPER2WIRE> &stepper, int &pos) {
  menu.DrawQuotes(1);
  stepper.enable();

  stepper.setAcceleration(STEPPER_Z_STEPS_COUNT * settings.acceleration / 60);
  stepper.setMaxSpeed(constrain(STEPPER_Z_STEPS_COUNT / 2, 1, STEPPER_SPEED_LIMIT));

  int o = pos;
  stepper.reset();

  do {
    stepper.tick();
    encoder.tick();

    if (encoder.turn()) {
      menu.IncCurrent(encoder.dir());
      stepper.setTargetDeg(pos - o);
    }

  } while (!encoder.click() || stepper.getStatus() != 0);

  stepper.disable();
  menu.DrawQuotes(0);
}

void KeyboardRead() {
  if (KEYBOARD_PIN == 0 || KEYBOARD_PIN == A6)
    return;

  static int8_t oldKey = -1;
  int8_t key = keyboard.pressed();

  if (oldKey != key) {
    switch (key) {
      case ButtonLEFT:
        layerStepper.enable();
        layerStepper.setSpeedDeg(STEPPER_A_MANUAL_SPEED);
        break;
      case ButtonRIGHT:
        layerStepper.enable();
        layerStepper.setSpeedDeg(-STEPPER_A_MANUAL_SPEED);
        break;
      case ButtonUP:
        shaftStepper.enable();
        shaftStepper.setSpeedDeg(STEPPER_Z_MANUAL_SPEED);
        break;
      case ButtonDOWN:
        shaftStepper.enable();
        shaftStepper.setSpeedDeg(-STEPPER_Z_MANUAL_SPEED);
        break;
      case ButtonSELECT: break;
      default:
        layerStepper.brake();
        shaftStepper.brake();
        layerStepper.disable();
        shaftStepper.disable();
    }
    oldKey = key;
  }

  if (layerStepper.getStatus())
    layerStepper.tick();
  if (shaftStepper.getStatus())
    shaftStepper.tick();
}


double speedMult = 1;

ISR(TIMER1_COMPA_vect) {
  if (planner.tickManual())
    setPeriod(planner.getPeriod() * speedMult);
  else
    stopTimer();
}

uint32_t getSpeed() {
  uint32_t p = planner.getPeriod() * speedMult;
  return (p == 0) ? 0 : (60000000ul / (STEPPER_Z_STEPS_COUNT * p));
}


void AutoWinding(const Winding &w, bool &direction)  // Sub-rotina de enrolamento automático
{
  Winding current;  // Volta a camada atual durante o enrolamento automático

  DebugWrite("Start");

  current.espiras = 0;
  current.camadas = 0;
  current.speed = w.speed;
  speedMult = 1;
  current.dir = w.dir;
  current.bitFio = w.bitFio;

  screen.Draw();

  pedal.tick();
  bool run = pedal.state();  // pedal pressionado - trabalho

  shaftStepper.enable();  // Permissão de controle do motor
  layerStepper.enable();

  planner.setAcceleration(STEPPER_Z_STEPS_COUNT * settings.acceleration / 60L);
  planner.setMaxSpeed(constrain(STEPPER_Z_STEPS_COUNT * w.speed / 60L, 1, PLANNER_SPEED_LIMIT));

  int32_t dShaft = STEPPER_Z_STEPS_COUNT * w.espiras;
  int32_t dLayer = STEPPER_A_STEPS_COUNT * w.espiras * w.bitFio / int32_t(PASSO_DO_FUSO) * (direction ? 1 : -1);
  int32_t p[] = { dShaft, dLayer };

  planner.reset();
  initTimer();

  while (1) {
    if (run && !planner.getStatus()) {
      DebugWrite("READY");
      if (current.camadas >= w.camadas)
        break;

      if (settings.stopPerLayer && (current.camadas > 0)) {
        screen.Message(STRING_2);  // "PRESS CONTINUE  "
        WaitButton();
        screen.Draw();
      }

      DebugWrite("setTarget", p[0], p[1]);
      planner.setTarget(p, RELATIVE);
      ++current.camadas;
      p[1] = -p[1];
      direction = !direction;

      startTimer();
      setPeriod(planner.getPeriod() * speedMult);

      screen.UpdateLayers(current.camadas);
    }

    encoder.tick();
    pedal.tick();

    bool oldState = run;
    if (pedal.press() || pedal.release())
      run = pedal.state();
    else if (pedal.state() && encoder.click())
      run = !run;

    if (run != oldState) {
      if (run) {
        if (current.camadas) {  // Se a meta ainda não foi definida, então não começamos
          noInterrupts();
          planner.resume();
          interrupts();
          if (planner.getStatus()) {
            startTimer();
            setPeriod(planner.getPeriod() * speedMult);
          }
        }
      } else {
        noInterrupts();
        planner.stop();
        interrupts();
      }
    }

    if (encoder.turn()) {
      // Se você girar o codificador durante o enrolamento automático,
      // então mudamos o valor da velocidade
      current.speed = constrain(current.speed + encoder.dir() * SPEED_INC, SPEED_INC, SPEED_LIMIT);
      //planner.setMaxSpeed(STEPPER_STEPS_COUNT * current.speed / 60L);
      speedMult = double(w.speed) / double(current.speed);
      screen.UpdateSpeed(current.speed);
    }

    static uint32_t tmr;
    if (millis() - tmr >= 500) {
      tmr = millis();

      int total_turns = (abs(shaftStepper.pos)) / STEPPER_Z_STEPS_COUNT;

      screen.UpdateTurns(total_turns % w.espiras + 1);
      DebugWrite("pos", shaftStepper.pos, layerStepper.pos);
      screen.PlannerStatus(planner.getStatus());
    }
  }

  layerStepper.disable();
  shaftStepper.disable();
}

void AutoWindingAll(const Winding windings[], byte n) {
  bool direction = windings[0].dir;

  for (byte i = 0; i < n; ++i) {
    const Winding &w = windings[i];
    if (!w.espiras || !w.camadas || !w.bitFio || !w.speed) continue;

    screen.Init(w);

    if (n > 1) {
      screen.Draw();
      screen.Message(STRING_3, i + 1);
      buzzer.Multibeep(2, 200, 200);
      WaitButton();
    }

    AutoWinding(w, direction);
  }

  screen.Message(STRING_1);  // "AUTOWINDING DONE"
  buzzer.Multibeep(3, 200, 200);
  WaitButton();
}

void WaitButton() {
  do {
    encoder.tick();
    KeyboardRead();
  } while (!encoder.click());
}
void LoadSettings() {
  int p = EEPROM_SETTINGS_ADDR;
  byte v = 0;
  EEPROM_load(p, v);
  if (v != EEPROM_SETTINGS_VERSION)
    return;
  Load(settings, p);
  settings.currentTransformer = constrain(settings.currentTransformer, 1, TRANSFORMER_COUNT);
}

void SaveSettings() {
  int p = EEPROM_SETTINGS_ADDR;
  byte v = EEPROM_SETTINGS_VERSION;
  EEPROM_save(p, v);
  Save(settings, p);
}

void LoadWindings() {
  int p = EEPROM_WINDINGS_ADDR + (settings.currentTransformer - 1) * EEPROM_WINDINGS_CLASTER;

  byte v = 0;
  EEPROM_load(p, v);

  for (int j = 0; j < WINDING_COUNT; ++j)
    if (v == EEPROM_WINDINGS_VERSION)
      Load(params[j], p);
    else
      params[j] = Winding();
}

void SaveWindings() {
  int p = EEPROM_WINDINGS_ADDR + (settings.currentTransformer - 1) * EEPROM_WINDINGS_CLASTER;

  byte v = EEPROM_WINDINGS_VERSION;
  EEPROM_save(p, v);
  for (int j = 0; j < WINDING_COUNT; ++j)
    Save(params[j], p);
}

`

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.