Jump to content
Ушик

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

Recommended Posts

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

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

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 ();  
}

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites
4 часа назад, Yuriy.pv сказал:

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

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

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

 

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

Share this post


Link to post
Share on other sites

Оценка точности измерения тока интеллектуальными силовыми ключами PROFET

Интеллектуальные силовые ключи PFOFET производства Infineon могут измерять ток нагрузки с разной точностью, зависящей как от абсолютной величины потребляемого тока, так и от технологии производства конечной продукции, в частности – от наличия или отсутствия этапа калибровки. В статье подробно разбирается расчет коэффициента передачи тока на примере ключа BTS7004-1EPP.
Подробнее

Posted (edited)

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

Edited by Ушик

Share this post


Link to post
Share on other sites

STMicroelectronics: электростатический разряд больше не проблема

Защита от статического электричества необходима каждому современному устройству. Компания STMicroelectronics представляет решения, соответствующие стандарту IEC61000-4-2, а также специальное приложение PROTECTION FINDER, которое поможет легкого и эффективно подобрать необходимые компоненты. Рассмотрим практические примеры защиты от ESD, отраслевые стандарты и ряд ключевых параметров важных при проектировании электростатической защиты устройств.

Подробнее

4 часа назад, Ушик сказал:

Есть подозрение

Как с подозрением?

Share this post


Link to post
Share on other sites

Удалось ли сделать резервную копию? Обеспечение бесперебойного питания

Для работы портативных электронных устройств с постоянным или длительным включением необходим резервный источник питания. Микросхемы диспетчеров питания производства Analog Devices LTC4040 или LTC4041 позволяют легко подключить резервное питание в виде Li-Ion-аккумулятора или суперконденсатора соответственно в случае сбоя или потери основного питания. Рассмотрим решения по резервированию питания на основе этих микросхем.
Подробнее

Спасибо, что проявляете интерес к моему скромному проекту :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();};
}

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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

 

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

Share this post


Link to post
Share on other sites

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

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

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

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

Share this post


Link to post
Share on other sites

После многих бессонных дней оно таки заработало. Температура с Вашей, 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:

Share this post


Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...