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

sergik5
Offline
Зарегистрирован: 28.01.2018

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

Вот вспомнил, допустим выставил шкала начало у фена 24гр., канал фена выключен -фен на столе лежит. Перемещаю фен на подставку и температура на табло растет до 28гр. Это магнит так на термопару влияет ?

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

У меня примерно так же - чуть больше минуты жало подтягивается к заданной точке. Тут только смириться ))

sergik5 пишет:
Это магнит так на термопару влияет ?

Попробовал у себя, такой эффект проявляется, но крайне незначительно. Водил круглым магнитом от динамика (D~6см), слышно, как геркон клацает. Показания без магнита стоят колом на значении 21 град., при поднесении магнита - тоже, но изредка всё же выпрыгивает 22. Какое-то влияние всё же имеет место быть, но, повторюсь, очень незначительное...

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

snag пишет:

OlegK пишет:
Вот есть интересная статья на эту тему.

Прочел внимательно (как и книжку Карпова), от туда и взял что бусины давят в более высокочастотном диапазоне :-). Только я бусинами назвал SMD элементы (похожи не кондеры). Транзистортестер их считает пикофарадной емкостью))). Мультимером в них несколько ом. У них же импеданс. 

Получил только сейчас паяльник и фен. Продавец, редиска, подсунул паяльник с термопарой, хотя в описании лота -керамика, да и на фото А1321. Буду скандалить.

Да и фен подозрительный - проводки тонковаты, и турбинка 24в, 0,15 а, хотя обычно там 0,25а. Уж не на 110 вольт ли он мне подсунул. Не подскажите как это определить? Сопротивление спирали 73 Ом.

Мне тоже такой козёл попался, с термопарой прислал. Спор я проиграл, али принял сторону продавца. Турбинка тоже на 0,15А, но фен работает нормально, без нареканий. Хотя поначалу казалось что поток воздуха слабоват. По факту редко когда поднимаю поток выше 40%. Только когда много термоусадки надо осадить выкручиваю в 80%

snag
Offline
Зарегистрирован: 29.05.2015

alex1978 пишет:

Мне тоже такой козёл попался, с термопарой прислал. Спор я проиграл, али принял сторону продавца.

Уж не Summer Repair ли?

Я еще на почте почувствовал не ладное - вскрыл - а паяльник типа поломан под углом (хотя скрутил все нормально) взял на всякий случай акт. Посмотрю на его реакцию.

А если смотреть философски - меньше будет потреблять тока - можно обойтись без мягкого старта.

Да и продаются жала А1321 не дорого. А пока придется обходиться тем что есть :-)

И нужно сказать что жало подогнано точно без зазора. Но то что шнур 65 см - это конечно плохо ((

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

Ха, именно этот козёл. И тоже паяльник кривой был. И шнур короткий. В общем докупил уже полтора метра шнура в силиконе, пару новых гаек с прижимной втулкой, нагреватель еще не приехал. И ценник на паяльник ощутимо вырос. Можно было сразу хаковский оригинал покупать. :) А вот с феном все хорошо. Тоже конечно не супер, но в пределах нормы.

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

alex1978 пишет:
Мне тоже такой козёл попался, с термопарой прислал. Спор я проиграл, али принял сторону продавца.

Скорее всего, если открывать спор с полным возвратом, то так и будет. Возможно, следует оспаривать половину суммы, апеллируя к тому, что товар не такой, как заявлен (обязательно приложить фото). Особенно, если покупаешь паяльник под замену для уже готовой ПС - с другим термодатчиком она просто не будет работать.
А на возвращённую сумму можно прикупить нагревателей с терморезистором.

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

Так и было. Спор открывал на половину. Продавец сказал хрен тебе, и али принял его сторону.

snag
Offline
Зарегистрирован: 29.05.2015

Коллеги, отпишитесь пожалуйста кто заказывал керамические нагреватели у адекватного продавца и пользуется относительно продолжительное время.

Понятно все HAKKO А1321 - это HAKO или HAKD, есть жалобы на продольную щель вдоль нагревателя. Адекватных отзывов мало - "не проверял, но вешь хорошая". Еще по ссылке на нагреватель, что давал Олег указано 220в (возможно лот сменили). Хотя довольно часто попадается 220в. Это китайские вольты или китайская блондинка-менеджер? :-)

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

Китайские описания иной раз нужно воспринимать с юмором ))
По нагревателям.
Там, где я брал, товар уже закончился, но зная, как выглядят оригинальные и обязательно читая отзывы, можно найти искомое.
Хорошие вряд ли ниже 240-250р стоят.

snag
Offline
Зарегистрирован: 29.05.2015

Добрый день, Олег! Спасибо. Вижу Вы в онлайне. Подбираю элементы попутно изучаю. Вопрос по пищалке - есть 3 шт. - пассивный, активный из набора ардуино, и один активный для повторителя поворотов на авто (который бодро пищит от 3 вольт). Склоняюсь использовать активный - не стоит дергать таймеры.

У меня вопрос по подключению - резистор и транзистор это вроде схема подключения пассивного, а почему активный не подключить напрямую? Столкнулся с тем что вблизи не нашел 814 (ближайший магазин 150 км) Не подскажите в каком доноре можно поискать?

Энкодер - Вы рекомендовали кондеры 22-150 nF. В теме Dimax-a подняли по этому поводу хай что 0,1 мкф гробят контакты.

Какой оптимальный по Вашему мнению номинал.

Извиняюсь, если засоряю тему...   

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

snag пишет:
У меня вопрос по подключению - резистор и транзистор это вроде схема подключения пассивного, а почему активный не подключить напрямую?

Мой буззер относительно много потребляет (на пределе нагрузки пина), поэтому, на всякий случай, я его через ключ включил. Если у Вас более экономичная пищалка, то можно и без ключа.

Цитата:
Столкнулся с тем что вблизи не нашел 814

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

Цитата:
В теме Dimax-a подняли по этому поводу хай что 0,1 мкф гробят контакты.

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

Цитата:
Извиняюсь, если засоряю тему...
 
Да, вроде всё по теме ))

snag
Offline
Зарегистрирован: 29.05.2015

OlegK пишет:

Если у Вас более экономичная пищалка, то можно и без ключа.

:-) Сам не догадался...

Ардуиновский потребляет 21 мА, а автомобильный, как я понимаю 12 вольтовый, 7,5 всего. Орёт конечно потише, но даже заклееный вполне слышно. Его и вкрячу.

И еще, Олег, чтобы не городить два этажа, какие допуски возможны по мощным резисторам в ZC/упралении семистором(20К, 360, 39)? 

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

snag пишет:
какие допуски возможны по мощным резисторам в ZC/упралении семистором(20К, 360, 39)?

20кОм -> 15...27кОм
360 -> 200...390
39 -> 33...56

Interhard
Offline
Зарегистрирован: 17.02.2018

Всем привет. Ребят, подскажите где засада - при включении фена и  выставлении температуры ниже 210 не включается нагрев.  Выше 210 все работает как часы. Либо при работающем фене выше этой температуры начинаешь понижать ниже 210 нагрев отключается. В коде ничего не менял кроме номеров выводов. С каналом паяльника такой проблемы нет, там все ок.

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

Interhard пишет:
В коде ничего не менял кроме номеров выводов.

Изменённый код предоставьте. Полностью. Кнопка "code", там вставьте код, а на соседней вкладке "дополнительно" поставьте чекбокс "сворачивать код по-умолчанию".
Или на яндекс-диск какой файл закиньте.

Interhard
Offline
Зарегистрирован: 17.02.2018


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                    Soldering Station v 1.6                */
/*                        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 */

/* 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 */


#define FIRMWARE_VERSION "1.6"

#ifdef LCD_1602
LiquidCrystal_I2C lcd(0x27, 16, 2);
#else
LiquidCrystal_I2C lcd(0x20, 0, 1, 2, 4, 5, 6, 7, 3,POSITIVE);
#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 2
#define pinFanPwm 6
#define pinSolderPwm 5
#define zeroPin 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 80
#define default_rpm 50

/* Buttons */
#define sw_HA 12
#define sw_S 11
#define bt_SON A0
#define bt_HAON A1
#define bt_Sel 13
#define bt_Up A2
#define bt_Dwn A3

/* 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
//#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.005
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 60

uint16_t last_HotAirT, last_SolderT;
byte last_RPM;


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

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(zeroPin, 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;
    D2_Out; //pinBuzzer
    D2_Low;
    ButtonsSetup();

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

    lcd.begin(20,4);
    lcd.createChar(0, degree);
    lcd.createChar(1, arrow);
    Splash();
    MemRead();
    delay_ms(2000);
    initDisplay();
    attachInterrupt(1, ZC, FALLING);
}

void loop() {
    ScanButtons();

    /* 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) {
                    Beep(100);    //Beep, if 1 minute left
                }
            } else {
                hotair_state = st_stop;
                Beep(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) {
                    Beep(100);    //Beep, if 1 minute left
                }
            } else {
                MemSolder();
                need_S_countdown = false;
                SolderON = false;
                Beep(200);
            }
            prevSmillis = millis();
        }
    } else {
        prevSmillis = millis();
    }

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

        /* 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
    }

    WorkWithHotAir();
    WorkWithSolder();
}

/* 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 100 times (+/-2 degrees), then signalize about it */
        int delta = ABS(SetHotAirT, GetHotAirT);
        static byte HAgood;
        if (!HA_temp_stable) {
            if (delta < 4) {
                HAgood++;
                if (HAgood == 100) {
                    Beep(50);
                    delay_ms(200);
                    Beep(50);
                    HAgood = 0;
                    HA_temp_stable = true;
                }
            } else {
                HAgood = 0;
            }
        } else {
            if (delta > 6) {
                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() {

    /* Read the thermoresistor value */
    //GetSolderT = A6_Read >> 1;
#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 (+/- 2 degrees) then signalize about it */
        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;
    }
}

/***************************************** 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;
    }

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

    /* 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;
    //}
    //}

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

#ifdef HA_ADV_PROT_ON

    /* Advanced protection: the themperature falls down/not changed & power > 0 */
    /* & */
    /* Advanced protection: the themperature rise up & power < 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) {

                /* themperature falls or not changed */
                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

                /* themperature rise */
                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

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

    /* 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;
    }

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

    /* 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;
    //}
    // }

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

#ifdef S_ADV_PROT_ON

    /* Advanced protection: the themperature falls down/not changed & power > 0 */
    /* & */
    /* Advanced protection: the themperature rise up & power < 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) {
                /* themperature falls or not changed */
                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
                /* themperature rise */
                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

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

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

/* 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) {
    tone(pinBuzzer, 1000, duration);
}

/* HotAir oversampling function */
//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;
}

/* 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 absolute difference function */
uint16_t ABS(uint16_t a, uint16_t b) {
    if (a > b) {
        return (a - b);
    }
    return (b - a);
}

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



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

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

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

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

/* HotAir PI regulator */
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 regulator with soft start */
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 regulator */
void S_P() {
    int TempPower = sKp * (SetSolderT - GetSolderT + 1);
    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() ;
            }
        }
        Beep(50);
    } else if (hotair_state == st_work && D12_Read == LOW) {
        D7_High;
        hotair_state = st_pause;
        need_Cooling = true;
        resetHotAirCountown();
    }

#ifdef SOLDER_TIMER_ON_STAND

    /* Solder stand switch - only on stand */
    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

    /* Solder stand switch simple check user activity */
    if (swSolder.update() && SolderON) {
        resetSolderCountdown();
        Beep(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;
                Activate_S_countdown();
                Graph_count = 0;
                selected_Mode = modeSolder;
                resetSolderStablePoint();
                set_s_f();
            } else {
                resetSolderCountdown();
            }
            SONbuttonState = true;
            SONbuttonPressTime = millis();
            Beep(50);
        }
    }

    if  (SONbuttonState) {
        if ( millis() - SONbuttonPressTime >= 1000 ) { //long press
            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);
            }
        }
    }

    /* Select button */
    if (SelButton.update()) {
        if (SelButton.fell()) {
            Beep(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();
            Beep(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();
                //integral = 0;
            }

            DWNbuttonState = true;
            short_press_flag = true;
            DWNbuttonPressTime = millis();
            Beep(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();
                //integral = 0;
            }
        }
    }
}

/* 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;
}

/**************************************** INTERFACE 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() {

#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) {
        lcd.print(S_countdown);
    }

    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: {
        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);

//if (hotair_state == ha_pause) {
//(scr_blink) ? (lcd.backlight()) : (lcd.noBacklight());
//} else {
//lcd.backlight();
//}

    if (hotair_state == st_pause) {
        lcd.setCursor(2, 1);
        lcd.blink_on();
    } else {
        lcd.blink_off();
    }

#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) {
        lcd.print(S_countdown);
    }

    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: {
        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);

    //if (hotair_state == st_pause) {
    //(scr_blink) ? (lcd.backlight()) : (lcd.noBacklight());
    //} else {
    //lcd.backlight();
    //}

    if (hotair_state == st_pause){
       lcd.setCursor(8, 2);
       {
       delay(500);
       }
       lcd.print(" P ");
       {
       delay(500);
       }
     }

    //lcd.setCursor(0, 0);
    //lcd.print(bspace);
    //lcd.print(bspace);
    //lcd.setCursor(0, 0);
    //lcd.print(integral);
#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 ********************************************/

 

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

Interhard, а ОУ какой у Вас установлен?

Interhard
Offline
Зарегистрирован: 17.02.2018

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

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

Странное какое-то значение в 210 град.))
Такое ощущение, что вместо
#define min_hotair_temp 20.0
установлено
#define min_hotair_temp 210.0
По идее, это единственный ограничитель...

Interhard
Offline
Зарегистрирован: 17.02.2018

Вообщем криворукость еще никто не отменял. Похоже что в #define min_hotair_temp 20.0 точка была записана в другой раскладке. Переписал оба дефайна и все заработало, но блин, почему 210 градусов, вот это загадка. 

Interhard
Offline
Зарегистрирован: 17.02.2018

Зато вылезло другое, начинаешь увеличивать обороты фена до 100% и нагрев отключается 95% - нагрев обратно включается

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

Чудеса, однако ))

MaD-TuX
MaD-TuX аватар
Offline
Зарегистрирован: 19.02.2018

Приветствую автора и всех кулибиных, повторяющих данную разработку :) !

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

Основное отличие получающегося у меня варианта, от обсуждаемого здесь, это Arduino Pro Micro + Энкодер (один на на всё) + Ds1307 (прикол ради прикола :).

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

Итак вопрос: Как себя ведет станция при включении и паяльника и фена одновременно?

Моё чудо ведет себя так:

Вариант 1. Включаю паяльник, он греется. Выключаю - остывает. ВСЁ ОК!

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

Вариант 3. Включаю паяльник, он греется. Включаю фен на скорости, например 40%. Фен оооочень долго греется и выходит с "ошибкой 6". После срабатывания ошибки 6 дуйка молотит 100% пока не вырубишь станцию или не включишь фен опять, на заданную темперетуру Cooling ему все равно.

Вариант 4. Включаю фен на скорости, например 40%, греется и стабилизируется. Включаю паяльник, он греется, а фен резко скидывает температуру на 10-20 градусов и наченает догреваться. Но все же вылетит с ошибкой 6, а дуйка молотит 100% пока не вырубишь станцию или не включишь фен опять.

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

Timer0 - это милисы и дэлэи, и наверно вентилятор фена

Timer1 - ZC, и нагрев фена соттветственно

Timer3 - Tone

Timer4 - нагреватель паяльника. Если не садить паяльник на Timer4 то PWM не работает, или 0 или 255

Timer2 - нету такова у Arduino Pro Micro

/* ВХОДЫ и ВЫХОДЫ ****************************************************/
#define pinHotAir       9       // Управление нагревателем термофена
#define pinHotAirProt   8       // Защита термофена
#define pinFanPwm       6       // Управление вентилятором термофена
#define pinHotAirTemp   A2      // Контроль температура термофена
#define sw_HA           5       // Концевик отключения термофена
#define pinSolderPwm    10      // Управление нагревателем паяльника
#define pinSolderProt   4       // Защита паяльника
#define pinSolderTemp   A3      // Контроль температура паяльника
#define sw_S            16      // Концевик отключения паяльника
#define pinZeroCross    7       // Контроль перехода через ноль
#define pinBuzzer       19      // Пьезоизлучатель
Rotary  r = Rotary(14, 15);     // Пины энкодера
OneButton button(18, true);     // Кнопка энкодера

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

MaD-TuX пишет:
Итак вопрос: Как себя ведет станция при включении и паяльника и фена одновременно?

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

Вот, небольшой видос по сценарию пункта 4 - работа фена, затем старт паяльника.

Цитата:
После срабатывания ошибки 6 дуйка молотит 100% пока не вырубишь станцию или не включишь фен опять, на заданную темперетуру

Это так и задумано - при аварии дуем, чтобы не сгорело, ведь в большинстве случаев контроль над температурой утерян и хз, что там происходит. Реле, опять же защитное залипнет, а симистор пробьётся ))

MaD-TuX
MaD-TuX аватар
Offline
Зарегистрирован: 19.02.2018

В общем я так и думал, что моя проблема в таймерах 1 и 4.

Еще пару вопросов.

1. В скетче применен StartTimer1 из библиотеки Cyberlib, который запускается в контроле перехода через ноль, а также перезапускается. В обработчике прерываний HeaterOn() он останавливается.

Использование RestartTimer1() в void ZC() и StopTimer1() в HeaterOn() обязательное? Без них никак? Боюсь это будет как-то негативно сказываться на паяльник если я его прицеплю на тот же таймер1.

2. При старте StartTimer1 использован ots, от величины которого выбирается делитель (в библиотеке Cyberlib).

Можно ли выбрать делитель постоянным? Хочу избавиться от библиотеки Cyberlib, т.к. она не адаптирована под мою железяку

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

MaD-TuX пишет:
Использование RestartTimer1() в void ZC() и StopTimer1() в HeaterOn() обязательное? Без них никак?

А как запускать-стопорить таймер?
Можете не использовать в том виде, как есть.
Посмотрите исходник СайберЛиб и используйте регистры, соответствующие своему МК.
RestartTimer1 - это юзать необязательно, если раскомментить закомментированную строку в СайберЛиб, вместо присвоения регистру TCNT1 нулевого значения.

Цитата:
Боюсь это будет как-то негативно сказываться на паяльник если я его прицеплю на тот же таймер1

Используйте ШИМ-пин, который использует Таймер0 или другой, свободный.

Цитата:
Хочу избавиться от библиотеки Cyberlib, т.к. она не адаптирована под мою железяку

Вариантов всегда есть два -
-Поменять железяку
-Адаптировать нужный код, всю библу переписывать не обязательно ;)

aleksandr23uam
Offline
Зарегистрирован: 22.01.2017

Залил скетч v1.6, как есть правда коэффициенты свои оставил. Стабилизация фена улучшилась, использую LM358, паяльник хоть и попискивает, но зато говорит о том, что он в работе :)
Автору спасибо большое за проект и помощь по сборке!

Русл@н
Offline
Зарегистрирован: 14.04.2016

Всем привет, рад что тема развивается и люди собирают станцию!) Еще раз спасибо Олегу!

Станция благополучно работает, паяльник приятно попискивает. Изменил немного архив в старт топике, добавил прошивку с отключенной ошибкой 6. Добавил ссылки на товары для сборки станции с Али.

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

Спасибо, Руслан, что также не бросаешь проект ))

snag
Offline
Зарегистрирован: 29.05.2015

Олег, добрый день! рс814 в Чипе не оказалось... По поводу вашей схемы на 2-х 817-х. Ограничен размером платы - повесить их в два этажа, "перехлестнув" выводы светодиодов. С резистором понятно - внутренняя подтяжка, а вот конденсатор обязателен? И какие допуски по напряжению - емкости?

И еще - я правильно понял, что у Вас на разъеме фена присустствует 220В даже при неактивном канале?

Т.е. безопаснее одну линию (N например) разрывать реле, а вторую (L) рулить симистором?

В нашем доме проводка делалась в советское время, когда нуль объединяли с землей. СтОит корпус фена прикручивать с корпусу станции (маталлический)? Розетка двухпроводная.

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

snag пишет:
С резистором понятно - внутренняя подтяжка, а вот конденсатор обязателен?

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

Цитата:
И еще - я правильно понял, что у Вас на разъеме фена присустствует 220В даже при неактивном канале?

Да. Для защиты, при отключенном от разъёма фена у меня есть резиновые крышки.

Цитата:
Т.е. безопаснее одну линию (N например) разрывать реле, а вторую (L) рулить симистором?

Да. Но ещё надёжнее реле с двумя группами контактов - по одной на каждый провод.

Цитата:
СтОит корпус фена прикручивать с корпусу станции (маталлический)? Розетка двухпроводная.

Я бы не стал. Заземлять стОит только при наличии отдельного провода заземления.

 

 
 
 

 

snag
Offline
Зарегистрирован: 29.05.2015

Олег, добрый день! Спасибо за Ваши советы.Двухэтажная РС817 работает. Импульсы поступают с частотой 100гц. Правда резисторы греются ...))

Уперся в ОУ(358).Плата сделана на основе платы ув. Федора. Левая сторона переделана симметрично под термопару. Правая сторона (оригинальная) завелась сразу и регулируется адекватно. Значения сопротивлений примерно как у Вас. Цепочка обратной связи суммарно 154 К, с входа (термопары) на плюс - 4,9 К. Резистор с -IN на землю 910 ом. А вот левая (моя переделка) работает не так. Разводку проверил много раз - ошибок не обнаруживаю. Выставил все параметры резисторов как в правой стороне, но значения показаний совсем другие и регулировки в узком диапазоне. Увеличение/уменьшение цепочки начала шкалы в 2 раза не помогло. Увеличил резистор с -IN на землю до 2.4 К, стало регулироваться, но как то тупо в сравнении с другим каналом). Значения цепочек: обратная связь - 208К, со входа - 24К. Вроде вопрос решается, но остается осадок, ведь схемы симметричны. Может такое быть? Микросхему не менял (поспешил впаять - все равно в перспективе думаю переводить на керамику/8552). При обрыве в обоих каналах по 765, при коротком в правой стороне - 8, левой - 28.

Не хотелось бы поступать по принципу - "если неправильно, но работает - оставь)))). Что посоветуете?

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

snag пишет:
Что посоветуете?

Выложите рисунок платы входного усилителя с переделкой, может чего угляжу.
Но вообще, попробовать бы ОУ сменить, для проверки...

snag
Offline
Зарегистрирован: 29.05.2015

https://yadi.sk/d/USHEfyFT3T5UBK Вкладка AMP 2хТС. Поменять, согласен, есть чем, но платка эта на советском текстолите - дорожки слабенькие. Как крайняя мера. Еще грешен кондеры (104) не проверил.

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

Все микросхемы  из посылки я проверил по известной схеме с делителем и двумя светодиодами.

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

Можно с исправного канала подкинуть ТП на вход "левого" и выход, соответственно, тоже - чисто для проверки канала ОУ.

snag
Offline
Зарегистрирован: 29.05.2015

Делал конечно, подстройки для термопар фена и паяльника немного разные, но неадекватно себя ведет именно левая половина ....

snag
Offline
Зарегистрирован: 29.05.2015

Впаял панельку в плату и зеркально второй разъем, с тем чтобы можно было оперативно менять местами фен-паяльник между каналами. Выставил регуляторы так, чтобы на соответствующих выводах половинках ОУ были одинаковые значения сопротивлений. И прогнал через этот станок 11 микросхем (10 из посылки с Али, одну из местного магазина). Повторяемости нет нигде, как между микросхемами, так и между половинками отдельных микросхем. Из всех отобрал одну с минимальным разносом. Все отрегулировал - и начало и шкалу (дунул феном 250 гр. и есть запас)

dron77777wef
Offline
Зарегистрирован: 08.03.2018

Всем доброе время суток. Помогите разобраться с каналом фена. При включении фена вкл. реле и обдув. Нагрев не в какую не хочет((((. Проверял симисторную сборку пoподав на оптик 5 вольт всё работает нагрев идет. Ссылка на фото осцылограмы с детектора нуля за качество не пинайтеhttps://drive.google.com/file/d/1eKFdO_TDNfgtpASVbDXQ-spEB66jWt2o/view?usp=sharing

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

Здравствуйте,dron77777wef при измерение осциллографом,вы используете закрытый вход,а надо открытый и про проверку детектора нуля почитайте #147.

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

Здраствуйте Олег собираю ваш проект по плате Руслана V 2.2 вы не подскажите без LCD возможно проверить схему или нужно все подключить,Спасибо!

snag
Offline
Зарегистрирован: 29.05.2015

nik 354 пишет:

Здраствуйте Олег собираю ваш проект по плате Руслана V 2.2 вы не подскажите без LCD возможно проверить схему или нужно все подключить,Спасибо!

Как вариант во всех местах где есть lcd.print(  (найти поиском) вставить serial.print с тем же реквизитом. Strial.println переводит строку.. Правда каша будет в мониторе, но при желании можно отформатировать.

Не забыть в setup serial.begin ...

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

Добрый день еще раз.Олег подскажите пожалуйста из Ардуино нано во всех схемах убирается светодиод с резистором с 13 пина.Спасибо!

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

Спасибо Snag я не силен в програмировании лутчше подожду I2C модуль дисплей есть плата готова,

snag
Offline
Зарегистрирован: 29.05.2015

nik 354 пишет:

Добрый день еще раз.Олег подскажите пожалуйста из Ардуино нано во всех схемах убирается светодиод с резистором с 13 пина.Спасибо!

Олег судя по всему занят, имеет же человет право на личную жизнь. :-)

По поводу D13 посмотрите коментарии sunjob в архиве файл eagle5_shem_win.txt , пункт 5.

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

dron77777wef пишет:
Проверял симисторную сборку пoподав на оптик 5 вольт всё работает нагрев идет.

Реле может и срабатывает, но через контакт реле тоже проходит ток? В ранних версиях плат была неточность в изображении реле, был нарисован нормально замкнутый контакт, вместо нормально разомкнутого.
По осциллограмме - мала амплитуда, посмотрите картинку в 147 сообщении.
Ну и осциллограф, как советовал pter, нужно переключить в режим открытого входа.

nik 354 пишет:
светодиод с резистором с 13 пина

Можно убрать (или резистор или светодиод), тогда внешний резистор подтяжки этого пина впаивать не нужно. А можно не убирать, тогда резистор потребуется.

dron77777wef
Offline
Зарегистрирован: 08.03.2018

 pter Спасибо за совет почитаю.

dron77777wef
Offline
Зарегистрирован: 08.03.2018

OlegK]</p> <p>[quote=dron77777wef пишет:
Проверял симисторную сборку пoподав на оптик 5 вольт всё работает нагрев идет.

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

Да через реле ток проходит в отключенном виде реле нормально разомкнутое.

snag
Offline
Зарегистрирован: 29.05.2015

Добрый, день.

Еще раз огромное спасибо Олегу за его бесценную помощь. Собрал я свою станцию (тестирую теперь), все хорошо, но не без небольших проблем. Заставил понервничать усилитель (я писал несколькими постами выше). Странно как то - такой разброс, возможно это моя статистика - все 10 микросхем из "левой" партии, а та что из магазина не далеко ушла от первых? При подключении геркона повторилась, описываемая здесь ситуация - на пине (подтянут к плюсу 8.6К) лог. единица, а фен отключается. Установка конденсатора (104) параллельно геркону радикально решила проблему. Ни чего не пищит (мосфеты с материнки - лог левел).

Остались два момента, которые работе особо не мешают, но немного портят настроение :-)

Паяльник (нагреватель нихром и термопара) Довольно долго выходит на стабилизацию более 10 сек и стабилизируется на 1 градус ниже уставки. (На видео Олега стабилизация 4-5 секунд и фиксируется четко на уставке). При этом иногда вываливается в 6-ю ошибку. Увеличение вдвое выборок с АЦП проблему не решило. Уменьшение коэффициента еще более снижает планку, увеличение до 80 - большая "болтанка" температуры. sKp=70 - вполне приемлемый вариант - стабилизация 5 сек, ошибок пока не наблюдаю  (буду тестить) но все равно фиксация на градус ниже (на графике это видно).

Фен - при активации канала при отключенной рукоятке - ошибка 1, обороты выставляются на 100%. И выйти из этого состояния кроме как перезапуском станции или подключением рукоятки нельзя. Если подключить фен включается продувка 100% (реле отключено). Здесь уже можно либо выключить канал длинным удержанием кнопки, либо включить нагрев. В принципе щелкнуть тумблером не сложно, но осадок остается...

 

 

 

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

snag пишет:
но все равно фиксация на градус ниже (на графике это видно).

Финт ушами для устранения одноградусного недогрева -
добавьте +1 в процедуре регулирования темп. паяльника S_P()
int TempPower = sKp * (SetSolderT - GetSolderT + 1)

Цитата:
Фен - при активации канала при отключенной рукоятке - ошибка 1, обороты выставляются на 100%.

Правильное поведение. Ошибка 1 - это критический перегрев или, в данном случае, обрыв ТП.
А т.к. температура не контролируется, то всё вырубаем и охлаждаем макс. потоком воздуха.
Встречный вопрос - зачем включать канал при отключенной рукоятке?))

Цитата:
При этом иногда вываливается в 6-ю ошибку

Такое периодически наблюдается с "термопарными" паяльниками, по "терморезисторным" вроде никто не жаловался. Я статистику не собирал.
Попробуйте немного увеличить время реакции защиты - в защитной функции паяльника SDoProtect()
увеличить в строке 618 предельное значение счётчика t_cnt до 10-12
if (t_cnt == 7) <- тут

Цитата:
В принципе щелкнуть тумблером не сложно, но осадок остается...

Проект в свободном доступе, Вы имеете возможность реализовать своё видение вопроса. ))

snag
Offline
Зарегистрирован: 29.05.2015

Цитата:
Финт ушами для устранения одноградусного недогрева -
добавьте +1 в процедуре регулирования темп. паяльника S_P()
int TempPower = sKp * (SetSolderT - GetSolderT + 1)

Да  не раздражает это, просто сомневался насколько это нормально. Как по Вашему 70 это не много? Кстати +1 и так там стоит. Это в 1.5 не было.. Тогда получается +2 надо?

Цитата:
Правильное поведение. Ошибка 1 - это критический перегрев или, в данном случае, обрыв ТП.
А т.к. температура не контролируется, то всё вырубаем и охлаждаем макс. потоком воздуха.
Встречный вопрос - зачем включать канал при отключенной рукоятке?))

Включать не надо - выключить длинным удержанием как вариант. Дело в том, что я вывел индикацию работы каналов светодиодами, использовав D0 и D1, управляя ими синхронно с D4 и D7(реле). По этому и обратил внимание. Как то не красиво канал не активен, а синий светодиод светится. А отловить когда он включается никак не могу. Ведь условие error == 0 не выполняется. Хотя с другой стороны реле то не дергается. А активация D7 и D1 стоит рядом. Деактивируется D1 в HotAirOff().Полтергейст((((( NEED_GRAPH естественно закомментирован.

Цитата:
Такое периодически наблюдается с "термопарными" паяльниками, по "терморезисторным" вроде никто не жаловался. Я статистику не собирал.
Попробуйте немного увеличить время реакции защиты - в защитной функции паяльника SDoProtect()
увеличить в строке 618 предельное значение счётчика t_cnt до 10-12
if (t_cnt == 7) <- тут
Да при sKp=70 нормально пока 5 сек. Я тоже подозревал, что дело в нагревателе. Тем более планирую перевести на керамику. Но для начала нужно было ответить на вопрос - смогу ли я собрать подобную конструкцию))))

Цитата:
Проект в свободном доступе, Вы имеете возможность реализовать своё видение вопроса. ))
Ни коим образом не хотел Вас обидеть ))) Вы и так все мыслимые хотелки удовлетворили. Осадок от того, что сам туплю..

И хотелось бы Вашего мнения по поводу LM-ок. Это нормальный разброс параметров или мне попался хлам? 8552 в запасе имеется (нет пока переходника). Жду второй паяльник и нагреватель (вчера выписал)