I'm currently using a custom PCB, but this also happened when testing with an Arduino Uno R3 on a breadboard.
I'm making a voice activated soldering iron for a project I'm working on, everything works fine except when it gets close to temperature, or close enough that the PID control would change the PWM on the output pin. Once it gets within 50 degrees C the display resets, and stops responding. I'm not sure what could be causing this.
// https://learn.adafruit.com/thermocouple/
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "max6675.h"
#include <PID_v1.h>
#include "DFRobot_DF2301Q.h"
#define PIN_INPUT 0
#define PIN_OUTPUT 11
//Define Variables we'll be connecting to
//I2C communication
DFRobot_DF2301Q_I2C DF2301Q;
char status = 'o';
double Setpoint, Input;
//Define the aggressive and conservative Tuning Parameters
double aggKp=4, aggKi=0.2, aggKd=1;
double consKp=1, consKi=0.05, consKd=0.25;
double Output = 0.00;
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT);
int thermoDO = 2;
int thermoCS = 3;
int thermoCLK = 4;
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);
// make a cute degree symbol
uint8_t degree[8] = {140,146,146,140,128,128,128,128};
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library.
// On an arduino UNO: A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO: 2(SDA), 3(SCL), ...
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define NUMFLAKES 10 // Number of snowflakes in the animation example
#define LOGO_HEIGHT 16
#define LOGO_WIDTH 16
static const unsigned char PROGMEM logo_bmp[] =
{ 0b00000000, 0b11000000,
0b00000001, 0b11000000,
0b00000001, 0b11000000,
0b00000011, 0b11100000,
0b11110011, 0b11100000,
0b11111110, 0b11111000,
0b01111110, 0b11111111,
0b00110011, 0b10011111,
0b00011111, 0b11111100,
0b00001101, 0b01110000,
0b00011011, 0b10100000,
0b00111111, 0b11100000,
0b00111111, 0b11110000,
0b01111100, 0b11110000,
0b01110000, 0b01110000,
0b00000000, 0b00110000 }; //displays the Adafruit logo
int tempF = thermocouple.readFahrenheit(); //sets tempF to the thermocouple's reported fahrenheit temperature
int tempC = thermocouple.readCelsius();//sets tempC to the thermocouple's reported celsius temperature
int Output2 = 0; //sets output 2 to zero at startup for PID to function correctly
int increment = 1;
int set = 0;
void setup() {
Serial.begin(9600);
// Init the sensor
while( !( DF2301Q.begin() ) ) {
Serial.println("Communication with device failed, please check connection");
delay(3000);
}
Serial.println("Begin ok!");
/**
* @brief Set voice volume
* @param voc - Volume value(1~7)
*/
DF2301Q.setVolume(3);
/**
* @brief Set mute mode
* @param mode - Mute mode; set value 1: mute, 0: unmute
*/
DF2301Q.setMuteMode(0);
/**
* @brief Set wake-up duration
* @param wakeTime - Wake-up duration (0-255)
*/
DF2301Q.setWakeTime(15);
/**
* @brief Get wake-up duration
* @return The currently-set wake-up period
*/
uint8_t wakeTime = 0;
wakeTime = DF2301Q.getWakeTime();
Serial.print("wakeTime = ");
Serial.println(wakeTime);
/**
* @brief Play the corresponding reply audio according to the command word ID
* @param CMDID - Command word ID
* @note Can enter wake-up state through ID-1 in I2C mode
*/
// DF2301Q.playByCMDID(1); // Wake-up command
DF2301Q.playByCMDID(23); // Common word ID
Input = tempC;
Setpoint = 100;
//turn the PID on
myPID.SetMode(AUTOMATIC);
Serial.println("MAX6675 test");
// wait for MAX chip to stabilize
delay(500);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
// Show initial display buffer contents on the screen --
// the library initializes this with an Adafruit splash screen.
display.display();
delay(2000); // Pause for 2 seconds
// Clear the buffer
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0,0);
// Draw a single pixel in white
display.print(tempF);
// Show the display buffer on the screen. You MUST call display() after
// drawing commands to make them visible on screen!
display.display();
}
void loop() {
/**
* @brief Get the ID corresponding to the command word
* @return Return the obtained command word ID, returning 0 means no valid ID is obtained
*/
uint8_t CMDID = 0;
CMDID = DF2301Q.getCMDID();
switch (CMDID) {
case 5:
Setpoint = 315;
break;
case 6:
Setpoint = 380;
break;
case 7:
Setpoint = 420;
break;
case 8:
Setpoint = 450;
break;
case 9:
if(increment < 15)
{
increment++;
}
break;
case 10:
if(increment > 1){
increment--;
}
break;
case 129:
status = 'i';
Serial.print("\n");
Serial.print(status);
Serial.print("\n");
Serial.print(CMDID);
break;
case 128:
status = 'o';
Serial.print("\n");
Serial.print(status);
Serial.print("\n");
Serial.print(CMDID);
break;
case 126:
if(Setpoint < 480){
Setpoint = Setpoint + increment;
}
break;
case 127:
if(Setpoint > 300){
Setpoint = Setpoint - increment;
}
}
delay(250);
// basic readout test, just print the current temp
tempC = thermocouple.readCelsius();
if (status == 'i'){
Input = tempC;
double gap = abs(Setpoint-Input); //distance away from setpoint
if (gap < 10)
{ //we're close to setpoint, use conservative tuning parameters
myPID.SetTunings(consKp, consKi, consKd);
}
else
{
//we're far from setpoint, use aggressive tuning parameters
myPID.SetTunings(aggKp, aggKi, aggKd);
}
myPID.Compute();
Output2 = map(Output, 0, 255, 255, 0); //reverses output value for transistor to process correctly
analogWrite(PIN_OUTPUT, Output2); // writes the output value given by the PID to pin 11 on the arduino
}
else{
analogWrite(PIN_OUTPUT, 255);
}
Serial.print(tempC); // prints the temperature celsius to the serial monitor to check for errors
set = Setpoint;
display.clearDisplay(); //clears OLED display to reset image
display.setCursor(0, 0); //sets cursor to top left
display.print("C"); // prints the temperature celsius on the screen
display.setCursor(0, 55);//sets the cursor to just above the bottom left corner
if(status == 'i'){
display.print("Heat: ON");//displays the output from the PID control
}
if(status == 'o'){
display.print("Heat: OFF");//displays the output from the PID control
}
display.setCursor(40,27);
display.print("Temp: ");
display.print(tempC);
display.setCursor(46, 37);
display.print("Set: ");
display.print(set);
display.setCursor(85, 55);
display.print("incr: ");
display.print(increment);
display.display();//tells the display to show all the information
// For the MAX6675 to update, you must delay AT LEAST 250ms between reads!
delay(250);
}