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

Warcan
Offline
Зарегистрирован: 23.05.2018

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

1) Разобрал фен и обнаружил что один проводок от термопары не пропаян на плате внутри фена, вроде пропаял сейчас он не выскакивает если потнуь пинцетом. Пропаивал с обычной канифолью. Не подскажите может какимто флюсом лучше воспользоваться? Померил на всякий случай сопротивления термопары и нагревателя. 3,4 ома у термопары, и 79 ом нагреватель. Проверил полярность термопары, померив тестером на её выходе напряжение и нагревая метал корпуса вроде правильно подключено. 

2) Внутри фена есть провод,  с одной стороны он припаян к плате а вот второй его кончик не был закреплён ни где. Поидее это копусной провод фен, но вот не как не пойму как он должен крепится к корпусу металической ческой части фена?

3) Я попробовал пока не знаю что делать с феном, отключить плату усилителей термодатчиков. Так вот, если плата амп отключена, станция показывает на дисплее температуры на каналах фена и паяльника близкие к 500(450-503 или ---) и эти значения постоянно плавают. Это нормально или они должны быть ---? 

Oleg_D
Offline
Зарегистрирован: 13.06.2018

При не подключённом разъёме фена и : вытащенном ОУ - на дисплее 0 гр. При вставленном ОУ п на дисплее 511 гр. И не плавает ничего. ОУ AD8552. Ищите ошибку в схеме или номиналах. Может глючит ардуино, проблемы/помехи с питанием. Замените черточки в скетче на getsoldertemp, getfantemp, чтобы отображались текущая измеренная температура.

Alchimy91
Offline
Зарегистрирован: 28.07.2018

Добрый день!
Хочу повторить проект заказую радиодитали не могу разобрать на схеме маркировку 24 вольтовых реле.
Подскажите пожайлуста каке реле стоят в врианте от Русл@на ? Смотрел по рараметрах есть только выводи подругом расположены чтобы не переделывать печатку

dimich
Offline
Зарегистрирован: 12.10.2016

Простите но нужно подключить дисплей по шине I2C. Что поменять в скетче?

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

Я так думаю, прошивка уже ориентирована на I2C.
Во всяком случае v1.6.1, которая у меня стоит ничего не "требовала".

Alchimy91
Offline
Зарегистрирован: 28.07.2018

Добрый вечер! Dimich Вы не знаете какие реле стоят в схеме от Русл@н (одно платный вариант)?

mr.nikon
Offline
Зарегистрирован: 20.05.2016

 

 

mr.nikon
Offline
Зарегистрирован: 20.05.2016

Alchimy91 пишет:

Добрый вечер! Dimich Вы не знаете какие реле стоят в схеме от Русл@н (одно платный вариант)?

 Ребята а чего так упорно не хотим почитать тему и найти ответы на интересующие Вас ответы ????

mr.nikon
Offline
Зарегистрирован: 20.05.2016

DEL

 

mr.nikon
Offline
Зарегистрирован: 20.05.2016

Alchimy91 пишет:

Добрый вечер! Dimich Вы не знаете какие реле стоят в схеме от Русл@н (одно платный вариант)?

 Ребята а чего так упорно не хотим почитать тему и найти ответы на интересующие Вас ответы ????

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

Alchimy91 пишет:

Добрый день!
Хочу повторить проект заказую радиодитали не могу разобрать на схеме маркировку 24 вольтовых реле.
Подскажите пожайлуста каке реле стоят в врианте от Русл@на ? Смотрел по рараметрах есть только выводи подругом расположены чтобы не переделывать печатку

Реле AZ8-1CH-24DSEA. Не самая популярная релюшка. Ищите по типу корпуса Т72 вроде. А проще найти другие реле на 24В с нормально разомкнутой контактной парой до 10А или более, и переделать плату под них. Если интересует, то есть на продажу одна собранная и настроенная плата, типа как у Руслана. Вопросы на alexfree78@yandex.ru 

Oleg_D
Offline
Зарегистрирован: 13.06.2018

Alchimy91 пишет:

... какие реле стоят в схеме от Русл@н (одно платный вариант)?


Я, например, брал эти, на 24в:
Automotive Relays SRA-05VDC-AL SRA-12VDC-AL SRA-24VDC-AL 5V 12V 24V 20A T74 4PIN Relay Wholesale Price
http://s.aliexpress.com/IzmAfiya
Переделаную плату найдёте ранее в моих сообщениях. Можете выдернуть оттуда трафарет этих реле, если хочется. Подошли 1:1.

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

Я тоже такие хотел вставить.

Но они ко мне не приехали. 

Не знаю как работают.

Сейчас делаю на этих https://ru.aliexpress.com/item/894H-2AH1-F-S-24VDC-12A-6-24-U04-10A/32844280839.html?spm=a2g0s.9042311.0.0.43d533edRaZAcC

По схеме идёт отключение обоих проводов 220В на фене и 24В на паяле.

Плюс нет сети на разьёме фена.

минус меньшая мех надежность.

Еще не дособрал и не гонял.

Прошу пинать только по существу.

 

Alchimy91
Offline
Зарегистрирован: 28.07.2018

Добрый вечер 
Спасибо за ответы заказал на али ждать еще долго
Хочу поблагодарить рабработчика и всех кто ее совершенствовал, Вы сделали реально надежную схему, спасибо.
Я начинаюций начинаю с минимума инструмента самодельного
Сдерал бп на DPS5020 начал паяльную станцию....
Как прийдут запчасти начну сборку отпишу
 

YURSA
YURSA аватар
Offline
Зарегистрирован: 28.09.2017

Здравствуйте уважаемые форумчане. Хочу предложить как-бы маленько доработанный AMP Module с возможностью переключения канала паяльника под термопару или терморезистор. Не нужно прт замене нагревателя с нихрома на керамику менять модуль, просто переключить микрики и настроить температуру. Только надо плату подкорректировать, приделать кондёры в цепи ОС.

https://cloud.mail.ru/public/8LhF/Ed94pEwkx

il86md
Offline
Зарегистрирован: 22.11.2017

Спаял канал фена  так как он первый нужен, паяльник у меня в тумбочке воляется от t12 как я понял надо было одинаковые каналы усилителя паять что для фена что для t12 этого не учел...если не сложно киньте ссылку на ручку для схемы в архиве

1) отключил защиты  #define HA_ADV_PROT_ON - для канала фена #define S_ADV_PROT_ON - для канала паяльника

2) включил станцию, отрегулировал Старт до комнатной температуры, включаю канал фена (темпер выставил 150) кулер дует, на канале фена  100 вольт приходит по мультиметрку переменка, фен дует холодным воздухом, через 30-50сек вырубается канал фена, температура так и не поднялась. Канал фена тоесть нагревать имеет 68 ом сопротивление. термопала 1.7 ома. усилитель на LM, но это второстепенно главное что не греется нагревать при подаче напряжения с симистора bt136 (опто moc3023)

всю установку питаю через лампу 60ватт - как предохранитель поставил и она начинает загораться не в полную мощь при включении канала фена

куда рыть как узнать что детектор нуля работает правильно и почему фен выключчается? Не пинайте сильно я ваш брат )))

YURSA
YURSA аватар
Offline
Зарегистрирован: 28.09.2017

А зачем лампа-то?,да и 60 ватт это очень мало, надо мощность лампы раза в полтора-два больше мощности нагревателя фена (300-400 ватт)

Oleg_D
Offline
Зарегистрирован: 13.06.2018

У вас на лампочке падает 120 В. Отсюда сопротивление спирали при 60Вт =120^2/60=240Ом. А если горит не в полную силу, то и того более. Конечно у вас лампочка не даст разогрется фену, потому что у фена 68 Ом. Уберите лампочку вообще. Включите канал и наблюдайте за температурой. Выставите для начала 100 градусов, чтобы не перегреть в случае неправильно настроенного диапазона шкала. Будьте готовы к экстренному обесточиванию станции в случае неконтролируемого нагрева. А выключается потому что срабатывает защита от ненагрева.

il86md
Offline
Зарегистрирован: 22.11.2017

и правда , напрямую запитал нагрев идет и все равно вырубается через 5-20сек Причем максимум до 70 нагревается и сам отключается, а иногда поднимает до 100% продув и выключается 

бесы управляют феном :)

такое ощущение что то отключает нагрев фена и кулера одновременно, а реле защиты во вкл положении остается и таймер 10 минут работает

на ZC показывает 1,4 вольта через мутиметр

пересмотрел все платы , снова все включил всё работает. НО пришлось отключить провод геркона

1) выставил HotAir ,220 градусов, реально 80 на термопаре показывает , при 300 выдает 130

2) вместо таймера 10мин стоит двоеточее

Oleg_D
Offline
Зарегистрирован: 13.06.2018

Теперь подбирайте сопротивления для Шкалы и начала. Для каждого оу свои номиналы. Найдёте в теме.

il86md
Offline
Зарегистрирован: 22.11.2017

Oleg_D пишет:
Теперь подбирайте сопротивления для Шкалы и начала. Для каждого оу свои номиналы. Найдёте в теме.

на табло установочная температура 200 , рядом отображается температура термопары внутри фена и она около  70 градусов и ардуина не хочет увеличивать нагрев фена до установочной 200, тупо до 70 поднялась и все баста , устанавливаю 300 так в результате на табло активные данные выдает около  130 градусов , я понимаю температура сэт и актив должны совпадать спустя 20-30 секунд чего у меня не происходит

блин и кросзеро напряжение всего 1,4 вольта такое ощущение что не совсем правильно модуль детектора нуля работает

Oleg_D
Offline
Зарегистрирован: 13.06.2018

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

il86md
Offline
Зарегистрирован: 22.11.2017

Oleg_D пишет:
Это очень мало. Должно быть около 4 вольт. Край - это 3В. Да, при плохой работе контроля нуля жалуются именно на недогрев. Проверьте номиналы конденсаторов в этом узле.

pnp транзистор впаял в схему ZC по ошибке, перепаял на npn в итоге сигнал на контакте ардуины ZC стал

похоже на верные показания.

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

после отстроййки температуры подбора резисторов, перепрошивки ардуины (отключение защиты) всё заработало нормально, тоесть логично.

какой паяльник требуется к данной паялке?

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

Здравствуйте,il86md чтобы в фене нормально работал геркон,установите параллельно ему конденсатор 100 нФ.

il86md
Offline
Зарегистрирован: 22.11.2017

pter пишет:

Здравствуйте,il86md чтобы в фене нормально работал геркон,установите параллельно ему конденсатор 100 нФ.

запаял 0.1mkF

а паяло такое подойдет? никогда таким не пользовался просто, как я понял он на 50 Ватт. У вас такие же? Ранее юзал китайскую t12 (70 Ватт) не понравилось очень длинная ручка, да и без фена не айс, спасибо за ответы

 

Oleg_D
Offline
Зарегистрирован: 13.06.2018

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

il86md
Offline
Зарегистрирован: 22.11.2017

ребят чет всё равно не так работает фен, при установочной T в 450 градусов, фен выдает активную 310 градусов на табло и больше не разогревается , при установочной в 200 активная темп 60 и не растет , после долгого нагрева выдет ошибку 6 , мол показания зависли ... 

при включении станции фен пракильно выводит комнатную температуру 25-27 гр

использую LM358, в прошивке раскоментировал дэфайн LM.

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

ошибки при компиляции в ардуино (не шарю в ардуино) версия 1.6.5

Sketch uses 13 764 bytes (44%) of program storage space. Maximum is 30 720 bytes.
Global variables use 471 bytes (22%) of dynamic memory, leaving 1 577 bytes for local variables. Maximum is 2 048 bytes.
WARNING: Spurious .github folder in 'Adafruit SSD1306' library
WARNING: Spurious .github folder in 'Adafruit SSD1306' library

при 300 установленной максимум 110 вырастает температура...фото ниже

по наминалам в кросзеро

PS походу никто не сталкивался с таким поведением, вроде физика вся работает чего не хватает? LM менял ничего не происходит кроме как заново калибровать

HELP ребята куда еще залезть щупом?

 

Bolotov75
Offline
Зарегистрирован: 15.06.2018

Доброго времени суток. Приглянулась и понравилась схема этой паяльной станции. Немного переделал под свои элементы. ZC пришлось собрать на резисторе и оптопаре РС814..... вот и итог)))).... оказалось, что нужно инвертировать сигнал на D3 МК. Добрые люди подскажите пожалуйста можно ли в програмном коде исправить и где? Я начинающий в программировании, боюсь понапортить в коде)))... прошивка    Soldering Station v 1.6.1 coded by OlegK. заранее благодарен

YURSA
YURSA аватар
Offline
Зарегистрирован: 28.09.2017

Посмотрите сообщение 2440

Oleg_D
Offline
Зарегистрирован: 13.06.2018

il86md пишет:

HELP ребята куда еще залезть щупом?

 


А на выходе zc сколько вольт? Иногда его притягивали 10к к 5в. У некоторых были проблемы при конденсаторе 2.2 uf 50v. Решалась заменой на 10uF. Иногда bt 139 глючил, ставили bt138. Остальное у Вас работает. Лмка вроде рабочая, температуру показывает верно. Тут элементов раз два и обчёлся. По коду - особо не подскажу. Дефайн раскоментировали - ок. У меня такие же ошибки вылазят. Ничего страшного, всё заливается. Больше ничего не трогал, работает нормально.

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

Исходя из доступного, у меня получилось так (схемы в архиве)

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

il86md
Offline
Зарегистрирован: 22.11.2017

провел ревизию крос зеро, заменил транзистор c а42 на 2n2222, проверил диод- ок, кондесатор в цепи эмиттера ставил 2,2 , потом 10 и в конце поставил среднее 4,7мкф керамику - изменений не было. а теперь по напряжеиям на резисторе 22k, диод, резистор 1к , на оптопаре диод и транзистор (4вольта как и должно быть)

Bolotov75
Offline
Зарегистрирован: 15.06.2018

YURSA, спасибо за быструю и четкую помощь)... исправил в коде, только не заработала схемка все же, у меня по такой же схеме узла ZC и симистора собрано как 2681 (какое совпадение)))) отличие только на ZC резюк стоит 30к 2 Вт, при этом ток светодиодов 7,5 мА (должно хватить как бы?) , а симисторная часть ВТ139 (360 Ом) и МОС3023 (470 Ом свето диод) обвязка как у всех.. а вот не работает... на МОС3023 с МК сигнал приходит какй то странный (пачки импульсов разрозненные).. резюки 360 Ом 2 Вт греются как больные)))... лампочка 40Вт (вместо фена) может не включится а может и невыключится и то в полнакала... как ей вздумеатся.... подскажите пожалуйста что я не так делаю? 

Oleg_D
Offline
Зарегистрирован: 13.06.2018

il86md
ZC в порядке. Какие номиналы резисторов в оу. У меня был lm358 посмотрите в моих предыдущих сообщениях номиналы и полные сопротивления , сравните.

Bolotov75
Там в схеме резисторы на 2.2к потому что напряжение 22 вольт. У вас тоже 22 Вольта? Если да, то 30к будет много. Для 220 В - нормально. Хотя у меня стоят 22к и 2 спаренных pc817 и всё работает. Смотрите что идёт с zc на МК. И что за светодиод? Если последовательно с 470 ом, - moc3023 может не заработать.

Bolotov75
Offline
Зарегистрирован: 15.06.2018

Oleg_D, ))) 22V ???!!!)))))).... только доглядел, что на той схеме. У меня 220.  а на МОС3023 стоит 470 и все. Победил уже, оказалось что 7,5 мА для РС814 маловато, поднял до 15 мА, на D3 пришлось подтяжку ставить 10к, не помогло... сигнал на осцилографе выглядел все равно худиньким)), поставил транзисторный ключ, получил нормальный "высокий" сигнал, вернул прошивку на место,  заменил ВТ139 (оказался с придурью)))).  ВСЕ заработало!!)))) Уже температуру откалибровал, в принципе очень доволен разработкой, молодцы Автор идеи и все кто учавствовал в таком полезном проекте. Вот только маленькие непонятности возникли во время обкатки, если Вам не трудно разъясните пожалуйста:

1. на фене на оборотах ниже 100%, начинаеют творится чудеса, срабатывает таймер, загорается 10, фен на продувку, нагрев отключается. сначала подумал канал геркона глючит, поставил подтяжку, не помогло. Что это может быть такое? барабахи какие могли завестись?))))

2. после установки фена на подставку, остывает до 50 градусов, вент выключается, температура ползет до 70 (пр.). Вент должен повторно включиться на сброс температуры или нет? Фен жалко как то)))

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

Уважаемые автор и все форумчане. Хочу повторить этот проект на голой Atmega168, так как их много валяется без дела. В программировании не силён, поэтому прошу кого-нибудь проверить, правильно я переназначил пины в скетче? Скетч и печатка лежат здесь https://yadi.sk/d/_rMBX16E3aLfHm 

Заранее огромное спасибо.

YURSA
YURSA аватар
Offline
Зарегистрирован: 28.09.2017

Bolotov75 пишет:

YURSA, спасибо за быструю и четкую помощь)... исправил в коде, только не заработала схемка все же, у меня по такой же схеме узла ZC и симистора собрано как 2681 (какое совпадение)))) отличие только на ZC резюк стоит 30к 2 Вт, при этом ток светодиодов 7,5 мА (должно хватить как бы?) , а симисторная часть ВТ139 (360 Ом) и МОС3023 (470 Ом свето диод) обвязка как у всех.. а вот не работает... на МОС3023 с МК сигнал приходит какй то странный (пачки импульсов разрозненные).. резюки 360 Ом 2 Вт греются как больные)))... лампочка 40Вт (вместо фена) может не включится а может и невыключится и то в полнакала... как ей вздумеатся.... подскажите пожалуйста что я не так делаю? 

Многослоен я не буду, но при использовании PC814 более-менее адекватный сигнал получается при токе светодиодов от 20ти миллиампер, посммотрите даташит на оптопару https://www.alldatasheet.com/datasheet-pdf/pdf/43364/SHARP/PC814.html Я использовал из ряда 2210 по 68кОм два штуки в послед, ток через светодиоды PC814 получился точно не помню но около 25-30 мА

 

YURSA
YURSA аватар
Offline
Зарегистрирован: 28.09.2017

Ещё раз риветствую сех.

Попытался переделать вриант от  Spinne под энкодер в версию 1.6.1

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                    Soldering Station v 1.6.1              */
/*                        coded by OlegK                     */
/* arduino.ru/forumy/proekty/ocherednaya-payalnaya-stantsiya */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 
#include <EEPROM.h>
#include <CyberLib.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Bounce2.h>
#include <avr/io.h>
#include <avr/interrupt.h>
 
/* it's fuckin' magic! */
#if 1
__asm volatile ("nop");
#endif
 
/* Options */
 
/* если вам нужно создать их диаграмму, то раскомментируйте ее */
//#define NEED_GRAPH
 
/* если используется не rail-to-rail OPA, то раскомментируйте ее */
//#define LM358
 
/* если используется пассивный busser, то раскомментируйте его */
//#define PASSIVE_BUZZER
 
/* если вы хотите отключить дополнительную защиту, то прокомментируйте это */
#define HA_ADV_PROT_ON
#define S_ADV_PROT_ON
 
/* if used LCD 1602, then uncomment it */
//#define LCD_1602
 
/* Паяльник - если вы хотите удалить прыжки цифр, то раскомментируйте его */
//#define SOLDER_DIGIT_JUMPS_REMOVE
 
/* Фен - если вы хотите удалить прыжки цифр, тогда раскомментируйте его */
//#define HOTAIR_DIGIT_JUMPS_REMOVE
 
/* если вы хотите мягкий старт паяльника, тогда раскомментируйте его */
//#define SOLDER_SOFT_START
 
/* если вы хотите активировать паяльник, таймер только на стенде, тогда раскомментируйте его */
#define SOLDER_TIMER_ON_STAND
 
/*если используется ENCODER, тогда раскомментируйте его */
#define ENCODER 
 
/* End options */
 
 
#define FIRMWARE_VERSION "1.6.1enc"
 
#ifdef LCD_1602
LiquidCrystal_I2C lcd(0x27, 16, 2);
#else
LiquidCrystal_I2C lcd(0x27, 20, 4);
#endif
 
 
/* Символ градуса */
uint8_t degree[8] = {
    B01100,
    B10010,
    B10010,
    B01100,
    B00000,
    B00000,
    B00000,
    B00000
};
 
/* Символ стрелки */
uint8_t arrow[8] =  {
    B00000,
    B00100,
    B00010,
    B11111,
    B00010,
    B00100,
    B00000,
    B00000
};
 
/* селектор режимов */
#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;
 
#ifdef ENCODER
uint32_t Enc_ButtonPressTime = 0;
boolean Enc_ButtonState;
#else
uint32_t UPbuttonPressTime = 0;
uint32_t DWNbuttonPressTime = 0;
boolean UPbuttonState, DWNbuttonState,
#endif
 
uint32_t SONbuttonPressTime = 0;
uint32_t HAONbuttonPressTime = 0;
boolean SONbuttonState, HAONbuttonState;
 
byte Count;
uint16_t Duration, Interval;
 
char bspace[ ] = "    ";
 
#define pinBuzzer 12
#define pinFanPwm 6
#define pinSolderPwm 5
 
#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
 
/* Кнопки */
#define sw_HA 10
#define sw_S 9
#define bt_SON 13
#define bt_HAON 14
/*Енкодер*/
#ifdef ENCODER
#define e_button 15 //pin A1 button
#define e_dir 16    //pin A2 enc_a
#define e_step 17   //pin A3 enc_b
#else
#define bt_Sel 15   //pin A1
#define bt_Up 16    //pin A2
#define bt_Dwn 17   //pin A3
#endif
 
/* Bounce killers */
Bounce swHotAir = Bounce();
Bounce swSolder = Bounce();
Bounce SolderOnButton = Bounce();
Bounce HotAirOnButton = Bounce();
 
#ifdef ENCODER
Bounce Enc_Button = Bounce();
#else
Bounce SelButton = Bounce();
Bounce UpButton = Bounce();
Bounce DwnButton = Bounce();
#endif
 
/* Hot Air */
 
/* states */
#define st_stop 0
#define st_work 1
#define st_pause 2
#define st_protection 3
//#define st_lowpower 4
 
byte hotair_state = st_stop;
 
volatile uint16_t ots = 9990;
volatile float HAPower = 0.0;
uint16_t GetHotAirT = 0;
uint16_t SetHotAirT = 100;
byte SetHotAirRPM = 100;
boolean HA_temp_stable = false;
boolean need_Cooling = true;
boolean scr_blink = false;
 
byte ha_error = 0;
boolean HA_prot_beep = false;
boolean ha_f1 = false;
boolean ha_f2 = false;
uint32_t prevHAcontrol;
 
/* HA PI regulator */
#define Kp 1.0
#define Ki 0.007 //0.003 //0.005 //0.05
int integral = 0;
 
/* Soldering iron */
uint16_t GetSolderT = 0;
uint16_t SetSolderT = 100;
boolean S_temp_stable = false;
boolean SolderON = false;
boolean SolderProtect = false;
int SPower = 0;
//byte solder_state = st_stop;
 
byte s_error = 0;
uint32_t prevScontrol;
boolean S_prot_beep = false;
boolean s_f1 = false;
boolean s_f2 = false;
 
/* Solder P regulator */
#define sKp 50
 
uint16_t last_HotAirT, last_SolderT;
byte last_RPM;
 
 
/********************************************* ОСНОВНЫЕ ПРОЦЕДУРЫ *********************************************/
 
void setup() {
    //ADC change speedup
    //ADCSRA &= ~(1 <<ADPS2) | (1 <<ADPS1) | (1 <<ADPS0); // reset default divider 128
    //ADCSRA |= 1 <<ADPS2; // set div to 16 (1MHz)
    //ADCSRA |= 1 <<ADPS1; // set div to 64 (250kHz)
 
    pinMode(3, INPUT_PULLUP); //Zero cross pin
    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();
 
    /* Отключение таймера для фена, обратный отсчет с 1 минутой */
    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) {
                    Beep(100);    //Звуковой сигнал, если осталось 1 минута
                }
            } else {
                hotair_state = st_stop;
                Beep(200);
            }
        }
    } else {
        prevHAmillis = millis();
    }
 
    /* Таймер отключения для паяльника, обратный отсчет с 1 минутой */
    static uint32_t prevSmillis = millis();
    if (need_S_countdown) {
        if (millis() - prevSmillis > 60000) {
            if (S_countdown > 1) {
                S_countdown--;
                if (S_countdown == 1) {
                    Beep(100);    //Звуковой сигнал, если осталось 1 минута
                }
            } else {
                MemSolder();
                need_S_countdown = false;
                SolderON = false;
                Beep(200);
            }
            prevSmillis = millis();
        }
    } else {
        prevSmillis = millis();
    }
 
    /* Обновить ЖК-дисплей с интервалом 500 мс */
    static uint32_t prevDisplayMillis = millis();
    static boolean blink_state = true;
    if (millis() - prevDisplayMillis > 500) {
        scr_blink = ! scr_blink;
        prevDisplayMillis = millis();
        DisplayUpdate(blink_state);
        blink_state = !blink_state;
 
        /* Отправка данных в последовательный порт */
#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
    }
 
    WorkWithHotAir();
    WorkWithSolder();
}
 
/* Рабочая процедура HotAir */
void WorkWithHotAir() {
 
    /* Прочитать значение термопары */
#ifdef LM358
    GetHotAirT = getOversampled_HA();
#else
    GetHotAirT = getOversampled_HA() >> 1;
#endif
 
    switch (hotair_state) {
    case st_stop: {
        HotAirOff();
        Cooling();
        break;
    }
 
    case st_work: {
        /* Установите крутящий момент охладителя (конвертировать от 30-100% до 80-255 ШИМ) */
        analogWrite(pinFanPwm, map(SetHotAirRPM, min_rpm, max_rpm, 80, 255));
 
        ha_error = HADoProtect();
 
        /* Включить реле защиты */
        if (ha_error == 0) D7_High;
 
        /* Регулятор температуры PI */
        HA_PI();
 
        /* Если температура была стабильной в 100 раз (+/- 2 градуса), тогда сигнализируем об этом
 */
        int delta = ABS(SetHotAirT, GetHotAirT);
        static byte HAgood;
        if (!HA_temp_stable) {
            if (delta < 3) {
                HAgood++;
                if (HAgood == 100) {
                    Beep(50);
                    delay_ms(200);
                    Beep(50);
                    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 */
void WorkWithSolder() {
 
    /* Прочитать значение терморезистора */
    //GetSolderT = A6_Read >> 1;
#ifdef LM358
    GetSolderT = getOversampled_S();
#else
    GetSolderT = getOversampled_S() >> 1;
#endif
 
    if ( SolderON ) {
        s_error = SDoProtect();
 
        /* Включить реле защиты */
        if (s_error == 0) D4_High;
 
        /* регулятор температуры P */
        S_P();
 
        /* Если их температура была стабильной для 200-кратного цикла (+/- 2 градуса), тогда сигнализируем об этом */
        uint16_t delta = ABS(SetSolderT, GetSolderT);
        static byte Sgood;
        if (!S_temp_stable) {
            if (delta < 3) {
                Sgood++;
                if (Sgood == 200) {
                    Beep(50);
                    delay_ms(200);
                    Beep(50);
                    //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;
    }
}
 
/***************************************** КОНЕЦ ОСНОВНЫХ ПРОЦЕДУР ******************************************/
 
 
 
/****************************************** ЗАЩИТА И ВКЛ-ВЫКЛ ********************************************/
 
/* Защита HotAir */
byte HADoProtect() {
 
    /* ------------------------------------------------------------------------------------------------------- */
 
    /* Crytical protection: высокое значение перегрева или термопары недействительно или разрыв провода */
    if (GetHotAirT > max_hotair_temp + 20) {
        HAProtectionOut();
        return 1;
    }
 
    /* ------------------------------------------------------------------------------------------------------- */
 
    /* Crytical protection: thermocouple value is not valid or wiresCrytical protection: значение термопары недействительно или короткое замыкание на провода short circuit */
    if (GetHotAirT < 10) {
        HAProtectionOut();
        return 2;
    }
 
    /* ------------------------------------------------------------------------------------------------------- */
 
#ifdef HA_ADV_PROT_ON
 
    /* Защита от перегрева*/
    if (ha_f1 && GetHotAirT > SetHotAirT + 20) {
        ha_f1 = false;
        HAProtectionOut();
        return 3;
    }
 
    if (ha_f2 && GetHotAirT < SetHotAirT + 15) {
        ha_f1 = true;
        ha_f2 = false;
    }
 
    /* ------------------------------------------------------------------------------------------------------- */
 
    /* Отклонение от температуры защиты +/- 10 градусов */
    //if (HA_temp_stable) {
    //ha_f3 = true;
    //}
//
    //if (ha_f3) {
    //if (GetHotAirT > SetHotAirT + 10) {
    //HAProtectionOut();
    //return 4;
    //}
//
    //if (GetHotAirT < SetHotAirT - 10) {
    //HAProtectionOut();
    //return 5;
    //}
    //}
 
    /* ------------------------------------------------------------------------------------------------------- */
 
 
 
    /* Расширенная защита: температура падает / не изменяется, а мощность> 0 */
    /* & */
    /* Усовершенствованная защита: повышение температуры и мощность <0 */
    static byte t_cnt = 0;
    static byte t_cnt2 = 0;
    static boolean ha_ctrl = true;
    if (!HA_temp_stable) {
        static uint16_t prev_t;
        if (ha_ctrl) {
            prev_t = GetHotAirT;
            ha_ctrl = false;
            prevHAcontrol = millis();
        }
 
        if (!ha_ctrl && millis() - prevHAcontrol > 1000) {
            ha_ctrl = true;
 
            if (HAPower > 0.0) {
 
                /* температура падает или не изменяется */
                if (prev_t >= GetHotAirT && GetHotAirT < SetHotAirT) {
                    t_cnt++;
                    if (t_cnt == 7) {
                        HAProtectionOut();
                        t_cnt = 0;
                        return 6;
                    }
                } else t_cnt = 0;
 
            } else { //HAPower == 0.0
 
                /* повышение температуры */
                if (prev_t < GetHotAirT && GetHotAirT > SetHotAirT) {
                    t_cnt2++;
                    if (t_cnt2 == 7) {
                        HAProtectionOut();
                        t_cnt2 = 0;
                        return 7;
                    }
                } else t_cnt2 = 0;
            }
        }
    } else {
        prevHAcontrol = millis();
        t_cnt = 0;
        t_cnt2 = 0;
        ha_ctrl = true;
    }
 
#endif
 
    /* ------------------------------------------------------------------------------------------------------- */
 
    /* если все в порядке */
    return 0;
}
 
/* Защита паяльника */
byte SDoProtect() {
 
    /* ------------------------------------------------------------------------------------------------------- */
 
    /* Критическая защита: высокое значение перегрева или терморезистора недействительно или разрыв провода */
    if (GetSolderT > max_solder_temp + 20) {
        SProtectionOut();
        return 1;
    }
 
    /* ------------------------------------------------------------------------------------------------------- */
 
    /* Критическая защита: значение терморезистора недействительно или короткое замыкание на провода */
    if (GetSolderT < 10) {
        SProtectionOut();
        return 2;
    }
 
    /* ------------------------------------------------------------------------------------------------------- */
 
#ifdef S_ADV_PROT_ON
 
    /* Защита от перегрева */
    if (s_f1 && GetSolderT > SetSolderT + 20) {
        s_f1 = false;
        SProtectionOut();
        return 3;
    }
 
    if (s_f2 && GetSolderT < SetSolderT + 15) {
        s_f1 = true;
        s_f2 = false;
    }
 
    /* ------------------------------------------------------------------------------------------------------- */
 
    /* Отклонение от температуры защиты +/- 10 градусов */
    //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;
    //}
    // }
 
    /* ------------------------------------------------------------------------------------------------------- */
 
 
 
    /* Расширенная защита: температура падает / не изменяется, а мощность> 0 */
    /* & */
    /* Усовершенствованная защита: повышение температуры и мощность <0 */
    static byte t_cnt = 0;
    static byte t_cnt2 = 0;
    static boolean s_ctrl = true;
    if (!S_temp_stable) {
        static uint16_t prev_t = 0;
        if (s_ctrl) {
            prev_t = GetSolderT;
            s_ctrl = false;
            prevScontrol = millis();
        }
 
        if (!s_ctrl && millis() - prevScontrol > 1000) {
            s_ctrl = true;
 
            if (SPower > 0) {
                /* температура падает или не изменяется */
                if (prev_t >= GetSolderT && GetSolderT < SetSolderT) {
                    t_cnt++;
                    if (t_cnt == 10) {
                        SProtectionOut();
                        t_cnt = 0;
                        return 6;
                    }
                } else t_cnt = 0;
            } else { //SPower == 0
                /* повышение температуры */
                if (prev_t < GetSolderT && GetSolderT > SetSolderT) {
                    t_cnt2++;
                    if (t_cnt2 == 10) {
                        SProtectionOut();
                        t_cnt2 = 0;
                        return 7;
                    }
                } else t_cnt2 = 0;
            }
        }
    } else {
        prevScontrol = millis();
        t_cnt = 0;
        t_cnt2 = 0;
        s_ctrl = true;
    }
 
#endif
 
    /* ------------------------------------------------------------------------------------------------------- */
 
    /* все в порядке */
    return 0;
}
 
/* Solder full off */
void SolderOff() {
    analogWrite(pinSolderPwm, 0);
    D5_Low;
    D4_Low;
    resetSolderStablePoint();
    if (S_prot_beep) {
        S_prot_beep = false;
        Beep(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;
        Beep(1000);
        MemHotAir();
    }
}
 
/* Охлаждение нагревателя до температуры ниже 50 градусов */
void Cooling() {
    if (GetHotAirT >= 50 && need_Cooling) {
        analogWrite(pinFanPwm, 255);
    } else {
        analogWrite(pinFanPwm, 0);
        need_Cooling = false;
    }
}
 
/* внутренняя процедура */
void set_ha_f() {
    boolean a = SetHotAirT >= GetHotAirT;
    ha_f1 = a;
    ha_f2 = !a;
}
 
/* внутренняя процедура */
void set_s_f() {
    boolean a = SetSolderT >= GetSolderT;
    s_f1 = a;
    s_f2 = !a;
}
 
/* Защита паяльника */
void SProtectionOut() {
    SolderProtect = true;
    S_prot_beep = true;
    SolderON = false;
    SolderOff();
}
 
/* Защита фена */
void HAProtectionOut() {
    analogWrite(pinFanPwm, 255);
    HA_prot_beep = true;
    HotAirOff();
    hotair_state = st_protection;
}
 
/****************************************** КОНЕЦ ЗАЩИТЫ И ВКЛ-ВЫКЛ *************************************/
 
 
 
/************************************************ ДРУГИЕ РЕЖИМЫ *******************************************/
 
/* Чтение целочисленного значения */
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;
}
 
/* Запись целочисленного значения */
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]);
    }
}
 
/* Чтение последних параметров из памяти */
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;
    }
}
 
/* Записывать последнюю использованную температуру паяльника в память */
void MemSolder() {
    if (last_SolderT != SetSolderT) {
        EEPROM_int_write(0, SetSolderT);
        last_SolderT = SetSolderT;
    }
}
 
/* Записывать последнюю использованную температуру фена и обороты куллера в память */
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;
    }
}
 
/* Звуковая процедура */
void Beep(uint16_t duration) {
#ifdef PASSIVE_BUZZER
    tone(pinBuzzer, 1000, duration);
#else
    D12_High;
    delay_ms(duration);
    D12_Low;
#endif
}
 
/* Функция передискретизации HotAir */
//uint16_t getOversampled_HA() {
//uint32_t tmp = 0;
//for (byte z = 0; z < 64; z++) {
//tmp +=  A7_Read;
//}
//return tmp >> 6;
//}
 
uint16_t getOversampled_HA() {
    uint32_t tmp = 0;
    for (byte z = 0; z < 128; z++) {
        tmp +=  A7_Read;
    }
    return tmp >> 7;
}
 
/* Функция передискретизации паяльника */
uint16_t getOversampled_S() {
    uint32_t tmp = 0;
    for (byte z = 0; z < 64; z++) {
        tmp +=  A6_Read;
    }
    return tmp >> 6;
}
 
/* Получить функцию абсолютной разности */
uint16_t ABS(uint16_t a, uint16_t b) {
    if (a > b) {
        return (a - b);
    }
    return (b - a);
}
 
/****************************************** КОНЕЦ ДРУГИХ РЕЖИМОВ ******************************************/
 
 
 
/*************************************** АВТОМАТИЧЕСКОЕ УПРАВЛЕНИЕ СИМИСТОРОМ ****************************************/
 
/* Zero cross INT1 */
void ZC() {
    StartTimer1(HeaterOn, ots);
    RestartTimer1();
}
 
/* Triac open impulse */
void HeaterOn() {
    StopTimer1();
    if (HAPower > 0.0) {
        D8_High;
        delay_us(30);
    }
    D8_Low;
}
 
/* Вычислить задержку триггера */
void CalctImpulseControl() {
    ots = (uint16_t)(acos(HAPower / 50.0 - 1.0 ) * 9900.0 / pi);
}
 
/* Регулятор HotAir PI */
void HA_PI() {
    int err = SetHotAirT - GetHotAirT;
    float tmp_power = ((Kp * (float)err) + (Ki * (float)integral));
    float max_power = map((float)SetHotAirT, min_hotair_temp, max_hotair_temp, 10.0, 60.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 с плавным пуском */
void S_P() {
    int TempPower = sKp * (SetSolderT - GetSolderT + 1);
    byte maxPower = 255;
    if (GetSolderT < 100) {
        maxPower = 100;
    }
    SPower = constrain(TempPower, 0, maxPower);
    analogWrite(pinSolderPwm, SPower);
}
#else
/* Регулятор Solder P */
void S_P() {
    int TempPower = sKp * (SetSolderT - GetSolderT + 1);
    SPower = constrain(TempPower, 0, 255);
    analogWrite(pinSolderPwm, SPower);
}
#endif
 
/************************************* END АВТОМАТИЧЕСКОЕ УПРАВЛЕНИЕ СИМИСТОРОМ ***********************************/
 
 
 
/****************************************КОНТРОЛЬ ИНТЕРФЕЙСА И ТАЙМЕРЫ **************************************/
 
/* сканирование кнопок */
void ScanButtons() {
 
    /*  переключатель подсставки фена */
    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() ;
            }
        }
        Beep(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
 
    /* Выключатель подставки паяльника - только на подставке */
    if (swSolder.update()) {
        if (swSolder.fell() && SolderON) {
            if (!need_S_countdown) {
                Activate_S_countdown();
                Beep(50);
            }
        }
 
        if (swSolder.rose())  {
            if (need_S_countdown) {
                need_S_countdown = false;
                Beep(50);
            }
        }
    }
 
#else
 
    /* Выключатель подставки для паяльника простой проверки активности пользователя */
    if (swSolder.update() && SolderON) {
        resetSolderCountdown();
        Beep(50);
    }
 
#endif // SOLDER_TIMER_ON_STAND
 
    /* Кнопка паяльника «включено-выключено» */
    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();
            Beep(50);
        }
    }
 
    if  (SONbuttonState) {
        if ( millis() - SONbuttonPressTime >= 1000 ) { //удержание кнопки
            SONbuttonPressTime = millis();
            if (SolderON) {
                SolderON = false;
                resetSolderStablePoint();
                MemSolder();
                Beep(200);
            }
        }
    }
 
    /* 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();
            Beep(50);
        }
    }
 
    if  (HAONbuttonState) {
        if ( millis() - HAONbuttonPressTime >= 1000 ) { //long press
            HAONbuttonPressTime = millis();
            resetHotAirStablePoint();
            if (hotair_state == st_work || hotair_state == st_pause) {
                hotair_state = st_stop;
                need_Cooling = true;
                MemHotAir();
                Beep(200);
            }
        }
    }
 
#ifdef ENCODER    
    /* Короткое нажатие кнопки Encoder */
    if (Enc_Button.update()) {
        if (Enc_Button.fell()) {
            Beep(50);
            Enc_ButtonPressTime = millis();
            Enc_ButtonState = true;
        } else {
            if (Enc_ButtonState) {
                (selected_Mode < modeFanPWM) ? (selected_Mode++) : (selected_Mode = modeSolder);
            }
            Enc_ButtonState = false;
        }
    }
#else
    /* Кнопка выбора */
    if (SelButton.update()) {
        if (SelButton.fell()) {
            Beep(50);
            (selected_Mode < modeFanPWM) ? (selected_Mode++) : (selected_Mode = modeSolder);
        }
    }
 
    /* Кнопка ВВЕРХ */
    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();
            Beep(50);
        }
    }
 
    /* Кнопка вверх (длительное нажатие) */
    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;
                resetSolderStablePoint();
                set_s_f();                
                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;
            }
        }
    }
 
    /* Кнопка Вниз */
    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();
                //integral = 0;
            }
 
            DWNbuttonState = true;
            short_press_flag = true;
            DWNbuttonPressTime = millis();
            Beep(50);
        }
    }
 
    /* Кнопка «Вниз» (длительное нажатие) */
    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();
                //integral = 0;
            }
        }
    }
#endif
}
 
#ifdef ENCODER 
/* Encoder interrrupt */
ISR(PCINT1_vect) {
    static byte old_n=PINC & B1100; // ????? B00001100 ??? ? ?????? ?????? ?????? 2 ????
    byte new_n = PINC & B1100;
 
    if (old_n == B0100 && new_n == B1100 || old_n == B1000 && new_n == B0000) { //CW turn
            
            switch (selected_Mode)
      {
            case modeSolder:
                if (SetSolderT < max_solder_temp)
              { SetSolderT += 5; }
                resetSolderStablePoint();
                set_s_f();
                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();
            }
            Beep(50);
    }
    
    if (old_n == B1000 && new_n == B1100 || old_n == B0100 && new_n == B0000) { //CCW turn
            
            switch (selected_Mode) 
      {
            case modeSolder:
                if (SetSolderT > min_solder_temp)
              { SetSolderT -= 5; }
                resetSolderStablePoint();
                set_s_f();
                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();
            }
            Beep(50);
    }
    old_n = new_n;
}
#endif
 
/* Инициализация кнопок */
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);
 
#ifdef ENCODER
    pinMode(e_button, INPUT_PULLUP);//enc button 
    Enc_Button.attach(e_button);
    Enc_Button.interval(5);
    
    pinMode(e_dir, INPUT_PULLUP);   //pin A2 enc_a
    
    pinMode(e_step, INPUT_PULLUP);  //pin A3 enc_b
 
    PCICR=1<<PCIE1;     // enable interrrupt for group 1
    PCMSK1 |= (1 << PCINT10) | (1 << PCINT11);  // This enables the interrupt for pin 2 and 3 of Port C.   
#else
    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);
#endif
}
 
/* внутренняя процедура */
void resetHotAirStablePoint() {
    HA_temp_stable = false;
}
 
/* внутренняя процедура */
void resetSolderStablePoint() {
    S_temp_stable = false;
}
 
/* Сбросить обратный отсчет HotAir */
void resetHotAirCountown() {
    HA_countdown = HA_sleeptime;
}
 
/* Сброс обратного отсчета паялька */
void resetSolderCountdown() {
    S_countdown = S_sleeptime;
}
 
/* Активировать процедуру обратного отсчета паяльника */
void Activate_S_countdown() {
    need_S_countdown = true;
    S_countdown = S_sleeptime;
}
 
/**************************************** КОНТРОЛЬ ИНТЕРФЕЙСА И ТАЙМЕРЫ **************************************/
 
 
/************************************************* 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);
}
 
/*Настройка ЖК-дисплея */
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
}
 
/* Обновить ЖК-дисплей */
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 ********************************************/
 

 



Если у кого собранно в железе проверьте пожалуйсто на работоспособность

YURSA
YURSA аватар
Offline
Зарегистрирован: 28.09.2017

Проу прощения, маленько не понял как код в спойлер свернуть

YURSA
YURSA аватар
Offline
Зарегистрирован: 28.09.2017

alex1978 пишет:

Уважаемые автор и все форумчане. Хочу повторить этот проект на голой Atmega168, так как их много валяется без дела. В программировании не силён, поэтому прошу кого-нибудь проверить, правильно я переназначил пины в скетче? Скетч и печатка лежат здесь https://yadi.sk/d/_rMBX16E3aLfHm 

Заранее огромное спасибо.

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

Разводка проводников на плате,в принципе удачно получается.

YURSA
YURSA аватар
Offline
Зарегистрирован: 28.09.2017

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

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

YURSA пишет:

alex1978 пишет:

Уважаемые автор и все форумчане. Хочу повторить этот проект на голой Atmega168, так как их много валяется без дела. В программировании не силён, поэтому прошу кого-нибудь проверить, правильно я переназначил пины в скетче? Скетч и печатка лежат здесь https://yadi.sk/d/_rMBX16E3aLfHm 

Заранее огромное спасибо.

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

Разводка проводников на плате,в принципе удачно получается.

Вы я так понял, скетчи не правили, просто плату переразвели под голый камень? Я бы не сказал, что в этом случае плата удачно разводится. Кроме того, у меги в ДИП корпусе отсутствуют пины А6 и А7. По любому переназначать надо.

YURSA
YURSA аватар
Offline
Зарегистрирован: 28.09.2017

Прошу прощения если ввёл в заблуждение, у меня камни в корпусе SOIC как и на ардуинке предлагаемой автором.

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

Я так и понял. В таком случае ничего менять не надо. Только кварц на плату вывести.

YURSA
YURSA аватар
Offline
Зарегистрирован: 28.09.2017

Да кварц обязательно, ещё надо бы залить загрузчик чтобы через ТТЛ можно было бы заливать скетч,сннимать графики,так я думаю проще будет

Bolotov75
Offline
Зарегистрирован: 15.06.2018

YURSA , добый день. поясните пожалуйста "ряд 2210" ?)).... у меня два по 30к 2Вт в параллель стоят и ток 15 мА, чтото не сходится. по моим рассчетам для тока 20-25 мне резюки под 5 Вт нужно тулить.... место уже непозволяет(((

Oleg_D
Offline
Зарегистрирован: 13.06.2018

YURSA пишет:

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


Я так и сделал. Последовательно, после 470 Ом, перед оптопарой канала реле, на стороне ардуино. Работает без корректировки номинала резистора. Хотя можно чуть чуть уменьшить номинал резистора, будет светить ярче. Меня устраивает.

Bolotov75
Offline
Зарегистрирован: 15.06.2018

YURSA, и еще вопросик. не подскажите по поводу вопросов в #2685

il86md
Offline
Зарегистрирован: 22.11.2017
санта барбара продолжается... Устал ковырят не пойму в чем дело...
кросзеро и управление BT136 графики выкладываю - считаю идеал(!) 
 
настройка резисторов ФЕН: Начало 420R (постоянный)+860R (переменный)= 1280R; Шкала 50K+15K=65K (мне кажется малова-то но тогда я не могу установить температуру станции с реальной)
 
 
У кого есть схема усилителя под ДВЕ ТЕРМОПАРЫ? 
YURSA
YURSA аватар
Offline
Зарегистрирован: 28.09.2017

Bolotov75 пишет:

YURSA , добый день. поясните пожалуйста "ряд 2210" ?)).... у меня два по 30к 2Вт в параллель стоят и ток 15 мА, чтото не сходится. по моим рассчетам для тока 20-25 мне резюки под 5 Вт нужно тулить.... место уже непозволяет(((

Прошу прощения опечатка вышла, резистор SMD ТИПОРАЗМЕРРА 2010 (5025) 68 килоом два шт. последовательно, мощность 0,75Вт . У меня греются судя по тепловизору 50-60 градусов, ток упоминал выше,номинал подбирал эксперементально. 

http://wow-only.ru/2011-04-14-14-57-54/51-2011-05-05-16-47-48/234-smd.html