Tiny Reflow Controller v1, który omawialiśmy w pierwszym artykule, wykorzystuje wyświetlacz LCD i głównie komponenty SMD. Ten rodzaj sterownila jest wymagany do sterowania procesem cieplnym w piecach rozpływowych, aby zapewnić dostarczenie odpowiedniej ilości ciepła na wszystkich etapach procesu rozpływowego.
Kontroler Tiny Reflow v2, w odróżnieniu od wersji v1, jest oparty na mikrokontrolerze Atmega328p. Zachowuje on interfejs termopary MAX31856 zastosowany w modelu v1, ale jest wyposażony w układ interfejsu USB-Serial ułatwiający programowanie oraz wyświetlacz OLED zamiast wyświetlacza LCD 20×4 zastosowanego w modelu v1. Wyświetlacz OLED zapewnia więcej informacji, takich jak wykres krzywej rozpływu, które mogą być dostarczone jako informacja zwrotna dla użytkowników, dając nam lepsze zrozumienie procesu rozpływu i jego stanu.
Podobnie jak v1, sterownik Tiny Reflow v2 zawiera głównie elementy SMD, aby utrzymać niski koszt montażu, a jedynym elementem przewlekanym jest blok zacisków (który nie występuje w wersji SMD). Pomogło to zredukować rozmiary sterownika rozpływowego do najmniejszych z możliwych i czyni go sterownikiem preferowanym w aplikacjach o ograniczonej przestrzeni. Aby ułatwić zasilanie sterownika i uprościć projekt, wszystkie użyte komponenty zostały dobrane tak, aby działały na poziomie napięcia 3,3 V.
Sterownik rozpływowy v2 obejmuje wszystko, czego potrzebujesz do kontroli ciepła rozpływu i wystarczy podłączyć termoparę typu K (zalecamy te z włóknem szklanym lub płaszczem stalowym), przekaźnik półprzewodnikowy (SSR) (o wartości znamionowej odpowiedniej dla twojego pieca) i oczywiście piec, podłączony do zacisków sterownika.
Niektóre z wyróżnionych właściwości sterownika rozpływu V2:
- Zasilany przez ATmega328p
- Interfejs termopary MAX31856
- 0,96″ 128×64 OLED żółty i niebieski kolor
- 1 blok zacisków do sterowania SSR przez tranzystor NPN, wyjście 5 mA @ 5 V) do kontroli elementu grzejnego/pieca
- 1 blok zacisków do sterowania SSR (przez tranzystor NPN, wyjście 5 mA @ 5 V) do sterowania wentylatorem
- Sygnały ostrzegawcze poprzez brzęczyki
- Wyprowadzenie pinów ISP ułatwiające przeprogramowanie
- Wbudowany interfejs szeregowy USB do wgrywania firmware i interfejs szeregowy
- Zasilanie przez złącze MicroUSB z bezpiecznikiem 500mA
- Dostarczany z dodatkowymi 4 elementami dystansowymi M2*5 mm (męsko-żeńskimi) i 4 śrubami M2*5 mm, jeśli zdecydowałeś się zamontować go na panelu przednim pieca
- Płytka drukowana FR4 TG140 z wykończeniem w kolorze złota zanurzeniowego (ENIG)
- Zgodność z RoHS
Zasadnicze elementy
- Mikrokontroler ATmega328p
- Układ scalony interfejsu termopary MAX31856
- Termopara typu K (Rocket Stream zaleca te z włóknem szklanym lub stalowym płaszczem)
- Wyświetlacz OLED 0,96″
- 2 przyciski
- LED
- 3 (podwójny port) bloki zacisków
- 1 Buzzer
- Piec
- Zewnętrzny przekaźnik półprzewodnikowy
- Mały wentylator
Aby lista nie stała się nieuporządkowana, inne potrzebne elementy są podane w poniższej tabeli. Piec, zewnętrzny przekaźnik półprzewodnikowy i wentylator to wszystko czego potrzebujemy do przetestowania zbudowanego sterownika.
Schemat
Jak wspomniałem we wstępie, w Tiny Reflow Controller v2 użyto części SMD, co automatycznie oznacza, że potrzebujemy płytki PCB do naszej konstrukcji. Głównym tego powodem jest chęć uczynienia projektu schludnym, przenośnym i tanim. Jednakże, możesz również zdecydować się na zakup przelotowej wersji tych komponentów i użyć ich do realizacji projektu na płytce drukowanej.
Aby ułatwić implementację schematu i przejście na płytkę drukowaną, schemat tego projektu został opracowany przy użyciu programu Kicad. Komponenty są podłączone tak jak pokazano na poniższym schemacie.
Ostateczny projekt PCB będzie wyglądał jak na poniższym widoku.
Aby ułatwić powielanie płytki, wszystkie pliki projektu, w tym schematy i PCB są załączone w sekcji download. Zachęcamy do korzystania z nich zgodnie z warunkami licencji.
Kod
Kod dla tego projektu zostanie opracowany przy użyciu Arduino ID i jest oparty na przykładowym kodzie, który jest dostarczony z Tiny Reflow Oven V2 firmy Rocket Stream. Szkic wykorzystuje algorytm sterowania oparty na PID z biblioteki Arduino PID opracowanej przez Bretta Beauregarda i jest używany do zarządzania procesem rozpływu, wykorzystując grzałkę i wentylator, aby zapewnić odpowiednią ilość ciepła na każdym etapie procesu rozpływu.
Szkic wykorzystuje trzy główne biblioteki, w tym wspomnianą już bibliotekę PID Arduino, bibliotekę Adafruit MAX31856, bibliotekę Adafruit SSD1306 oraz bibliotekę Adafruit GFX. Biblioteka PID, jak wspomniano wcześniej, została użyta do zapewnienia odpowiedniej dokładności w nastawach poziomów ciepła. Biblioteki Adafruit SSD1306 i GFX, z drugiej strony, zostały użyte do ułatwienia interakcji z OLED, a biblioteka Adafruit Max318356 została użyta do zmniejszenia ilości pracy związanej z uzyskaniem odczytów z czujnika termopary.
Oto krótkie wyjaśnienie podstawowych części kodu. Posłużymy się przykładem kodu dla pracy z uwzględnienierm zarówno ołowiowej jak i bezołowiowej konfiguracji pieca rozpływowego, pozwalając użytkownikowi na zmianę z jednej na drugą za pomocą jednego przycisku.
Rozpoczynamy szkic od dołączenia wszystkich bibliotek, z których będziemy korzystać. Oprócz wspomnianych już bibliotek, użyjemy także biblioteki Arduino EEPROM, biblioteki Wire oraz biblioteki SPI. Wszystkie te biblioteki są dołączone do Arduino IDE, więc nie ma potrzeby ich ręcznego instalowania.
// ***** INCLUDES *****
#include <SPI.h>
#include <Wire.h>
#include <EEPROM.h>
#include <LiquidCrystal.h>
#include <Adafruit_GFX.h> // Comment for VERSION 1
#include <Adafruit_SSD1306.h> // Comment for VERSION 1
#include <Adafruit_MAX31856.h>
#include <PID_v1.h>
Następnie tworzymy definicję typu, która przechowuje kilka parametrów wskazujących na stan procesu rozpływu.
// ***** TYPE DEFINITIONS *****
typedef enum REFLOW_STATE
{
REFLOW_STATE_IDLE,
REFLOW_STATE_PREHEAT,
REFLOW_STATE_SOAK,
REFLOW_STATE_REFLOW,
REFLOW_STATE_COOL,
REFLOW_STATE_COMPLETE,
REFLOW_STATE_TOO_HOT,
REFLOW_STATE_ERROR
} reflowState_t;
Tworzymy również inne deklaracje typów, aby przechowywać status reflow, status przełącznika, stan odbicia i Reflow_Profile w oparciu o status przełącznika.
ypedef enum REFLOW_STATUS
{
REFLOW_STATUS_OFF,
REFLOW_STATUS_ON
} reflowStatus_t;
typedef enum SWITCH
{
SWITCH_NONE,
SWITCH_1,
SWITCH_2
} switch_t;
typedef enum DEBOUNCE_STATE
{
DEBOUNCE_STATE_IDLE,
DEBOUNCE_STATE_CHECK,
DEBOUNCE_STATE_RELEASE
} debounceState_t;
typedef enum REFLOW_PROFILE
{
REFLOW_PROFILE_LEADFREE,
REFLOW_PROFILE_LEADED
} reflowProfile_t;
Następnie tworzymy zmienne przechowujące stałe wartości, które będą używane niezależnie od wybranego profilu (General Profile constants), a po nich tworzymy zmienne przechowujące wartości specyficzne dla profilu bezołowiowego i również tworzymy te specyficzne dla profilu ołowiowego. W ten sposób zapewniamy, że niezależnie od wybranego przez użytkownika profilu, niezbędne informacje będą dostępne.
// ***** CONSTANTS *****
// ***** GENERAL *****
#define VERSION 2 // Replace with 1 or 2
// ***** GENERAL PROFILE CONSTANTS *****
#define PROFILE_TYPE_ADDRESS 0
#define TEMPERATURE_ROOM 50
#define TEMPERATURE_SOAK_MIN 150
#define TEMPERATURE_COOL_MIN 100
#define SENSOR_SAMPLING_TIME 1000
#define SOAK_TEMPERATURE_STEP 5
// ***** LEAD FREE PROFILE CONSTANTS *****
#define TEMPERATURE_SOAK_MAX_LF 200
#define TEMPERATURE_REFLOW_MAX_LF 250
#define SOAK_MICRO_PERIOD_LF 9000
// ***** LEADED PROFILE CONSTANTS *****
#define TEMPERATURE_SOAK_MAX_PB 180
#define TEMPERATURE_REFLOW_MAX_PB 224
#define SOAK_MICRO_PERIOD_PB 10000
// ***** SWITCH SPECIFIC CONSTANTS *****
#define DEBOUNCE_PERIOD_MIN 100
Następnie tworzymy zmienne, które będą używane przez algorytm PID, określamy wersję projektu, aby był używany odpowiedni wyświetlacz, oraz tworzymy komunikaty, które będą wyświetlane na OLED wraz z kilkoma innymi zmiennymi. Nazwy są bardzo opisowe, więc powinno być łatwo to śledzić.
/ ***** PID PARAMETERS *****
// ***** PRE-HEAT STAGE *****
#define PID_KP_PREHEAT 100
#define PID_KI_PREHEAT 0.025
#define PID_KD_PREHEAT 20
// ***** SOAKING STAGE *****
#define PID_KP_SOAK 300
#define PID_KI_SOAK 0.05
#define PID_KD_SOAK 250
// ***** REFLOW STAGE *****
#define PID_KP_REFLOW 300
#define PID_KI_REFLOW 0.05
#define PID_KD_REFLOW 350
#define PID_SAMPLE_TIME 1000
#if VERSION == 2
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define X_AXIS_START 18 // X-axis starting position
#endif
// ***** LCD MESSAGES *****
const char* lcdMessagesReflowStatus[] = {
"Ready",
"Pre",
"Soak",
"Reflow",
"Cool",
"Done!",
"Hot!",
"Error"
};
Szkic został zaprojektowany tak, aby był kompatybilny z wersją v1 projektu, przy czym o wersji decyduje wersja wskazana przez użytkownika w kodzie. W efekcie możesz nadal widzieć rzeczy, które odnoszą się do pierwszej wersji projektu. Następnie deklarujemy piny, do których podłączone są wyświetlacze, przy czym deklaracje OLED-ów znajdują się pod wersją v2.
// ***** PIN ASSIGNMENT *****
#if VERSION == 1
unsigned char ssrPin = 3;
unsigned char thermocoupleCSPin = 2;
unsigned char lcdRsPin = 10;
unsigned char lcdEPin = 9;
unsigned char lcdD4Pin = 8;
unsigned char lcdD5Pin = 7;
unsigned char lcdD6Pin = 6;
unsigned char lcdD7Pin = 5;
unsigned char buzzerPin = 14;
unsigned char switchPin = A1;
unsigned char ledPin = LED_BUILTIN;
#elif VERSION == 2
unsigned char ssrPin = A0;
unsigned char fanPin = A1;
unsigned char thermocoupleCSPin = 10;
unsigned char ledPin = 4;
unsigned char buzzerPin = 5;
unsigned char switchStartStopPin = 3;
unsigned char switchLfPbPin = 2;
#endif
Kilka innych ważnych zmiennych jest również zadeklarowanych z nazwami opisowymi.
// ***** PID CONTROL VARIABLES *****
double setpoint;
double input;
double output;
double kp = PID_KP_PREHEAT;
double ki = PID_KI_PREHEAT;
double kd = PID_KD_PREHEAT;
int windowSize;
unsigned long windowStartTime;
unsigned long nextCheck;
unsigned long nextRead;
unsigned long updateLcd;
unsigned long timerSoak;
unsigned long buzzerPeriod;
unsigned char soakTemperatureMax;
unsigned char reflowTemperatureMax;
unsigned long soakMicroPeriod;
// Reflow oven controller state machine state variable
reflowState_t reflowState;
// Reflow oven controller status
reflowStatus_t reflowStatus;
// Reflow profile type
reflowProfile_t reflowProfile;
// Switch debounce state machine state variable
debounceState_t debounceState;
// Switch debounce timer
long lastDebounceTime;
// Switch press status
switch_t switchStatus;
switch_t switchValue;
switch_t switchMask;
// Seconds timer
unsigned int timerSeconds;
// Thermocouple fault status
unsigned char fault;
Po utworzeniu wszystkich zmiennych, tworzymy instancję biblioteki PID, SSD1306 oraz MAX31856, po czym przechodzimy do funkcji void setup().
/ PID control interface
PID reflowOvenPID(&input, &output, &setpoint, kp, ki, kd, DIRECT);
#if VERSION == 1
// LCD interface
LiquidCrystal lcd(lcdRsPin, lcdEPin, lcdD4Pin, lcdD5Pin, lcdD6Pin, lcdD7Pin);
#elif VERSION == 2
Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire);
#endif
// MAX31856 thermocouple interface
Adafruit_MAX31856 thermocouple = Adafruit_MAX31856(thermocoupleCSPin);
Funkcję void setup() rozpoczynamy od sprawdzenia aktualnie wybranego profilu rozpływowego w pamięci EEPROM, co pozwala określić, która z grup zmiennych powinna być wybrana. Jeśli żaden profil rozpływu nie był wcześniej zapisany, system domyślnie wybiera profil bezołowiowy.
void setup()
{
// Check current selected reflow profile
unsigned char value = EEPROM.read(PROFILE_TYPE_ADDRESS);
if ((value == 0) || (value == 1))
{
// Valid reflow profile value
reflowProfile = value;
}
else
{
// Default to lead-free profile
EEPROM.write(PROFILE_TYPE_ADDRESS, 0);
reflowProfile = REFLOW_PROFILE_LEADFREE;
}
Następnie inicjalizujemy pin SSR, aby upewnić się, że piec rozpływowy jest otwarty, po czym inicjalizujemy brzęczyk, ustawiając go tak, aby włączał się natychmiast po włączeniu zasilania systemu, dioda LED statusu jest również włączana po uruchomieniu systemu.
// SSR pin initialization to ensure reflow oven is off
digitalWrite(ssrPin, LOW);
pinMode(ssrPin, OUTPUT);
// Buzzer pin initialization to ensure annoying buzzer is off
digitalWrite(buzzerPin, LOW);
pinMode(buzzerPin, OUTPUT);
// LED pins initialization and turn on upon start-up (active high)
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
Następnie inicjalizujemy termoparę, podając jej typ, a także inicjalizujemy OLED i wyświetlamy coś w rodzaju splash screena z datą i wersją sterownika. Kod selektywnie uruchamia każdą rzecz zaznaczoną na 2.
// Initialize thermocouple interface
thermocouple.begin();
thermocouple.setThermocoupleType(MAX31856_TCTYPE_K);
// Start-up splash
digitalWrite(buzzerPin, HIGH);
#if VERSION == 1
lcd.begin(8, 2);
lcd.createChar(0, degree);
lcd.clear();
lcd.print(F(" Tiny "));
lcd.setCursor(0, 1);
lcd.print(F(" Reflow "));
#elif VERSION == 2
oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
oled.display();
#endif
digitalWrite(buzzerPin, LOW);
delay(2000);
#if VERSION == 1
lcd.clear();
lcd.print(F(" v1.00 "));
lcd.setCursor(0, 1);
lcd.print(F("26-07-17"));
delay(2000);
lcd.clear();
#elif VERSION == 2
oled.clearDisplay();
oled.setTextSize(1);
oled.setTextColor(WHITE);
oled.setCursor(0, 0);
oled.println(F(" Tiny Reflow"));
oled.println(F(" Controller"));
oled.println();
oled.println(F(" v2.00"));
oled.println();
oled.println(F(" 04-03-19"));
oled.display();
delay(3000);
oled.clearDisplay();
#endif
Następnie inicjalizujemy komunikację szeregową, wyłączamy LED i inicjalizujemy zmienne, które będą używane do monitorowania czasu podczas działania szkicu.
// Serial communication at 115200 bps
Serial.begin(115200);
// Turn off LED (active high)
digitalWrite(ledPin, LOW);
// Set window size
windowSize = 2000;
// Initialize time keeping variable
nextCheck = millis();
// Initialize thermocouple reading variable
nextRead = millis();
// Initialize LCD update timer
updateLcd = millis();
}
Po wykonaniu tych czynności przechodzimy do funkcji void loop(), w której odbywają się wszystkie najważniejsze akcje.
Kod funkcji void loop() jest dość obszerny, ale idea jest prosta. Używamy zmiennych utworzonych wcześniej do zarządzania procesem rozpływu, monitorując ilość ciepła za pomocą termopary i używając tej informacji jako wejścia do algorytmu PID, który następnie określa sposób działania grzałki. Dla każdego etapu procesu rozpływu, PID działa w taki sposób, że wyznaczona ilość ciepła dla tego etapu jest osiągnięta. Podczas gdy to wszystko się dzieje, informacje o czasie i temperaturze są również wyświetlane na ekranie, aby zapewnić wizualną informację zwrotną dla użytkownika, a przełączniki, które są używane do ustawiania statusu rozpływu i profilu rozpływu są również obserwowane, aby system mógł natychmiast działać na każdą zmianę ich stanu.
void loop()
{
// Current time
unsigned long now;
// Time to read thermocouple?
if (millis() > nextRead)
{
// Read thermocouple next sampling period
nextRead += SENSOR_SAMPLING_TIME;
// Read current temperature
input = thermocouple.readThermocoupleTemperature();
// Check for thermocouple fault
fault = thermocouple.readFault();
// If any thermocouple fault is detected
if ((fault & MAX31856_FAULT_CJRANGE) ||
(fault & MAX31856_FAULT_TCRANGE) ||
(fault & MAX31856_FAULT_CJHIGH) ||
(fault & MAX31856_FAULT_CJLOW) ||
(fault & MAX31856_FAULT_TCHIGH) ||
(fault & MAX31856_FAULT_TCLOW) ||
(fault & MAX31856_FAULT_OVUV) ||
(fault & MAX31856_FAULT_OPEN))
{
// Illegal operation
reflowState = REFLOW_STATE_ERROR;
reflowStatus = REFLOW_STATUS_OFF;
Serial.println(F("Error"));
}
}
if (millis() > nextCheck)
{
// Check input in the next seconds
nextCheck += SENSOR_SAMPLING_TIME;
// If reflow process is on going
if (reflowStatus == REFLOW_STATUS_ON)
{
// Toggle red LED as system heart beat
digitalWrite(ledPin, !(digitalRead(ledPin)));
// Increase seconds timer for reflow curve plot
timerSeconds++;
// Send temperature and time stamp to serial
Serial.print(timerSeconds);
Serial.print(F(","));
Serial.print(setpoint);
Serial.print(F(","));
Serial.print(input);
Serial.print(F(","));
Serial.println(output);
}
else
{
// Turn off red LED
digitalWrite(ledPin, LOW);
}
}
if (millis() > updateLcd)
{
// Update LCD in the next 100 ms
updateLcd += UPDATE_RATE;
#if VERSION == 1
// Clear LCD
lcd.clear();
// Print current system state
lcd.print(lcdMessagesReflowStatus[reflowState]);
lcd.setCursor(6, 0);
if (reflowProfile == REFLOW_PROFILE_LEADFREE)
{
lcd.print(F("LF"));
}
else
{
lcd.print(F("PB"));
}
lcd.setCursor(0, 1);
// If currently in error state
if (reflowState == REFLOW_STATE_ERROR)
{
// Thermocouple error (open, shorted)
lcd.print(F("TC Error"));
}
else
{
// Display current temperature
lcd.print(input);
#if ARDUINO >= 100
// Display degree Celsius symbol
lcd.write((uint8_t)0);
#else
// Display degree Celsius symbol
lcd.print(0, BYTE);
#endif
lcd.print("C ");
}
#elif VERSION == 2
oled.clearDisplay();
oled.setTextSize(2);
oled.setCursor(0, 0);
oled.print(lcdMessagesReflowStatus[reflowState]);
oled.setTextSize(1);
oled.setCursor(115, 0);
if (reflowProfile == REFLOW_PROFILE_LEADFREE)
{
oled.print(F("LF"));
}
else
{
oled.print(F("PB"));
}
// Temperature markers
oled.setCursor(0, 18);
oled.print(F("250"));
oled.setCursor(0, 36);
oled.print(F("150"));
oled.setCursor(0, 54);
oled.print(F("50"));
// Draw temperature and time axis
oled.drawLine(18, 18, 18, 63, WHITE);
oled.drawLine(18, 63, 127, 63, WHITE);
oled.setCursor(115, 0);
// If currently in error state
if (reflowState == REFLOW_STATE_ERROR)
{
oled.setCursor(80, 9);
oled.print(F("TC Error"));
}
else
{
// Right align temperature reading
if (input < 10) oled.setCursor(91, 9);
else if (input < 100) oled.setCursor(85,9);
else oled.setCursor(80, 9);
// Display current temperature
oled.print(input);
oled.print((char)247);
oled.print(F("C"));
}
if (reflowStatus == REFLOW_STATUS_ON)
{
// We are updating the display faster than sensor reading
if (timerSeconds > timerUpdate)
{
// Store temperature reading every 3 s
if ((timerSeconds % 3) == 0)
{
timerUpdate = timerSeconds;
unsigned char averageReading = map(input, 0, 250, 63, 19);
if (x < (SCREEN_WIDTH - X_AXIS_START))
{
temperature[x++] = averageReading;
}
}
}
}
unsigned char timeAxis;
for (timeAxis = 0; timeAxis < x; timeAxis++)
{
oled.drawPixel(timeAxis + X_AXIS_START, temperature[timeAxis], WHITE);
}
// Update screen
oled.display();
#endif
}
// Reflow oven controller state machine
switch (reflowState)
{
case REFLOW_STATE_IDLE:
// If oven temperature is still above room temperature
if (input >= TEMPERATURE_ROOM)
{
reflowState = REFLOW_STATE_TOO_HOT;
}
else
{
// If switch is pressed to start reflow process
if (switchStatus == SWITCH_1)
{
// Send header for CSV file
Serial.println(F("Time,Setpoint,Input,Output"));
// Intialize seconds timer for serial debug information
timerSeconds = 0;
#if VERSION == 2
// Initialize reflow plot update timer
timerUpdate = 0;
for (x = 0; x < (SCREEN_WIDTH - X_AXIS_START); x++)
{
temperature[x] = 0;
}
// Initialize index for average temperature array used for reflow plot
x = 0;
#endif
// Initialize PID control window starting time
windowStartTime = millis();
// Ramp up to minimum soaking temperature
setpoint = TEMPERATURE_SOAK_MIN;
// Load profile specific constant
if (reflowProfile == REFLOW_PROFILE_LEADFREE)
{
soakTemperatureMax = TEMPERATURE_SOAK_MAX_LF;
reflowTemperatureMax = TEMPERATURE_REFLOW_MAX_LF;
soakMicroPeriod = SOAK_MICRO_PERIOD_LF;
}
else
{
soakTemperatureMax = TEMPERATURE_SOAK_MAX_PB;
reflowTemperatureMax = TEMPERATURE_REFLOW_MAX_PB;
soakMicroPeriod = SOAK_MICRO_PERIOD_PB;
}
// Tell the PID to range between 0 and the full window size
reflowOvenPID.SetOutputLimits(0, windowSize);
reflowOvenPID.SetSampleTime(PID_SAMPLE_TIME);
// Turn the PID on
reflowOvenPID.SetMode(AUTOMATIC);
// Proceed to preheat stage
reflowState = REFLOW_STATE_PREHEAT;
}
}
break;
case REFLOW_STATE_PREHEAT:
reflowStatus = REFLOW_STATUS_ON;
// If minimum soak temperature is achieve
if (input >= TEMPERATURE_SOAK_MIN)
{
// Chop soaking period into smaller sub-period
timerSoak = millis() + soakMicroPeriod;
// Set less agressive PID parameters for soaking ramp
reflowOvenPID.SetTunings(PID_KP_SOAK, PID_KI_SOAK, PID_KD_SOAK);
// Ramp up to first section of soaking temperature
setpoint = TEMPERATURE_SOAK_MIN + SOAK_TEMPERATURE_STEP;
// Proceed to soaking state
reflowState = REFLOW_STATE_SOAK;
}
break;
case REFLOW_STATE_SOAK:
// If micro soak temperature is achieved
if (millis() > timerSoak)
{
timerSoak = millis() + soakMicroPeriod;
// Increment micro setpoint
setpoint += SOAK_TEMPERATURE_STEP;
if (setpoint > soakTemperatureMax)
{
// Set agressive PID parameters for reflow ramp
reflowOvenPID.SetTunings(PID_KP_REFLOW, PID_KI_REFLOW, PID_KD_REFLOW);
// Ramp up to first section of soaking temperature
setpoint = reflowTemperatureMax;
// Proceed to reflowing state
reflowState = REFLOW_STATE_REFLOW;
}
}
break;
case REFLOW_STATE_REFLOW:
// We need to avoid hovering at peak temperature for too long
// Crude method that works like a charm and safe for the components
if (input >= (reflowTemperatureMax - 5))
{
// Set PID parameters for cooling ramp
reflowOvenPID.SetTunings(PID_KP_REFLOW, PID_KI_REFLOW, PID_KD_REFLOW);
// Ramp down to minimum cooling temperature
setpoint = TEMPERATURE_COOL_MIN;
// Proceed to cooling state
reflowState = REFLOW_STATE_COOL;
}
break;
case REFLOW_STATE_COOL:
// If minimum cool temperature is achieve
if (input <= TEMPERATURE_COOL_MIN)
{
// Retrieve current time for buzzer usage
buzzerPeriod = millis() + 1000;
// Turn on buzzer to indicate completion
digitalWrite(buzzerPin, HIGH);
// Turn off reflow process
reflowStatus = REFLOW_STATUS_OFF;
// Proceed to reflow Completion state
reflowState = REFLOW_STATE_COMPLETE;
}
break;
case REFLOW_STATE_COMPLETE:
if (millis() > buzzerPeriod)
{
// Turn off buzzer
digitalWrite(buzzerPin, LOW);
// Reflow process ended
reflowState = REFLOW_STATE_IDLE;
}
break;
case REFLOW_STATE_TOO_HOT:
// If oven temperature drops below room temperature
if (input < TEMPERATURE_ROOM)
{
// Ready to reflow
reflowState = REFLOW_STATE_IDLE;
}
break;
case REFLOW_STATE_ERROR:
// Check for thermocouple fault
fault = thermocouple.readFault();
// If thermocouple problem is still present
if ((fault & MAX31856_FAULT_CJRANGE) ||
(fault & MAX31856_FAULT_TCRANGE) ||
(fault & MAX31856_FAULT_CJHIGH) ||
(fault & MAX31856_FAULT_CJLOW) ||
(fault & MAX31856_FAULT_TCHIGH) ||
(fault & MAX31856_FAULT_TCLOW) ||
(fault & MAX31856_FAULT_OVUV) ||
(fault & MAX31856_FAULT_OPEN))
{
// Wait until thermocouple wire is connected
reflowState = REFLOW_STATE_ERROR;
}
else
{
// Clear to perform reflow process
reflowState = REFLOW_STATE_IDLE;
}
break;
}
// If switch 1 is pressed
if (switchStatus == SWITCH_1)
{
// If currently reflow process is on going
if (reflowStatus == REFLOW_STATUS_ON)
{
// Button press is for cancelling
// Turn off reflow process
reflowStatus = REFLOW_STATUS_OFF;
// Reinitialize state machine
reflowState = REFLOW_STATE_IDLE;
}
}
// Switch 2 is pressed
else if (switchStatus == SWITCH_2)
{
// Only can switch reflow profile during idle
if (reflowState == REFLOW_STATE_IDLE)
{
// Currently using lead-free reflow profile
if (reflowProfile == REFLOW_PROFILE_LEADFREE)
{
// Switch to leaded reflow profile
reflowProfile = REFLOW_PROFILE_LEADED;
EEPROM.write(PROFILE_TYPE_ADDRESS, 1);
}
// Currently using leaded reflow profile
else
{
// Switch to lead-free profile
reflowProfile = REFLOW_PROFILE_LEADFREE;
EEPROM.write(PROFILE_TYPE_ADDRESS, 0);
}
}
}
// Switch status has been read
switchStatus = SWITCH_NONE;
// Simple switch debounce state machine (analog switch)
switch (debounceState)
{
case DEBOUNCE_STATE_IDLE:
// No valid switch press
switchStatus = SWITCH_NONE;
switchValue = readSwitch();
// If either switch is pressed
if (switchValue != SWITCH_NONE)
{
// Keep track of the pressed switch
switchMask = switchValue;
// Intialize debounce counter
lastDebounceTime = millis();
// Proceed to check validity of button press
debounceState = DEBOUNCE_STATE_CHECK;
}
break;
case DEBOUNCE_STATE_CHECK:
switchValue = readSwitch();
if (switchValue == switchMask)
{
// If minimum debounce period is completed
if ((millis() - lastDebounceTime) > DEBOUNCE_PERIOD_MIN)
{
// Valid switch press
switchStatus = switchMask;
// Proceed to wait for button release
debounceState = DEBOUNCE_STATE_RELEASE;
}
}
// False trigger
else
{
// Reinitialize button debounce state machine
debounceState = DEBOUNCE_STATE_IDLE;
}
break;
case DEBOUNCE_STATE_RELEASE:
switchValue = readSwitch();
if (switchValue == SWITCH_NONE)
{
// Reinitialize button debounce state machine
debounceState = DEBOUNCE_STATE_IDLE;
}
break;
}
// PID computation and SSR control
if (reflowStatus == REFLOW_STATUS_ON)
{
now = millis();
reflowOvenPID.Compute();
if ((now - windowStartTime) > windowSize)
{
// Time to shift the Relay Window
windowStartTime += windowSize;
}
if (output > (now - windowStartTime)) digitalWrite(ssrPin, HIGH);
else digitalWrite(ssrPin, LOW);
}
// Reflow oven process is off, ensure oven is off
else
{
digitalWrite(ssrPin, LOW);
}
}
Kompletny szkic projektu jest dość obszerny, więc został dołączony do pliku zip w sekcji download.
Demo
Jedną z zalet Tiny Reflow Controller v2 jest fakt, że jest on wyposażony w port USB, przez który można go zaprogramować. Być może jednak trzeba będzie jeszcze trochę popracować nad swoim Arduino IDE (np. wgrać bootloader do Atmeg328p, jeśli nie ma go w zestawie), aby mieć pewność, że będzie można wgrać do niego kod.
Ta płytka używa standardowego bootloadera Arduino Pro Mini ATmega328 3,3V 8 MHz i może być załadowana tak samo jak V1 przy użyciu AVRISP mkII.
Podłącz ukończony Reflow Controller v2 do swojego komputera. Skopiuj powyższy kod, wklej do IDE, zweryfikuj i naciśnij przycisk "upload". Po przesłaniu kodu powinieneś zobaczyć, że pojawi się splashscreen, jak pokazano na poniższym obrazku, podłącz swój SSR, wentylator i termoparę. Kontroler Reflow jest gotowy do użycia.
Instalacja
Zainstalowaliśmy mini sterownik rozpływowy Tiny Reflow Controller v2 na małym piecu o mocy 900 W i przetestowaliśmy jego działanie. Jak widać na poniższych zdjęciach, sterownik rozpływu jest zainstalowany na przedniej ściance, a przekaźnik półprzewodnikowy i zasilacz mini 5 V z tyłu. Mieliśmy zamiar zainstalować również wentylator chłodzący, ale zgodnie z radą autora projektu, chłodzenie naturalne działa lepiej i minimalnie obciąża komponenty. Ponadto, wyjście FAN na płycie nie jest zaimplementowane w firmware, więc wymagałoby to dodatkowego kodu, aby zadziałało. Tak więc, zdecydowaliśmy się nie instalować wentylatora w tym momencie.
Wyniki reflow
Jak wspomnieliśmy wcześniej, płytka obsługuje dwa profile rozpływu, PB i bezołowiowy (LF), oba wybierane przed rozpoczęciem cyklu rozpływu. Sterownik posiada wbudowany konwerter szeregowy na USB, więc aby przechwycić dane podczas rozpływu, wszystko czego potrzebujesz to podłączyć kabel USB, uruchomić swój ulubiony terminal RS232, ustawić konfigurację szeregową na 115200 bps 8N1 i jesteś gotowy do pracy. Po naciśnięciu przycisku start, dane temperatury są rejestrowane na terminalu wraz z czasem, wartością zadaną i czasem włączenia elementów grzejnych. Przetestowaliśmy oba profile wykonując pełny cykl reflow dla każdego z nich i dzielimy się wynikami tutaj. Podczas naszych wstępnych testów doświadczyliśmy pewnych problemów, jak nie mogliśmy pomyślnie zakończyć cyklu rozpływu, po czym na ekranie pojawił się komunikat Error. Mogło to oznaczać, że termopara dotknęła przewodzącej części płytki PCB, co spowodowało zwarcie, lub że TC został odłączony od płytki, lub że na szynie zasilającej był większy szum niż płyta może tolerować. Okazało się, że w naszym przypadku był to problem z szumem i po wymianie kabla USB na taki, który miał w linii ferrytowy koralik, cykl reflow został zakończony pomyślnie.
Jak widać na powyższych wykresach, oba profile rozpoczynają pracę w temperaturze pokojowej (25ºC) i osiągają fazę zanurzenia po około 115 sekundach. Następnie rozpoczyna się faza rozpływu, która osiąga 220ºC dla PB i 245ºC dla LF. Widzimy, że oba profile są gładkie i czyste, co gwarantuje, że lutowanie rozpływowe może zakończyć się sukcesem.
Wnioski
Główną różnicą pomiędzy TinyReflow Controller v2 a v1 jest zastosowanie wyświetlacza OLED, który wyświetla wykres procesu rozpływu oraz wbudowany interfejs USB-Serial, który eliminuje potrzebę stosowania konwertera podczas programowania płytki.
Szukasz dobrego pieca rozpływowego, który będzie dobrze współpracował z tym kontrolerem? Możesz przejrzeć tę listę stworzoną przez Rocket Stream, aby uzyskać sugestie na temat najlepszych rodzajów pieców do użycia z mini sterownikiem rozpływowym lub odwiedzić ich sklep internetowy, aby kupić już zmontowaną i przetestowaną płytkę.