Очередная паяльная станция

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Проектов паялок в инете немало, но всё ж где-то, что-то в них меня не устраивало. Решил делать "под себя". Возможно, какие-то решения кому-то покажутся излишними или код не в профессиональном тренде, но что получилось, то получилось...

Вкратце, по характеристикам:
Диапазон работы паяльника 100...350 град. С, фена - 50...450 град. С, обороты фена - 20...100%.
Точность поддержания температуры +/- 2 град. С.
Управление - пятикнопочное, потенциометры или энкодеры не захотелось использовать по определённым причинам, а кнопок у меня много.
Паяльная станция имеет защиты по обрыву и к.з. датчиков температуры фена и паяльника, а так же превышению текущей температуры относительно заданной на 50 градусов. Защита отключает регулирующий элемент канала и отключает силовую цепь с помощью реле. Также, имеются плавкие предохранители в цепях нагревателей паяльника и фена.
Время работы фена и паяльника, после включения, ограничено индивидуальным таймером (10минут). Таймер сбрасывается при использовании фена и паяльника при снятии или установки их на подставку. Т.е. пока пользуемся - таймер сбрасывается, не пользуемся - через 10 минут таймер отключит канал. Для фена это работает, а для паяльника все необходимые "концы" выведены на разъём сзади, но ещё не полностью реализовано (нужно смонтировать фотодатчик в подставку).
После отключения фена защитой или штатно, происходит его продувка полными оборотами вентилятора, независимо от того, какие обороты были использованы ранее. Температура "сдувается" до 50 градусов, затем вентилятор отключается.
Вся индикация о состоянии станции выводится на 4-х строчный дисплей, а нажатия кнопок, выход на заданную тепературу, окончание времени таймера и срабатывание защиты озвучиваются бипером.

Паяльная станция выполнена на базе Ардуино Нано на Атмега168 и конструктивно имеет несколько плат -
1. Силовая плата, где расположены стабилизатор питания контроллера, все силовые ключи и схема перехода сетевого напряжения через ноль. Силовые цепи и схема "нуля" развязаны от контроллера через оптопары, а сама плата расположена на стойках над трансформатором питания и соединяется с платой контроллера через разъём.
Все остальные цепи подключаются через клеммные колодки.

2. Плата контроллера. Имеет размер платы индикации и скручена с ней "бутербродом". На ней расположена плата Ардуино Нано (в панельке), резисторы обвязки, бипер и разъёмы для подключения остальных плат.

3.Плата ЛЦД дисплея. Дисплей подключается через I2C шину, для экономии выводов контроллера.

4. Плата кнопок. Параллельно каждой кнопке впаяны керамические конденсаторы на 0,022-0,1 мкф.

5. Плата усилителей сигнала термодатчиков фена и паяльника. В качестве ОУ использован rail-to rail ОУ AD8552. Можно применить и что-то проще, типа LM358, но в коде придётся сделать небольшое исправление.

Из комплектующих покупал только дисплей с I2C переходником, ОУ, разъёмы для фена и паяльника и сами паяльник с феном. Остальное найдено "в тумбочке" или было "добыто" уже давно и лежало без дела.

В этом архиве содержатся чертежи плат, схемы (довольно сумбурные) и проект для Атмел Студио с необходимыми библиотеками. В коде, думаю, подробно всё прокомментировано.

Ну и пару картинок -

 

Графики выхода на заданную температуру для фена

и паяльника

pter
Offline
Зарегистрирован: 15.02.2016

OlegK спасибо за выложенный материал и скажите какой вы применили трансформатор.

P.S С праздником.

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Первое сообщение не могу изменить, к сожалению.
Архив, с печаткой и последней прошивкой (v1.6)  здесь.

Небольшое видео на Ютубе.
Видео набора температуры паяльника и фена.

ВНИМАНИЕ!
Перед печатью необходимо установить галку "зеркально", т.к. они нарисованы со стороны печатных проводников.

Модификации участников темы:

Вариант, модифицированный Spinne под энкодер.

"Одноплатный" вариант от Русл@н тут.
Вариант печаток под ProMini от Фёдора тут. Зеркалить не надо. Фото в сообщении #1691

Простая софтина для снятия графиков тут. (#1153) Требуется NET Framework 4.0
или
программа Advanced Grapher

Книга Карпова "ПИД-регулирование в нестрогом изложении" - более простой объясняловки мне не попадалось.

По нагревателям.

Сопротивление керамического нагревателя при комнатной температуре составляет около 2,5–3,5 Ом.
Термодатчик - терморезистор. Его сопротивление — примерно 43–58 Ом.

У нихромовых нагревателей при комнатной температуре нагреватель имеет сопротивление около 10–17 Ом, а термодатчик - термопара, сопротивление, приблизительно 2–3 Ом.

------------------------------------------------------------------------------------------------------------------------

>>>

Трансформатор применён какой был - тороидальный, ватт на 70. Вернее, было только железо, мотал сам.
Трансформатор применил по нескольким причинам -
1. Потому что уже есть и не нужно покупать.
2. Придаёт вес паялке и она не будет "бегать за шнурами"

В общем, подойдёт любой трансформатор ватт на 50-100 с парой вторичных обмоток на 24 вольта для паяльника и вентилятора фена и 7-10 вольт для питания платы контроллера. У меня в защите применены реле на 12 вольт (не было в наличии на 24), поэтому цепи обмоток реле питаются от стабилизатора 7812 от обмотки на 24 вольта.
В трансформатор можно не и упираться, многие делают на импульсных БП.

pter
Offline
Зарегистрирован: 15.02.2016

У меня еще один вопрос какие вы применили полевики и что означает  на плате sensors amp названия "начало" и"шкала".

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Полевики применены IRFZ44 по причине, что указаны выше (были в наличии). Можно применить любые N-канальные полевики, подходящие по току. В моём случае они управляются через оптопару, поэтому logic level полкевики не требуются.
 

Подстроечники "начало" - ими задаётся начальное смещение, т.е. выставляется комнатная температура по образцовому термометру. Соответственно, подстроечники "шкала" отвечают за растяжку шкалы - ими выставляются правильные показания при температуре 300-400 град. Тогда для не rail-to-rail ОУ показания АЦП будут прямыми для измеренной температуры. Для rail-to-rail ОУ их придётся делить на 2, что и сделано у меня в программе.

pter
Offline
Зарегистрирован: 15.02.2016

Еще один вопрос по плате mcu,что за номинал у катушек индуктивности.

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Индуктивности любые, 50-200 микрогенри

ЗЫ. Можно оставить только ту,что питает плату на ОУ, а вторую заменить перемычкой.

pter
Offline
Зарегистрирован: 15.02.2016

OlegK возникли вопросы по плате mcu возле конденсатора 100мкф и бипера это обозначено питание и что за транзистор там стоит и какие применины диодные мосты на плате power.

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Транзистор "возле бипера" - абсолютно любой, маломощный, npn структуры, у меня  впаян КТ503.

Диодные мосты (можно применить и дискретные диоды) -
1. в схеме "контроля нуля сети" - любой маломощный, выдерживающий напряжение сети (не ниже 400 вольт).
2. в цепи стабилизатора питания контроллера - на напряжение от 50 вольт и ток от 500мА
3. в цепи питания паяльника и вентилятора фена - на напряжение от 50 вольт и ток 10А (у меня стоит какой-то из серии KBPCxx10 c тонкими выводами (бывают ещё с плоскими, под плоскую "лопаточку"))

Ещё. Если потребуется расширить вверх температуру паяльника (для пайки безсвинцовыми припоями) - то это не проблема, в прошивке нужно изменить всего одну константу max_solder_temp до "сколько нужно", т.е. до 400-450 град.

 

pter
Offline
Зарегистрирован: 15.02.2016

Спасибо за ответы,еще один вопрос у фена в качестве датчика используется геркон.

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Не за что, спрашивайте всё, что непонятно ))

Да, в фене есть геркон, изначально, поэтому подставка должна иметь магнит. В качестве держателя фена я использовал зажимы (клипсы) для пластиковых труб, они чуть меньше, чем требуется, пришлось нагреть термофеном и разогнуть "рога" до нужной величины - что бы фен входил с лёгким щелчком. Клипсы (2шт.) закреплены на уголке, а уголок прикручивается к корпусу. Между клипсами размещён магнит. Его я не крепил, он сам неплохо держится, т.к. уголок стальной. Держатель фена съёмный, ибо фен требуется не так уж часто, проще его хранить в "отстёгнутом" состоянии и, соответственно, снимать держатель. В случае надобности, всё монтируется за минуту.

pter
Offline
Зарегистрирован: 15.02.2016

Тогда где он подключается не могу найти.

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

pter пишет:
Тогда где он подключается не могу найти.

В прошивке объявлены пины -
 

#define sw_HA 10
#define sw_S 9

Для фена и паяльника, соответственно. На плате MCU есть разъём, подписанный "концевики", туда выведены 9 и 10 ноги Ардуино. К этому разъёму и подключать. Разъём ранее планировался для подключения преобразователя сигнала термпары на специализированной микросхеме, но, после экспериментов, я от неё отказался и сделал усилитель на ОУ.

Оттуда же (с этого разъёма) используются +5V (через резистор 51Ом) и общий провод для будущего питания фотодатчика подставки паяльника. Для паяльника можно и не использовать никаких датчиков, в принципе, таймер можно сбросить регулируя температуру или нажатием кнопки "select" (за минуту до отключения станция подаст звуковой сигнал), но, думается, с датчиком будет удобнее. Можно и время таймера увеличить, если 10 минут мало.
Конструктивно планируется возле "дырки", куда пихаем паяльник разместить ИК-светодиод и ИК-фотодиод, которые будут перекрываться вставленным паяльником.

Подставка вот такая нашлась, думаю, там будет удобно фотодатчики разместить и она имеет пару выдвижных отсеков для хранения жал и губки.

pter
Offline
Зарегистрирован: 15.02.2016

Что необходимио будет поменять в скетче если преминить Nano V3.0, а то не могу найти  на али Ардуино Нано на Атмега168.

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Ничего менять не требуется, ни в схеме (плате), ни в коде, просто у 328-й Атмеги памяти больше в 2 раза, против 168-й.

Вот распиновка для Нано на 328-м камне, сравните сами рисунок платы и на картинке

Vln
Offline
Зарегистрирован: 17.12.2015

подпишусь на тему

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

В общем, с фотодатчиками решил не заморачиваться, применил, как по мне, более простое и интересное решение.
Подставка для паяльника - обычная "спиралька" на основании.

К "спиральке" крокодилом цепляю сигнальный провод (он через разъём втыкается в заднюю панель станции), а на "спиральке", меж её витков вставлена полоска жестянки от фотоглянцевателя, которая частично заходит в карболитовую "воронку", куда вставляется паяльник.

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

Вторым проводом для цепи является провод заземления корпуса паяльника, который подключается к общему проводу схемы.

Такое решение позволяет использовать подставку и "классического" типа - "рогульки", на которые паяльник кладётся горизонтально, лишь бы "рогулька", которая соприкасается с металлом корпуса паяльника была токопроводящей.
К ней и цепляется крокодил.

ЗЫ. С картинкой, думается, будет более понятно -

VitaliyDF
Offline
Зарегистрирован: 02.02.2016

Я себе думаю добавить вибродатчик в паяльник, потребуется конечно замена провода и гнезда с штекером.

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

...и ещё место, куда его там запихать ))

На самом деле, с вибродатчиком тоже неплохая идея, но вариант с "проводком и жестянкой" вполне себе работает и требует меньших усилий (сам вибродатчик, замена кабеля, разъёма).

 

keefa
Offline
Зарегистрирован: 19.06.2015

Я решил не заморачиваться системой обнаружения паяльника на подставке. После включения паяльника, запускается 15-ти минутный таймер, по истечении которого, за 5 сек до выключения, запускается пищалка. И если в это время не нажать кнопку запуска паяльника, происходит отключение нагрева. Если нажать, то таймер обнуляется, греем еще 15 мин. Отключение и включение паяльника происходит одной и той же кнопкой. Включение - короткое нажатие, выключение - длинное.

А вот на фен бы придумал что нить, там это необходимо.

 

 

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

keefa пишет:
А вот на фен бы придумал что нить, там это необходимо.

Фен имеет геркон и провод от него в кабеле. Так что достаточно магнита на подставке.

Цитата:
за 5 сек до выключения, запускается пищалка. И если в это время не нажать кнопку запуска паяльника, происходит отключение нагрева.

Не мало 5 сек? Если сигнал прозвучит в процессе пайки, то нужно успеть, как минимум, освободить одну руку, что бы ткнуть вкнопку.

 

keefa
Offline
Зарегистрирован: 19.06.2015

OlegK пишет:

Не мало 5 сек? Если сигнал прозвучит в процессе пайки, то нужно успеть, как минимум, освободить одну руку, что бы ткнуть вкнопку.

Не, не мало. если не успел, то можно и позже ткнуть... за несколько секунд не успеет остыть. в общем не критично. да, забыл сказать что пищит не непрерывно, а с частотой 1Гц, где то. Так же как и у ТС, реализовал защиту от пробоя управляющих элементов (тиристора и мосфета), поставил релюшки, и при превышении предельных значений, происходит отключение этих самых реле. Если не включить в разъем паяльник или фен, то тоже реле не включится и на разъеме не появится напряжение, на экране будет предупреждение Error.

Vln
Offline
Зарегистрирован: 17.12.2015

keefa пишет:

15-ти минутный таймер, по истечении которого, за 5 сек до выключения, запускается пищалка. 

а код можете выложить?

keefa
Offline
Зарегистрирован: 19.06.2015

Vln пишет:

а код можете выложить?

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

/* Паяльная станция
 * Simon
 * 21.09.2015 v1.6
*/

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

#define BTN_START_SOLDER 12 // Кнопка включения нагрева паяльника
#define BTN_START_AIR 13 // Кнопка включения нагрева фена
#define CONTROL_PIN_SOLD 6  // выход на мосфет нагревателя паяльника
#define TEMP_SOLDER_PIN A3
#define TEMP_AIR_PIN A6
#define CONTROL_PIN_FAN 5
#define CONTROL_PIN_AIR 8
#define TON_PIN 9
#define ENC_BTN 4
#define ENC_FOR 2
#define ENC_REV 3
#define RELE_SOLDER 11
#define RELE_AIR 10

unsigned long lastMillis_ENC_BTN_delay = 0;
unsigned long lastmillisPrint_LCD = 0;
int encSetTempSold = EEPROM.read(1) * 5; //180;
int encSetTempAir = EEPROM.read(3) * 5; //180;
int encSetSpeedFan = EEPROM.read(2); //99;
int TempSolder = 0;
int TempAir = 0;
boolean encBtnStat = 0;
boolean flag_btn = 0;
boolean solderEnable = false;
boolean airEnable = false;
boolean airFanEnable = false;
boolean airOverheat = 0;
boolean solderOverheat = 0;
boolean flag_1, flag_2 = 0;
byte set = 0;
byte x, y, z, c = 0;
byte gradus[8] = {0b00110, 0b01001, 0b01001, 0b00110, 0b00000, 0b00000, 0b00000, 0b00000};
byte up[8] = {0b00100, 0b01110, 0b10101, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100};
byte down[8] = {0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b10101, 0b01110, 0b00100};

void setup() {
  //TCCR2B = TCCR2B & 0b11111000 | 0x01; // Частота ШИМ 11 и 3
  //TCCR0B = TCCR0B & 0b11111000 | 0x01; // Частота ШИМ 5 и 6
  lcd.init();
  Serial.begin(115200);
  pinMode(TEMP_AIR_PIN, INPUT);
  pinMode(BTN_START_SOLDER, INPUT);
  pinMode(TON_PIN, OUTPUT);
  pinMode(BTN_START_AIR, INPUT);
  pinMode(RELE_SOLDER, OUTPUT);
  pinMode(RELE_AIR, OUTPUT);
  pinMode(CONTROL_PIN_SOLD, OUTPUT);
  pinMode(CONTROL_PIN_FAN, OUTPUT);
  pinMode(CONTROL_PIN_AIR, OUTPUT);
  pinMode(ENC_BTN, INPUT);
  digitalWrite(CONTROL_PIN_FAN, LOW);
  digitalWrite(CONTROL_PIN_SOLD, LOW);
  digitalWrite(BTN_START_AIR, HIGH);
  digitalWrite(BTN_START_SOLDER, HIGH);
  digitalWrite(ENC_BTN, HIGH);
  digitalWrite(ENC_FOR, HIGH);
  digitalWrite(ENC_REV, HIGH);
  digitalWrite(RELE_SOLDER, HIGH);
  digitalWrite(RELE_AIR, HIGH);
  lcd.createChar(1, gradus);
  lcd.createChar(2, up);
  lcd.createChar(3, down);
  lcd.backlight();
  testDisp();
  main_displ();
  tone(TON_PIN, 2000, 100);
}

void loop() {

  /******************СТАРТ СТОП ПАЯЛЬНИК*******************/
  static unsigned long lastMillisSolder = millis();
  if (digitalRead(BTN_START_SOLDER) == LOW && flag_1 == 0 && solderOverheat == 0) {
    solderEnable = true;
    lastMillisSolder = millis();
    x = 0;
    y = 0;
  }
  if (millis() - lastMillisSolder > 600000) solderEnable = false;
  if (millis() - lastMillisSolder > 595000 && solderEnable == true ) tonOff();
  if (solderEnable == true && digitalRead(BTN_START_SOLDER) == LOW) {
    z++;
    if (z > 200) {
      tone(TON_PIN, 2000, 500);
      solderEnable = false;
      z = 0;
      flag_1 = 1;
      x = 0;
      delay(1000);
    }
  }
  if (digitalRead(BTN_START_SOLDER) == HIGH) z = 0;
  if (digitalRead(BTN_START_SOLDER) == HIGH && flag_1 == 1) flag_1 = 0;
  digitalWrite(RELE_SOLDER, !solderEnable);
  /*****************************************************************/
  /********************СТАРТ СТОП ФЕН*********************************/
  static unsigned long lastMillisAir = millis();
  if (digitalRead(BTN_START_AIR) == LOW && flag_2 == 0 && airOverheat == 0) {
    airEnable = true;
    lastMillisAir = millis();
    y = 0;
    x = 0;
  }
  if (millis() - lastMillisAir > 300000) airEnable = false;
  if (millis() - lastMillisAir > 295000 && airEnable == true) tonOff();
  if (airEnable == true && digitalRead(BTN_START_AIR) == LOW) {
    c++;
    if (c > 200) {
      tone(TON_PIN, 2000, 500);
      airEnable = false;
      c = 0;
      flag_2 = 1;
      y = 0;
      delay(1000);
    }
  }
  if (digitalRead(BTN_START_AIR) == HIGH) c = 0;
  if (digitalRead(BTN_START_AIR) == HIGH && flag_2 == 1) flag_2 = 0;
  digitalWrite(RELE_AIR, !airEnable);
  /***************************************************************/

  /**************ВЕНТИЛЯТОР ФЕНА*************************************/
  if (airFanEnable == true) analogWrite(CONTROL_PIN_FAN, map(encSetSpeedFan, 0, 99, 0, 255));
  else {
    if (TempAir > 50) analogWrite(CONTROL_PIN_FAN, 255);
    else analogWrite(CONTROL_PIN_FAN, 0);
  }
  /***************************************************************/
  /*****ОБРАБОТКА ЭНКОДЕРА И КНОПКИ ЭНКОДЕРА*******************/
  encBtnStat = digitalRead(ENC_BTN);
  if (encBtnStat == LOW) {
    btn();
    lastMillis_ENC_BTN_delay = millis();
  }
  if (encBtnStat == HIGH) flag_btn = 0;

  if (digitalRead(ENC_REV) != HIGH || digitalRead(ENC_FOR) != HIGH) lastMillis_ENC_BTN_delay = millis();
  if (millis() - lastMillis_ENC_BTN_delay >= 10000)  {
    static int encSetTempSoldLast = 0;
    static int encSetSpeedFanLast = 0;
    static int encSetTempAirLast = 0;
    if (encSetTempSold != encSetTempSoldLast) {
      EEPROM.write(1, encSetTempSold / 5);
      encSetTempSoldLast = encSetTempSold;
    }
    if (encSetSpeedFanLast != encSetSpeedFan) {
      EEPROM.write(2, encSetSpeedFan);
      encSetSpeedFanLast = encSetSpeedFan;
    }
    if (encSetTempAir != encSetTempAirLast) {
      EEPROM.write(3, encSetTempAir / 5);
      encSetTempAirLast = encSetTempAir;
    }
    set = 0;
  }
  switch (set) {
    case 1:
      encSetTempSold = enc(encSetTempSold, 5);
      encSetTempSold = constrain(encSetTempSold, 180, 440);
      break;
    case 2:
      encSetSpeedFan = enc(encSetSpeedFan, 1);
      encSetSpeedFan = constrain(encSetSpeedFan, 30, 99);
      break;
    case 3:
      encSetTempAir = enc(encSetTempAir, 10);
      encSetTempAir = constrain(encSetTempAir, 180, 500);
      break;
  }
  /******КОНТРОЛЬ И ПОДДЕРЖАНИЕ ТЕМПЕРАТУРЫ ПАЯЛЬНИКА*****************/
  TempSolder = map(getOversampled(analogRead(TEMP_SOLDER_PIN)), 230, 440, 27 , 460) - 20; //230, 440, 27 , 460
  if (encSetTempSold - TempSolder > 3 && solderEnable == true && digitalRead(BTN_START_SOLDER == HIGH)) {
    if (TempSolder < 200) analogWrite(CONTROL_PIN_SOLD, 120);
    if (TempSolder >= 200 && TempSolder <= 300) analogWrite(CONTROL_PIN_SOLD, 170);
    if (TempSolder > 300) digitalWrite(CONTROL_PIN_SOLD, HIGH);
  }
  else digitalWrite(CONTROL_PIN_SOLD, LOW);
  if (TempSolder > 450) {
    solderEnable = false;
    solderOverheat = 1;
  }
  /******КОНТРОЛЬ И ПОДДЕРЖАНИЕ ТЕМПЕРАТУРЫ ФЕНА*****************/
  TempAir = map(getOversampled(analogRead(TEMP_AIR_PIN)), 0, 500, 0, 500);//, 0, 500, 0, 500;
  if (encSetTempAir > TempAir && airEnable == true) digitalWrite(CONTROL_PIN_AIR, HIGH);
  else digitalWrite(CONTROL_PIN_AIR, LOW);
  airFanEnable = airEnable;
  if (TempAir >= 550) {
    airEnable = false;
    airOverheat = 1;
  }
  /******ВЫВОД ИНФОРМАЦИИ НА lCD********/
  /**********************************************************/
  if (millis() - lastmillisPrint_LCD > 250) {
    static int encSetTempSoldStat = 0;
    static int encSetTempAirStat = 0;
    static byte encSetSpeedFanStat = 0;
    static boolean solderEnableStat = 0;
    static boolean airEnableStat = 0;
    if (solderOverheat == 1) {
      lcd.setCursor(5, 0);
      lcd.print("Error       ");
    }
    else {
      if (set == 1 && Blink() == 0) {
        lcd.setCursor(5, 0);
        lcd.print("    ");
      }
      else {
        lcd.setCursor(5, 0);
        lcd.print(encSetTempSold);
        lcd.write(1);
        lcd.print(" ");
      }
      if (TempSolder < 100) {
        lcd.setCursor(10, 0);
        lcd.print("<100");
        lcd.write(1);
      }
      else {
        lcd.setCursor(10, 0);
        lcd.print(" ");
        lcd.print(TempSolder);
        lcd.write(1);
      }
      if (solderEnableStat != solderEnable) {
        if (solderEnable == true) {
          lcd.setCursor(15, 0);
          lcd.write(2);
        }
        else {
          lcd.setCursor(15, 0);
          lcd.write(3);
        }
        solderEnableStat = solderEnable;
      }
    }
    /**********************************************************/
    if (airOverheat == 1) {
      lcd.setCursor(4, 1);
      lcd.print("Error       ");
    }
    else {
      if (set == 3 && Blink() == 0) {
        lcd.setCursor(4, 1);
        lcd.print("    ");
      }
      else {
        lcd.setCursor(4, 1);
        lcd.print(encSetTempAir);
        lcd.write(1);
        lcd.print(" ");
      }
      if (TempAir < 100) {
        lcd.setCursor(8, 1);
        lcd.print("<100");
        lcd.write(1);
      }
      else {
        lcd.setCursor(8, 1);
        lcd.print(" ");
        lcd.print(TempAir);
        lcd.write(1);
      }
      if (set == 2 && Blink() == 0) {
        lcd.setCursor(13, 1);
        lcd.print("  ");
      }
      else {
        lcd.setCursor(13, 1);
        lcd.print(encSetSpeedFan);
      }
      if (airEnableStat != airEnable) {
        if (airEnable == true) {
          lcd.setCursor(15, 1);
          lcd.write(2);
        }
        else {
          lcd.setCursor(15, 1);
          lcd.write(3);
        }
        airEnableStat = airEnable;
      }
    }
    lastmillisPrint_LCD = millis();
  }
  /*****Вывод информации в COM-порт********************/
  Serial.print(TempAir);
  Serial.print("\t");
  Serial.print(analogRead(TEMP_AIR_PIN));
  Serial.print("\t");
  Serial.print(TempSolder);
  Serial.print("\t");
  Serial.print(x);
  Serial.print("\t");
  Serial.println(y);
}
/********ФУНКЦИИ**************************/
void main_displ() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Sold:"); // Задание температуры паяльника
  lcd.setCursor(0, 1);
  lcd.print("Air:"); // Задание температуры Фена
  lcd.setCursor(15, 0);
  lcd.write(3);
  lcd.setCursor(15, 1);
  lcd.write(3);
  lcd.setCursor(13, 1);
  lcd.print(encSetSpeedFan);
}
void testDisp () {
  for (int i = 0; i <= 16; i++) {
    lcd.setCursor(i, 0);
    lcd.write(36);
    delay(100);
  }
  for (int i = 0; i <= 16; i++) {
    lcd.setCursor(i, 1);
    lcd.write(36);
    delay(100);
  }
  lcd.clear();
  lcd.setCursor(2, 0);
  lcd.print("Start Solder");
  lcd.setCursor(10, 1);
  lcd.print("v1.6");
  delay(2000);
}
int getOversampled (int sensorPin) {
  unsigned long int res = 0;
  for (int i = 0; i < 64; i++) res += sensorPin;
  return res >> 6; // divide result by 64.
}
int enc(int c, int d) {
  static boolean x, y = 0;
  boolean a = digitalRead(ENC_FOR);
  boolean b = digitalRead(ENC_REV);
  if (a == 1 && b == 0 && x == 0 && y == 0) {
    c = c + d;
    x = 1;
  }
  if (a == 1 && b == 1 && x == 1) x = 0;
  if (a == 0 && b == 1 && y == 0 && x == 0) {
    c = c - d;
    y = 1;
  }
  if (a == 1 && b == 1 && y == 1) y = 0;
  if (c <= 0) c = 0;
  return c;
}
void btn() {
  if (encBtnStat == LOW && flag_btn == 0) {
    set = set + 1;
    flag_btn = 1;
  }
  if (set >= 4) set = 0;
  delay(50);
}
boolean Blink() {
  static unsigned long lastMillis = 0;
  static boolean a;
  static int del = 100;
  if (millis() - lastMillis > del) {
    lastMillis = millis();
    a = !a;
  }
  if (a == 1) {
    del = 600;
  }
  else {
    del = 100;
  }
  return a;
}

void tonOff() {
  static unsigned long tonLastMillis = 0;
  if (millis() - tonLastMillis > 1000) {
    tonLastMillis = millis();
    tone(TON_PIN, 2000, 50);
    x++;
    y++;
    if (x >= 5 || y >= 5) {
      tone(TON_PIN, 2000, 500);
      x = 0;
      y = 0;
    }
  }
}

 

ссылка на схему: https://yadi.sk/i/4f54fjo_pZrk4

Vln
Offline
Зарегистрирован: 17.12.2015

keefa пишет:

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

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

 

keefa
Offline
Зарегистрирован: 19.06.2015

Vln пишет:

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

Таймер запускается в момент нажатия кнопки включения паяльника: 

 static unsigned long lastMillisSolder = millis(); // Инициализирую переменную lastMillisSolder
  if (digitalRead(BTN_START_SOLDER) == LOW && flag_1 == 0 && solderOverheat == 0) {
    solderEnable = true; // Включаю нагрев паяльника
    lastMillisSolder = millis(); // Запоминаем время включения
    x = 0; // не помню для чего )))
    y = 0; // не помню для чего )))
  }
  if (millis() - lastMillisSolder > 600000) solderEnable = false; // отключаю паяльник по истечении 10минут. Если нажать повторно кноп                                                                  //ку, таймер обнулится

 

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Vln пишет:
хотелось бы "прикрутить" к ней таймер на паяльник, если получится разобраться в коде, как это сделано.

А что там прикручивать? Мой исходник откройте, в главной процедуре (loop) оба таймера.
К примеру, таймер для паяльника -

 /* Off-timer for Solder, countdown with 1 min */
        unsigned long currSmillis = millis();
        if (currSmillis - prevSmillis > 60000) {
            if (Scountdown > 1) {
                Scountdown--;
                if (Scountdown == 1) {
                    Beep(20);    //Beep, if 1 minute left
                }
            } else {
                Scountdown = 1;
                prevSmillis = 0;
                SolderON = false;
                Beep(100);
            }
            prevSmillis = currSmillis;
        }

Вкратце. Каждую минуту (60000 мсек) списываем счётчик на единицу. Если в счётчике 1, т.е. осталась минута - подаём сигнал. Если досчитали до конца - вырубаем и подаём более длинный сигнал. Всё.

Vln
Offline
Зарегистрирован: 17.12.2015

keefa пишет:

Таймер запускается в момент нажатия кнопки включения паяльника: 

Спасибо за выделенный участок кода! Именно об этом и хотел попросить :)

Сброс только надо сделать на потенциометр регулировки температуры.

keefa
Offline
Зарегистрирован: 19.06.2015

Vln пишет:

Спасибо за выделенный участок кода! Именно об этом и хотел попросить :)

Сброс только надо сделать на потенциометр регулировки температуры.

Думаю что тоже не сложно:

Создаешь переменную. пишешь в нее значение резистора

Сравниваешь и при изменении обнуляешь таймер переменная lastMillisSolder. Точнее делаешь lastMillisSolder=millis();

Miamin
Offline
Зарегистрирован: 29.02.2016

Добрый вечер уважаемы OlegK.М

Могли бы вы разьяснить некоторые строчки кода.  А именно функции HA_PI(), CalctImpulseControl(), ZC(),HeaterOn().

Что за кофицеенты в функции HA_PI(), как их расчитывали? Как у вас работет поддержкатемпературы фена. 

За работу фена как я понял отвечает таймер прерывания, не могу поймать суть! Раскажите по подробней!

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Miamin пишет:
Добрый вечер

Приветствую.

Цитата:
Могли бы вы разьяснить некоторые строчки кода.  А именно функции HA_PI(), CalctImpulseControl(), ZC(),HeaterOn().

В принципе, почти всё в исходнике прокомментировано, но если не всё понятно, то вкратце:

1. HA_PI() - процедура, реализует пропорционально-интегральный закон регулирования нагревателя фена.

2. CalctImpulseControl() - процедура, воздействует на глобальную переменную, которая определяет задержку начала включения симистора от начала полупериода.

3. ZC() - процедура, привязанная к прерыванию INT1, собственно, при каждом пересечении синусоидой 0 значения, запускает таймер, формирующий задержку включения симистора.

4. HeaterOn() - процедура, формирует открывающий импульс (100 мксек) для симистора. Закрывается симистор автоматически, со спадом полупериода.

Цитата:
Что за кофицеенты в функции HA_PI(), как их расчитывали?

Коэффициенты подбирались опытным путём, сперва пропорциональный, затем интегральный, с контролем выхода на режим по графикам, на всех этапах настройки. Для этой цели предусмотрена переменная need_log, установка в 1 которой, разрешает передачу в сериал порт пары значений время-температура. Критерий настройки - минимальное перерегулирование и отсутствие автоколебаний.

Цитата:
Как у вас работет поддержкатемпературы фена.

ПИ-регулятор,  с фазоимпульсным управлением.
На основании требуемой рассчитанной мощности (HA_PI), определяем на какое время требуется задержать включение симистора (CalctImpulseControl), затем, на это время, при каждом переходе через 0 сети (отслеживаются оба полупериода) запускаем таймер с этой величиной задержки. При срабатывании таймера, кратковременно открываем симистор и останавливаем таймер.
Далее всё повторяется.

 

ЗЫ. Ну а паяльник регулируется с пом. ШИМ, управление пропорциональное.

 

 

Miamin
Offline
Зарегистрирован: 29.02.2016

Большое спасибо. В принцепе понял. Управление феном похоже на сетевой диммер, уменьшая полуволну значит уменьшам и мощность. Попытаюсь реализоваить у себя.

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Да, всё именно так.

Miamin
Offline
Зарегистрирован: 29.02.2016

Добрый день! Скажите пожайлуста почему используете данные строки? loopuint32_t currWorkMillis = millis();

    if (currWorkMillis - prevWorkMillis > 50) {
        prevWorkMillis = currWorkMillis;
        WorkWithHotAir();
        WorkWithSolder();
    }

Ведь можно и без задержки в цикле loop использовать WorkWithHotAir(); WorkWithSolder();. Почему так решили ?

Miamin
Offline
Зарегистрирован: 29.02.2016

И еще, как я понял для управленяи феном вы укорачиваете полуволну после детекции нуля. И если получится так что симистер будет открываться когда полуволна  на пике(максемальная амплитуда), как это будет влиять на нагреватильный элемент и на сеть 220 в целом. Помехи будут? Как с ними бороться?

Я собрал проект из другой темы, там используется moc3063. Этот moc не подходит для фузового управления, схему переделывать не особо хочется. Для управленяи мощностью думаю нужно испильзовать пропускание полуволн, но сколько не знаю. Вдруг у вас есть опыт управленяи мощностью на этой оптопаре, или подскажите как можно это реализовать программно. 

За рание заранее благодарю!

 

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Miamin пишет:
Помехи будут?

Обязаны быть. Где-нибудь в СВ-диапазоне на приёмнике, послушайте.

Цитата:
Как с ними бороться?

1. Забить и забыть (как я и многие)
2. Применить по входу LC фильтр

Цитата:
Для управленяи мощностью думаю нужно испильзовать пропускание полуволн, но сколько не знаю. Вдруг у вас есть опыт управленяи мощностью на этой оптопаре, или подскажите как можно это реализовать программно

Посмотрите код других паялок тут, на форуме или в инете. Как правило, реализуется простое управление -
если температура ниже заданной - вкл. симистор, если равна или больше - выключаем. Работать будет, просто болтать будет температуру сильнее, возле точки стабилизации. Фен этот (как  у меня), штука достаточно малоинерционная, ему для нагрева до температуры 500 градусов достаточно 30% подаваемой мощности. Сперва я тоже тоже сделал через оптопару с зеро-кросс, но мне не понравилось такое сильное качание температуры и я переделал на ФИ-управление.

PS. Если будете регулировать "релейно", т.е. через вкл-выкл симистора, то можно заранее "придушить" фен - отрезать ему одну полуволну диодом, второй ему хватит за глаза, возможно не так будет колбасить температуру.

m-zzz
Offline
Зарегистрирован: 30.05.2015

Господа, но ведь это же глупость... в чем проблема использования оптопары с ZC-модулем?.. Типа того, что мол мы включили. а она, зараза, не включается(ждет перехода через ноль)... Ну и что? При работе паяльника(фена) тепловая интерция запросто съест все кратковременные колебания, а задержка моментов включения(не забываем про ZC модуль), все равно будет компенсирована обратной связью.. 

m-zzz
Offline
Зарегистрирован: 30.05.2015

"штука достаточно малоинерционная," позвольте вам не поверить... для добсуждаемого здесь применения, более чем инерционная, что и хорошо...  Вы же не будете уверять , что нагрев (охлаждение) воздушного потока, происходит более, чем на 25-30 градусов в секунду? А при меньших изменениях, вполне работоспособен способ управления, по пропусканию полуволн питающего напряжения.

 

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

m-zzz пишет:
Господа, но ведь это же глупость...

Глупость - это навыдумывать самому себе неизвестно чего.
Где вы увидели, что есть "проблема"? Я всего лишь объяснил, почему применил ФИ управление - меньше болтает температуру (1-2 град.) относительно релейного регулирования (до 10 град.). И всё это конкретно - у меня, ещё раз подчёркиваю.
Я не знаю, как оно работает у вас, предоставьте график, по типу, как я выкладывал выше. Его снять очень несложно. Хотя бы в одном режиме - старт от комнатной температы до заданной (ну 400 град, к примеру) и немного в устоявшемся режиме.

Цитата:
"штука достаточно малоинерционная," позвольте вам не поверить...

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

Miamin
Offline
Зарегистрирован: 29.02.2016

Добрый день!

Переделал свою станция на для определения ZC, заметил одну особенность, мождет и у вас так, если раздница между установленной и текущей фена больше 50 градусов, то фен перестает набирать температуру и остывает.  Снижаем установленную темпертуру до раздницы <50 все работает как надо.

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Miamin пишет:
если раздница между установленной и текущей фена больше 50 градусов, то фен перестает набирать температуру и остывает.  Снижаем установленную темпертуру до раздницы <50 все работает как надо.

Не совсем понял. Разница должна быть в каком случае? Если выставленная температура больше текущей или наоборот? В первом случае это нормально - куда его греть, если текущая и так выше.

К примеру, если фен был включён, держал температуру 400 град, затем его выключили и пока он остывает установили, к примеру, 200  и включили, т.е. разница, что бы была более 50 град. Такая ситуация?

Объясните поподробнее, я у себя проверю.

 

Miamin
Offline
Зарегистрирован: 29.02.2016

Станция не прогретая по умолчанию 50г. устанавливаю медленно температуру до 200,фен набирает 200. Далее выкручиваю температуру до 400 и все фен начинает остывать. А если буду устанавливать температуру порциями ,допустим по 30 до 400, то фен набирает и работает.

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Miamin пишет:
Станция не прогретая по умолчанию 50г. устанавливаю медленно температуру до 200,фен набирает 200. Далее выкручиваю температуру до 400 и все фен начинает остывать. А если буду устанавливать температуру порциями ,допустим по 30 до 400, то фен набирает и работает.

Ну, у меня не получится сразу выкрутить до 400, ибо управляется кнопками. Сейчас, вот, попробовал - температура с датчика 23 град. - комнатная, выставил 200 градусов, включил фен.
Набрали 200 градусов. Затем утапливаю кнопку "больше" - при постоянном нажатии, заданная температура автоматом накидывается по 10 град., текущая старается за ней "успеть", т.е. растёт. В 450 упёрся, тут "подъехала" фактическая температура.
Попробовал и "порциями", с 200, короткими нажатиями (в этом случае накидывается по 5 град.) - аналогично, всё нормально. Тоже самое, всё гуд и в "минус".

Вы уверены, что дело в "применении ZC", а не в чём-то ином?
 

Miamin
Offline
Зарегистрирован: 29.02.2016

Уверен,да у меня ремпература ругелируется потонциаметром. Могу показать скеч если хотите?

Поправил так HAPower = constrain(TempPower, 0.0, 99.0); вроде работает))) но когда делаю вентилятор на максимум опчять температура падает(( 

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Покажите, может чего угляжу.

Miamin
Offline
Зарегистрирован: 29.02.2016
/*
  пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ ver. 0.5.1


*/

#include <LiquidCrystal.h>
#include <CyberLib.h>
LiquidCrystal lcd(13, 12, 11, 10, 9, 8);  // пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ 1602

int pinSolderOut = 5;  // пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ
int pinSolderPotenciom = A4;  // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ
int pinSolderTermopara = A3;  // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ
int pinSolderButton = 1;  // пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ. пїЅ пїЅпїЅпїЅпїЅ. пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ
int setSolderTemp = 0; // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ (+ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ)


int pinHotAirOut = 6;  // пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅ
int pinHotAirIn = A2;  // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ
int pinHotAirTCouple = A1;  // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ
int pinHotAirCoolerOut = 3;  // пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ ( PWM )
int pinHotAirCoolerIn = A0;  // пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ
int pinHotAirButton = 4;  // пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ.пїЅ пїЅпїЅпїЅпїЅ. пїЅпїЅпїЅпїЅ
int setHotAirTemp = 0; //пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅsetпїЅпїЅпїЅAirTempsetпїЅпїЅпїЅAirTemp
int solderTCouple=0;
int PwmSolderTCouple = 0;
int HotAirTCouple = 0;
int PwmHotAirTCouple = 0;
int displayHotAirCooler = 0;
int setHotAirCooler = 0;
volatile uint16_t ots = 9990;
float HAPower = 0.0;
#define Kp 1.0
#define Ki 0.005 //0.008 //0.0035
int integral = 0;

int TempACPSoldArray[6] = {30,70,210,330,460,560}; //50,100,200,300,400,480
int TempACPAirArray[6] = {80,149,312,476,630,760}; //50,100,200,300,400,480

boolean FAN = true;

unsigned long prevWorkMillis = 0;
unsigned long prevDisplayMillis = 0;
#define sKp 20




uint8_t char_cel[8] = {
  B00111, B00101, B00111, B00000, B00000, B00000, B00000
};

void setup()
{
  TCCR2B = TCCR2B & 0b11111000 | 0x05; // пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ 11 пїЅ 3
  TCCR0B = TCCR0B & 0b11111000 | 0x01;
  pinMode(3,INPUT_PULLUP); //Zero cross pin
 // pinMode(pinSolderOut, OUTPUT); //5
  pinMode(pinSolderButton, INPUT); //1
 // pinMode(pinHotAirOut, OUTPUT); //6
  pinMode(pinHotAirButton, INPUT); //4
  
    D5_Out; //pinSolderOut
    //D5_Low;
    D6_Out; //pinHotAir
    D6_Low;
   
  
  lcd.begin(16, 2);
  lcd.createChar(1, char_cel);  
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("SOLDER STATION");
  lcd.setCursor(0, 1);
  lcd.print("ver. 0.5.2");
  delay_ms(1000);
  
  
  attachInterrupt(1, ZC, FALLING);
 }



void loop()
{
 
  int PwnSetSolderTemp = getOversampled(pinSolderPotenciom);
  int setTempMassSolder = map(PwnSetSolderTemp, 0, 1023, 0, 46);
  PwmSolderTCouple = getOversampled(pinSolderTermopara);
  //int solderTCouple = map(PwmSolderTCouple, 50, 760, 50, 480); //760
  solderTCouple = getTemp(PwmSolderTCouple,TempACPSoldArray[0],TempACPSoldArray[1],TempACPSoldArray[2],TempACPSoldArray[3],TempACPSoldArray[4],TempACPSoldArray[5]);
  int MassTempSolder[] = {200, 205, 210, 215, 220, 225, 230, 235, 240, 245, 250, 255, 260, 265, 270, 275, 280,
                          285, 290, 295, 300, 305, 310, 315, 320, 325, 330, 335, 340, 345, 350, 355, 360, 365,
                          370, 375, 380, 385, 390, 395, 400, 405, 410, 415, 420, 425, 430};
  setSolderTemp = MassTempSolder[setTempMassSolder];


 
  int PwmSetHotAirTemp = getOversampled(pinHotAirIn);
  int setTempMassAir = map(PwmSetHotAirTemp, 0, 1023, 0, 81);
  PwmHotAirTCouple = getOversampled(pinHotAirTCouple);
  HotAirTCouple = getTemp(PwmHotAirTCouple,TempACPAirArray[0],TempACPAirArray[1],TempACPAirArray[2],TempACPAirArray[3],TempACPAirArray[4],TempACPAirArray[5]);
  int MassTempAir[] = {50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145,
                       150, 155, 160, 165, 170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230,
                       235, 240, 245, 250, 255, 260, 265, 270, 275, 280, 285, 290, 295, 300, 305, 310, 315,
                       320, 325, 330, 335, 340, 345, 350, 355, 360, 365, 370, 375, 380, 385, 390, 395, 400,
                       405, 410, 415, 420, 425, 430, 435, 440, 445, 450, 455};
  setHotAirTemp = MassTempAir[setTempMassAir];
  setHotAirCooler = map(getOversampled(pinHotAirCoolerIn), 0, 1023, 130, 255);
  displayHotAirCooler = map(getOversampled(pinHotAirCoolerIn), 0, 1023, 0, 99);


  if (solderTCouple > 460) { //480
    setSolderTemp = 0;
  }
  if (HotAirTCouple > 465) { //460
    setHotAirTemp = 0;
  }



 //Air(setHotAirTemp,HotAirTCouple);
 //Solder(setSolderTemp,solderTCouple);
// HA_PI();
 //AirCoole();
 //Solder(setSolderTemp,solderTCouple);
 

unsigned long currWorkMillis = millis();
    if (currWorkMillis - prevWorkMillis > 50) {
        prevWorkMillis = currWorkMillis;
        Solder(setSolderTemp,solderTCouple);
		    HA_PI();
        AirCoole();
    }


 unsigned long currDisplayMillis = millis();
    if (currDisplayMillis - prevDisplayMillis > 100)
    {
        prevDisplayMillis = currDisplayMillis;
        DispU();
    }
    
 
}

int getOversampled(int sensorPin) {      // пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ
  unsigned long int res = 0;
 for (int i = 0; i < 64; i++) res += analogRead(sensorPin);
  return res >> 6; // divide result by 64.
}

//uint16_t getOversampled(uint16_t ADC_value) {
//	unsigned long int result = 0;
//	for (byte z = 0; z < 64; z++) result += ADC_value;
//	return result >> 6;
//} 

int getTemp( int PWM, int getx, int gety, int getcc, int getz, int gete,int geteb){
  if (PWM < getx) {return map(PWM,0,getx,0,50);}
  if (PWM >= getx && PWM <gety) {return map(PWM,getx,gety,50,100);}
  if (PWM >= gety && PWM <getcc) {return map(PWM,gety,getcc,100,200);}
  if (PWM >= getcc && PWM <getz) {return map(PWM,getcc,getz,200,300);}
  if (PWM >= getz && PWM <gete) {return map(PWM,getz,gete,300,400);}
  if (PWM >= gete) {return map(PWM,gete,geteb,400,480);}
}


void Solder(int setTemp,int TemCouple) {
  
if ( digitalRead(pinSolderButton) == HIGH ) 
	  {
		int err = setTemp - TemCouple;
		int TempPower = sKp * err;
		uint16_t SPower = constrain(TempPower, 0, 255);
		analogWrite(pinSolderOut, SPower);
      }
	else {analogWrite(pinSolderOut, 0);}
}

void  Air(int setAirTemp,int HotAirTemp )
{
 if (setAirTemp >= HotAirTemp && digitalRead(pinHotAirButton) == HIGH)
  {
    D6_High;
	//digitalWrite(pinHotAirOut, HIGH);
    delay_ms(120);
    //digitalWrite(pinHotAirOut, LOW);
	D6_Low;
  }
  else {
    //digitalWrite(pinHotAirOut, LOW);
	D6_Low;
  }
}




 
void DispU() 
 {
	  lcd.clear();
	  lcd.print("S:");
	  lcd.setCursor(2, 0);
	  if (digitalRead(pinSolderButton) == HIGH)
	  {
  		if (solderTCouple < 460)
    		{
    		  lcd.print(setSolderTemp);
    		  lcd.setCursor(7, 0);
    		  lcd.print(solderTCouple);
    		  lcd.setCursor(11, 0);
    		  lcd.print(PwmSolderTCouple);
    		}
  		else
    		{
    		  lcd.print("Er");
    		  lcd.setCursor(10, 0);
    		  lcd.print(PwmSolderTCouple);
    		  setSolderTemp = 0;
    		}
	  }
	  else
  	  {
    		lcd.print("Off");
    		lcd.setCursor(6, 0);
    		lcd.print(solderTCouple);
    		lcd.print("\1");
    		setSolderTemp = 0;
  	  }
//ФЕН
		  lcd.setCursor(0, 1);
		  lcd.print("A:");
		  lcd.setCursor(2, 1);
		  if (digitalRead(pinHotAirButton) == HIGH)
		  {
				if (HotAirTCouple < 465)
					{
					  lcd.print(setHotAirTemp);
					  lcd.setCursor(6, 1);
					  lcd.print(HotAirTCouple);
					  lcd.setCursor(10, 1);
					  lcd.print(PwmHotAirTCouple);
					  lcd.setCursor(14, 1);
					  lcd.print(displayHotAirCooler);
					  
					}
				else 
					 {
						  lcd.print("Er");
						  lcd.setCursor(7, 1);
						  lcd.print(PwmHotAirTCouple);
						  setHotAirTemp = 0;
					  }
		  }
		  else
		  {
				lcd.print("Off");
				lcd.setCursor(6, 1);
				lcd.print(HotAirTCouple);
				lcd.print("\1");
				// пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ
				lcd.setCursor(14, 1);
				lcd.print(displayHotAirCooler);
				setHotAirTemp = 0;
		   }
 
 }
 
 void AirCoole()
 {
	 if (HotAirTCouple > 70 && digitalRead(pinHotAirButton) == LOW && FAN) 
	  { 
		analogWrite(pinHotAirCoolerOut, 255);
	  } 
	  else if (HotAirTCouple <= 70 && digitalRead(pinHotAirButton) == LOW && FAN) 
			{
			  analogWrite(pinHotAirCoolerOut, 0);
			  FAN = false;
			}
	  else if (HotAirTCouple < 90 && digitalRead(pinHotAirButton) == LOW && FAN == false)
		  {
			analogWrite(pinHotAirCoolerOut, 0);
		  } 
	  else if (HotAirTCouple > 90 && digitalRead(pinHotAirButton) == LOW && FAN == false)
			{
			   FAN  = true;
			 analogWrite(pinHotAirCoolerOut, 255);         
			}
	  else    
  	  {
      		analogWrite(pinHotAirCoolerOut, setHotAirCooler);
      		FAN = true;
  		}
 
 }

 void ZC() {
    StartTimer1(HeaterOn, ots);
    RestartTimer1();
}
 
void HeaterOn() {
    if (digitalRead(pinHotAirButton) == HIGH) {
        if (HAPower > 0.0) {
            //digitalWrite(pinHotAirOut, HIGH);
            D6_High;
			      delay_us(100);
            //digitalWrite(pinHotAirOut, LOW);
			     D6_Low;
        } else {
            //digitalWrite(pinHotAirOut, LOW);
			    D6_Low;
        }
    }
    StopTimer1();
} 

    
void HA_PI() {
    int err = setHotAirTemp - HotAirTCouple;
    float TempPower = ((Kp * err) + (Ki * integral));
	if (TempPower < 100.0 && TempPower > 0.0) integral += err;
    HAPower = constrain(TempPower, 0.0, 99.0);
    CalctImpulseControl();
}

/* Calculate delay for triac */
void CalctImpulseControl() {
    ots = (uint16_t)(acos(HAPower / 50.0 - 1.0 ) * 9900.0 / pi);
}

 

Miamin
Offline
Зарегистрирован: 29.02.2016

и еще как должна менятся температура если увеличевать Ki ?  быстро будет набираить или медлено температуру?

Miamin
Offline
Зарегистрирован: 29.02.2016

и еще как должна менятся температура если увеличевать Ki ?  быстро будет набираить или медлено температуру?

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Попробуйе скидывать в терминал значение setHotAirTemp, лучше из HA_PI и посмотрите, что получается если выкрутить резко.

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Miamin пишет:
если увеличевать Ki ?  быстро будет набираить или медлено температуру?

Тут не в скорости дело, наоборот, интегральная компонента "притормаживает" рост, что бы не было "вылета" температуры.

Miamin
Offline
Зарегистрирован: 29.02.2016

У меня в дип корпусе мега, платы ардуины нет, прошиваю Minipro TL866, попробую на дисплей вывисти ну это уже заврта