Serwisy partnerskie:
Close icon
Serwisy partnerskie

Mini sterownik rozpływu z wyświetlaczem OLED

Article Image
Elmax
W innym artykule omówiliśmy jak zbudować sterownik DIY Reflow Oven przy użyciu Tiny Reflow Oven Controller v1 firmy Rocket Stream. Firma Rocket Stream wypuściła również drugą wersję tego sterownika - Tiny Reflow Controller V2, którą przedstawiamy w tym artykule.

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.

Schemat elektryczny sterownika z wyświetlaczem OLED

Ostateczny projekt PCB będzie wyglądał jak na poniższym widoku.

Projekt płytki drukowanej dla mini sterownika reflow v2

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.

Tiny Reflow Controller v2 zmontowany

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.

Tiny Reflow v2 zainstalowany na przedniej ściance 900W pieca
Przekaźnik półprzewodnikowy i mały zasilacz 5V został zainstalowany z tyłu pieca...
...widok pod kątem pieca, który właśnie zakończył cykl reflow

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.

Cykl reflow dla profilu PB
Cykl reflow dla profilu LF

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.

Gotowy piec rozpływowy v2

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ę.

Wideo
Do pobrania
Download icon Materiały dodatkowe do ministerownika z wyświetlaczem OLED

Artykuł TINY REFLOW CONTROLLER WITH OLED DISPLAY opracowano w wersji polskiej na podstawie współpracy z portalem www.electronics-lab.com.

Firma:
Tematyka materiału: OLED, sterownik, piec
AUTOR
Źródło
www.electronics-lab.com
Udostępnij
Zobacz wszystkie quizy
Quiz weekendowy
Edukacja
1/10 Jak działa rezystor LDR?
UK Logo
Elektronika dla Wszystkich
Zapisując się na nasz newsletter możesz otrzymać GRATIS
najnowsze e-wydanie magazynu "Elektronika dla Wszystkich"