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

 

Link to comment
Share on other sites

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

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

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

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

 

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

Link to comment
Share on other sites

Вебинар «Новые тенденции сетевых технологий: Ethernet по одной витой паре» (09.12.2021)

Приглашаем 9 декабря всех желающих посетить вебинар, посвященный технологии Ethernet и её новому стандарту 10BASE-T1S/L. Стандарт 802.3cg описывает передачу данных на скорости до 10 Мбит в секунду по одной витой паре. На вебинаре будут рассмотрены и другие новшества, которые недавно вошли в семейство технологий Ethernet: SyncE, PTP, TSN. Не останется в стороне и высокоскоростной 25G+ Ethernet от Microchip.

Подробнее

Posted (edited)

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

Edited by Ушик
Link to comment
Share on other sites

DC/DC-преобразователи Mornsun со склада Компэл

В сложный период для рынка электронных компонентов, когда производители увеличивают сроки поставки продукции, со склада Компэл можно приобрести широкий ассортимент DC/DC-преобразователей производства компании Mornsun. На складе представлены наиболее популярные семейства изолированных и неизолированных DC/DC-преобразователей новых поколений R3 и R4, а также предыдущего, но по-прежнему востребованного поколения R2.

Подробнее

Новые компоненты STMicroelectronics для учета электроэнергии

Внедрение автоматизированных систем контроля и учета всех видов энергоресурсов, невозможно без инструментов, позволяющих помимо измерения параметров, преобразовывать их для обработки цифровыми интеллектуальными системами. Микросхемы STPM32, STPM33 и STPM34 STMicroelectronics являются наиболее точными и высокопроизводительными представителями своего семейства и способны максимально точно измерять параметры электросети в системах электроснабжения переменного тока, а также осуществлять их первичную обработку. Рассмотрим подробнее их преимущества и средства разработки.

Подробнее

Карбид кремния позволяет повысить КПД и удельную мощность ИБП с двойным преобразованием

Построение источников бесперебойного питания с двойным преобразованием, широко используемых в современных хранилищах данных, на базе карбид-кремниевых MOSFETs производства Wolfspeed позволяет уменьшить мощность потерь в них до 40%, а также значительно снизить занимаемый ими объем и стоимость комплектующих.

Подробнее

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

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

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

 

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

Link to comment
Share on other sites

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

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

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

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

Link to comment
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:

Link to comment
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...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Сообщения

    • Ну давайте подождём. Собственно пост @Zawinul я и не собирался обсуждать. Примерно догадываюсь, почему ту дискуссию Я среагировал на ваш, @I_Avals, пост, потому что подумал, что здесь есть смысл что-то обсудить. В частности то, что ГОСТ писали неглупые люди.
    • Вот кстати да, грешу на переходники китайские к кабелю. Вспоминаю когда первый раз мерял, у меня другой провод был и переходники другие.) Никак его не найду, Завтра если найду надо с ним испробовать, думаю всё наладится.  
    • Я, чуть выше, говорил. Прежде спорить, давайте договоримся о терминологии. Максимальный уровень должен быть чем то ограничен. Например, Ку, при стандартных 5 мВ, на входе. Либо искажениями. Скажем, пресловутым 1-м %%. Только, боюсь, что в первом случае, на выходе одного и того же корректора, может оказаться 500 - 700 милливольт, а во втором, 20 - 30 Вольт. Поэтому, использование в качестве "опоры" именно 5 мВ, и именно на входе, лично для меня, выглядит полностью обоснованным. Но, повторюсь, у Zawinul  есть какая то, не то теория, не то методика, которую, судя по анонсам, он собирается по каплям выдавливать сюда. Давайте, лучше, подождём. Правда. Пусть человек выскажется. Тогда и обсудим.
    • Ты забыл уточнить: - От какой "ЭТОЙ" ситуации?  От убийства Навального выгода была бы только для путниа.  А ситуация с полным провалом этой операции сильно ударила  по репутации всех силовиков и самого путина.   Ну так озвучь свою аргументированную версию отравления, а не задавай вопросы. А что получили ваши партнёры? И кто они, эти партнёры?
    • Ну вот... слава богу. Теперь сможете просверлить дырки в плате.
    • так опровергнуть ранее сказанные  факты есть чем ? а выгодно - это моно сейчас что хощь говорить - помер в самолете - и дело с концом - докажи ! вот и все )

  • Набор разъемов micro usb, 25 моделей

×
×
  • Create New...