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

gogirystaveli
Offline
Зарегистрирован: 12.11.2017

Записано от банка ноутбука там на выходе 23.6вольта

gogirystaveli
Offline
Зарегистрирован: 12.11.2017

Запитано от бп ноутбука 23.5 вольта. Поставил на выход с бп керамику 0.1 немного меньше плавает!

valentinjon
Offline
Зарегистрирован: 29.03.2018

подскажите,пожалуйста. как быть если lcd1602 без I2P. Придется изменять прошивку?

valentinjon
Offline
Зарегистрирован: 29.03.2018

подскажите,пожалуйста. как быть если lcd1602 без I2P. Придется изменять прошивку?

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

valentinjon пишет:
как быть если lcd1602 без I2P.

А I2C "переходник" надыбать - проблема?

Цитата:
Придется изменять прошивку?

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

gogirystaveli
Offline
Зарегистрирован: 12.11.2017

Дросселя на платах 100 мгн должны быть?

valentinjon
Offline
Зарегистрирован: 29.03.2018

надыбать не проблема. просто заказал с али без i2с. а как быть если паяльник с термопарой? какие измения в схеме тогда?

alex1978
alex1978 аватар
Offline
Зарегистрирован: 09.09.2017

Если подойдут мои платы, то пожалуйста. В архиве есть печатки и под термопару и под термистор. https://yadi.sk/d/RkKMd_xZ3PhBF7 Так же платы под термопару есть в проекте от Русл@на. Ссылка в сообщении 2 данной темы.

gogirystaveli
Offline
Зарегистрирован: 12.11.2017

Подскажите сначала настраивать нужно а потом смотреть график!!! ?????

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

А нафига нужен график ненастроенной станции? Оно и работать-то не будет, улетит в защиту...

nik 354
Offline
Зарегистрирован: 07.03.2018

добрый вечер Олег вы не подскажите реле должн

о быть как по схеме или с разомкнутыми контактами

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

Реле д. быть с НР (нормально разомкнутыми) контактами.

nik 354
Offline
Зарегистрирован: 07.03.2018

спасибо Олег уже разобрался нашел в коменнтариях

gogirystaveli
Offline
Зарегистрирован: 12.11.2017

sKp 10 температура паяльника на графике стабильно держит заданной ! Включаю канал фена набора температуры нет! ПОМОГИТЕ
Залил прошивку Федора работает! Что нужно изменить Вашей прошивке 1.6?

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

Открываете вариант Фёдора и смотрите, какие пины он поменял -

/*
my corrections
|---------------|------|------|
| param         | orig |  my  |
|---------------|------|------|
| sw_S          |  9   |  11  |
| ZC pin        |  3   |  2   |
| pinHotAir     |  8   |  3   |
|---------------|------|------|
*/
gogirystaveli
Offline
Зарегистрирован: 12.11.2017

.

Surikat
Offline
Зарегистрирован: 13.07.2016

SERG_K пишет:

 

Спасибо Олегу и Руслану за проект. Собрал станцию на прошивке Руслана v 2.2  немного подправив код и плату под себя. Заменил регулирование на ПИД ,  сделал расчет отставания открывающего импульса по прервванию Zero cross INT1 . Рассчитывается для каждой полуволны.  Убрал морзянку из паяльника. С ПИД фен держит температуру +-2 градуса во всем диапазоне температур. Ну и несколько фото. Еще раз спасибо за проделанную работу.

Добрый день! понравилась ваш вариант ПП, можно архив проекта загрузит ?

Alsi2010
Offline
Зарегистрирован: 25.09.2017

Добрый день OlegK. У меня есть паяльная станция YOUYUE 8586 с алиэкспресс. Станция имеет только индикацию температуры фена, все остальное контролируется только по шкале потенциометров, про защиту фена и паяльника не разбирался, полагаю что она отсутствует совсем, если судить по стоимости самой станции и того, что перед первым включением пришлость заняться креплением трансформатора и прочими мелкими недочетами. Задумался о сборке другой станции, более компактной и с контролем всех режимов на дисплее. Лучше Вашего проекта на просторах интернета, на мой взгляд, не нашел. По Вашим схемам плат разработал свою печатную плату (одноплатный вариант) под размеры корпуса CD-Rom, осталось развести рэле, их пока не купил.  Есть дисплеи 16х2, да и 4-х строчный не вместить в столь маленький корпус.  Читал (где бегло, где более внимательно) данный форум и так до конца и не понял по теме дисплея. Стоит ли использовать 2-х строчный, какие "подводные камни" меня ожидают? Если можно, Ваш совет на эту тему...

 

Alsi2010
Offline
Зарегистрирован: 25.09.2017

Surikat пишет:

SERG_K пишет:

 

Спасибо Олегу и Руслану за проект. Собрал станцию на прошивке Руслана v 2.2  немного подправив код и плату под себя. Заменил регулирование на ПИД ,  сделал расчет отставания открывающего импульса по прервванию Zero cross INT1 . Рассчитывается для каждой полуволны.  Убрал морзянку из паяльника. С ПИД фен держит температуру +-2 градуса во всем диапазоне температур. Ну и несколько фото. Еще раз спасибо за проделанную работу.

Добрый день! понравилась ваш вариант ПП, можно архив проекта загрузит ?

Добрый день!  Хорошо получилось. А можно прошивку загрузить?

Alsi2010
Offline
Зарегистрирован: 25.09.2017

Surikat пишет:

SERG_K пишет:

 

Спасибо Олегу и Руслану за проект. Собрал станцию на прошивке Руслана v 2.2  немного подправив код и плату под себя. Заменил регулирование на ПИД ,  сделал расчет отставания открывающего импульса по прервванию Zero cross INT1 . Рассчитывается для каждой полуволны.  Убрал морзянку из паяльника. С ПИД фен держит температуру +-2 градуса во всем диапазоне температур. Ну и несколько фото. Еще раз спасибо за проделанную работу.

Добрый день! понравилась ваш вариант ПП, можно архив проекта загрузит ?

Добрый день!  Хорошо получилось. А можно прошивку загрузить?

Alsi2010
Offline
Зарегистрирован: 25.09.2017

Surikat пишет:

SERG_K пишет:

 

Спасибо Олегу и Руслану за проект. Собрал станцию на прошивке Руслана v 2.2  немного подправив код и плату под себя. Заменил регулирование на ПИД ,  сделал расчет отставания открывающего импульса по прервванию Zero cross INT1 . Рассчитывается для каждой полуволны.  Убрал морзянку из паяльника. С ПИД фен держит температуру +-2 градуса во всем диапазоне температур. Ну и несколько фото. Еще раз спасибо за проделанную работу.

Добрый день! понравилась ваш вариант ПП, можно архив проекта загрузит ?

Добрый день!  Хорошо получилось. А можно прошивку загрузить?

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

Alsi2010 пишет:
Стоит ли использовать 2-х строчный, какие "подводные камни" меня ожидают? Если можно, Ваш совет на эту тему...

Какой там совет...
4 строки, ПМСМ, лучше в данном случае, чем 2, но и двухстрочник можно применить - всего лишь раскомментировать в коде дефайн  в этой строке -
#define LCD_1602

Jevega
Jevega аватар
Offline
Зарегистрирован: 27.12.2016

Здравия, честнОй компании! Весьма признателен автору ПС.
К фену вопросы отсутствуют - работает замечательно.
Паяльник у меня с термопарой, но нагреватель в металле. Потому, наверное и греется намного медленнее, чем описано в теме. К тому же, при "set"=350, "act"=348-354 на жале получилась температура не более 272. Вот и думаю - может лучше заменить на керамику?
И операционники поставил OP07 - лучшее из того, что доступно у нас сейчас.
Паяльник же, часто отключается, показывая ошибку !6. При замене операционника, "захват" режима прошёл только один раз.
В общем, танцы с бубном пока ещё продолжаются.

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

Jevega пишет:
но нагреватель в металле.

Не попадалось такого варианта, тут не могу сказать ничего.

Цитата:
при "set"=350, "act"=348-354 на жале получилась температура не более 272.

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

Цитата:
Вот и думаю - может лучше заменить на керамику?

Это будет хороший вариант, если потянет БП - керамика при старте большой ток потребляет. Только усилитель придётся переделать - у керамического нагревателя в кач-ве датчика применён терморезистор.

Цитата:
Паяльник же, часто отключается, показывая ошибку !6. При замене операционника, "захват" режима прошёл только один раз.

Тут надо разбираться, хорошо бы график снять.
Можно попробовать уменьшить коэффициент sKp до 10-30.
Ещё попробовать добавить параллельно цепи ОС ОУ конденсатор 0,01...0,1 мкф.
Можно увеличить немного зону "захвата" delta и уменьшить количество проверок этой дельты до взведения флага.
Можно, наконец, вообще отключить доп. защиты канала паяльника, закомментив дефайн
#define S_ADV_PROT_ON

alex1978
alex1978 аватар
Offline
Зарегистрирован: 09.09.2017

Видел такие нагреватели. Не стал заказывать именно из-за того, что подумал лишняя металлическая оболочка ни к чему хорошему не приведёт. Мне кажется эти нагреватели вообще не для паяльников.

Alex-59
Offline
Зарегистрирован: 14.03.2018

Что-то не работает ZC. Монтаж проверил.

1.Какое напряжение после моста- у меня около 7 в.

2. Конденсатор с эмитера на плюс в схеме 1 мкф - это критично? Куда копать?

MVS
Offline
Зарегистрирован: 19.04.2018

Добрый вечер! Давно читаю этот форум. И вот, собрал наконец я свою паяльную станцию. Спасибо, Вам, ОлегК  огромное, за Ваши труды и терпение. Действительно, что не говори, станция получилась отличная. 

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

Alex-59 пишет:
Что-то не работает ZC.

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

Цитата:
Какое напряжение после моста- у меня около 7 в.

Многовато почему то - 3..4В, там примерно д.быть. Батарейка в мультиметре свежая? ))
Лучше посмотреть осциллографом, после оптрона, со стороны МК - должны быть короткие импульсы частотой 100гц и амплитудой около 5В.

Цитата:
1 мкф - это критично?

Нормально. До 10 мкф, в принципе, можно.

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

MVS пишет:
И вот, собрал наконец я свою паяльную станцию.

Красотища! ;)

Alex-59
Offline
Зарегистрирован: 14.03.2018

ZC заработал (проблема в электролите). Но! Фен влючается и подает теплый воздух, и здесь наступает НОНСЕНС!!!!!!!!!!!!! - температура на индикаторе начинает падать (доходит до 10 и включается защита, ошибка 2). Это фен дохлый или настройки?

Jevega
Jevega аватар
Offline
Зарегистрирован: 27.12.2016

может, стоит перевернуть провода термодатчика? Ведь термопара полярна.

Alex-59
Offline
Зарегистрирован: 14.03.2018

Да, помогло (большое спасибо) . Тогда выходит, что на плюс термопары подключен геркон.

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

Так китайцы тоже люди, напутали при сборке. Нужно внутри фена перекинуть полярность ТП.

MVS
Offline
Зарегистрирован: 19.04.2018

OlegK. Как уже писал ранее, собрал Вашу, не побоюсь этого слова, паяльную станцию. Не нарадуюсь. Спасибо Вам за ваши труды. На работе Lukey рядом не стоит. Вопрос: При включении фена на низкие температуры 100-200 гр. при низких оборотах, срабатывает защита №3, превышение температуры на 20гр. Не успевает отрабатывать PI регулятор. Коэффициентами поиграл, но результатов не дало тут не успевает и регулятор и вентилятор. Повышать уставку защиты не хочется, а Т.к. в программировании не особо)), можно ли ввести таймер на срабатывание этой защиты, буквально около секунды при запуске. Заранее спасибо.

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

MVS, версия скетча какая у Вас?
При более высокой температуре нормально или только внизу такой эффект?
Какие коэффициенты Kp и Ki?
На какой насадке (диаметр) и при каком потоке воздуха в защиту уходит?

Если только внизу защита срабатывает, то попробовать можно в процедуре HA_PI(), в ф-ии map() сместить нижнюю границу
ещё пониже.
В строке

float max_power = map(SetHotAirT, min_hotair_temp, max_hotair_temp, 10.0, 90.0);

ограничивается максимально "вдуваемое" значение мощности, взависимости от заданной, в границах
 (в данном случае) от 10 до 90. Можно нижнюю величину "придавить" до 2-5.
Возможно перерегулирование уменьшится.

MVS
Offline
Зарегистрирован: 19.04.2018

OlegK. Версия скетча 1.6.1. Ошибка вылазит именно при температуре 100-150 гр. без насадки, при оборотах кулера 30-70%, на 80-100% регулятор успевает отработать. Kp=1.0, Ki=0.003. 

float max_power . Придавил нижнюю границу до "2.0" не помогло((. 

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

MVS пишет:
Версия скетча 1.6.1.

Попробуйте залить вариант под спойлером

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                    Soldering Station v 1.6.3              */
/*                        coded by OlegK                     */
/* arduino.ru/forumy/proekty/ocherednaya-payalnaya-stantsiya */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

//
#include <EEPROM.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Bounce2.h>

/* it's fuckin' magic! */
#if 1
__asm volatile ("nop");
#endif

/* Options */

/* if you need to create themperature diagramm then uncomment it */
//#define NEED_GRAPH

/* if used not rail-to-rail OPA, then uncomment it */
//#define LM358

/* if used passive busser, then uncomment it */
//#define PASSIVE_BUZZER

/* if you want deactivate additional protection, then COMMENT it */
#define HA_ADV_PROT_ON
#define S_ADV_PROT_ON

/* if used LCD 1602, then uncomment it */
//#define LCD_1602

/* Soldering iron - if you want to remove the digit jumps, then uncomment it */
//#define SOLDER_DIGIT_JUMPS_REMOVE

/* Hot Air - if you want to remove the digit jumps, then uncomment it */
//#define HOTAIR_DIGIT_JUMPS_REMOVE

/* if you want soldering iron soft start, then uncomment it */
//#define SOLDER_SOFT_START

/* if you want to activate soldering iron off-timer only on stand, then uncomment it */
#define SOLDER_TIMER_ON_STAND

/* End options */

//macroses from Cyberlib
//****************INPUT PINS*************
#define D0_In DDRD &=B11111110
#define D1_In DDRD &=B11111101
#define D2_In DDRD &=B11111011
#define D3_In DDRD &=B11110111
#define D4_In DDRD &=B11101111
#define D5_In DDRD &=B11011111
#define D6_In DDRD &=B10111111
#define D7_In DDRD &=B01111111

#define D8_In DDRB &= B11111110
#define D9_In DDRB &= B11111101
#define D10_In DDRB &=B11111011
#define D11_In DDRB &=B11110111
#define D12_In DDRB &=B11101111
#define D13_In DDRB &=B11011111

#define D14_In DDRC &=B11111110
#define D15_In DDRC &=B11111101
#define D16_In DDRC &=B11111011
#define D17_In DDRC &=B11110111
#define D18_In DDRC &=B11101111
#define D19_In DDRC &=B11011111

//***************Output Pins*************
#define D0_Out DDRD |=B00000001
#define D1_Out DDRD |=B00000010
#define D2_Out DDRD |=B00000100
#define D3_Out DDRD |=B00001000
#define D4_Out DDRD |=B00010000
#define D5_Out DDRD |=B00100000
#define D6_Out DDRD |=B01000000
#define D7_Out DDRD |=B10000000

#define D8_Out DDRB |= B00000001
#define D9_Out DDRB |= B00000010
#define D10_Out DDRB |=B00000100
#define D11_Out DDRB |=B10001000
#define D12_Out DDRB |=B00010000
#define D13_Out DDRB |=B00100000

#define D14_Out DDRC |=B00000001
#define D15_Out DDRC |=B00000010
#define D16_Out DDRC |=B00000100
#define D17_Out DDRC |=B00001000
#define D18_Out DDRC |=B00010000
#define D19_Out DDRC |=B00100000

//***************Status High Pins*************
#define D0_High PORTD |=B00000001
#define D1_High PORTD |=B00000010
#define D2_High PORTD |=B00000100
#define D3_High PORTD |=B00001000
#define D4_High PORTD |=B00010000
#define D5_High PORTD |=B00100000
#define D6_High PORTD |=B01000000
#define D7_High PORTD |=B10000000

#define D8_High PORTB |=B00000001
#define D9_High PORTB |=B00000010
#define D10_High PORTB|=B00000100
#define D11_High PORTB|=B00001000
#define D12_High PORTB|=B00010000
#define D13_High PORTB|=B00100000

#define D14_High PORTC |=B00000001
#define D15_High PORTC |=B00000010
#define D16_High PORTC |=B00000100
#define D17_High PORTC |=B00001000
#define D18_High PORTC |=B00010000
#define D19_High PORTC |=B00100000

//***************Status Low Pins*************
#define D0_Low PORTD &= B11111110
#define D1_Low PORTD &= B11111101
#define D2_Low PORTD &= B11111011
#define D3_Low PORTD &= B11110111
#define D4_Low PORTD &= B11101111
#define D5_Low PORTD &= B11011111
#define D6_Low PORTD &= B10111111
#define D7_Low PORTD &= B01111111

#define D8_Low PORTB &= B11111110
#define D9_Low PORTB &= B11111101
#define D10_Low PORTB &=B11111011
#define D11_Low PORTB &=B11110111
#define D12_Low PORTB &=B11101111
#define D13_Low PORTB &=B11011111

#define D14_Low PORTC &= B11111110
#define D15_Low PORTC &= B11111101
#define D16_Low PORTC &= B11111011
#define D17_Low PORTC &= B11110111
#define D18_Low PORTC &= B11101111
#define D19_Low PORTC &= B11011111

//**************Invert Status Pins*************
#define D0_Inv PORTD ^=B00000001
#define D1_Inv PORTD ^=B00000010
#define D2_Inv PORTD ^=B00000100
#define D3_Inv PORTD ^=B00001000
#define D4_Inv PORTD ^=B00010000
#define D5_Inv PORTD ^=B00100000
#define D6_Inv PORTD ^=B01000000
#define D7_Inv PORTD ^=B10000000

#define D8_Inv PORTB ^=B00000001
#define D9_Inv PORTB ^=B00000010
#define D10_Inv PORTB^=B00000100
#define D11_Inv PORTB^=B00001000
#define D12_Inv PORTB^=B00010000
#define D13_Inv PORTB^=B00100000

#define D14_Inv PORTC ^=B00000001
#define D15_Inv PORTC ^=B00000010
#define D16_Inv PORTC ^=B00000100
#define D17_Inv PORTC ^=B00001000
#define D18_Inv PORTC ^=B00010000
#define D19_Inv PORTC ^=B00100000

//**************READ Status Pins*************
#define D0_Read (PIND & B00000001)
#define D1_Read ((PIND & B00000010)>>1)
#define D2_Read ((PIND & B00000100)>>2)
#define D3_Read ((PIND & B00001000)>>3)
#define D4_Read ((PIND & B00010000)>>4)
#define D5_Read ((PIND & B00100000)>>5)
#define D6_Read ((PIND & B01000000)>>6)
#define D7_Read ((PIND & B10000000)>>7)

#define D8_Read (PINB & B00000001)
#define D9_Read ((PINB & B00000010)>>1)
#define D10_Read ((PINB & B00000100)>>2)
#define D11_Read ((PINB & B00001000)>>3)
#define D12_Read ((PINB & B00010000)>>4)
#define D13_Read ((PINB & B00100000)>>5)

#define D14_Read (PINC & B00000001)
#define D15_Read ((PINC & B00000010)>>1)
#define D16_Read ((PINC & B00000100)>>2)
#define D17_Read ((PINC & B00001000)>>3)
#define D18_Read ((PINC & B00010000)>>4)
#define D19_Read ((PINC & B00100000)>>5)

//**************Analog READ*******************
#define A0_Read (AnRead(B01000000))
#define A1_Read (AnRead(B01000001))
#define A2_Read (AnRead(B01000010))
#define A3_Read (AnRead(B01000011))
#define A4_Read (AnRead(B01000100))
#define A5_Read (AnRead(B01000101))
#define A6_Read (AnRead(B01000110))
#define A7_Read (AnRead(B01000111))

#define FIRMWARE_VERSION "1.6.3"

#ifdef LCD_1602
LiquidCrystal_I2C lcd(0x27, 16, 2);
#else
LiquidCrystal_I2C lcd(0x27, 20, 4);
#endif

/* Degree symbol */
uint8_t degree[8] = {
    B01100,
    B10010,
    B10010,
    B01100,
    B00000,
    B00000,
    B00000,
    B00000
};

/* Arrow symbol */
uint8_t arrow[8] =  {
    B00000,
    B00100,
    B00010,
    B11111,
    B00010,
    B00100,
    B00000,
    B00000
};

/* mode selector */
#define  modeSolder 1
#define  modeHotAir 2
#define  modeFanPWM 3

boolean need_S_countdown = false;
byte selected_Mode = modeSolder;
byte HA_countdown = 1;
byte S_countdown = 1;
uint16_t HA_sleeptime = 10;
uint16_t S_sleeptime = 10;
uint16_t Graph_count = 0;
uint32_t UPbuttonPressTime = 0;
uint32_t DWNbuttonPressTime = 0;
uint32_t SONbuttonPressTime = 0;
uint32_t HAONbuttonPressTime = 0;

boolean UPbuttonState, DWNbuttonState, SONbuttonState, HAONbuttonState;
byte Count;
uint16_t Duration, Interval;

char bspace[ ] = "    ";

#define pinBuzzer 12
#define pinFanPwm 6
#define pinSolderPwm 5
#define pinZeroCross 3

#define min_solder_temp 100
#define max_solder_temp 400
#define min_hotair_temp 20.0
#define max_hotair_temp 450.0
#define min_rpm 30
#define max_rpm 100
#define default_temp 280
#define default_rpm 50

/* Buttons */
#define sw_HA 10
#define sw_S 9
#define bt_SON 13
#define bt_HAON 14
#define bt_Sel 15
#define bt_Up 16
#define bt_Dwn 17

/* Bounce killers */
Bounce swHotAir = Bounce();
Bounce swSolder = Bounce();
Bounce SolderOnButton = Bounce();
Bounce HotAirOnButton = Bounce();
Bounce SelButton = Bounce();
Bounce UpButton = Bounce();
Bounce DwnButton = Bounce();

/* Hot Air */

/* states */
#define st_stop 0
#define st_work 1
#define st_pause 2
#define st_protection 3

byte hotair_state = st_stop;

volatile uint16_t ots = 9950;
volatile float HAPower = 0.0;
int GetHotAirT = 0;
int SetHotAirT = 100;
byte SetHotAirRPM = 100;
boolean HA_temp_stable = false;
boolean need_Cooling = true;

byte ha_error = 0;
boolean HA_prot_beep = false;
boolean ha_f1 = false;
boolean ha_f2 = false;
uint32_t prevHAcontrol;

/* HA PI regulator */
const float Kp = 1.0;
const float Ki = 0.005;
int integral = 0;

/* Soldering iron */
int GetSolderT = 0;
int SetSolderT = 100;

boolean S_temp_stable = false;
boolean SolderON = false;
boolean SolderProtect = false;
int SPower = 0;

byte s_error = 0;
uint32_t prevScontrol;
boolean S_prot_beep = false;
boolean s_f1 = false;
boolean s_f2 = false;

/* Solder P regulator */
const int sKp = 50; //100

uint16_t last_HotAirT, last_SolderT;
byte last_RPM;


/********************************************* MAIN PROCEDURES *********************************************/

void setup() {
	
    pinMode(pinZeroCross, INPUT_PULLUP);
    D5_Out; //pinSolder
    D5_Low;
    D4_Out; //pinSolderProt
    D4_Low;
    D7_Out; //pinHotAirProt
    D7_Low;
    D8_Out; //pinHotAir
    D8_Low;
    D12_Out; //pinBuzzer
    D12_Low;
    ButtonsSetup();

#ifdef NEED_GRAPH
    Serial.begin(9600);
#endif

    lcd.begin();
    lcd.backlight();
    lcd.createChar(0, degree);
    lcd.createChar(1, arrow);
    Splash();
    MemRead();
    delay_ms(2000);
    initDisplay();

    attachInterrupt(1, ZC, FALLING);
}

void loop() {
    ScanButtons();
	beep_proc();
	WorkWithHotAir();
	WorkWithSolder();

    /* Off-timer for HotAir, countdown with 1 min */
    static uint32_t prevHAmillis = millis();
    if (hotair_state == st_pause) {
        if (millis() - prevHAmillis > 60000) {
            prevHAmillis = millis();
            if (HA_countdown > 1) {
                HA_countdown--;
                if (HA_countdown == 1) {   
					beepOnce(100); //Beep, if 1 minute left
                }
            } else {
                hotair_state = st_stop;
				beepOnce(200);
            }
        }
    } else {
        prevHAmillis = millis();
    }

    /* Off-timer for Solder, countdown with 1 min */
    static uint32_t prevSmillis = millis();
    if (need_S_countdown) {
        if (millis() - prevSmillis > 60000) {
            if (S_countdown > 1) {
                S_countdown--;
                if (S_countdown == 1) {    
					beepOnce(100); //Beep, if 1 minute left
                }
            } else {
                MemSolder();
                need_S_countdown = false;
                SolderON = false;
				beepOnce(200);
            }
            prevSmillis = millis();
        }
    } else {
        prevSmillis = millis();
    }

    /* Update LCD with 500ms interval */
    static uint32_t prevDisplayMillis = millis();
    static boolean scr_blink = false;
    if (millis() - prevDisplayMillis > 500) {
        prevDisplayMillis = millis();
        DisplayUpdate(scr_blink);
        scr_blink = ! scr_blink;

        /* Send data to Serial port */
#ifdef NEED_GRAPH
        if (SolderON || hotair_state == st_work) {
            Graph_count++;
            //Serial.print(Graph_count);
            //Serial.print(";");
        } else {
            Graph_count = 0;
        }
        if (SolderON && hotair_state != st_work) {
            Serial.println(GetSolderT);
        } else if (!SolderON && hotair_state == st_work) {
            Serial.println(GetHotAirT);
        }
#endif
    }
}

/* HotAir working procedure */
void WorkWithHotAir() {

    /* Read the thermocouple value */
#ifdef LM358
    GetHotAirT = getOversampled_HA();
#else
    GetHotAirT = getOversampled_HA() >> 1;
#endif

    switch (hotair_state) {
    case st_stop: {
        HotAirOff();
        Cooling();
        break;
    }

    case st_work: {
        /* Set the cooler rpm (convert from 30-100% to 80-255 PWM) */
        analogWrite(pinFanPwm, map(SetHotAirRPM, min_rpm, max_rpm, 80, 255));

        ha_error = HADoProtect();

        /* Turn ON protection relay */
        if (ha_error == 0) D7_High;

        /* Themperature PI regulator */
        HA_PI();

        /* If themperature was stable for 200 times (+/-3 degrees), then signalize about it */
        int delta =  GetDelta(SetHotAirT, GetHotAirT);
        static byte HAgood;
        if (!HA_temp_stable) {
            if (delta < 4) {
                HAgood++;
                if (HAgood > 200) {
					beepTwice();
                    HAgood = 0;
                    HA_temp_stable = true;
                }
            } else {
                HAgood = 0;
            }
        } else {
            if (delta > 5) {
                HA_temp_stable = false;
            }
        }
        break;
    }

    case st_pause: {
        HAPower = 0.0;
        HA_temp_stable = false;
        CalctImpulseControl();
        Cooling();
        ha_error = HADoProtect();
        break;
    }

    case st_protection: {
        need_Cooling = true;
        break;
    }

    } //switch (state)
}

/* Solder working procedure */
void WorkWithSolder() {

#ifdef LM358
    GetSolderT = getOversampled_S();
#else
    GetSolderT = getOversampled_S() >> 1;
#endif

    if ( SolderON ) {
        s_error = SDoProtect();

        /* Turn ON relay */
        if (s_error == 0) D4_High;

        /* themperature P regulator */
        S_P();

        /* If themperature was stable for 200 times loop (+/- 3 degrees) then signalize about it */
        uint16_t delta =  GetDelta(SetSolderT, GetSolderT);
        static byte Sgood;
        if (!S_temp_stable) {
            if (delta < 4) {
                Sgood++;
                if (Sgood > 200) {
					beepTwice();
                    Sgood = 0;
                    S_temp_stable = true;
                }
            } else {
                Sgood = 0;
            }
        } else {
            if (delta > 5) {
                S_temp_stable = false;
            }
        }
    } else {
        SolderOff();
        need_S_countdown = false;
        S_countdown = 1;
    }
}

/***************************************** END OF MAIN PROCEDURES ******************************************/



/****************************************** PROTECTION & ON-OFF ********************************************/

/* HotAir protection */
byte HADoProtect() {

    /* ------------------------------------------------------------------------------------------------------- */

    /* Crytical protection: high overheat or thermocouple value is not valid or wire break */
    if (GetHotAirT > max_hotair_temp + 20) {
        HAProtectionOut();
        return 1;
    }

    /* ------------------------------------------------------------------------------------------------------- */

    /* Crytical protection: thermocouple value is not valid or wires short circuit */
    if (GetHotAirT < 10) {
        HAProtectionOut();
        return 2;
    }

    /* ------------------------------------------------------------------------------------------------------- */

#ifdef HA_ADV_PROT_ON

    /* Overheat protection */
    if (ha_f1 && GetHotAirT > SetHotAirT + 20) {
        ha_f1 = false;
        HAProtectionOut();
        return 3;
    }

    if (ha_f2 && GetHotAirT < SetHotAirT + 15) {
        ha_f1 = true;
        ha_f2 = false;
    }

    /* ------------------------------------------------------------------------------------------------------- */

    /* Deviation themperature protection +/- 10 degrees */
    //if (HA_temp_stable) {
    //ha_f3 = true;
    //}
//
    //if (ha_f3) {
    //if (GetHotAirT > SetHotAirT + 10) {
    //HAProtectionOut();
    //return 4;
    //}
//
    //if (GetHotAirT < SetHotAirT - 10) {
    //HAProtectionOut();
    //return 5;
    //}
    //}

    /* ------------------------------------------------------------------------------------------------------- */



    /* Advanced protection: the themperature falls down/not changed & power > 0 */
    /* & */
    /* Advanced protection: the themperature rise up & power < 0 */
    static byte ha_t_cnt = 0;
    static byte ha_t_cnt2 = 0;
    static boolean ha_ctrl = true;
    if (!HA_temp_stable) {
        static int ha_prev_t;
        if (ha_ctrl) {
            ha_prev_t = GetHotAirT;
            ha_ctrl = false;
            prevHAcontrol = millis();
        }

        if (!ha_ctrl && millis() - prevHAcontrol > 1000) {
            ha_ctrl = true;

            if (HAPower > 0.0) {

                /* themperature falls or not changed */
                if (ha_prev_t >= GetHotAirT && GetHotAirT < SetHotAirT) {
                    ha_t_cnt++;
                    if (ha_t_cnt == 10) {
                        HAProtectionOut();
                        ha_t_cnt = 0;
                        return 6;
                    }
                } else ha_t_cnt = 0;

            } else { //HAPower == 0.0

                /* themperature rise */
                if (ha_prev_t < GetHotAirT && GetHotAirT > SetHotAirT) {
                    ha_t_cnt2++;
                    if (ha_t_cnt2 == 10) {
                        HAProtectionOut();
                        ha_t_cnt2 = 0;
                        return 7;
                    }
                } else ha_t_cnt2 = 0;
            }
        }
    } else {
        prevHAcontrol = millis();
        ha_t_cnt = 0;
        ha_t_cnt2 = 0;
        ha_ctrl = true;
    }

#endif

    /* ------------------------------------------------------------------------------------------------------- */

    /* if everything is OK */
    return 0;
}

/* Solder protection */
byte SDoProtect() {

    /* ------------------------------------------------------------------------------------------------------- */

    /* Crytical protection: high overheat or thermoresistor value is not valid or wire break */
    if (GetSolderT > max_solder_temp + 20) {
        SProtectionOut();
        return 1;
    }

    /* ------------------------------------------------------------------------------------------------------- */

    /* Crytical protection: thermoresistor value is not valid or wires short circuit */
    if (GetSolderT < 10) {
        SProtectionOut();
        return 2;
    }

    /* ------------------------------------------------------------------------------------------------------- */

#ifdef S_ADV_PROT_ON

    /* Overheat protection */
    if (s_f1 && GetSolderT > SetSolderT + 20) {
        s_f1 = false;
        SProtectionOut();
        return 3;
    }

    if (s_f2 && GetSolderT < SetSolderT + 15) {
        s_f1 = true;
        s_f2 = false;
    }

    /* ------------------------------------------------------------------------------------------------------- */

    /* Deviation themperature protection +/- 10 degrees */
    //if (S_temp_stable) {
    //s_f3 = true;
    //}
//
    //if (s_f3) {
    //if (GetSolderT > SetSolderT + 10) {
    //SProtectionOut();
    //return 4;
    //}
    //Not required for soldering iron
    //if (GetSolderT < SetSolderT - 10) {
    //SProtectionOut();
    //return 5;
    //}
    // }

    /* ------------------------------------------------------------------------------------------------------- */

    /* Advanced protection: the themperature falls down/not changed & power > 0 */
    /* & */
    /* Advanced protection: the themperature rise up & power < 0 */
    static byte s_t_cnt = 0;
    static byte s_t_cnt2 = 0;
    static boolean s_ctrl = true;
    if (!S_temp_stable) {
        static int s_prev_t = 0;
        if (s_ctrl) {
            s_prev_t = GetSolderT;
            s_ctrl = false;
            prevScontrol = millis();
        }

        if (!s_ctrl && millis() - prevScontrol > 1000) {
            s_ctrl = true;

            if (SPower > 0) {
                /* themperature falls or not changed */
                if (s_prev_t >= GetSolderT && GetSolderT < SetSolderT) {
                    s_t_cnt++;
                    if (s_t_cnt == 10) {
                        SProtectionOut();
                        s_t_cnt = 0;
                        return 6;
                    }
                } else s_t_cnt = 0;
            } else { //SPower == 0
                /* themperature rise */
                if (s_prev_t < GetSolderT && GetSolderT > SetSolderT) {
                    s_t_cnt2++;
                    if (s_t_cnt2 == 10) {
                        SProtectionOut();
                        s_t_cnt2 = 0;
                        return 7;
                    }
                } else s_t_cnt2 = 0;
            }
        }
    } else {
        prevScontrol = millis();
        s_t_cnt = 0;
        s_t_cnt2 = 0;
        s_ctrl = true;
    }

#endif

    /* ------------------------------------------------------------------------------------------------------- */

    /* everything is OK */
    return 0;
}

/* Solder full off */
void SolderOff() {
    analogWrite(pinSolderPwm, 0);
    D5_Low;
    D4_Low;
    resetSolderStablePoint();
    if (S_prot_beep) {
        S_prot_beep = false;
		beepOnce(1000);
        MemSolder();
    }
}

/* HotAir full off */
void HotAirOff() {
    HAPower = 0.0;
    D8_Low;
    delay_ms(10);
    D7_Low;
    hotair_state = st_stop;
    resetHotAirStablePoint();
    if (HA_prot_beep) {
        HA_prot_beep = false;
        beepOnce(1000);
        MemHotAir();
    }
}

/* Cooling the heater until the temperature is below 50 degrees */
void Cooling() {
    if (GetHotAirT >= 50 && need_Cooling) {
        analogWrite(pinFanPwm, 255);
    } else {
        analogWrite(pinFanPwm, 0);
        need_Cooling = false;
    }
}

/* internal procedure */
void set_ha_f() {
    boolean a = SetHotAirT >= GetHotAirT;
    ha_f1 = a;
    ha_f2 = !a;
}

/* internal procedure */
void set_s_f() {
    boolean a = SetSolderT >= GetSolderT;
    s_f1 = a;
    s_f2 = !a;
}

/* Solder protection */
void SProtectionOut() {
    SolderProtect = true;
    S_prot_beep = true;
    SolderON = false;
    SolderOff();
}

/* HotAir protection out */
void HAProtectionOut() {
    analogWrite(pinFanPwm, 255);
    HA_prot_beep = true;
    HotAirOff();
    hotair_state = st_protection;
}

/****************************************** END OF PROTECTION & ON-OFF *************************************/



/************************************************ OTHER ROUTINES *******************************************/

/* Read integer value */
int EEPROM_int_read(int addr) {
    byte raw[2];
    for (byte i = 0; i < 2; i++) {
        raw[i] = EEPROM.read(addr + i);
    }
    int &num = (int&)raw;
    return num;
}

/* Write integer value */
void EEPROM_int_write(int addr, int num) {
    byte raw[2];
    (int&)raw = num;
    for (byte i = 0; i < 2; i++) {
        EEPROM.write(addr + i, raw[i]);
    }
}

/* Read last parameters from memory */
void MemRead() {
    SetSolderT = EEPROM_int_read(0);
    if (SetSolderT < min_solder_temp || SetSolderT > max_solder_temp)  {
        SetSolderT = default_temp;
        last_SolderT = SetSolderT;
    }
    SetHotAirT = EEPROM_int_read(4);
    if (SetHotAirT < min_hotair_temp || SetHotAirT > max_hotair_temp) {
        SetHotAirT = default_temp;
        last_HotAirT = SetHotAirT;
    }
    SetHotAirRPM = EEPROM_int_read(8);
    if (SetHotAirRPM < min_rpm || SetHotAirRPM > max_rpm) {
        SetHotAirRPM = default_rpm;
        last_RPM = SetHotAirRPM;
    }
}

/* Write last used solder themperature to memory */
void MemSolder() {
    if (last_SolderT != SetSolderT) {
        EEPROM_int_write(0, SetSolderT);
        last_SolderT = SetSolderT;
    }
}

/* Write last used HotAir themperature and fan r.p.m. to memory */
void MemHotAir() {
    if (last_HotAirT != SetHotAirT) {
        EEPROM_int_write(4, SetHotAirT);
        last_HotAirT = SetHotAirT;
    }
    if (last_RPM != SetHotAirRPM) {
        EEPROM_int_write(8, SetHotAirRPM);
        last_RPM = SetHotAirRPM;
    }
}

/* Sound procedure */
//void Beep(uint16_t duration) {
//#ifdef PASSIVE_BUZZER
    //tone(pinBuzzer, 1000, duration);
//#else
    //D12_High;
    //delay_ms(duration);
    //D12_Low;
//#endif
//}

/* New sound procedure without delay */
#ifdef PASSIVE_BUZZER
/* Passive */
void beep_proc() {
	static boolean T1 = true;
	static boolean T2 = false;
	static boolean T3 = false;
	static uint32_t prevMillis = millis();

	if (Count > 0) {
		if (T1) {
			T1 = false;
			T2 = true;
			tone(pinBuzzer, 1000, Duration);
		}

		if (T2) {
			T2 = false;
			Count--;
			if (Count > 0) {
				T3 = true;
				prevMillis = millis();
				} else {
				T1 = true;
			}
		}

		if (T3 && millis() - prevMillis > Interval) {
			T3 = false;
			T1 = true;
		}
	} else {
		prevMillis = millis();
	}
}

#else
/* Active */
void beep_proc() {
	static boolean T1 = true;
	static boolean T2 = false;
	static boolean T3 = false;
	static uint32_t prevMillis = millis();

	if (Count > 0) {
		if (T1) {
			T1 = false;
			T2 = true;
			D12_High;
			prevMillis = millis();
		}

		if (T2 && millis() - prevMillis > Duration) {
			T2 = false;
			D12_Low;
			Count--;
			if (Count > 0) {
				T3 = true;
				prevMillis = millis();
				} else {
				T1 = true;
			}
		}

		if (T3 && millis() - prevMillis > Interval) {
			T3 = false;
			T1 = true;
		}
	} else {
		prevMillis = millis();
	}
}

#endif

/* Set the values for once beep */
void beepOnce(uint16_t duration) {
	Count = 1;
	Duration = duration;
	Interval = 0;
}

/* Set the values for twice short beeps */
void beepTwice() {
	Count = 2;
	Duration = 50;
	Interval = 200;
}

/* HotAir oversampling function */
uint16_t getOversampled_HA() {
    uint32_t tmp = 0;
    for (byte z = 0; z < 64; z++) {//128
        tmp +=  A7_Read;
    }
    return tmp >> 6; //7;
}

/* Solder oversampling function */
uint16_t getOversampled_S() {
    uint32_t tmp = 0;
    for (byte z = 0; z < 64; z++) {
        tmp +=  A6_Read;
    }
    return tmp >> 6;
}

/* Get difference value function */
uint16_t GetDelta(int a, int b) {
    if (a > b) {
	    return (a - b);
    }
    return (b - a);
}

/* AnalogRead (from Cyberlib) */
uint16_t AnRead(uint8_t An_pin) {
    ADMUX=An_pin;
    delay_us(10);
    ADCSRA=B11000110;	//B11000111-125kHz B11000110-250kHz
    while (ADCSRA & (1 << ADSC));
    An_pin = ADCL;
    uint16_t An = ADCH;
    return (An<<8) + An_pin;
}

/****************************************** END OF OTHER ROUTINES ******************************************/



/********************************** TRIAC & MOSFET CONTROL & AUTOMATHIC ************************************/

/* delay ms (from Cyberlib) */
void delay_ms(uint16_t tic_ms) {
    while(tic_ms) {
        delay_us(999);
        tic_ms--;
    }
}

/* delay us (from Cyberlib) */
void delay_us(uint16_t tic_us) {
    tic_us *= 4;
    __asm__ volatile
    (
        "1: sbiw %0,1" "\n\t"
        "brne 1b"
        : "=w" (tic_us)
        : "0" (tic_us)
    );
}

volatile uint16_t dub_tcnt1;
void (*func)();

/* Timer1 start (from Cyberlib) */
void StartTimer1(void (*isr)(), uint32_t set_us) {
    TIMSK1 &= ~(1<<TOIE1);
    func = *isr;
    TCCR1A = 0;		//timer1 off
    TCCR1B = 0; 	//prescaler off
    if(set_us > 5 && set_us < 4096) {
        set_us = 65584 - (set_us << 4);
        TCCR1B = (1 << CS10); // 0
    } else if(set_us > 4095 && set_us < 32768) {
        set_us = 65542 - (set_us << 1);
        TCCR1B = (1 << CS11); // 8
    } else TCCR1B = 1;
    dub_tcnt1 = set_us;
    TCNT1 = dub_tcnt1;
    TIMSK1 |= (1 << TOIE1);
}

/* Timer1 stop (from Cyberlib) */
void StopTimer1(void) {
    TIMSK1 &= ~(1<<TOIE1);
}

/* Timer1 overflow ISR */
ISR(TIMER1_OVF_vect) {
    (*func)();
}

/* Zero cross INT1 */
void ZC() {
    StartTimer1(HeaterOn, ots);
}

/* Triac on impulse */
void HeaterOn() {
    StopTimer1();
    if (HAPower > 0.0) {
        D8_High;
        delay_us(50);
    }
    D8_Low;
}

/* Calculate triac on delay */
void CalctImpulseControl() {
    ots = (uint16_t)(acos(HAPower / 100.0 - 1.0) * 9950.0 / 3.14);
}

/* HotAir PI regulator */
void HA_PI() {
    int err = SetHotAirT - GetHotAirT;
    float tmp_power = Kp * err + Ki * integral;
    float max_power = map(SetHotAirT, min_hotair_temp, max_hotair_temp, 10.0, 90.0);
    if (tmp_power < max_power && tmp_power > 0.0) {
        integral += err;
    }
    HAPower = constrain(tmp_power, 0.0, max_power);
    CalctImpulseControl();
}

#ifdef SOLDER_SOFT_START
/* Solder P regulator with soft start */
void S_P() {
    int TempPower = sKp * (SetSolderT - GetSolderT);
    byte maxPower = 255;
    if (GetSolderT < 100) {
        maxPower = 100;
    }
    SPower = constrain(TempPower, 0, maxPower);
    analogWrite(pinSolderPwm, SPower);
}
#else
/* Solder P regulator */
void S_P() {
    int TempPower = sKp * (SetSolderT - GetSolderT);
    SPower = constrain(TempPower, 0, 255);
    analogWrite(pinSolderPwm, SPower);
}
#endif

/************************************* END OF TRIAC CONTROL & AUTOMATHIC ***********************************/



/**************************************** INTERFACE CONTROLS & TIMERS **************************************/

/* Scan buttons */
void ScanButtons() {

    /* HotAir stand switch */
    if (swHotAir.update() && hotair_state != st_stop) {
        if (swHotAir.fell()) {
            hotair_state = st_pause;
            need_Cooling = true;
            resetHotAirCountown();
        } else {
            if (hotair_state == st_pause) {
                hotair_state = st_work;
                integral = 0;
                set_ha_f() ;
            }
        }
		beepOnce(50);
    } else if (hotair_state == st_work && D10_Read == LOW) {
        D7_High;
        hotair_state = st_pause;
        need_Cooling = true;
        resetHotAirCountown();
    }

#ifdef SOLDER_TIMER_ON_STAND

    /* Solder stand switch - only on stand */
    if (swSolder.update()) {
        if (swSolder.fell() && SolderON) {
            if (!need_S_countdown) {
                Activate_S_countdown();
				beepOnce(50);
            }
        }

        if (swSolder.rose())  {
            if (need_S_countdown) {
                need_S_countdown = false;
				beepOnce(50);
            }
        }
    }

#else

    /* Solder stand switch simple check user activity */
    if (swSolder.update() && SolderON) {
        resetSolderCountdown();
		beepOnce(50);
    }

#endif // SOLDER_TIMER_ON_STAND

    /* Solder "on-off" button */
    if (SolderOnButton.update()) {
        if (SolderOnButton.read()) {
            SONbuttonState = false;
        } else {
            if (!SolderON) {
                SolderON = true;
                SolderProtect = false;

#ifdef SOLDER_TIMER_ON_STAND
                if (!D9_Read) Activate_S_countdown();
#else
                Activate_S_countdown();
#endif

                Graph_count = 0;
                selected_Mode = modeSolder;
                resetSolderStablePoint();
                set_s_f();
            } else {
                resetSolderCountdown();
            }
            SONbuttonState = true;
            SONbuttonPressTime = millis();
			beepOnce(50);
        }
    }

    if  (SONbuttonState) {
        if ( millis() - SONbuttonPressTime >= 500 ) { //long press
            SONbuttonPressTime = millis();
            SolderON = false;
            MemSolder();
			beepOnce(200);
            SONbuttonState = false;
        }
    }

    /* HotAir "on-off" button */
    if (HotAirOnButton.update()) {
        if (HotAirOnButton.read()) {
            HAONbuttonState = false;
        } else {
            if (hotair_state != st_work) {
                hotair_state = st_work;
                Graph_count = 0;
                selected_Mode = modeHotAir;
                need_Cooling = true;
                resetHotAirStablePoint();
                set_ha_f();
                integral = 0;
            } else {
                resetHotAirCountown();
            }
            HAONbuttonState = true;
            HAONbuttonPressTime = millis();
			beepOnce(50);
        }
    }

    if  (HAONbuttonState) {
        if ( millis() - HAONbuttonPressTime >= 500 ) { //long press
            HAONbuttonPressTime = millis();
            hotair_state = st_stop;
            need_Cooling = true;
            MemHotAir();
			beepOnce(200);
            HAONbuttonState = false;
        }
    }

    /* Select button */
    if (SelButton.update()) {
        if (SelButton.fell()) {
			beepOnce(50);
            (selected_Mode < modeFanPWM) ? (selected_Mode++) : (selected_Mode = modeSolder);
        }
    }

    /* UP button */
    static boolean short_press_flag = false;

    if (UpButton.update()) {
        if (UpButton.rose()) {
            UPbuttonState = false;
            short_press_flag = false;
        } else {
            switch (selected_Mode) {
            case modeSolder:
                if (SetSolderT < max_solder_temp) {
                    SetSolderT += 5;
                }
                set_s_f();
                resetSolderStablePoint();
                resetSolderCountdown();
                break;
            case modeHotAir:
                if (SetHotAirT < max_hotair_temp) {
                    SetHotAirT += 5;
                }
                break;
            case modeFanPWM:
                if (SetHotAirRPM < max_rpm) {
                    SetHotAirRPM += 5;
                }
                break;
            }

            if (selected_Mode > 1) {
                set_ha_f();
                resetHotAirStablePoint();
                resetHotAirCountown();
                integral = 0;
            }

            UPbuttonState = true;
            short_press_flag = true;
            UPbuttonPressTime = millis();
			beepOnce(50);
        }
    }

    /* UP button (long press) */
    if  (UPbuttonState) {
        if ( millis() - UPbuttonPressTime >= 500 ) {
            UPbuttonPressTime = millis();
            byte step = 10;
            if (short_press_flag) {
                step = 5;
                short_press_flag = false;
            }
            switch (selected_Mode) {
            case modeSolder:
                SetSolderT += step;
                if (SetSolderT > max_solder_temp) SetSolderT = max_solder_temp;
                set_s_f();
                resetSolderStablePoint();
                resetSolderCountdown();
                break;
            case modeHotAir:
                SetHotAirT += step;
                if (SetHotAirT > max_hotair_temp) SetHotAirT = max_hotair_temp;
                break;
            case modeFanPWM:
                SetHotAirRPM += step;
                if (SetHotAirRPM > max_rpm) SetHotAirRPM = max_rpm;
                break;
            }
            if (selected_Mode > 1) {
                set_ha_f();
                resetHotAirStablePoint();
                resetHotAirCountown();
                integral = 0;
            }
        }
    }

    /* Down button */
    if (DwnButton.update()) {
        if (DwnButton.read()) {
            DWNbuttonState = false;
            short_press_flag = false;
        } else {
            switch (selected_Mode) {
            case modeSolder:
                if (SetSolderT > min_solder_temp) {
                    SetSolderT -= 5;
                }
                set_s_f();
                resetSolderStablePoint();
                resetSolderCountdown();
                break;
            case modeHotAir:
                if (SetHotAirT > min_hotair_temp) {
                    SetHotAirT -= 5;
                }
                break;
            case modeFanPWM:
                if (SetHotAirRPM > min_rpm) {
                    SetHotAirRPM -= 5;
                }
                break;
            }

            if (selected_Mode > 1) {
                set_ha_f();
                resetHotAirStablePoint();
                resetHotAirCountown();
            }

            DWNbuttonState = true;
            short_press_flag = true;
            DWNbuttonPressTime = millis();
			beepOnce(50);
        }
    }

    /* Down button (long press) */
    if  (DWNbuttonState) {
        if ( millis() - DWNbuttonPressTime >= 500 ) {
            DWNbuttonPressTime = millis();

            byte step = 10;
            if (short_press_flag) {
                step = 5;
                short_press_flag = false;
            }

            switch (selected_Mode) {
            case modeSolder:
                SetSolderT -= step;
                if (SetSolderT < min_solder_temp) SetSolderT = min_solder_temp;
                set_s_f();
                resetSolderStablePoint();
                resetSolderCountdown();
                break;
            case modeHotAir:
                SetHotAirT -= step;
                if (SetHotAirT < min_hotair_temp) SetHotAirT = min_hotair_temp;
                break;
            case modeFanPWM:
                SetHotAirRPM -= step;
                if (SetHotAirRPM < min_rpm) SetHotAirRPM = min_rpm;
                break;
            }

            if (selected_Mode > 1) {
                set_ha_f();
                resetHotAirStablePoint();
                resetHotAirCountown();
            }
        }
    }
}

/* Buttons initialise */
void ButtonsSetup() {
    pinMode(sw_HA, INPUT_PULLUP);
    swHotAir.attach(sw_HA);
    swHotAir.interval(50);

    pinMode(sw_S, INPUT_PULLUP);
    swSolder.attach(sw_S);
    swSolder.interval(50);

    pinMode(bt_SON, INPUT_PULLUP);
    SolderOnButton.attach(bt_SON);
    SolderOnButton.interval(5);

    pinMode(bt_HAON, INPUT_PULLUP);
    HotAirOnButton.attach(bt_HAON);
    HotAirOnButton.interval(5);

    pinMode(bt_Sel, INPUT_PULLUP);
    SelButton.attach(bt_Sel);
    SelButton.interval(10);

    pinMode(bt_Up, INPUT_PULLUP);
    UpButton.attach(bt_Up);
    UpButton.interval(5);

    pinMode(bt_Dwn, INPUT_PULLUP);
    DwnButton.attach(bt_Dwn);
    DwnButton.interval(5);
}

/* internal procedure */
void resetHotAirStablePoint() {
    HA_temp_stable = false;
}

/* internal procedure */
void resetSolderStablePoint() {
    S_temp_stable = false;
}

/* Reset HotAir countdown */
void resetHotAirCountown() {
    HA_countdown = HA_sleeptime;
}

/* Reset Solder countdown */
void resetSolderCountdown() {
    S_countdown = S_sleeptime;
}

/* Activate Solder countdown procedure */
void Activate_S_countdown() {
    need_S_countdown = true;
    S_countdown = S_sleeptime;
}
/************************************* END OFINTERFACE CONTROLS & TIMERS ***********************************/



/************************************************* DISPLAY *************************************************/

/* "Hello" screen */
void Splash() {
    lcd.clear();
#ifdef LCD_1602
    lcd.setCursor(0, 0);
    lcd.print(F("Soldering Station"));
    lcd.setCursor(6, 1);
#else
    lcd.setCursor(2, 1);
    lcd.print(F("Soldering Station"));
    lcd.setCursor(7, 2);
#endif
    lcd.print(F("v "));
    lcd.print(FIRMWARE_VERSION);
}

/* Set LCD design */
void initDisplay() {
    lcd.clear();
#ifdef LCD_1602

#else
    lcd.setCursor(11, 0);
    lcd.print(F("Set"));

    lcd.setCursor(16, 0);
    lcd.print(F("Act"));

    lcd.setCursor(0, 1);
    lcd.print(F("Solder"));

    lcd.setCursor(0, 2);
    lcd.print(F("HotAir"));

    lcd.setCursor(0, 3);
    lcd.print(F("FanRPM"));
#endif
}

/* Update LCD */
void DisplayUpdate(boolean blink_state) {

#ifdef LCD_1602

    lcd.setCursor(0, 0);
    lcd.print(bspace);
    lcd.setCursor(0, 0);

    if (SolderProtect) {
        lcd.print(F("!"));
        lcd.print(s_error);
    } else if (need_S_countdown) {
        if (blink_state) lcd.print(S_countdown);
    } else if (SolderON) {
        (S_temp_stable) ? (lcd.print(F(" *"))) : (lcd.print(F(" :")));
    }

    lcd.setCursor(3, 0);
    lcd.print(bspace);
    lcd.setCursor(3, 0);
    lcd.print(SetSolderT);
    lcd.write((byte)0);

    byte pos;
    uint16_t s_view_t;

    if (GetSolderT > 505) {
        lcd.setCursor(8, 0);
        lcd.print(F("---"));
    } else {
        uint16_t s_view_t;
#ifdef SOLDER_DIGIT_JUMPS_REMOVE
        (S_temp_stable)? (s_view_t = SetSolderT) : (s_view_t = GetSolderT);
#else
        s_view_t = GetSolderT;
#endif
        pos = GetPos(s_view_t);
        lcd.setCursor(8, 0);
        lcd.print(bspace);
        lcd.setCursor(8+pos, 0);
        lcd.print(s_view_t);
    }
    lcd.write((byte)0);

    lcd.setCursor(0, 1);
    lcd.print(bspace);
    lcd.setCursor(0, 1);

    switch (hotair_state) {
    case st_stop: {
        break;
    }

    case st_work: {
        if (HA_temp_stable) {
            lcd.print(F(" *"));
        } else {
            lcd.print(F(" :"));
        }
        break;
    }

    case st_pause: {
        if (blink_state) lcd.print(HA_countdown);
        break;
    }

    case st_protection: {
        lcd.print(F("!"));
        lcd.print(ha_error);
        break;
    }

    }

    pos = GetPos(SetHotAirT);
    lcd.setCursor(3, 1);
    lcd.print(bspace);
    lcd.setCursor(3+pos, 1);
    lcd.print(SetHotAirT);
    lcd.write((byte)0);

    if (GetHotAirT > 505) {
        lcd.setCursor(8, 1);
        lcd.print(F("---"));
    } else {
        uint16_t ha_view_t;
#ifdef HOTAIR_DIGIT_JUMPS_REMOVE
        (HA_temp_stable) ? (ha_view_t = SetHotAirT) : (ha_view_t = GetHotAirT);
#else
        ha_view_t = GetHotAirT;
#endif
        pos = GetPos(ha_view_t);
        lcd.setCursor(8, 1);
        lcd.print(bspace);
        lcd.setCursor(8+pos, 1);
        lcd.print(ha_view_t);
    }
    lcd.write((byte)0);

    lcd.setCursor(13, 1);
    lcd.print(bspace);
    lcd.setCursor(13, 1);

    pos = GetPos(SetHotAirRPM);
    if (need_Cooling && hotair_state != st_work) {
        lcd.print(F("100%"));
    } else {
        lcd.setCursor(13+pos, 1);
        lcd.print(SetHotAirRPM);
        lcd.print(F("%"));
    }

    lcd.setCursor(2, 0);
    lcd.print(F(" "));
    lcd.setCursor(2, 1);
    lcd.print(F(" "));
    lcd.setCursor(12, 1);
    lcd.print(F(" "));

    switch (selected_Mode) {
    case modeSolder: {
        lcd.setCursor(2, 0);
        break;
    }

    case modeHotAir: {
        lcd.setCursor(2, 1);
        break;
    }

    case modeFanPWM: {
        lcd.setCursor(12, 1);
        break;
    }
    }
    lcd.write((byte)1);

#else //LCD2004

    lcd.setCursor(6, 1);
    lcd.print(bspace);
    lcd.setCursor(7, 1);

    if (SolderProtect) {
        lcd.print(F("!"));
        lcd.print(s_error);
    } else if (need_S_countdown) {
        if (blink_state) lcd.print(S_countdown);
    } else if (SolderON) {
        (S_temp_stable) ? (lcd.print(F(" *"))) : (lcd.print(F(" :")));
    }

    lcd.setCursor(11, 1);
    lcd.print(bspace);
    lcd.setCursor(11, 1);
    lcd.print(SetSolderT);
    lcd.write((byte)0);

    byte pos;
    uint16_t s_view_t;

    if (GetSolderT > 505) {
        lcd.setCursor(16, 1);
        lcd.print(F("---"));
    } else {
        uint16_t s_view_t;
#ifdef SOLDER_DIGIT_JUMPS_REMOVE
        (S_temp_stable) ? (s_view_t = SetSolderT) : (s_view_t = GetSolderT);
#else
        s_view_t = GetSolderT;
#endif
        pos = GetPos(s_view_t);
        lcd.setCursor(16, 1);
        lcd.print(bspace);
        lcd.setCursor(16+pos, 1);
        lcd.print(s_view_t);
    }
    lcd.write((byte)0);

    lcd.setCursor(6, 2);
    lcd.print(bspace);
    lcd.setCursor(7, 2);

    switch (hotair_state) {
    case st_stop: {
        break;
    }

    case st_work: {
        if (HA_temp_stable) {
            lcd.print(F(" *"));
        } else {
            lcd.print(F(" :"));
        }
        break;
    }

    case st_pause: {
        if (blink_state) lcd.print(HA_countdown);
        break;
    }

    case st_protection: {
        lcd.print(F("!"));
        lcd.print(ha_error);
        break;
    }

    }

    pos = GetPos(SetHotAirT);
    lcd.setCursor(11, 2);
    lcd.print(bspace);
    lcd.setCursor(11+pos, 2);
    lcd.print(SetHotAirT);
    lcd.write((byte)0);

    if (GetHotAirT > 505) {
        lcd.setCursor(16, 2);
        lcd.print(F("---"));
    } else {
        uint16_t ha_view_t;
#ifdef HOTAIR_DIGIT_JUMPS_REMOVE
        (HA_temp_stable) ? (ha_view_t = SetHotAirT) : (ha_view_t = GetHotAirT);
#else
        ha_view_t = GetHotAirT;
#endif
        pos = GetPos(ha_view_t);
        lcd.setCursor(16, 2);
        lcd.print(bspace);
        lcd.setCursor(16+pos, 2);
        lcd.print(ha_view_t);
    }
    lcd.write((byte)0);

    lcd.setCursor(11, 3);
    lcd.print(bspace);
    lcd.setCursor(11, 3);

    pos = GetPos(SetHotAirRPM);
    if (need_Cooling && hotair_state != st_work) {
        lcd.print(F("100%"));
    } else {
        lcd.setCursor(11+pos, 3);
        lcd.print(SetHotAirRPM);
        lcd.print(F("%"));
    }

    for (byte z = 1; z < 4; z++) {
        lcd.setCursor(10, z);
        lcd.print(F(" "));
    }

    lcd.setCursor(10, selected_Mode);
    lcd.write((byte)1);

#endif

}

/* Get print position */
byte GetPos(uint16_t number) {
    if (number >= 100) {
        return 0;
    } else if (number < 10) {
        return 2;
    }
    return 1;
}

/*********************************************** END OF DISPLAY ********************************************/

 

 

MVS
Offline
Зарегистрирован: 19.04.2018

Попробовал. Чет совсем интересно. Выставляю 100 гр. и скорость кулера 30%, при включении фена температура медленно растет до 63гр. останавливается и вылазит ошибка №6. повторно нажимаю кнопку вкл фена, и повторяется таже история, ошибка №3- перерегулирование до 130гр. Может как-то можно поставить таймер на эту защиту)))). Не хочется сильно уставку сдвигать. Спасибо.

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

MVS пишет:
Не хочется сильно уставку сдвигать.

В предыдущей прошивке попробуйте поднять Ki до 0.005 или 0.007
Если не поможет, то уставку, таки, лучше поднять. До 35.
Ну, или вообще доп. защиты отключить. ))

MVS
Offline
Зарегистрирован: 19.04.2018

OlegK, коэффициенты подбирал, не помогает. Да, с уставкой по защите №3  +40 все работает прекрасно. Спасибо Вам еще раз за этот отличнейший проект. Попробую допилить скетч, вот только чуть программирование подучу)))) Спасибо.

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

MVS пишет:
Попробовал. Чет совсем интересно.

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

 

Alsi2010
Offline
Зарегистрирован: 25.09.2017

Добрый день уважаемый OlegK и посетители форума. Дорабатывая печатные платы под размер своего корпуса (делаю одноплатный вариант), столкнулся с вопросом определения типа температурного датчика паяльника. У меня их два, оба от станции Youyue 8586.  Замерял сопротивление запасного нагревательного элемента (в паяльниках эти значения совпадают): синий и красный вывод= 1,2 Ом; вторые выводы 16 Ом. Подогревая нагревательный элемент открытым пламенем газовой горелки сопротивление начинает увеличиваться от 1,2 Ом до (немного нагрел) 34 Ом. По данным моих замеров и информации, полученной в сети, получается что у меня термопара. На запасном нагревательном элементе фена те же 1,2 Ом. Мне нужен Ваш совет: я не ошибаюсь в своих выводах? Мне схему разрабатывать под термопару?

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

Alsi2010 пишет:
Мне схему разрабатывать под термопару?

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

Да и по внешнему виду вашего нагревателя виднор, что это нихром + ТП.
Терморезисторные имеют такой вид кончика, с выраженной ступенькой -

alex1978
alex1978 аватар
Offline
Зарегистрирован: 09.09.2017

Alsi2010 пишет:

Добрый день уважаемый OlegK и посетители форума. Дорабатывая печатные платы под размер своего корпуса (делаю одноплатный вариант), столкнулся с вопросом определения типа температурного датчика паяльника. У меня их два, оба от станции Youyue 8586.

А чем вас не устраивают мои платы? У меня всё, кроме усилителя термодатчиков, на одной плате. А плата усилителя ставится на основную вторым этажом. 

Вот типа так. У меня даже комплект плат ещё один остался, могу продать недорого. Размер основной платы 113*95мм. Я так перешёл на керамику с нихрома, намного лучше температура держится.

Alsi2010
Offline
Зарегистрирован: 25.09.2017

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

Alsi2010
Offline
Зарегистрирован: 25.09.2017

OlegK  спасибо Вам за ответ.

triod2
Offline
Зарегистрирован: 22.07.2017

Alex-59
Offline
Зарегистрирован: 14.03.2018

Фен работает без проблем. Паяльник -никак. При нагреве показания колбасит от 148 до 158, на термометре показывае 150(так как надо).Режим захвата температуры не включается. LM358 менял 3 штуки, результат тот-же. sKp менял. Куда копать?

Alsi2010
Offline
Зарегистрирован: 25.09.2017

alex1978 пишет:

Alsi2010 пишет:

Добрый день уважаемый OlegK и посетители форума. Дорабатывая печатные платы под размер своего корпуса (делаю одноплатный вариант), столкнулся с вопросом определения типа температурного датчика паяльника. У меня их два, оба от станции Youyue 8586.

А чем вас не устраивают мои платы? У меня всё, кроме усилителя термодатчиков, на одной плате. А плата усилителя ставится на основную вторым этажом. 

Вот типа так. У меня даже комплект плат ещё один остался, могу продать недорого. Размер основной платы 113*95мм. Я так перешёл на керамику с нихрома, намного лучше температура держится.

Добрый день, aleks1978. Есть вопрос к Вам. На вашей п\плате рэле правильно подключены (контакты 1,3 и 4? 

alex1978
alex1978 аватар
Offline
Зарегистрирован: 09.09.2017

Ну ведь работает же))) Уже три экземпляра работает. И ещё четыре человека платы купили, никто пока не жаловался. Подключены правильно, возможно схема релюшки на плате нарисована не правильно. Не вникал.