Sfoglia il codice sorgente

initial working commit.

Abhinav Sinha 5 anni fa
commit
71da6a9d34
8 ha cambiato i file con 602 aggiunte e 0 eliminazioni
  1. 5 0
      .gitignore
  2. 67 0
      .travis.yml
  3. 7 0
      .vscode/extensions.json
  4. 39 0
      include/README
  5. 46 0
      lib/README
  6. 14 0
      platformio.ini
  7. 413 0
      src/main.cpp
  8. 11 0
      test/README

+ 5 - 0
.gitignore

@@ -0,0 +1,5 @@
+.pio
+.vscode/.browse.c_cpp.db*
+.vscode/c_cpp_properties.json
+.vscode/launch.json
+.vscode/ipch

+ 67 - 0
.travis.yml

@@ -0,0 +1,67 @@
+# Continuous Integration (CI) is the practice, in software
+# engineering, of merging all developer working copies with a shared mainline
+# several times a day < https://docs.platformio.org/page/ci/index.html >
+#
+# Documentation:
+#
+# * Travis CI Embedded Builds with PlatformIO
+#   < https://docs.travis-ci.com/user/integration/platformio/ >
+#
+# * PlatformIO integration with Travis CI
+#   < https://docs.platformio.org/page/ci/travis.html >
+#
+# * User Guide for `platformio ci` command
+#   < https://docs.platformio.org/page/userguide/cmd_ci.html >
+#
+#
+# Please choose one of the following templates (proposed below) and uncomment
+# it (remove "# " before each line) or use own configuration according to the
+# Travis CI documentation (see above).
+#
+
+
+#
+# Template #1: General project. Test it using existing `platformio.ini`.
+#
+
+# language: python
+# python:
+#     - "2.7"
+#
+# sudo: false
+# cache:
+#     directories:
+#         - "~/.platformio"
+#
+# install:
+#     - pip install -U platformio
+#     - platformio update
+#
+# script:
+#     - platformio run
+
+
+#
+# Template #2: The project is intended to be used as a library with examples.
+#
+
+# language: python
+# python:
+#     - "2.7"
+#
+# sudo: false
+# cache:
+#     directories:
+#         - "~/.platformio"
+#
+# env:
+#     - PLATFORMIO_CI_SRC=path/to/test/file.c
+#     - PLATFORMIO_CI_SRC=examples/file.ino
+#     - PLATFORMIO_CI_SRC=path/to/test/directory
+#
+# install:
+#     - pip install -U platformio
+#     - platformio update
+#
+# script:
+#     - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N

+ 7 - 0
.vscode/extensions.json

@@ -0,0 +1,7 @@
+{
+    // See http://go.microsoft.com/fwlink/?LinkId=827846
+    // for the documentation about the extensions.json format
+    "recommendations": [
+        "platformio.platformio-ide"
+    ]
+}

+ 39 - 0
include/README

@@ -0,0 +1,39 @@
+
+This directory is intended for project header files.
+
+A header file is a file containing C declarations and macro definitions
+to be shared between several project source files. You request the use of a
+header file in your project source file (C, C++, etc) located in `src` folder
+by including it, with the C preprocessing directive `#include'.
+
+```src/main.c
+
+#include "header.h"
+
+int main (void)
+{
+ ...
+}
+```
+
+Including a header file produces the same results as copying the header file
+into each source file that needs it. Such copying would be time-consuming
+and error-prone. With a header file, the related declarations appear
+in only one place. If they need to be changed, they can be changed in one
+place, and programs that include the header file will automatically use the
+new version when next recompiled. The header file eliminates the labor of
+finding and changing all the copies as well as the risk that a failure to
+find one copy will result in inconsistencies within a program.
+
+In C, the usual convention is to give header files names that end with `.h'.
+It is most portable to use only letters, digits, dashes, and underscores in
+header file names, and at most one dot.
+
+Read more about using header files in official GCC documentation:
+
+* Include Syntax
+* Include Operation
+* Once-Only Headers
+* Computed Includes
+
+https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

+ 46 - 0
lib/README

@@ -0,0 +1,46 @@
+
+This directory is intended for project specific (private) libraries.
+PlatformIO will compile them to static libraries and link into executable file.
+
+The source code of each library should be placed in a an own separate directory
+("lib/your_library_name/[here are source files]").
+
+For example, see a structure of the following two libraries `Foo` and `Bar`:
+
+|--lib
+|  |
+|  |--Bar
+|  |  |--docs
+|  |  |--examples
+|  |  |--src
+|  |     |- Bar.c
+|  |     |- Bar.h
+|  |  |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
+|  |
+|  |--Foo
+|  |  |- Foo.c
+|  |  |- Foo.h
+|  |
+|  |- README --> THIS FILE
+|
+|- platformio.ini
+|--src
+   |- main.c
+
+and a contents of `src/main.c`:
+```
+#include <Foo.h>
+#include <Bar.h>
+
+int main (void)
+{
+  ...
+}
+
+```
+
+PlatformIO Library Dependency Finder will find automatically dependent
+libraries scanning project source files.
+
+More information about PlatformIO Library Dependency Finder
+- https://docs.platformio.org/page/librarymanager/ldf.html

+ 14 - 0
platformio.ini

@@ -0,0 +1,14 @@
+; PlatformIO Project Configuration File
+;
+;   Build options: build flags, source filter
+;   Upload options: custom upload port, speed and extra flags
+;   Library options: dependencies, extra library storages
+;   Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[env:nanoatmega328]
+platform = atmelavr
+board = nanoatmega328
+framework = arduino

+ 413 - 0
src/main.cpp

@@ -0,0 +1,413 @@
+/*
+
+  GraphicsTest.ino
+
+  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
+
+  Copyright (c) 2016, olikraus@gmail.com
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without modification, 
+  are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice, this list 
+    of conditions and the following disclaimer.
+    
+  * Redistributions in binary form must reproduce the above copyright notice, this 
+    list of conditions and the following disclaimer in the documentation and/or other 
+    materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
+  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
+
+*/
+
+#include <Arduino.h>
+#include <U8g2lib.h>
+#include <PID_v1.h>
+#include <MAX6675.h>
+#include <SPI.h>
+
+#define THERMOCOUPLE_CS_PIN 7
+
+#define DISPLAY_CS_PIN 10
+#define DISPLAY_DC_PIN 8
+#define DISPLAY_RESET_PIN 9
+
+#define RED_LED_PIN 6
+#define GREEN_LED_PIN 5
+#define SSR_PIN 4
+#define BUTTON_PIN 3
+
+const char* lcdMessagesReflowStatus[] = {
+  "Ready",
+  "Heating",
+  "Holding temp",
+  "Cool",
+  "Complete",
+  "Wait,hot",
+  "Error"
+};
+
+typedef enum REFLOW_STATE
+{
+  REFLOW_STATE_IDLE,
+  REFLOW_STATE_PREHEAT,
+  REFLOW_STATE_SOAK,
+  REFLOW_STATE_COOL,
+  REFLOW_STATE_COMPLETE,
+  REFLOW_STATE_TOO_HOT,
+  REFLOW_STATE_ERROR
+} reflowState_t;
+
+typedef enum REFLOW_STATUS
+{
+  REFLOW_STATUS_OFF,
+  REFLOW_STATUS_ON
+} reflowStatus_t;
+
+typedef enum DEBOUNCE_STATE
+{
+  DEBOUNCE_STATE_IDLE,
+  DEBOUNCE_STATE_CHECK,
+  DEBOUNCE_STATE_RELEASE
+} debounceState_t;
+
+typedef	enum SWITCH
+{
+	SWITCH_NONE,
+	SWITCH_1
+}	switch_t;
+
+// ***** CONSTANTS *****
+#define TEMPERATURE_ROOM 70
+#define TEMPERATURE_SOAK 70
+#define TEMPERATURE_COOL_MIN 40
+#define SENSOR_SAMPLING_TIME 1000
+#define SOAK_PERIOD_MS 1800000 // 30*60*1000 30 minutes
+#define DEBOUNCE_PERIOD_MIN 50
+
+// ***** PID PARAMETERS *****
+// ***** PRE-HEAT STAGE *****
+#define PID_KP_PREHEAT 80    // default 100
+#define PID_KI_PREHEAT 0.025   // default 0.025
+#define PID_KD_PREHEAT 20     // default 20
+// ***** SOAKING STAGE *****
+#define PID_KP_SOAK 300     // default 300
+#define PID_KI_SOAK 0.05     // default 0.05
+#define PID_KD_SOAK 250     // default 250
+
+#define PID_SAMPLE_TIME 1000  //default 1000
+
+// ***** PID CONTROL VARIABLES *****
+double setpoint;
+double inputTemp;
+double output;
+double kp = PID_KP_PREHEAT;
+double ki = PID_KI_PREHEAT;
+double kd = PID_KD_PREHEAT;
+int windowSize;
+unsigned long now;
+unsigned long windowStartTime;
+unsigned long nextRead;
+unsigned long soakStartTime;
+unsigned long timerSoak;
+unsigned long completePeriod;
+// Reflow oven controller state machine state variable
+reflowState_t reflowState = REFLOW_STATE_IDLE;
+// Reflow oven controller status
+reflowStatus_t reflowStatus = REFLOW_STATUS_OFF;
+// Switch debounce state machine state variable
+debounceState_t debounceState;
+// Switch debounce timer
+long lastDebounceTime;
+// Switch press status
+switch_t switchStatus;
+// did encounter a thermocouple error?
+bool TCError = false;
+
+
+MAX6675 tcouple(THERMOCOUPLE_CS_PIN);
+U8G2_SSD1305_128X64_ADAFRUIT_F_4W_HW_SPI u8g2(U8G2_R0, DISPLAY_CS_PIN, DISPLAY_DC_PIN, DISPLAY_RESET_PIN);
+PID reflowOvenPID(&inputTemp, &output, &setpoint, kp, ki, kd, DIRECT);
+
+void u8g2_prepare(void) {
+  u8g2.setFont(u8g2_font_8x13_tf);
+  u8g2.setFontRefHeightExtendedText();
+  u8g2.setDrawColor(1);
+  u8g2.setFontPosTop();
+  u8g2.setFontDirection(0);
+}
+
+void readTemp(void) {
+  inputTemp = tcouple.readTempC();
+  if(inputTemp == 32.00) {
+    TCError = true;
+    reflowState = REFLOW_STATE_ERROR;
+    reflowStatus = REFLOW_STATUS_OFF;
+  }
+}
+
+void setup(void) {
+  // Turn off SSR.
+  digitalWrite(SSR_PIN, LOW);
+  pinMode(SSR_PIN, OUTPUT);
+
+  pinMode(BUTTON_PIN, INPUT_PULLUP);
+
+  u8g2.begin();
+  u8g2.clearBuffer();
+  u8g2_prepare();
+
+   // Set window size
+  windowSize = 2000;
+  // Initialize thermocouple reading variable
+  nextRead = millis();
+}
+
+void handleSwitch(void) {
+
+  // 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;
+    }
+  } 
+
+  // Simple switch debounce state machine (for switch #1 (both analog & digital
+  // switch supported))
+  switch (debounceState)
+  {
+  case DEBOUNCE_STATE_IDLE:
+    // No valid switch press
+    switchStatus = SWITCH_NONE;
+    // If switch #1 is pressed
+      if (digitalRead(BUTTON_PIN) == LOW)
+      {
+        // Intialize debounce counter
+        lastDebounceTime = millis();
+        // Proceed to check validity of button press
+        debounceState = DEBOUNCE_STATE_CHECK;
+      }  
+    break;
+
+  case DEBOUNCE_STATE_CHECK:
+    // If switch #1 is still pressed
+    if (digitalRead(BUTTON_PIN) == LOW)
+      {
+        // If minimum debounce period is completed
+        if ((millis() - lastDebounceTime) > DEBOUNCE_PERIOD_MIN)
+        {
+          // 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:
+    if (digitalRead(BUTTON_PIN) == HIGH)
+    {
+      // Valid switch 1 press
+      switchStatus = SWITCH_1;
+      // Reinitialize button debounce state machine
+      debounceState = DEBOUNCE_STATE_IDLE; 
+    }
+    break;
+  }
+}
+
+// Reflow oven controller state machine
+void handleReflowState(void) {
+  switch (reflowState)
+  {
+  case REFLOW_STATE_IDLE:
+    // If oven temperature is still above room temperature
+    if (inputTemp >= TEMPERATURE_ROOM)
+    {
+      reflowState = REFLOW_STATE_TOO_HOT;
+    }
+    else
+    {
+      // If switch is pressed, start reflow process
+      if (switchStatus == SWITCH_1)
+      {
+        switchStatus = SWITCH_NONE;
+        // Initialize PID control window starting time
+        windowStartTime = millis();
+        // Ramp up to minimum soaking temperature
+        setpoint = TEMPERATURE_SOAK;
+        // 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 achieved.
+    if (inputTemp >= TEMPERATURE_SOAK)
+    {
+      soakStartTime = millis();
+      // Chop soaking period into smaller sub-period
+      timerSoak = soakStartTime + SOAK_PERIOD_MS;
+      // Set less agressive PID parameters for soaking ramp
+      reflowOvenPID.SetTunings(PID_KP_SOAK, PID_KI_SOAK, PID_KD_SOAK);
+      // Proceed to soaking state
+      reflowState = REFLOW_STATE_SOAK; 
+    }
+    break;
+
+  case REFLOW_STATE_SOAK:
+    // If micro soak temperature is achieved       
+    if (millis() > timerSoak)
+    {
+      timerSoak = millis() + SOAK_PERIOD_MS;
+      reflowStatus = REFLOW_STATUS_OFF;
+      reflowState = REFLOW_STATE_COOL; 
+    }
+    break;
+
+  case REFLOW_STATE_COOL:
+    // If minimum cool temperature is achieve       
+    if (inputTemp <= TEMPERATURE_COOL_MIN)
+    {
+      completePeriod = millis() + 1000;
+      // Turn off reflow process
+      reflowStatus = REFLOW_STATUS_OFF;   
+      // Proceed to reflow Completion state
+      reflowState = REFLOW_STATE_COMPLETE; 
+    }         
+    break;    
+
+  case REFLOW_STATE_COMPLETE:
+    if (millis() > completePeriod)
+    {
+      // Reflow process ended
+      reflowState = REFLOW_STATE_IDLE; 
+    }
+    break;
+  
+  case REFLOW_STATE_TOO_HOT:
+    // If oven temperature drops below room temperature
+    if (inputTemp < TEMPERATURE_ROOM)
+    {
+      // Ready to reflow
+      reflowState = REFLOW_STATE_IDLE;
+    }
+    break;
+    
+  case REFLOW_STATE_ERROR:
+    
+    // If thermocouple problem is still present
+    if (isnan(inputTemp))
+    {
+      // Wait until thermocouple wire is connected
+      reflowState = REFLOW_STATE_ERROR; 
+    }
+    else
+    {
+      // Clear to perform reflow process
+      reflowState = REFLOW_STATE_IDLE; 
+    }
+    break;    
+  }    
+}
+
+// PID computation and SSR control
+void handleSSR(void) {
+  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(SSR_PIN, HIGH);
+    } else {
+      digitalWrite(SSR_PIN, LOW);
+    }
+  } else {
+    // Reflow oven process is off, ensure oven is off
+    digitalWrite(SSR_PIN, LOW);
+  }
+
+}
+
+void drawScreen(void) {
+  char temperatureStr[8];
+  dtostrf(inputTemp, 4, 2, temperatureStr);
+  u8g2.drawStr( 0, 0, "Temp: ");
+  u8g2.drawStr( 60, 0, temperatureStr);
+  u8g2.drawStr( 100, 0, "C");
+
+  u8g2.drawStr( 0, 12, "tc_err: ");
+  if (TCError)
+  {
+    u8g2.drawStr( 60, 12, "true");
+  } else {
+    u8g2.drawStr( 60, 12, "false");
+  }
+  
+  u8g2.drawStr( 0, 24, lcdMessagesReflowStatus[reflowState]);
+
+  if(reflowState == REFLOW_STATE_SOAK) {
+    char soakSecondsStr[8];
+    itoa((millis() - soakStartTime)/1000, soakSecondsStr, 10);
+    // dtostrf((millis() - soakStartTime)/1000, 4, 2, soakSecondsStr);
+    u8g2.drawStr( 0, 36, "Time: ");
+    u8g2.drawStr( 40, 36, soakSecondsStr);
+    u8g2.drawStr( 80, 36, "/1800");
+
+  }
+
+  u8g2.sendBuffer();
+}
+
+void loop(void) {
+  u8g2.clearBuffer();
+  if (millis() > nextRead) {
+    readTemp();
+  }
+
+  handleReflowState();
+
+  handleSwitch();
+
+  handleSSR();
+
+  drawScreen();
+}

+ 11 - 0
test/README

@@ -0,0 +1,11 @@
+
+This directory is intended for PIO Unit Testing and project tests.
+
+Unit Testing is a software testing method by which individual units of
+source code, sets of one or more MCU program modules together with associated
+control data, usage procedures, and operating procedures, are tested to
+determine whether they are fit for use. Unit testing finds problems early
+in the development cycle.
+
+More information about PIO Unit Testing:
+- https://docs.platformio.org/page/plus/unit-testing.html