Перейти к содержанию

Прошивка для станка PET-pull`era (прошу помощи)


Рекомендуемые сообщения

Здравствуйте, уважаемые. Прошу помощи в написании прошивки станочка для протяжки ПЭТ бутылок в пруток. Точнее, не всей прошивки,а кусочка кода.

Написал я кое-как программу, уж как сумел, и она даже почти работает. Вот это "почти" и не дает закрыть проект :) Предполагаемый алгоритм работы таков: 

1. Система запускается, все хорошо.

2. Из EEPROM читаются 2 переменных, температура нагревателя и скорость мотора.

3. Нагреватель (при необходимости) начинает греться. Температура нагрева контролируется ч помощью ПИД регулятора (засада №1).

4. Когда температура устаканится, либо, по мнению пользователя, уже и так сойдет - ручками запускаем мотор, протягивающий ленту через нагреватель. Скорость вращения мотора задается средствами библиотеки AccelStepper (засада №2). Двигатель протяжки можно остановить в любой момент через менюшку.

5. В любой момент можно поменять скорость движка и температуру нагревателя. 

Остальные задумки уже не влазят в процессор :), да и не особо нужны.

 

Но пункт 5 немножко как раз и не работает. Система при старте считывает ранее заданные значения температуры и скорости, применяет их, а на дальнейшие мои попытки изменить их гордо корчит рожу. И, соотетственно, не меняет. Вот и хочу попросить совета, что я делаю не так. Самое противное, что примеры к библиотекам работают исправно, а в составе моего проекта - авотхрен. Проект строится на Atmega168P (Nano v2), мотор Nema17 с драйвером A4988. Из управления - 3 дискретных кнопки и экранчик 2*16 строчек.  Прошу помощи :)

 

Вот скетч (надеюсь, получится правильно вставить :) ) , схему подключений тоже нарисую, если нужно будет. Хотя там все задействованные лапы в дефайнах видны :).

 

#include "Wire.h"
#include "LiquidCrystal_I2C.h"
#include "GyverButton.h"
#include <GyverTimers.h>
#include <EEPROM.h>
#define PID_INTEGER
#include "GyverPID.h"
//#include <GyverStepper.h>
#include <AccelStepper.h>

//-----------------------------------------------------------------------------------------------------------------------
#define btn_dec_pin 11
#define btn_ok_pin  10
#define btn_inc_pin 9
#define btn_inc_step 20
#define btn_dec_step 20

// PWM пины: 3, 5, 6, 9, 10, 11
#define heater_pin     5      // Контакт D5
#define tsens_pin      21     // Контакт A7
#define fan_pin        6      // Контакт D6

#define thermistor_r   100000 // Номинальное сопротивление термистора при 25 градусах 100К
#define t_nominal      25     // Температура, при которой меряется номинальное сопротивление термистора
#define thermo_b       3950   // Какой-то бетта коэффициент термистора (обычно 3000-4000). ХЗ что это
#define thermo_r       11880  // Постоянный резистор второго плеча термистора, 11.88К
#define num_pas        10     // Количество измерений температуры для усреднения

#define temp_addr 0           // Адрес в EEPROM для хранения температуры нагревателя
#define speed_addr 2          // Адрес в EEPROM для хранения скорости протяжки

// ПИД регулятор
#define dt             500    // Частота регулировки ПИД 0.5 секунды
#define PID_kp         5.2    
#define PID_ki         0.5
#define PID_kd         0.5

// Мотор протяжки
#define motor_steps     200    // Количество шагов мотора на оборот (для Nema17 200)
#define motor_step_pin  15     // Контакт А1
#define motor_dir_pin   14     // Контакт А0
#define motor_en_pin    16     // Контакт А2
#define motor_max_speed 1000   // Максимальное число шагов в секунду
//=======================================================================================================================

LiquidCrystal_I2C lcd(0x27, 16, 2);
GButton btn_dec(btn_dec_pin);
GButton btn_inc(btn_inc_pin);
GButton btn_ok(btn_ok_pin);
//GyverPID regulator(1, 0, 0, 500);  // коэф. П, коэф. И, коэф. Д, период дискретизации dt (мс)
GyverPID regulator(0.1, 0.05, 0.01, 100);  // коэф. П, коэф. И, коэф. Д, период дискретизации dt (мс)
//GyverPID regulator(0.1, 0.05, 0.01);  // коэф. П, коэф. И, коэф. Д
// Определение тип интерфейса двигателя
#define motorInterfaceType 1
AccelStepper motor(motorInterfaceType, motor_step_pin, motor_dir_pin);

//=======================================================================================================================
String menu_item [] = {"Temp  ","Speed ","Motor ", "Heat  ", "Fan   ", "Save  ", "Load  "};
int menu_pos = 0;
int heater_current_temp = 0;
int heater_new_temp = 0;
int motor_speed = 0;
float error, error0, pid, pwr, integ;
uint16_t Kp, Ki, Kd;
bool heater_logo = false;

static bool motor_enable = false;
//-----------------------------------------------------------------------------------------------------------------------
void Logo (void);
void Btn_dec (int);
void Btn_inc (int);
void Btn_OK ();
void Show ();
void Save ();
void Load ();
int GetTemp ();
void PID_heater ();
void Motor_step ();
void Ticks ();
//=======================================================================================================================
//-----------------------------------------------------------------------------------------------------------------------
// Прерывание А таймера 1
ISR(TIMER1_A) {  // прерывание таймера
  btn_dec.tick();
  btn_inc.tick();
  btn_ok.tick();
}
//-----------------------------------------------------------------------------------------------------------------------
void Logo (void)
{
  String logo_str = "Extruder ver.0.0";
  int pos = 0;
  for (pos==0; pos<logo_str.length (); pos++) {
    lcd.setCursor (pos,0); lcd.print (logo_str[pos]); delay (100);
  }
  delay (1000);
  lcd.clear ();
}
//-----------------------------------------------------------------------------------------------------------------------
void Btn_dec (int clicks)
{
//   0        1        2        3         4          5         6
//"Temp  ","Speed ","Motor ", "Heat  ", "Fan   ", "Save  ", "Load  "  
// Одиночные нажатия
  if (clicks==1) {
    switch (menu_pos) {
      case 0: if (heater_new_temp>0) {heater_new_temp--;}; break;
      case 1: {motor_speed=motor_speed-1;}; break;
      case 2: motor_enable = false; digitalWrite (motor_en_pin, HIGH); break;
      case 3: break;
      case 4: break;
      case 5: Save (); break;
      case 6: Load (); break; 
    }
  };
// Долгое удержание
  if (clicks==2) {
    switch (menu_pos) {
      case 0: if (heater_new_temp>btn_dec_step) {heater_new_temp=heater_new_temp-btn_dec_step;}; break;
      case 1: {motor_speed=motor_speed-btn_dec_step;}; break;
    }
  };
}
//-----------------------------------------------------------------------------------------------------------------------
void Btn_inc (int clicks)
{
//   0        1        2        3         4          5         6
//"Temp  ","Speed ","Motor ", "Heat  ", "Fan   ", "Save  ", "Load  "  
// Одиночные нажатия
  if (clicks==1) {
    switch (menu_pos)
      {
      case 0: heater_new_temp++; break;
      case 1: if (motor_speed<motor_max_speed) {motor_speed=motor_speed+1;}; break;
      case 2: motor_enable = true; digitalWrite (motor_en_pin, LOW); break;
      case 3: break;
      case 4: break;
      case 5: Save (); break;
      case 6: Load (); break; 
    }
  };

// Долгое удержание
  if (clicks==2) {
    switch (menu_pos) {
      case 0: heater_new_temp=heater_new_temp+btn_inc_step; break;
      case 1: if (motor_speed<motor_max_speed-btn_inc_step) {motor_speed=motor_speed+btn_inc_step;}; break;
    };
  };
}
//-----------------------------------------------------------------------------------------------------------------------
void Btn_OK ()
{
//   0        1        2        3         4          5         6
//"Temp  ","Speed ","Motor ", "Heat  ", "Fan   ", "Save  ", "Load  "  
  switch (menu_pos) {
    case 0: break;
    case 1: motor.stop (); delay (20); motor.setSpeed(motor_speed); break;
    case 2: break;
    case 3: break;
    case 4: break;
    case 5: break;
    case 6: break; 
  }
  menu_pos++;
  if (menu_pos==7) {menu_pos=0;};
}
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------

void Show (void) {
  lcd.setCursor (0,0); lcd.print (menu_item[menu_pos]);

  lcd.setCursor (6,0); lcd.print ("T="); lcd.print (heater_new_temp); lcd.print("/"); lcd.print(heater_current_temp); lcd.print(" ");
  lcd.setCursor (6,1); lcd.print ("S="); lcd.print (motor_speed); lcd.print(" ");

  lcd.setCursor (14,1); if (heater_logo==true) {lcd.print('h');} else {lcd.print(' ');};
  lcd.setCursor (13,1); if (motor_enable==true) {lcd.print('m');} else {lcd.print(' ');};

  //lcd.setCursor (0,1); lcd.print(regulator.getResultTimer()); lcd.print("  ");
}
//-----------------------------------------------------------------------------------------------------------------------
void Save (void) {
  eeprom_update_word (temp_addr, heater_new_temp);
  eeprom_update_word (speed_addr, motor_speed);
  menu_pos = 0;
}
//-----------------------------------------------------------------------------------------------------------------------
void Load (void) {
  heater_new_temp = eeprom_read_word (temp_addr);
  motor_speed = eeprom_read_word (speed_addr);
  menu_pos = 0;
}
//-----------------------------------------------------------------------------------------------------------------------
int GetTemp(void) //Функция измерения температуры
{
  int16_t At = 0;
  for (uint8_t i = 0; i < 10; i++) At += analogRead(tsens_pin); //Усредняем
  At /= 10;                                               //10 последовательных измерений

  float Rt = 1023.0 / At - 1;
  Rt = thermo_r / Rt;
  float T;
  T = Rt / thermistor_r;
  T = log (T);
  T /= thermo_b;
  T += 1 / (t_nominal + 273.15);
  T = 1 / T;
  T -= 273.15;
  int xx;
  xx = T;
  return xx;
}
//-----------------------------------------------------------------------------------------------------------------------
void PID_heater (void) {
  //heater_current_temp = GetTemp ();
  regulator.input = heater_current_temp;   // сообщаем регулятору текущую температуру
  pwr = regulator.getResultTimer();
  analogWrite(heater_pin, pwr);  // отправляем на мосфет  
  if (pwr>0) {heater_logo = true;} else {heater_logo = false;};
}
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
void Ticks (void) {
  btn_dec.tick();
  btn_inc.tick();
  btn_ok.tick();  

  if (motor_enable==true) {motor.runSpeed();};
}
//-----------------------------------------------------------------------------------------------------------------------
void PreSave (void) {
  motor_speed = 500; heater_new_temp = 50; Save ();
  lcd.clear ();
  lcd.print ("EEPROM saved");
  lcd.setCursor (0,1);
  lcd.print ("T=50, S=500");
  delay (1000);
}
//-----------------------------------------------------------------------------------------------------------------------
void PreLoad (void) {
  Load ();
  lcd.clear ();
  lcd.print ("EEPROM loaded");
  lcd.setCursor (0,1);
  lcd.print ("T="); lcd.print (heater_new_temp);
  lcd.print ("S=500"); lcd.print (motor_speed);
  delay (1000);  
}
//-----------------------------------------------------------------------------------------------------------------------
//=======================================================================================================================
void setup() {
  // Инициализация портов
  {
  pinMode (motor_en_pin, OUTPUT);
  pinMode (motor_dir_pin, OUTPUT);
  pinMode (motor_step_pin, OUTPUT);
  pinMode (heater_pin, OUTPUT);
  pinMode (fan_pin, OUTPUT);

  digitalWrite (motor_en_pin, HIGH);
  digitalWrite (motor_dir_pin, HIGH);
  digitalWrite (motor_step_pin, HIGH);
  digitalWrite (heater_pin, LOW);
  digitalWrite (fan_pin, LOW);  
  }
  // Инициализация дисплея
  {
    lcd.init();
    lcd.backlight();
    lcd.clear ();
  }

  Load ();
  
  // Инициализация таймера
  {
    //Timer1.setFrequency(1000);          // 1KHz
    //Timer1.enableISR();                 // Запускаем прерывание (по умолч. канал А)    
  }
  // Инициализация ПИД регулятора
  {
  regulator.setDirection(NORMAL); // направление регулирования (NORMAL/REVERSE). ПО УМОЛЧАНИЮ СТОИТ NORMAL
  regulator.setLimits(0, 255);    // пределы (ставим для 8 битного ШИМ). ПО УМОЛЧАНИЮ СТОЯТ 0 И 255
  regulator.setpoint = heater_new_temp;  // сообщаем регулятору температуру, которую он должен поддерживать

  // в процессе работы можно менять коэффициенты
  //regulator.Kp = 5.2;
  //regulator.Ki += 0.5;
  //regulator.Kd = 0;  
  regulator.Kp = PID_kp;
  regulator.Ki +=PID_ki;
  regulator.Kd = PID_kd;  
  }
  // Инициализация двигателя протяжки
  {
      // Устанавливаем максимальную скорость, коэффициент ускорения, начальную скорость
    motor.setMaxSpeed(motor_max_speed);
    motor_speed = -1000;
    motor.setSpeed(motor_speed);
  }
  
  // Прочее
  {
  Logo ();
  // Загрузка сохраненных в ЕЕПРОМ значений, если это необходимо
  if (digitalRead (btn_dec_pin)==0&&digitalRead (btn_inc_pin)==0) {PreSave (); Logo();};
  if (digitalRead (btn_ok_pin)==0&&digitalRead (btn_inc_pin)==0) {PreLoad (); Logo();};
  }
}
//-----------------------------------------------------------------------------------------------------------------------
//=======================================================================================================================
void loop() {
  Ticks ();
  heater_current_temp = GetTemp ();
  if (btn_dec.isClick()) {Btn_dec(1);};
  if (btn_inc.isClick()) {Btn_inc(1);};
  if (btn_ok.isClick())  {Btn_OK();};
  if (btn_dec.isHolded()) {Btn_dec(2);};
  if (btn_inc.isHolded()) {Btn_inc(2);};
  
  Show ();
  PID_heater ();  
}

 

Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

4 часа назад, Yuriy.pv сказал:

Температуру ты то поменял, а присваивать пид функции кто будет? 

Эээ... Ну да, действительно :blush: Вот ведь, Семен Семеныч :D

Наверное, с двигателем тоже самое происходит :)

 

Спасибо, слона-то я и не заметил :)

Ссылка на комментарий
Поделиться на другие сайты

Выбираем схему BMS для заряда литий-железофосфатных (LiFePO4) аккумуляторов

Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Действительно, с температурой теперь все в норме,  нагрев управляется вовремя, произвольно и как и задумано :) Теперь с двигателем воюю. Проверил сто раз весь код, переполз на библиотеку  GyverStepper, вытаскивал в отдельный скетч относящиеся к делу куски - там работает. И запускается, и скорость меняется, и тормозится... А в вышеприведенном скетче - авотхрен, фигвам! Точнее, вообще не запускается, хотя кусочки код копипастю из работающего окна в неработающее. Есть подозрение, что ресурсов мало осталось ( 94%/62%  RAM/FLASH), но как-то так себе предположение. В общем, ищу пока решение B)

Изменено пользователем Ушик
Ссылка на комментарий
Поделиться на другие сайты

Спасибо, что проявляете интерес к моему скромному проекту :rolleyes: С подозрениями все хорошо - их есть у меня :) Но увы, кроме подозрений еще нужны веские доказательства, псакинг тут не прокатит. Вот думаю, может еще параною подключить, для надежности? При RAM=61% и  FLASH=93% без паранои никак :)

 

Сегодня еще не занимался проектом, не успел. Постараюсь пару часиков поковыряться. Хочу другие библиотеки еще попробовать - порой такой финт прокатывает на ардуине. Хоть и не всегда, конечно. Самое удивительное, что копипаст кода в пустой скетч двигателем крутит (и кнопками кнопит), а в нужном проекте - нет. Есть мысль переписать все нафиг с чистого листа, но сомнения гложут.

 

А что, прошу прощения, не так с функцией Ticks()?

void Ticks (void) {
  btn_dec.tick();
  btn_inc.tick();
  btn_ok.tick();  

  if (motor_enable==true) {motor.runSpeed();};
}

Для опроса кнопок там вызываются, собственно, опросы кнопок и затем, если мотору можно крутиться (значение параметра задается вручную) - делаем один шажок. Это если я правильно понял описание функций библиотеки. Вроде бы никакого криминала в ней нет, да и на изменение скорости она не влияет. Честно говоря, не вижу, на что в ней можно грозно посмотреть. Эта переменная (motor_enable) так же используется в функции Show() - выводит символ m, если мотору можно крутиьтся. Так вот там она вполне корректно отрабатывается, так что и переменная тоже меняется. Я так думаю.

 

Сейчас, после переезда на гайверовскую библиотеку (нравятся они мне, как-то удобненько работают, а про внутренний мир этих библиотек я не в курсе :)) управления мотором функция приобрела немного иной вид: 

void Ticks (void) {
  btn_dec.tick();
  btn_inc.tick();
  btn_ok.tick();  
  if (motor_enable==true) {motor.tick();};
}

В общем, пойду ковыряться, авось это поможет :)  Потом расскажу, что получится.

Ссылка на комментарий
Поделиться на другие сайты

Ардуино это зло.. вся это "накидал,подключил"  ето ведет к тому что человек не хочет разбираться в механике  библиотек. Сжирание памяти космическое, я б еще столько же впихнул. А управление драйвером настолько простое что и библиотек тут не надо. Я не дуинщик функция Ticks вызывается сама? 

Ссылка на комментарий
Поделиться на другие сайты

Юрий, Вы таки тоже правы :) Дунька - это как магия: она не зло и не добро, она просто есть. Вопрос в том, как ее применять :) Для меня платформа ардуино - это кучка железа, имеющий какое-то подобие устаканенного набора функций (зачастую несовместимого само с с собой), кучка программных поддержек (работающих только в демках), крайне убогую оболочку (порой легче в блокноте работать) и т.д. и т.п. Хаять можно долго и со вкусом - это существенно повышает моё ЧСВ :) Однако есть же и плюсы: оно уже есть, можно спросить совета у уже нахававшихся, можно скачай и прошей без особых трепыханий и будет тебе метеостанция... Все это сливается в понятие "порог вхождения". Впрочем. Вы и сами все это прекрасно понимаете, не будем тут холиваром развлекаться :) Я не хочу разбираться в начинке библиотек, не хочу оптимизировать и выцарапывать ресурсы (знаете сказку об одном байте?) и все такое. Буду по существу лучше :)

Почему на дуньке делаю? Потому, что я не настолько крут, чтобы написать поддержку экрана, подключенного по I2C :rolleyes: Драйвер мотора уж подцепил бы, там действительно все неприлично просто. Да и с кнопками тоже доводилось дело иметь. На резонный вопрос "ну и?" превентивно отвечу: "ну, эта..." Так-то, если уж касаться этой темы о предпочтениях в программировании, то мне больше всех нравится FlowCode - визуальная среда, строишь алгоритм программы из школьных блок-схем, а на выходе кекс, асм и си. Все бы хорошо, да вот закрытая она, эта ФК, поддержки нормального железа нет, только свои модули продвигают, а под самодельщину поддержку писать - опять же, я не хочу этим заниматься. Впрочем, я увлекся, узвините.

 

Функция Ticks() вызывается в бесконечном цикле loop() - это аналог идеологически истинного while (1) do {}; В результате программа крутится внутри этого лупа, выскакивая ненадолго на всякие там прерывания (если они есть) и прочие функции (в том числе и наш Ticks()). Все как всегда, те же фаберже, вид сбоку. Была мысль злобно плюнуть в код и настрочить, как Вы говорите, самому это управление драйвером. И даже не вижу сложностей особоых, по крайней мере сейчас не вижу :). Возможно, этим все и закончится :) 

Ссылка на комментарий
Поделиться на другие сайты

В писатели вам надо.. талант пропадает)) тикс увидел, не заметил.

11 часов назад, Ушик сказал:

Возможно, этим все и закончится :) 

Правильное решение.  А что хоть за станок, че с этим прутком делать, для 3д принтера?

Ссылка на комментарий
Поделиться на другие сайты

После многих бессонных дней оно таки заработало. Температура с Вашей, Yuriy.pv, подсказкой давно уже пофикшена, а вот двигатель лентопротяжки - буквально пол часа как заработал нормально. Условно нормально, т.к. 30 минут надругательств - это не тест.

Что сделано:

1. Перетащил на библиотеку GyverStepper. В целом это без разницы, просто я пошел не самым логичным путем :)

2. Забросил проект на пару дней. 

3. Перетащил с места на место строчки кода в процедуре loop ().

4. Причесал код, убрал закомментированные куски.

5. Выбросил все старые файлы из папки с проектом и перекомпилил заново в стопицотый раз.

 

Что именно дало толчок к работе - не знаю. Но случилось чудо и картинка поплыла, как Солнце среди звезд, как жирный конь в компоте, как главком на красной площади, как деньги из бюджета - продолжать можно долго :) Еще раз спасибо за внимание, за помощь и поддержку. Вот текущий код:

/*
 * Станок по протяжке ленты из ПЭТ бутылок в пруток.
 * Версия 0.1 от 03.08.2021
 */
#include "Wire.h"
#include "LiquidCrystal_I2C.h"
#include "GyverButton.h"
#include <GyverStepper.h>
#define PID_INTEGER
#include "GyverPID.h"
#include <EEPROM.h>

//-----------------------------------------------------------------------------------------------------------------------
#define ver            "0.1" 
#define btn_dec_pin 11
#define btn_ok_pin  10
#define btn_inc_pin 9
#define btn_inc_step 20
#define btn_dec_step 20

// PWM пины: 3, 5, 6, 9, 10, 11
#define heater_pin     5      // Контакт D5
#define tsens_pin      21     // Контакт A7
#define fan_pin        6      // Контакт D6

#define thermistor_r   100000 // Номинальное сопротивление термистора при 25 градусах 100К
#define t_nominal      25     // Температура, при которой меряется номинальное сопротивление термистора
#define thermo_b       3950   // Какой-то бетта коэффициент термистора (обычно 3000-4000). ХЗ что это
#define thermo_r       11880  // Постоянный резистор второго плеча термистора, 11.88К
#define num_pas        10     // Количество измерений температуры для усреднения

#define temp_addr 0           // Адрес в EEPROM для хранения температуры нагревателя
#define speed_addr 2          // Адрес в EEPROM для хранения скорости протяжки

// ПИД регулятор
#define dt             500    // Частота регулировки ПИД 0.5 секунды
#define PID_kp         5.2    
#define PID_ki         0.5
#define PID_kd         0.5

// Мотор протяжки
#define motor_max_speed 1000   // Максимальное число шагов в секунду
#define motor_steps     200    // Количество шагов мотора на оборот (для Nema17 200)
#define motor_acceleration 300 
#define motor_step_pin  15     // Контакт А1
#define motor_dir_pin   14     // Контакт А0
#define motor_en_pin    16     // Контакт А2
//=======================================================================================================================

LiquidCrystal_I2C lcd(0x27, 16, 2);
GButton btn_dec(btn_dec_pin);
GButton btn_inc(btn_inc_pin);
GButton btn_ok(btn_ok_pin);
GyverPID regulator(0.1, 0.05, 0.01, 100);  // коэф. П, коэф. И, коэф. Д, период дискретизации dt (мс)
GStepper<STEPPER2WIRE> motor(motor_steps, motor_step_pin, motor_dir_pin, motor_en_pin); // драйвер step-dir + пин enable

//=======================================================================================================================
String menu_item [] = {"Temp  ","Speed ","Motor ", "Heat  ", "Fan   ", "Save  ", "Load  "};
int menu_pos = 0;
int heater_current_temp = 0;
int heater_new_temp = 0;
int motor_speed = 0;
float error, error0, pid, pwr, integ;
uint16_t Kp, Ki, Kd;
bool heater_logo = false;

static bool motor_enable = false;
//-----------------------------------------------------------------------------------------------------------------------
void Logo (void);
void Btn_dec (int);
void Btn_inc (int);
void Btn_OK ();
void Show ();
void Save ();
void Load ();
int GetTemp ();
void PID_heater ();
void Motor_step ();
void Ticks ();
//=======================================================================================================================
void Logo (void)
{
  String logo_str = "Extruder ver.0.1";
  int pos = 0;
  for (pos==0; pos<logo_str.length (); pos++) {
    lcd.setCursor (pos,0); lcd.print (logo_str[pos]); delay (100);
  }
  delay (1000);
  lcd.clear ();
}
//-----------------------------------------------------------------------------------------------------------------------
void Btn_dec (int clicks){
//   0        1        2        3         4          5         6
//"Temp  ","Speed ","Motor ", "Heat  ", "Fan   ", "Save  ", "Load  "  
// Одиночные нажатия
  if (clicks==1) {
    switch (menu_pos) {
      case 0: if (heater_new_temp>0) {heater_new_temp--;}; break;
      case 1: {motor_speed=motor_speed-5; motor.setSpeed(motor_speed);}; break;
      case 2: motor_enable = false; break;
      case 3: break;
      case 4: break;
      case 5: Save (); break;
      case 6: Load (); break; 
    }
  };
// Долгое удержание
  if (clicks==2) {
    switch (menu_pos) {
      case 0: if (heater_new_temp>btn_dec_step) {heater_new_temp=heater_new_temp-btn_dec_step;}; break;
      case 1: {motor_speed=motor_speed-20; motor.setSpeed(motor_speed);}; break;
    }
  };
}
//-----------------------------------------------------------------------------------------------------------------------
void Btn_inc (int clicks){
//   0        1        2        3         4          5         6
//"Temp  ","Speed ","Motor ", "Heat  ", "Fan   ", "Save  ", "Load  "  
// Одиночные нажатия
  if (clicks==1) {
    switch (menu_pos)
      {
      case 0: heater_new_temp++; break;
      case 1: if (motor_speed<motor_max_speed) {motor_speed=motor_speed+5; motor.setSpeed(motor_speed);}; break;
      case 2: motor_enable = true; break;
      case 3: break;
      case 4: break;
      case 5: Save (); break;
      case 6: Load (); break; 
    }
  };

// Долгое удержание
  if (clicks==2) {
    switch (menu_pos) {
      case 0: heater_new_temp=heater_new_temp+btn_inc_step; break;
      case 1: {motor_speed=motor_speed+20; motor.setSpeed(motor_speed);}; break;
    };
  };
}
//-----------------------------------------------------------------------------------------------------------------------
void Btn_OK (){
//   0        1        2        3         4          5         6
//"Temp  ","Speed ","Motor ", "Heat  ", "Fan   ", "Save  ", "Load  "  
  switch (menu_pos) {
    case 0: regulator.setpoint = heater_new_temp; break;
    case 1: break;
    case 2: break;
    case 3: break;
    case 4: break;
    case 5: break;
    case 6: break; 
  }
  menu_pos++;
  if (menu_pos==7) {menu_pos=0;};
}
//-----------------------------------------------------------------------------------------------------------------------
void Show (void) {
  lcd.setCursor (0,0); lcd.print (menu_item[menu_pos]);
  lcd.setCursor (6,0); lcd.print ("T="); lcd.print (heater_new_temp); lcd.print("/"); lcd.print(heater_current_temp); lcd.print(" ");
  lcd.setCursor (6,1); lcd.print ("S="); lcd.print (motor_speed); lcd.print("  ");
  lcd.setCursor (14,1); if (heater_logo==true) {lcd.print('h');} else {lcd.print(' ');};
  lcd.setCursor (13,1); if (motor_enable==true) {lcd.print('m');} else {lcd.print(' ');};
}
//-----------------------------------------------------------------------------------------------------------------------
void Save (void) {
  eeprom_update_word (temp_addr, heater_new_temp);
  eeprom_update_word (speed_addr, motor_speed);
  menu_pos = 0;
}
//-----------------------------------------------------------------------------------------------------------------------
void Load (void) {
  heater_new_temp = eeprom_read_word (temp_addr);
  motor_speed = eeprom_read_word (speed_addr);
  menu_pos = 0;
  //Проверка на -1 (после обновления прошивки из ЕЕПРОМ читается -1)
  if (motor_speed==-1) motor_speed = 0;
  if (heater_new_temp==-1) heater_new_temp = 0;
}
//-----------------------------------------------------------------------------------------------------------------------
int GetTemp(void) { //Функция измерения температуры
  int16_t At = 0;
  for (uint8_t i = 0; i < 10; i++) At += analogRead(tsens_pin); //Усредняем
  At /= 10;                                               //10 последовательных измерений

  float Rt = 1023.0 / At - 1;
  Rt = thermo_r / Rt;
  float T;
  T = Rt / thermistor_r;
  T = log (T);
  T /= thermo_b;
  T += 1 / (t_nominal + 273.15);
  T = 1 / T;
  T -= 273.15;
  int xx;
  xx = T;
  return xx;
}
//-----------------------------------------------------------------------------------------------------------------------
void PID_heater (void) {
  regulator.input = heater_current_temp;   // сообщаем регулятору текущую температуру
  pwr = regulator.getResultTimer();
  analogWrite(heater_pin, pwr);  // отправляем на мосфет  
  if (pwr>0) {heater_logo = true;} else {heater_logo = false;};
}
//-----------------------------------------------------------------------------------------------------------------------
void Ticks (void) {
  btn_dec.tick();
  btn_inc.tick();
  btn_ok.tick();  
  if (motor_enable==true) {motor.tick();};
}
//-----------------------------------------------------------------------------------------------------------------------
void PreSave (void) {
  motor_speed = 500; heater_new_temp = 50; Save ();
  lcd.clear ();
  lcd.print ("EEPROM saved");
  lcd.setCursor (0,1);
  lcd.print ("T=50, S=500");
  delay (1000);
}
//-----------------------------------------------------------------------------------------------------------------------
void PreLoad (void) {
  Load ();
  lcd.clear ();
  lcd.print ("EEPROM loaded");
  lcd.setCursor (0,1);
  lcd.print ("T="); lcd.print (heater_new_temp);
  lcd.print ("S=500"); lcd.print (motor_speed);
  delay (1000);  
}
//-----------------------------------------------------------------------------------------------------------------------
//=======================================================================================================================
void setup() {
  // Инициализация портов
  {
  pinMode (heater_pin, OUTPUT);
  pinMode (fan_pin, OUTPUT);
  digitalWrite (heater_pin, LOW);
  digitalWrite (fan_pin, LOW);  
  }
  // Инициализация дисплея
  {
    lcd.init();
    lcd.backlight();
    lcd.clear ();
  }

  Load ();

  // Инициализация ПИД регулятора
  {
  regulator.setDirection(NORMAL); // направление регулирования (NORMAL/REVERSE). ПО УМОЛЧАНИЮ СТОИТ NORMAL
  regulator.setLimits(0, 255);    // пределы (ставим для 8 битного ШИМ). ПО УМОЛЧАНИЮ СТОЯТ 0 И 255
  regulator.setpoint = heater_new_temp;  // сообщаем регулятору температуру, которую он должен поддерживать
  regulator.Kp = PID_kp;
  regulator.Ki +=PID_ki;
  regulator.Kd = PID_kd;  
  }
  // Инициализация двигателя протяжки
  {
    motor.invertEn(false);
    motor.setRunMode(KEEP_SPEED);
    motor.setMaxSpeed(motor_max_speed);
    motor.setAcceleration(motor_acceleration);
    motor.setSpeed(motor_speed);
  }
  
  // Прочее
  {
  Logo ();
  // Загрузка сохраненных в ЕЕПРОМ значений, если это необходимо
  if (digitalRead (btn_dec_pin)==0&&digitalRead (btn_inc_pin)==0) {PreSave (); Logo();};
  if (digitalRead (btn_ok_pin)==0&&digitalRead (btn_inc_pin)==0) {PreLoad (); Logo();};
  }
}
//=======================================================================================================================
void loop() {
  heater_current_temp = GetTemp ();
  PID_heater ();
  Ticks ();  
  Show ();
  if (btn_dec.isClick()) {Btn_dec(1);};
  if (btn_inc.isClick()) {Btn_inc(1);};
  if (btn_ok.isClick())  {Btn_OK();};
  if (btn_dec.isHolded()) {Btn_dec(2);};
  if (btn_inc.isHolded()) {Btn_inc(2);}; 
}

 

Странно, предыдущий ответ пропал, а потом снова появился - это ваще законно? :)

 

Простите, у нас тут локальная котоклизьма была, света больше суток не видели - даже пиво пили темное! :)

21 час назад, Yuriy.pv сказал:

В писатели вам надо.. талант пропадает)) тикс увидел, не заметил.

Правильное решение.  А что хоть за станок, че с этим прутком делать, для 3д принтера?

Пишу иногда, по настроению. Точнее, пописываю :) Так, фанфики на все, что глаза видят :)

 

Вы правы, станочек задумывался как вытягиватель ПЭТ-филамента для принтера, но пока делал - пришло много новых хотелок. Уж как там с филаментом пойдет я не знаю, все-таки вонюч он сверхмерно. Это я уже из экспериментов с предыдущей итерацией станка уяснил, а то в инете на сей счет мнения диаметрально разнятся. Еще хочу корзины научиться плести из этого прутка, сплести полноценный грузовой прицеп для велика, подвязки для помидоров в теплицу, розги для соседских детей, леску для триммера, гамак... Боюсь, моя печень не одобрит такой размах хотелок :bomb_phone:

Ссылка на комментарий
Поделиться на другие сайты

  • 7 месяцев спустя...
В 04.08.2021 в 19:04, Ушик сказал:

///////////////

Добрый день, есть продолжение и развитие  данной прошивки?. Адаптация под различные дисплеи ssd1306 и 12864, использование датчика холла на выходе из нагревательного элемента для корректировки толщины нити, датчик обрыва нити, корректировка нагревательного элемента от второго комнатного датчика температуры, использование дополнительного нагревательного элемента для спайки прутка, использование энкодера и/или вместо кнопок.

Изменено пользователем Falconist
Оверквотинг
Ссылка на комментарий
Поделиться на другие сайты

2 часа назад, APToni сказал:

Добрый день, есть продолжение и развитие  данной прошивки?. Адаптация под различные дисплеи ssd1306 и 12864, использование датчика холла на выходе из нагревательного элемента для корректировки толщины нити, датчик обрыва нити, корректировка нагревательного элемента от второго комнатного датчика температуры, использование дополнительного нагревательного элемента для спайки прутка, использование энкодера и/или вместо кнопок.

И Вам мое почтение :) Нет, я не развивал пока этот станочек, так что новыми плюшками не порадую. Пока что просто удалось завести эту адскую машинку, она исправно тянет пруток из коричневых полторашек. Пробовал тянуть бутылки других цветов - тянет. Но у них толщина стенок меньше (разница видна на моем механическом штангенциркуле, счет идет на сотые доли мм) и поэтому заполнение прутка получается более рыхлое. У коричневых пивных бутылок (мой текущий источник сырья) и так пруток получается с "пропилом", т.е. не сплошное заполнение, а где-то около 90% на глаз. У цветных бутылок это тпропил получается  чуть больше. Недостаточную толщину прутка я компенсирую в настройках слайсера (Cura) - поставил 1,65 мм и успокоился. Сейчас я неспешно работаю над сваркой кусков прутка, а то уж слишком быстро бутьылки закончились :) А, да. Цветными бутылками еще не пробовал печатать, т.к. у них пруток мягче на ощупь, а мне нужен сейчас жосткий, брутальный материал. Пока на батарее сушатся :) 

 

Теперь о том, что Вы спрашиваете :) В самых важных планах - это увеличение сорости протяжки, а то 2 часа на одну полторашку как-то слишком жирно выходит. Второе ОЧЕНЬ нужное дополнение - это датчик окончания ленты. Без него очень неудобно работать: чуть не уследил и конец прутка заматывается в редуктор, заминается там, шестерни портятся. Переделать ПИД, а то температура плавает +10/-20 градусов. В общем, эту прошивку, что сейчас работает в станочке можно рассматривать как преальфу в свободном доступе :) 

 

Что еще. Другие типы дисплеев я не рассматриваю, т.к. их у меня просто нет, следовательно нужды в их поддержке тоже нет, да и отлаживать как? В протеусе? :) Контроль за диаметром прутка? Практика показывает, что если она и плавает, то на печати это не сказывается. Во всяком случае, я еще не сталкивался с необходимостью в такой точности. Смастерить и отладить спайщик - тут да, это нужно. Когда будет чем делиться - обязательно расскажу. 

Сейчас задумал переработать все это в один станок, включающий в себя протяжку, спайку и сушилку в одном флаконе. Но поскольку с элементной базой у меня традиционно напряги (есть много чего, а вот нужного почему-то нет :) ) то дело идет как-то не очень быстро. Опять же весна заходит, огород, другие хотелки повалят... В общем, работаю над проектом, но очень медленно :) 

Ссылка на комментарий
Поделиться на другие сайты

  • 4 недели спустя...
В 04.08.2021 в 19:04, Ушик сказал:
#define ver            "0.1" 
#define btn_dec_pin 11
#define btn_ok_pin  10
#define btn_inc_pin 9
#define btn_inc_step 20
#define btn_dec_step 20

Доброго времени, тут наверное опечатка, на одном пине два сигнала висят, и 20-е контакты наверное для мега используются, так как на нано аналоговых 6, а цифровых 14. 

Есть электрическая схема для подключения всего этого?

Ссылка на комментарий
Поделиться на другие сайты

В 16.04.2022 в 19:58, APToni сказал:

Доброго времени, тут наверное опечатка, на одном пине два сигнала висят, и 20-е контакты наверное для мега используются, так как на нано аналоговых 6, а цифровых 14. 

Есть электрическая схема для подключения всего этого?

Вы меня просто разнесли в клочья. Уже час, наверное, роюсь в своих многочисленных папочках "PetPuller_ver_xxx", но пока не нашел того самого исходника, в котором содержится вышеприведенный кусочек. Буду искать до победного, а то получается, что я всех нагло и подло обманул. А это не правильно. Схемы в удобочитаемом виде тоже не существовало никогда - весь проект был собран на макетке и модифицировался по мере необходимости. Точнее, схема была и даже весьма близкая к действительности, но где мы и где она... Пожалуй, настало время его запротоколировать - вдруг самому понадобится, так хоть буду знать, где искать :) 

 

Спасибо за хорошую критику.

Ссылка на комментарий
Поделиться на другие сайты

Нашел древнюю рукопись, постирал ее и спешу поделиться. Нацепляю на нос очки и пытаюсь разобрать полустертые письмена. Так, что тут у нас:

"...кровь рогатой жабы, язык черного петуха, Е402, варить до первого крика совы..." Стоп, это чернила для струйного принтера. А, вот, на другой стороне.

Картинка:

Спойлер

image.png.d142eaa8f1782f2fc189945242b784c8.png

 

Здесь просто указаны названия клемм, к которым подключены провода к кнопкам, экрану и прочему фаршу. Вот куда звонятся эти клеммы:

Heater - D5.

Узел управления нагревателем - красный MOSFET-модуль на IRF520 (кажется так). В принципе, можно любой транзистор поставить, который выдержит длительный ток в 3+А. 

Нагреватель - от принтера, 12В 40Ватт.

Термистор при комнатной температуре показывает сопротивление около 10К и подключен к ножке А7. Добавочное сопротивление тоже 10К, соответственно, подключено к +5V.

Tsens - A7

Кнопки не имеют никаких конденсаторов или сопротивлений, просто идут на ножки ардуины:

BTN_MNS - D11

BTN_OK - D10

BTN_PLS - D9

Драйвер мотора подключен к следующим ножкам модуля ардуино:

Step - A1

Dir - A0

EN - A2

Мотор изначально стоял 17HS2408, потом он начал проскальзывать и был заменен на 17HS44_чего_то_там. А потом оказалось, что это шестерня проскальзывает на валу. Залил все суперклеем и теперь шестерня сидит очень хорошо, а более мощный мотор остался в виде бонуса.

 

Кормится вся эта вершина инженерной мысли от блока питания АТХ. Так же имеются еще куча незадействованных клеммников, для чего они были туда вкорячены - я вам не скажу, это надо на сеансы репродуктивного... перспективного... А, вспомнил - ретроспективного гипноза записываться. 

Вроде бы все рассказал. Если возникнут какие-либо вопросы - буду рад пролить свет на этот ужас :) 

Изменено пользователем Ушик
Ссылка на комментарий
Поделиться на другие сайты

В 18.04.2022 в 17:58, Ушик сказал:

"...кровь рогатой жабы, язык черного петуха, Е402, варить до первого крика совы..."

Драйвер для двигателя какой использовали? я собрал всю эту схему, с температурой понятно, там цветные картинки есть в интернете как NTC датчик подключать, а с драйвером проблема вышла, на А4988 он так и не заработал, выкручивал скорость до 1000 еле двигается.

Ссылка на комментарий
Поделиться на другие сайты

9 часов назад, APToni сказал:

Драйвер для двигателя какой использовали? я собрал всю эту схему, с температурой понятно, там цветные картинки есть в интернете как NTC датчик подключать, а с драйвером проблема вышла, на А4988 он так и не заработал, выкручивал скорость до 1000 еле двигается.

Именно этот драйвер и стоит, А4988. В настоящий момент у меня на станочке скорость установлена 2000, хотя в программе стоит ограничение 1000 шагов в секунду. Честно говоря я уже не помню, из каких соображений вводил этот предел. Когда станочек только запускася, у меня двигатель тоже долго не подавал признаков вращения. Из-за этого, помню, еще долго копался в библиотеках: хотелось и плавный разгон, и простоту управления, и чтоб работало... Наивный. Сейчас понимаю, что лучше было бы сделать все самому и ручками - уж написать-то код для "дергать лапкой" с определенной периодичностью можно :) Для ардуин есть славная библиотека TimerOne - удобная обертка для таймеров, с ее помощью можно очень удобно подбные периодичные процессы инициировать. Я ее сейчас везде пихаю, к месту и не очень :) Собственно, обновленная версия прошивки именно на таймерах и завязана. Но поскольку она еще не опробована в железе, то говорить об этом рано.

 

Настроечные перемычки, которыми выставляется микрошаг - оставлены открытыми. 

 

Сейчас более подробно выпишу подключение драйвера: хоть там все и подключал по интернетовским мануалам, однако парадоксы могуть иметь место быть. Вы ток, кстати, настроили? Может быть на драйвере потенциометр выкручен в ноль? 

Ссылка на комментарий
Поделиться на другие сайты

Авотфиг, не смогу перерисовать схему подключения драйвера: в этом хаосе проводков улчше лишний раз не копаться. Добавлю лишь, что на обратной стороне макетки есть парочка мелких конденсаторов - один на NTC резисторе, второй как раз в области драйвера. Куда он там припаян на самом деле - то никому неведомо, даже детям китайских инженеров и индийских кодеров. Скорее всего это фильтр на шине питания (5В или 12В). Большого электролита на линии 12В, как советуют в инетах, я не ставил. 

 

Слил на всякий случай прошивку с ардуины, вдруг она Вам поможет. У меня весь станочек построен на ардуине нано 168, где установлен процессор ATMega168PA, фьюзы ардуинские по умолчанию (Lock bits = 0x3F, H = 0xDC, L = 0xFF, E = 0x00). Вы вообще на каком модуле ардуино собираете? Или какой-то иной процессор используете?

stanoc_v0.hex

Изменено пользователем Ушик
Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы публикуете как гость. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...