stazione saldante problema
ciao a tutti e buon giorno.
mi sto facendo questa stazione saldante con arduino
https://hackermagnet.com/soldering-station/
con questo codice
e l ho leggermente modificato cosi per mettere un lcd ic2
funziona, cioe' in parte..(in entrambi i modi), quando vado ad accendere il saldatore, mi scrive on ma non esce segnale e non mi riscalda la punta.
la temperatura e corretta, e mi da circa quella dell ambiente, ma se lo scaldo con la mado o con un altro saldatore la temperatura sale
pero non funziona , arduino nuovo mosfet nuovo, provato ad mettere segnale sul gate e funziona
ho provato con autotune, mettendo la punta in temperatura piu o meno a 250 gradi.ma nulla...scondo voi cosa sto sbagliando...
a questo punto vi chiedo se esiste un semplicissimo controller per lo stilo 907,che funzioni..visto che ne ho messi di vari ma o perche non riesco a convertirli a ic2 o perche non riesco a farli andare mi sono scoraggiato...
mi potreste dare qualche dritta?
grazie mille
mi sto facendo questa stazione saldante con arduino
https://hackermagnet.com/soldering-station/
con questo codice
- Codice: Seleziona tutto
/*******************************************************************************************
Soldering Station controller for Chinese Hakko 907
Original code by Kuro - https://hackaday.io/project/3417-hakko-907-based-soldering-station
Edited by Yannis Kari - https://hackermagnet.com/portfolio/soldering-station
# Change Log
## [0.6b:]
- ability to limit PWM_MAX below 100˚C (requested by Molodchaga)
## [0.6:]
- turn off if temp exceeds MAX+30 for more than SAFETY_OFF_TIME (5")
- turn off if sleeping for more than AUTO_OFF_TIME (5')
- boot screen that goes away after putting the iron on base stand
## [0.5:]
- sleep mode using reed switch on pin 18 and a magnet on base after AUTO_SLEEP_TIME (30")
## [0.4:]
- options to clear EEPROM and start autotune during startup with confirmation
- new progress bar
- new temp icon
- print duty cycle on screen
## [0.3:]
- sound alerts with buzzer on pin 13
## [0.2:]
- Auto turn off
## [0.1b:]
- initial release
********************************************************************************************/
#include <Wire.h>
#include "LiquidCrystal.h"
#include "TimerOne.h"
#include "Button.h"
#include "PID_v1.h"
#include "PID_AutoTune_v0.h"
#include "EEPROMex.h"
#include <avr/wdt.h>
#define OFF 0
#define ON 1
// PIN DEFINITIONS
#define HEATER 9
#define TEMP_PIN 21
#define POT 20
#define REED 18
#define Button1 8
#define Button2 7
#define Button3 4
#define Button4 19
#define Buzzer 13
//LCD
#define LCD_LED 10
#define LCD_RS 17
#define LCD_EN 16
#define LCD_D4 15
#define LCD_D5 14
#define LCD_D6 12
#define LCD_D7 11
//LED
const int LED_R = 6;
const int LED_G = 5;
const int LED_B = 3;
int flash_on = 0;
int flash_off = 0;
//SETTINGS
char ver[] = "0.6";
int boot_screen = 1;
#define TEMP_WO_IRON 749 // readTemp(); returns about 749 when I disconnect the iron
#define LCD_INTERVAL 200 // Time im ms between LCD updates
#define PTC_INTERVAL 100 // Time im ms between average analog readings
#define FLASH_ON 600 // Time im ms for RGB to stay on when flashing, keep it multiple of LCD_INTERVAL
#define FLASH_OFF 400 // Time im ms for RGB to stay off when flashing, keep it multiple of LCD_INTERVAL
#define RGB_EFECT_MIN 60 // degrees below temperature to start the RGB effect with blue color
#define RGB_EFECT_MAX 30 // degrees above temperature to finish the RGB effect with red color
#define BAR_STEP 4 // graph will move every 4˚C
#define AUTO_SLEEP_TIME 30000 // Auto sleep time
#define AUTO_OFF_TIME 300000// Auto OFF time if iron is in sleep mode
#define SAFETY_OFF_TIME 5000 // Auto OFF time if temp exceeds max+30
#define BUZ_DUR 10 //buzzer sound duration
// Temperature control definitions
#define MIN_TEMP 200 // Minimum setpoint temperature, sleep temp = min - 50
#define MAX_TEMP 370 // Maximum setpoint temperature, turn off temp = max + 30
#define PWM_MAX 1012 // PWM limit, max 1023
#define PWM_LIMIT 0.8 // Limit PWM_MAX below 100˚C
// Y = a*X + b, where Y is the temperature and X is the analog value read from the sensor.
#define EQUATION_A 0.907
#define EQUATION_B -177.81
// PID VALUES
#define KP_VAL 20.00
#define KI_VAL 3.50
#define KD_VAL 25.00
// PID Autotune Variables
//Setup a High Temp for Autotune e.g. 250˚C
//Preheat the Iron at a lower temp like 200˚C and start autotune with a preheated iron.
//Don't use a cold iron because it gives momentarely false readings at low temperatures
//and the Autotune algorithm won't calculate correct P,I,D parameters.
#define AUTOTUNE_SETPOINT 250 // Temperature around PID autotune will tune
#define AUTOTUNE_START_VALUE (PWM_MAX/2) // Do not change
#define AUTOTUNE_STEP_VALUE AUTOTUNE_START_VALUE // Do not change
#define AUTOTUNE_NOISEBAND 3
#define AUTOTUNE_LOOKBACK 10
int bright = 0; //brightness of LCD (1..10)
int temp_5 = OFF; //multiples of 5
int autoTurnOFF = OFF; //
uint8_t showAnalog = ON; //show analog values in PID values view
// Global variables
uint32_t last_lcd_update = 0;
uint32_t last_ptc_update = 0;
uint8_t heater_mode = OFF;
uint8_t sleeping = OFF;
uint8_t ironLifted = OFF;
uint32_t base_time = 0;
uint32_t sleeping_time = 0;
uint32_t overshoot_time = 0;
uint8_t showPID = OFF;
uint8_t clearEEPROM = OFF;
// PID Variables
double temperature;
double setpoint = 0.0;
double duty;
double kp;
double ki;
double kd;
uint16_t autotune_address;
uint16_t kp_address;
uint16_t ki_address;
uint16_t kd_address;
uint16_t bright_address;
uint16_t temp_5_address;
uint16_t autoTurnOFF_address;
PID heaterPid(&temperature, &duty, &setpoint, 2, 5, 1, DIRECT);
PID_ATune aTune(&temperature, &duty);
LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
Button heatButton = Button(Button1, LOW); // start/stop heating, start autotune
Button increaseBrightButton = Button(Button2, LOW); // change lcd brightness
Button temp_5_Button = Button(Button3, LOW); // enable or disable showing temp as multiple of 5
Button pidButton = Button(Button4, LOW); //show PID constants, save EEPROM on exit, reset EEPROM
void setup() {
// Autotune
uint8_t autotune = OFF;
uint8_t autotune_pid = 0;
// Enable Watchdog Timer, 1 second
wdt_enable(WDTO_1S);
// Define the EEPROM address for Kp, Ki and Kd
autotune_address = EEPROM.getAddress(sizeof(uint8_t));
kp_address = EEPROM.getAddress(sizeof(double));
ki_address = EEPROM.getAddress(sizeof(double));
kd_address = EEPROM.getAddress(sizeof(double));
bright_address = EEPROM.getAddress(sizeof(int));
temp_5_address = EEPROM.getAddress(sizeof(int));
autoTurnOFF_address = EEPROM.getAddress(sizeof(int));
// Set up pins
pinMode(LCD_LED, OUTPUT);
pinMode(HEATER, OUTPUT);
pinMode(LED_R, OUTPUT);
pinMode(LED_G, OUTPUT);
pinMode(LED_B, OUTPUT);
pinMode(Buzzer, OUTPUT);
pinMode(Button1, INPUT_PULLUP);
pinMode(Button2, INPUT_PULLUP);
pinMode(Button3, INPUT_PULLUP);
pinMode(Button4, INPUT_PULLUP);
pinMode(REED, INPUT_PULLUP);
// Set up Heater PWM
Timer1.PWM(HEATER, 0, 30);
// Set up PID
heaterPid.SetOutputLimits(0, PWM_MAX);
heaterPid.SetSampleTime(50); // Update PID every 50ms
heaterPid.SetMode(AUTOMATIC);
// Set up LCD
setBrightness(bright);
lcd.begin(16, 2);
charSetup();
//Check if reset EEPROM button is pressed at startup
if (digitalRead(Button4) == 0) {
clearEEPROM = ON;
}
// Check if PID autotune button is pressed at startup
else if (digitalRead(Button1) == 0) {
autotune = ON;
}
//Reset EEPROM
if (clearEEPROM){
setBrightness(10);
lcd.clear();
lcd.print(" Clear EEPROM ? ");
lcd.setCursor(0, 1);
lcd.print(" [YES] [NO] ");
while (clearEEPROM){
if (digitalRead(Button2) == 0){
EEPROM.writeByte(autotune_address, 0);
EEPROM.writeDouble(kp_address, 0);
EEPROM.writeDouble(ki_address, 0);
EEPROM.writeDouble(kd_address, 0);
EEPROM.writeInt(bright_address, 0);
EEPROM.writeInt(temp_5_address, 0);
EEPROM.writeInt(autoTurnOFF_address, 0);
lcd.clear();
lcd.print("Cleared!");
lcd.setCursor(0, 1);
lcd.print(">Press 3 to exit");
for (int i = 0; i < 2; i++){
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
delay(BUZ_DUR*15);
}
}
else if (digitalRead(Button3) == 0){
clearEEPROM = OFF;
}
wdt_reset();
}
}
// Start PID autotune
else if (autotune){
setBrightness(10);
lcd.clear();
lcd.print(" Autotune PID ? ");
lcd.setCursor(0, 1);
lcd.print(" [YES] [NO] ");
while (autotune){
if (digitalRead(Button2) == 0){
// Configure PID autotune
setpoint = AUTOTUNE_SETPOINT;
duty = AUTOTUNE_START_VALUE;
aTune.SetNoiseBand(AUTOTUNE_NOISEBAND);
aTune.SetOutputStep(AUTOTUNE_STEP_VALUE);
aTune.SetLookbackSec(AUTOTUNE_LOOKBACK);
aTune.SetControlType(1);
// Print some autotune info
lcd.clear();
lcd.print("Autotune PID at:");
lcd.setCursor(0, 1);
lcd.print((uint16_t)setpoint);
lcd.print((char)223);
lcd.print("C");
// Heat to the setpoint, temperature will rise above it
Timer1.setPwmDuty(HEATER, duty);
while(readTemp() < setpoint) {
// Reset the watchdog timer to prevent rebooting
wdt_reset();
}
// Wait for temperature to drop to setpoint
Timer1.setPwmDuty(HEATER, 0);
while(readTemp() > setpoint) {
// Reset the watchdog timer to prevent rebooting
wdt_reset();
}
// Start the autotune
while(autotune) {
// Get the current temperature
temperature = readTemp();
// Check if the autotune is finished
if(aTune.Runtime() != 0) {
autotune = OFF;
}
else {
Timer1.setPwmDuty(HEATER, duty);
}
// If finished, set up the PID and EEPROM values
if(!autotune) {
// Turn off the heater
Timer1.setPwmDuty(HEATER, 0);
// Get the values from autotune
kp = aTune.GetKp();
ki = aTune.GetKi();
kd = aTune.GetKd();
// Write them to the EEPROM
EEPROM.writeDouble(kp_address, kp);
EEPROM.writeDouble(ki_address, ki);
EEPROM.writeDouble(kd_address, kd);
EEPROM.writeByte(autotune_address, 1);
// Reset the setpoint
setpoint = 0.0;
}
wdt_reset();
}
for (int i = 0; i < 2; i++){
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
delay(BUZ_DUR*15);
}
}
else if (digitalRead(Button3) == 0){
autotune = OFF;
}
wdt_reset();
}
}
bright = EEPROM.readInt(bright_address);
setBrightness(bright);
if(boot_screen){
if (digitalRead(REED)){
lcd.clear();
lcd.print(char(162));
lcd.print("Soldering Iron");
lcd.setCursor(0, 1);
lcd.print(" Controller ");
lcd.print(ver);
lcd.print(char(163));
}
}
while (boot_screen){
if (!digitalRead(REED)){
boot_screen = 0;
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
wdt_reset();
}
temp_5 = EEPROM.readInt(temp_5_address);
autoTurnOFF = EEPROM.readInt(autoTurnOFF_address);
// Get the PID constant values from EEPROM if autotune was run
autotune_pid = EEPROM.readByte(autotune_address);
if(autotune_pid == 1) {
kp = EEPROM.readDouble(kp_address);
ki = EEPROM.readDouble(ki_address);
kd = EEPROM.readDouble(kd_address);
}
else{
kp = KP_VAL;
ki = KI_VAL;
kd = KD_VAL;
}
heaterPid.SetTunings(kp,ki,kd);
lcd.clear();
}
void loop() {
uint32_t current_time = millis(); // Get the current time
wdt_reset();
checkButton();
// Automatic turn-off
if(heater_mode) {
//if left on base and lifted at least once
if(!(digitalRead(REED)) && (ironLifted)){
if (autoTurnOFF) {
if (sleeping){
if ((millis() - sleeping_time) >= AUTO_OFF_TIME){
heater_mode = OFF;
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
}
else if ((millis() - base_time) >= AUTO_SLEEP_TIME) {
sleeping = ON;
setpoint = MIN_TEMP - 50;
sleeping_time = millis();
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
}
}
//lifted from base or hasn't lifted at least once
else{
if (sleeping){
sleeping = OFF;
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
else if (digitalRead(REED)) ironLifted = ON;
base_time = millis();
setpoint = readPot();
}
}
else setpoint = readPot();
// Read Analog data for PTC
if(current_time - last_ptc_update > PTC_INTERVAL) {
temperature = readTemp();
if(heater_mode){
if (temperature > MAX_TEMP + 30){
if (millis() - overshoot_time >= SAFETY_OFF_TIME){
heater_mode = OFF;
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
}
else overshoot_time = millis();
lightRGB(setpoint, temperature);
if(temperature < 100) heaterPid.SetOutputLimits(0, PWM_MAX * PWM_LIMIT);
else heaterPid.SetOutputLimits(0, PWM_MAX);
}
last_ptc_update = current_time;
}
heaterPid.Compute(); // Calculate PID value
// Adjust PWM Duty based on the PID
if(heater_mode) {
Timer1.setPwmDuty(HEATER, duty);
} else {
Timer1.setPwmDuty(HEATER, 0);
}
//Check if it's time to update the LCD
if(current_time - last_lcd_update > LCD_INTERVAL) {
lcd.setCursor(0, 0);
if((temperature > TEMP_WO_IRON-5) && (temperature < TEMP_WO_IRON+5)){
heater_mode = OFF;
lcd.print(" Please ");
lcd.setCursor(0, 1);
lcd.print(" Connect Iron ");
if (flash_on < FLASH_ON/LCD_INTERVAL){ // stay on for FLASH_ON ms
setColor(255, 0, 0); // red
flash_on++;
flash_off = 0;
}
else{
if(flash_off < FLASH_OFF/LCD_INTERVAL){ // stay off for FLASH_OFF ms
setColor(0, 0, 0);
flash_off++;
}
else flash_on = 0;
}
}
else{
if (!showPID) {
//1st Row
lcd.write(byte(0));
lcd.print(' ');
if (temp_5){
if (temperature < 98) lcd.print(' ');
if (int(temperature) % 5 < 3){
lcd.print(int(temperature / 5) * 5);
}
else{
lcd.print(int(temperature / 5 + 1) * 5);
}
}
else{
if (temperature < 100) lcd.print(' ');
lcd.print(temperature, 0);
}
lcd.print((char)223);
lcd.print("C ");
printGraph(setpoint, temperature);
//2nd Row
lcd.setCursor(0, 1);
if (!digitalRead(REED)) lcd.print(char(219));
else lcd.print(" ");
lcd.print(" ");
lcd.print(setpoint, 0);
lcd.print((char)223);
lcd.print("C ");
//print duty
int power;
if (heater_mode) power = duty * (100.0/1023);
//if (heater_mode) power = duty * (100.0/PWM_MAX);
else power = 0;
if (power < 10) lcd.print(" ");
else if (power < 100) lcd.print(" ");
lcd.print(power);
lcd.print("% ");
if (heater_mode){
if (sleeping) lcd.print("_zZ");
else{
lcd.print(" ");
lcd.write(byte(1));
lcd.print("N");
}
}
else{
lcd.print("OFF");
}
}
else displayPid();
if (!heater_mode) setColor(255, 255, 255); // white
}
last_lcd_update = current_time;
}
}
// Read Iron temperature
uint16_t readTemp() {
uint16_t temp = 0;
// Discard first reading
analogRead(TEMP_PIN);
// Read temperature eight times
for (int i = 0; i < 8; i++){
temp += analogRead(TEMP_PIN);
}
temp = (temp >> 3);
temp = (EQUATION_A*temp) + EQUATION_B;
return temp;
}
uint16_t readPot() {
uint16_t pot = 0;
// Discard first reading
analogRead(POT);
// Read the potentiometer four times
pot += analogRead(POT);
pot += analogRead(POT);
pot += analogRead(POT);
pot += analogRead(POT);
// Map the value read to the temperature range
pot = map(pot, 0, 4092, MIN_TEMP, MAX_TEMP);
if (pot % 5 < 3) return pot / 5 * 5;
else return (pot / 5 + 1) * 5;
}
// Check if heater start button was pressed
void checkButton() {
heatButton.listen();
increaseBrightButton.listen();
temp_5_Button.listen();
pidButton.listen();
//Button1
if(heatButton.onPress()) {
if (showPID) autoTurnOFF = !autoTurnOFF;
else{
if (heater_mode){
heater_mode = OFF;
}
else{
ironLifted = OFF;
overshoot_time = millis();
heater_mode = ON;
}
}
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
//Button2
if (increaseBrightButton.onPress()){
if (++bright > 10) bright = 1;
setBrightness(bright);
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
//Button3
if (temp_5_Button.onPress()){
temp_5 = !temp_5;
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
//Button4
if (pidButton.onPress()){
if (!showPID){
showPID = ON;
}
else{
showPID = OFF;
EEPROM.writeInt(bright_address, bright);
EEPROM.writeInt(temp_5_address, temp_5);
EEPROM.writeInt(autoTurnOFF_address, autoTurnOFF);
}
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
}
// Display PID Constants
void displayPid() {
lcd.clear();
lcd.print("P:");
lcd.print(kp, 2);
lcd.print(" I:");
lcd.print(ki, 2);
if(temp_5) lcd.print(" 5");
else lcd.print(" 1");
lcd.setCursor(0, 1);
lcd.print("D:");
lcd.print(kd, 2);
lcd.print(" slp");
if (autoTurnOFF) lcd.print("Y");
else lcd.print("N");
lcd.print(" ");
if (showAnalog){
uint16_t temp_analog = 0;
for (int i=0; i<5; i++){
temp_analog += analogRead(TEMP_PIN);
}
lcd.print(temp_analog/5);
}
else lcd.print(" ");
}
void setBrightness(int light){
light = map(light, 0, 10, 245, 10);
analogWrite(LCD_LED, light);
}
void setColor(int red, int green, int blue){
analogWrite(LED_R, 255-red);
analogWrite(LED_G, 255-green);
analogWrite(LED_B, 255-blue);
}
void lightRGB(double setpoint, double termperature){
double diff = setpoint - temperature;
if (diff > RGB_EFECT_MIN) diff = RGB_EFECT_MIN;
else if (diff < -RGB_EFECT_MAX) diff = -RGB_EFECT_MAX;
if (diff < 0){
diff = map(diff, -RGB_EFECT_MAX, 0, 255, 0);
setColor(diff, 255-diff, 0);
}
else{
diff = map(diff, 0, RGB_EFECT_MIN, 0, 255);
setColor(0, 255-diff, diff);
}
}
void printGraph(double setpoint, double termperature){
double diff = temperature - setpoint;
int boxes;
if (diff > BAR_STEP*7) boxes = 7;
else if (diff < -BAR_STEP*7) boxes = -7;
else boxes = diff / BAR_STEP;
int blanks = -abs(boxes)/2+3.5;
//if temp = setpoint
if (boxes == 0){
for (int i = 0; i < 3; i++){
lcd.write(byte(2));
}
lcd.write(byte(3));
lcd.write(byte(4));
for (int i = 0; i < 3; i++){
lcd.write(byte(2));
}
}
//if temp < setpoint
else if (boxes < 0) {
//print blanks
for (int i = 0; i < blanks; i++){
lcd.write(byte(2));
}
//print first box
if (boxes %2 == 0) lcd.write(byte(3));
else lcd.write(byte(5));
//print full box/es
for (int i=0; i < 3-blanks; i++){
lcd.write(byte(7));
}
//print 4 blanks
for (int i=0; i < 4; i++){
lcd.write(byte(2));
}
}
//if temp > setpoint
else{
//print 4 blanks
for (int i = 0; i < 4; i++){
lcd.write(byte(2));
}
//print full box/es
for (int i=0; i < 3-blanks; i++){
lcd.write(byte(7));
}
//print last box
if (boxes %2 == 0) lcd.write(byte(4));
else lcd.write(byte(6));
//print blanks
for (int i = 0; i < blanks; i++){
lcd.write(byte(2));
}
}
}
/*
| 2 | 3 | 4 | 5 | 6 | 7 |
| ## ## | ## ## | ## ## | ## ## | ## ## | ## ## |
| | | | | | |
| | | | ## | ## | ## ## |
| | ## | ## | ## ## | ## ## | ## ## |
| | ## | ## | ## ## | ## ## | ## ## |
| | | | ## | ## | ## ## |
| | | | | | |
| ## ## | ## ## | ## ## | ## ## | ## ## | ## ## |
*/
void charSetup() {
byte therm[8] = {0b10010,0b11010,0b10010,0b11010,0b10010,0b11110,0b11110,0b11110};
byte on[8] = {0b00100,0b00100,0b10101,0b10001,0b10001,0b10001,0b01110,0b00000};
byte bar[7][8] = {
{0b11011, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11011 },
{0b11011, 0b00000, 0b00000, 0b00011, 0b00011, 0b00000, 0b00000, 0b11011 },
{0b11011, 0b00000, 0b00000, 0b11000, 0b11000, 0b00000, 0b00000, 0b11011 },
{0b11011, 0b00000, 0b00011, 0b11011, 0b11011, 0b00011, 0b00000, 0b11011 },
{0b11011, 0b00000, 0b11000, 0b11011, 0b11011, 0b11000, 0b00000, 0b11011 },
{0b11011, 0b00000, 0b11011, 0b11011, 0b11011, 0b11011, 0b00000, 0b11011 }
};
lcd.createChar(0, therm);
lcd.createChar(1, on);
lcd.createChar(2, bar[0]);
lcd.createChar(3, bar[1]);
lcd.createChar(4, bar[2]);
lcd.createChar(5, bar[3]);
lcd.createChar(6, bar[4]);
lcd.createChar(7, bar[5]);
}
e l ho leggermente modificato cosi per mettere un lcd ic2
- Codice: Seleziona tutto
/*******************************************************************************************
Soldering Station controller for Chinese Hakko 907
Original code by Kuro - https://hackaday.io/project/3417-hakko-907-based-soldering-station
Edited by Yannis Kari - https://hackermagnet.com/portfolio/soldering-station
# Change Log
## [0.6b:]
- ability to limit PWM_MAX below 100˚C (requested by Molodchaga)
## [0.6:]
- turn off if temp exceeds MAX+30 for more than SAFETY_OFF_TIME (5")
- turn off if sleeping for more than AUTO_OFF_TIME (5')
- boot screen that goes away after putting the iron on base stand
## [0.5:]
- sleep mode using reed switch on pin 18 and a magnet on base after AUTO_SLEEP_TIME (30")
## [0.4:]
- options to clear EEPROM and start autotune during startup with confirmation
- new progress bar
- new temp icon
- print duty cycle on screen
## [0.3:]
- sound alerts with buzzer on pin 13
## [0.2:]
- Auto turn off
## [0.1b:]
- initial release
********************************************************************************************/
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include "LiquidCrystal.h"
#include "TimerOne.h"
#include "Button.h"
#include "PID_v1.h"
#include "PID_AutoTune_v0.h"
#include "EEPROMex.h"
#include <avr/wdt.h>
#define OFF 0
#define ON 1
// PIN DEFINITIONS
#define HEATER 3
#define TEMP_PIN 0
#define POT A7
#define REED 2
#define Button1 4
#define Button2 5
#define Button3 6
#define Button4 7
#define Buzzer 13
//LCD
#define LCD_LED 10
//LED
const int LED_R = 6;
const int LED_G = 5;
const int LED_B = 3;
int flash_on = 0;
int flash_off = 0;
//SETTINGS
char ver[] = "0.6";
int boot_screen = 1;
#define TEMP_WO_IRON 749 // readTemp(); returns about 749 when I disconnect the iron
#define LCD_INTERVAL 200 // Time im ms between LCD updates
#define PTC_INTERVAL 100 // Time im ms between average analog readings
#define FLASH_ON 600 // Time im ms for RGB to stay on when flashing, keep it multiple of LCD_INTERVAL
#define FLASH_OFF 400 // Time im ms for RGB to stay off when flashing, keep it multiple of LCD_INTERVAL
#define RGB_EFECT_MIN 60 // degrees below temperature to start the RGB effect with blue color
#define RGB_EFECT_MAX 30 // degrees above temperature to finish the RGB effect with red color
#define BAR_STEP 4 // graph will move every 4˚C
#define AUTO_SLEEP_TIME 30000 // Auto sleep time
#define AUTO_OFF_TIME 300000// Auto OFF time if iron is in sleep mode
#define SAFETY_OFF_TIME 5000 // Auto OFF time if temp exceeds max+30
#define BUZ_DUR 10 //buzzer sound duration
// Temperature control definitions
#define MIN_TEMP 200 // Minimum setpoint temperature, sleep temp = min - 50
#define MAX_TEMP 370 // Maximum setpoint temperature, turn off temp = max + 30
#define PWM_MAX 1012 // PWM limit, max 1023
#define PWM_LIMIT 0.8 // Limit PWM_MAX below 100˚C
// Y = a*X + b, where Y is the temperature and X is the analog value read from the sensor.
#define EQUATION_A 0.907
#define EQUATION_B -177.81
// PID VALUES
#define KP_VAL 20.00
#define KI_VAL 3.50
#define KD_VAL 25.00
// PID Autotune Variables
//Setup a High Temp for Autotune e.g. 250˚C
//Preheat the Iron at a lower temp like 200˚C and start autotune with a preheated iron.
//Don't use a cold iron because it gives momentarely false readings at low temperatures
//and the Autotune algorithm won't calculate correct P,I,D parameters.
#define AUTOTUNE_SETPOINT 250 // Temperature around PID autotune will tune
#define AUTOTUNE_START_VALUE (PWM_MAX/2) // Do not change
#define AUTOTUNE_STEP_VALUE AUTOTUNE_START_VALUE // Do not change
#define AUTOTUNE_NOISEBAND 3
#define AUTOTUNE_LOOKBACK 10
int bright = 0; //brightness of LCD (1..10)
int temp_5 = OFF; //multiples of 5
int autoTurnOFF = OFF; //
uint8_t showAnalog = ON; //show analog values in PID values view
// Global variables
uint32_t last_lcd_update = 0;
uint32_t last_ptc_update = 0;
uint8_t heater_mode = OFF;
uint8_t sleeping = OFF;
uint8_t ironLifted = OFF;
uint32_t base_time = 0;
uint32_t sleeping_time = 0;
uint32_t overshoot_time = 0;
uint8_t showPID = OFF;
uint8_t clearEEPROM = OFF;
// PID Variables
double temperature;
double setpoint = 0.0;
double duty;
double kp;
double ki;
double kd;
uint16_t autotune_address;
uint16_t kp_address;
uint16_t ki_address;
uint16_t kd_address;
uint16_t bright_address;
uint16_t temp_5_address;
uint16_t autoTurnOFF_address;
PID heaterPid(&temperature, &duty, &setpoint, 2, 5, 1, DIRECT);
PID_ATune aTune(&temperature, &duty);
LiquidCrystal_I2C lcd(0x27,16,2);
Button heatButton = Button(Button1, LOW); // start/stop heating, start autotune
Button increaseBrightButton = Button(Button2, LOW); // change lcd brightness
Button temp_5_Button = Button(Button3, LOW); // enable or disable showing temp as multiple of 5
Button pidButton = Button(Button4, LOW); //show PID constants, save EEPROM on exit, reset EEPROM
void setup() {
lcd.init();
lcd.backlight();
// Autotune
uint8_t autotune = OFF;
uint8_t autotune_pid = 0;
// Enable Watchdog Timer, 1 second
wdt_enable(WDTO_1S);
// Define the EEPROM address for Kp, Ki and Kd
autotune_address = EEPROM.getAddress(sizeof(uint8_t));
kp_address = EEPROM.getAddress(sizeof(double));
ki_address = EEPROM.getAddress(sizeof(double));
kd_address = EEPROM.getAddress(sizeof(double));
bright_address = EEPROM.getAddress(sizeof(int));
temp_5_address = EEPROM.getAddress(sizeof(int));
autoTurnOFF_address = EEPROM.getAddress(sizeof(int));
// Set up pins
pinMode(HEATER, OUTPUT);
pinMode(LED_R, OUTPUT);
pinMode(LED_G, OUTPUT);
pinMode(LED_B, OUTPUT);
pinMode(Buzzer, OUTPUT);
pinMode(Button1, INPUT_PULLUP);
pinMode(Button2, INPUT_PULLUP);
pinMode(Button3, INPUT_PULLUP);
pinMode(Button4, INPUT_PULLUP);
pinMode(REED, INPUT_PULLUP);
// Set up Heater PWM
Timer1.PWM(HEATER, 0, 30);
// Set up PID
heaterPid.SetOutputLimits(0, PWM_MAX);
heaterPid.SetSampleTime(50); // Update PID every 50ms
heaterPid.SetMode(AUTOMATIC);
// Set up LCD
charSetup();
//Check if reset EEPROM button is pressed at startup
if (digitalRead(Button4) == 0) {
clearEEPROM = ON;
}
// Check if PID autotune button is pressed at startup
else if (digitalRead(Button1) == 0) {
autotune = ON;
}
//Reset EEPROM
if (clearEEPROM){
setBrightness(10);
lcd.clear();
lcd.print(" Clear EEPROM ? ");
lcd.setCursor(0, 1);
lcd.print(" [YES] [NO] ");
while (clearEEPROM){
if (digitalRead(Button2) == 0){
EEPROM.writeByte(autotune_address, 0);
EEPROM.writeDouble(kp_address, 0);
EEPROM.writeDouble(ki_address, 0);
EEPROM.writeDouble(kd_address, 0);
EEPROM.writeInt(bright_address, 0);
EEPROM.writeInt(temp_5_address, 0);
EEPROM.writeInt(autoTurnOFF_address, 0);
lcd.clear();
lcd.print("Cleared!");
lcd.setCursor(0, 1);
lcd.print(">Press 3 to exit");
for (int i = 0; i < 2; i++){
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
delay(BUZ_DUR*15);
}
}
else if (digitalRead(Button3) == 0){
clearEEPROM = OFF;
}
wdt_reset();
}
}
// Start PID autotune
else if (autotune){
setBrightness(10);
lcd.clear();
lcd.print(" Autotune PID ? ");
lcd.setCursor(0, 1);
lcd.print(" [YES] [NO] ");
while (autotune){
if (digitalRead(Button2) == 0){
// Configure PID autotune
setpoint = AUTOTUNE_SETPOINT;
duty = AUTOTUNE_START_VALUE;
aTune.SetNoiseBand(AUTOTUNE_NOISEBAND);
aTune.SetOutputStep(AUTOTUNE_STEP_VALUE);
aTune.SetLookbackSec(AUTOTUNE_LOOKBACK);
aTune.SetControlType(1);
// Print some autotune info
lcd.clear();
lcd.print("Autotune PID at:");
lcd.setCursor(0, 1);
lcd.print((uint16_t)setpoint);
lcd.print((char)223);
lcd.print("C");
// Heat to the setpoint, temperature will rise above it
Timer1.setPwmDuty(HEATER, duty);
while(readTemp() < setpoint) {
// Reset the watchdog timer to prevent rebooting
wdt_reset();
}
// Wait for temperature to drop to setpoint
Timer1.setPwmDuty(HEATER, 0);
while(readTemp() > setpoint) {
// Reset the watchdog timer to prevent rebooting
wdt_reset();
}
// Start the autotune
while(autotune) {
// Get the current temperature
temperature = readTemp();
// Check if the autotune is finished
if(aTune.Runtime() != 0) {
autotune = OFF;
}
else {
Timer1.setPwmDuty(HEATER, duty);
}
// If finished, set up the PID and EEPROM values
if(!autotune) {
// Turn off the heater
Timer1.setPwmDuty(HEATER, 0);
// Get the values from autotune
kp = aTune.GetKp();
ki = aTune.GetKi();
kd = aTune.GetKd();
// Write them to the EEPROM
EEPROM.writeDouble(kp_address, kp);
EEPROM.writeDouble(ki_address, ki);
EEPROM.writeDouble(kd_address, kd);
EEPROM.writeByte(autotune_address, 1);
// Reset the setpoint
setpoint = 0.0;
}
wdt_reset();
}
for (int i = 0; i < 2; i++){
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
delay(BUZ_DUR*15);
}
}
else if (digitalRead(Button3) == 0){
autotune = OFF;
}
wdt_reset();
}
}
bright = EEPROM.readInt(bright_address);
setBrightness(bright);
if(boot_screen){
if (digitalRead(REED)){
lcd.clear();
lcd.print(char(162));
lcd.print("Soldering Iron");
lcd.setCursor(0, 1);
lcd.print(" Controller ");
lcd.print(ver);
lcd.print(char(163));
}
}
while (boot_screen){
if (!digitalRead(REED)){
boot_screen = 0;
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
wdt_reset();
}
temp_5 = EEPROM.readInt(temp_5_address);
autoTurnOFF = EEPROM.readInt(autoTurnOFF_address);
// Get the PID constant values from EEPROM if autotune was run
autotune_pid = EEPROM.readByte(autotune_address);
if(autotune_pid == 1) {
kp = EEPROM.readDouble(kp_address);
ki = EEPROM.readDouble(ki_address);
kd = EEPROM.readDouble(kd_address);
}
else{
kp = KP_VAL;
ki = KI_VAL;
kd = KD_VAL;
}
heaterPid.SetTunings(kp,ki,kd);
lcd.clear();
}
void loop() {
uint32_t current_time = millis(); // Get the current time
wdt_reset();
checkButton();
// Automatic turn-off
if(heater_mode) {
//if left on base and lifted at least once
if(!(digitalRead(REED)) && (ironLifted)){
if (autoTurnOFF) {
if (sleeping){
if ((millis() - sleeping_time) >= AUTO_OFF_TIME){
heater_mode = OFF;
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
}
else if ((millis() - base_time) >= AUTO_SLEEP_TIME) {
sleeping = ON;
setpoint = MIN_TEMP - 50;
sleeping_time = millis();
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
}
}
//lifted from base or hasn't lifted at least once
else{
if (sleeping){
sleeping = OFF;
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
else if (digitalRead(REED)) ironLifted = ON;
base_time = millis();
setpoint = readPot();
}
}
else setpoint = readPot();
// Read Analog data for PTC
if(current_time - last_ptc_update > PTC_INTERVAL) {
temperature = readTemp();
if(heater_mode){
if (temperature > MAX_TEMP + 30){
if (millis() - overshoot_time >= SAFETY_OFF_TIME){
heater_mode = OFF;
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
}
else overshoot_time = millis();
lightRGB(setpoint, temperature);
if(temperature < 100) heaterPid.SetOutputLimits(0, PWM_MAX * PWM_LIMIT);
else heaterPid.SetOutputLimits(0, PWM_MAX);
}
last_ptc_update = current_time;
}
heaterPid.Compute(); // Calculate PID value
// Adjust PWM Duty based on the PID
if(heater_mode) {
Timer1.setPwmDuty(HEATER, duty);
} else {
Timer1.setPwmDuty(HEATER, 0);
}
//Check if it's time to update the LCD
if(current_time - last_lcd_update > LCD_INTERVAL) {
lcd.setCursor(0, 0);
if((temperature > TEMP_WO_IRON-5) && (temperature < TEMP_WO_IRON+5)){
heater_mode = OFF;
lcd.print(" Please ");
lcd.setCursor(0, 1);
lcd.print(" Connect Iron ");
if (flash_on < FLASH_ON/LCD_INTERVAL){ // stay on for FLASH_ON ms
setColor(255, 0, 0); // red
flash_on++;
flash_off = 0;
}
else{
if(flash_off < FLASH_OFF/LCD_INTERVAL){ // stay off for FLASH_OFF ms
setColor(0, 0, 0);
flash_off++;
}
else flash_on = 0;
}
}
else{
if (!showPID) {
//1st Row
lcd.write(byte(0));
lcd.print(' ');
if (temp_5){
if (temperature < 98) lcd.print(' ');
if (int(temperature) % 5 < 3){
lcd.print(int(temperature / 5) * 5);
}
else{
lcd.print(int(temperature / 5 + 1) * 5);
}
}
else{
if (temperature < 100) lcd.print(' ');
lcd.print(temperature, 0);
}
lcd.print((char)223);
lcd.print("C ");
printGraph(setpoint, temperature);
//2nd Row
lcd.setCursor(0, 1);
if (!digitalRead(REED)) lcd.print(char(219));
else lcd.print(" ");
lcd.print(" ");
lcd.print(setpoint, 0);
lcd.print((char)223);
lcd.print("C ");
//print duty
int power;
if (heater_mode) power = duty * (100.0/1023);
//if (heater_mode) power = duty * (100.0/PWM_MAX);
else power = 0;
if (power < 10) lcd.print(" ");
else if (power < 100) lcd.print(" ");
lcd.print(power);
lcd.print("% ");
if (heater_mode){
if (sleeping) lcd.print("_zZ");
else{
lcd.print(" ");
lcd.write(byte(1));
lcd.print("N");
}
}
else{
lcd.print("OFF");
}
}
else displayPid();
if (!heater_mode) setColor(255, 255, 255); // white
}
last_lcd_update = current_time;
}
}
// Read Iron temperature
uint16_t readTemp() {
uint16_t temp = 0;
// Discard first reading
analogRead(TEMP_PIN);
// Read temperature eight times
for (int i = 0; i < 8; i++){
temp += analogRead(TEMP_PIN);
}
temp = (temp >> 3);
temp = (EQUATION_A*temp) + EQUATION_B;
return temp;
}
uint16_t readPot() {
uint16_t pot = 0;
// Discard first reading
analogRead(POT);
// Read the potentiometer four times
pot += analogRead(POT);
pot += analogRead(POT);
pot += analogRead(POT);
pot += analogRead(POT);
// Map the value read to the temperature range
pot = map(pot, 0, 4092, MIN_TEMP, MAX_TEMP);
if (pot % 5 < 3) return pot / 5 * 5;
else return (pot / 5 + 1) * 5;
}
// Check if heater start button was pressed
void checkButton() {
heatButton.listen();
increaseBrightButton.listen();
temp_5_Button.listen();
pidButton.listen();
//Button1
if(heatButton.onPress()) {
if (showPID) autoTurnOFF = !autoTurnOFF;
else{
if (heater_mode){
heater_mode = OFF;
}
else{
ironLifted = OFF;
overshoot_time = millis();
heater_mode = ON;
}
}
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
//Button2
if (increaseBrightButton.onPress()){
if (++bright > 10) bright = 1;
setBrightness(bright);
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
//Button3
if (temp_5_Button.onPress()){
temp_5 = !temp_5;
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
//Button4
if (pidButton.onPress()){
if (!showPID){
showPID = ON;
}
else{
showPID = OFF;
EEPROM.writeInt(bright_address, bright);
EEPROM.writeInt(temp_5_address, temp_5);
EEPROM.writeInt(autoTurnOFF_address, autoTurnOFF);
}
digitalWrite(Buzzer, HIGH);
delay(BUZ_DUR);
digitalWrite(Buzzer, LOW);
}
}
// Display PID Constants
void displayPid() {
lcd.clear();
lcd.print("P:");
lcd.print(kp, 2);
lcd.print(" I:");
lcd.print(ki, 2);
if(temp_5) lcd.print(" 5");
else lcd.print(" 1");
lcd.setCursor(0, 1);
lcd.print("D:");
lcd.print(kd, 2);
lcd.print(" slp");
if (autoTurnOFF) lcd.print("Y");
else lcd.print("N");
lcd.print(" ");
if (showAnalog){
uint16_t temp_analog = 0;
for (int i=0; i<5; i++){
temp_analog += analogRead(TEMP_PIN);
}
lcd.print(temp_analog/5);
}
else lcd.print(" ");
}
void setBrightness(int light){
light = map(light, 0, 10, 245, 10);
analogWrite(LCD_LED, light);
}
void setColor(int red, int green, int blue){
analogWrite(LED_R, 255-red);
analogWrite(LED_G, 255-green);
analogWrite(LED_B, 255-blue);
}
void lightRGB(double setpoint, double termperature){
double diff = setpoint - temperature;
if (diff > RGB_EFECT_MIN) diff = RGB_EFECT_MIN;
else if (diff < -RGB_EFECT_MAX) diff = -RGB_EFECT_MAX;
if (diff < 0){
diff = map(diff, -RGB_EFECT_MAX, 0, 255, 0);
setColor(diff, 255-diff, 0);
}
else{
diff = map(diff, 0, RGB_EFECT_MIN, 0, 255);
setColor(0, 255-diff, diff);
}
}
void printGraph(double setpoint, double termperature){
double diff = temperature - setpoint;
int boxes;
if (diff > BAR_STEP*7) boxes = 7;
else if (diff < -BAR_STEP*7) boxes = -7;
else boxes = diff / BAR_STEP;
int blanks = -abs(boxes)/2+3.5;
//if temp = setpoint
if (boxes == 0){
for (int i = 0; i < 3; i++){
lcd.write(byte(2));
}
lcd.write(byte(3));
lcd.write(byte(4));
for (int i = 0; i < 3; i++){
lcd.write(byte(2));
}
}
//if temp < setpoint
else if (boxes < 0) {
//print blanks
for (int i = 0; i < blanks; i++){
lcd.write(byte(2));
}
//print first box
if (boxes %2 == 0) lcd.write(byte(3));
else lcd.write(byte(5));
//print full box/es
for (int i=0; i < 3-blanks; i++){
lcd.write(byte(7));
}
//print 4 blanks
for (int i=0; i < 4; i++){
lcd.write(byte(2));
}
}
//if temp > setpoint
else{
//print 4 blanks
for (int i = 0; i < 4; i++){
lcd.write(byte(2));
}
//print full box/es
for (int i=0; i < 3-blanks; i++){
lcd.write(byte(7));
}
//print last box
if (boxes %2 == 0) lcd.write(byte(4));
else lcd.write(byte(6));
//print blanks
for (int i = 0; i < blanks; i++){
lcd.write(byte(2));
}
}
}
/*
| 2 | 3 | 4 | 5 | 6 | 7 |
| ## ## | ## ## | ## ## | ## ## | ## ## | ## ## |
| | | | | | |
| | | | ## | ## | ## ## |
| | ## | ## | ## ## | ## ## | ## ## |
| | ## | ## | ## ## | ## ## | ## ## |
| | | | ## | ## | ## ## |
| | | | | | |
| ## ## | ## ## | ## ## | ## ## | ## ## | ## ## |
*/
void charSetup() {
byte therm[8] = {0b10010,0b11010,0b10010,0b11010,0b10010,0b11110,0b11110,0b11110};
byte on[8] = {0b00100,0b00100,0b10101,0b10001,0b10001,0b10001,0b01110,0b00000};
byte bar[7][8] = {
{0b11011, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11011 },
{0b11011, 0b00000, 0b00000, 0b00011, 0b00011, 0b00000, 0b00000, 0b11011 },
{0b11011, 0b00000, 0b00000, 0b11000, 0b11000, 0b00000, 0b00000, 0b11011 },
{0b11011, 0b00000, 0b00011, 0b11011, 0b11011, 0b00011, 0b00000, 0b11011 },
{0b11011, 0b00000, 0b11000, 0b11011, 0b11011, 0b11000, 0b00000, 0b11011 },
{0b11011, 0b00000, 0b11011, 0b11011, 0b11011, 0b11011, 0b00000, 0b11011 }
};
lcd.createChar(0, therm);
lcd.createChar(1, on);
lcd.createChar(2, bar[0]);
lcd.createChar(3, bar[1]);
lcd.createChar(4, bar[2]);
lcd.createChar(5, bar[3]);
lcd.createChar(6, bar[4]);
lcd.createChar(7, bar[5]);
}
funziona, cioe' in parte..(in entrambi i modi), quando vado ad accendere il saldatore, mi scrive on ma non esce segnale e non mi riscalda la punta.
la temperatura e corretta, e mi da circa quella dell ambiente, ma se lo scaldo con la mado o con un altro saldatore la temperatura sale
pero non funziona , arduino nuovo mosfet nuovo, provato ad mettere segnale sul gate e funziona
ho provato con autotune, mettendo la punta in temperatura piu o meno a 250 gradi.ma nulla...scondo voi cosa sto sbagliando...
a questo punto vi chiedo se esiste un semplicissimo controller per lo stilo 907,che funzioni..visto che ne ho messi di vari ma o perche non riesco a convertirli a ic2 o perche non riesco a farli andare mi sono scoraggiato...
mi potreste dare qualche dritta?
grazie mille