PDA

Επιστροφή στο Forum : Μια μικρή βοήθεια σε arduino!



billtsig
22-05-16, 16:21
καλησπέρα παιδιά και χρονια πολλά στους εορτάζοντες


χρειάζομαι μια μικρή βοήθεια σχετικά με τον σταθμό κολλήσεις που προσπαθώ να κατασκευάσω


χρησιμοποιώ το ακόλουθο πρόγραμμα (στο 2ο post μου)και προσπαθώ να έχω μέτρηση της θερμοκρασίας με το max6675 έχω κάνει την ακόλουθη τροποποίηση και ενώ όλα δείχνουν να δουλεύουν μια χαρά αντιμετωπίζω πρόβλημα με το pid autotune συμπεριφέρεται σαν να μην μεταβάλλεται η θερμοκρασία πχ το τροφοδοτικό τραβάει μόνιμα 400mA και δεν παίζει με το duty cycle


με τελεστικό που το δοκίμασα δούλευε κανονικά το pid autotune


κάθε βοήθεια σας θα ήταν πολύτιμη ευχαριστώ πολύ

billtsig
22-05-16, 16:22
/************************************************** *****************************************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
version 0.1
************************************************** ******************************************/


#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>
#include <max6675.h>


#define OFF 0
#define ON 1


// PIN DEFINITIONS


#define HEATER 10
//#define TEMP_PIN 18
#define POT 19
#define Button1 8
#define Button2 7
#define Button3 2
#define Button4 4
//LCD
#define LCD_LED 9
#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 = 3;
const int LED_G = 5;
const int LED_B = 6;
int flash_on = 0;
int flash_off = 0;


int thermoDO = 0;
int thermoCS = 18;
int thermoCLK =1;
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);
//SETTINGS


#define LCD_INTERVAL 200 // Time im ms between LCD updates
#define PTC_INTERVAL 300 // Time im ms between average analog readings
#define FLASH_ON 600 // Time im ms for RGB to stay on when flashing
#define FLASH_OFF 400 // Time im ms for RGB to stay off when flashing
#define RGB_EFECT_MIN 60 // degrees below temperature to start the RGB effect
#define RGB_EFECT_MAX 30 // degrees above temperature to finish the RGB effect
#define TEMP_WO_IRON 0 // readTemp(); returns about 749 when I disconnect the iron


// Y = a*X + b, where Y is the temperature and X is the analog value read from the sensor.
#define EQUATION_A 0.60
#define EQUATION_B 0


// Temperature control definitions
#define MIN_TEMP 150 // Minimum setpoint temperature
#define MAX_TEMP 395 // Maximum setpoint temperature
#define PWM_MAX 1023 // PWM limit, max 1023 (my power supply was shutting down at 1023)


// PID VALUES
#define KP_VAL 26.67
#define KI_VAL 3.56
#define KD_VAL 50.01


// PID Autotune Variables
#define AUTOTUNE_SETPOINT 200 // 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 = 10; //brightness of LCD (1..10)
uint8_t showAnalog = OFF; //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 autotune = OFF;
uint8_t showPID = OFF;


// PID Variables
double temperature;
double setpoint = 0.0;
double duty;
double kp;
double ki;
double kd;
uint16_t kp_address;
uint16_t ki_address;
uint16_t kd_address;
uint16_t bright_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);
Button decreaseBrightButton = Button(Button2, LOW);
Button increaseBrightButton = Button(Button3, LOW);
Button pidButton = Button(Button4, LOW);


void setup() {
//Serial.begin(9600);
// Enable Watchdog Timer, 1 second
wdt_enable(WDTO_1S);


// Define the EEPROM address for Kp, Ki and Kd
kp_address = EEPROM.getAddress(sizeof(double));
ki_address = EEPROM.getAddress(sizeof(double));
kd_address = EEPROM.getAddress(sizeof(double));
bright_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(Button1, INPUT_PULLUP);
pinMode(Button2, INPUT_PULLUP);
pinMode(Button3, INPUT_PULLUP);
pinMode(Button4, INPUT_PULLUP);


// Set up Heater PWM
Timer1.pwm(HEATER, 0 , 30);

// Set up PID
heaterPid.SetOutputLimits(0, PWM_MAX);
heaterPid.SetMode(AUTOMATIC);

// Set up LCD
bright = EEPROM.readInt(bright_address);
setBrightness(bright);
lcd.begin(16, 2);
charSetup();


// Check if PID autotune button is pressed at startup
if(digitalRead(Button4) == 0) {
autotune = ON;
}

// Start PID autotune procedure if button was pressed
if(autotune == ON) {
// 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("PID Autotune 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 == ON) {
// 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 == OFF) {

// 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);

// Reset the setpoint
setpoint = 0.0;
}

// Reset the watchdog timer to prevent rebooting
wdt_reset();
}
}

// Get the PID constant values from EEPROM
kp = EEPROM.readDouble(kp_address);
ki = EEPROM.readDouble(ki_address);
kd = EEPROM.readDouble(kd_address);

// Set the to the PID
//heaterPid.SetTunings(kp,ki,kd);
heaterPid.SetTunings(kp,ki,kd);

// Clear the display
lcd.clear();
}


void loop() {
uint32_t current_time = millis(); // Get the current time


wdt_reset(); // Reset the watchdog timer to prevent rebooting
checkButton(); // Check the buttons
setpoint = readPot(); //Read Setpoint
if(current_time - last_ptc_update > PTC_INTERVAL) {
temperature = readTemp(); // Read Analog data for PTC
if(heater_mode == ON) lightRGB(setpoint, temperature);
last_ptc_update = current_time;
}


heaterPid.Compute(); // Calculate PID value
// Adjust PWM Duty based on the PID
if(heater_mode == ON) {
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(!showPID) {
//if((temperature > TEMP_WO_IRON-5) && (temperature < TEMP_WO_IRON+5)){
if(temperature ==TEMP_WO_IRON ){
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{
lcd.write(byte(0));
lcd.print(' ');
if(temperature < 98) {
lcd.print(' ');
}
if (int(temperature) % 5 < 3){
lcd.print(int(temperature / 5) * 5);
}
else{
lcd.print(int(temperature / 5 + 1) * 5);
}
lcd.print((char)223);
lcd.print("C ");
printGraph(setpoint, temperature);


lcd.setCursor(0, 1);
lcd.print(">");
lcd.print(" ");
lcd.print(setpoint, 0);
lcd.print((char)223);
lcd.print("C ");


if(heater_mode == ON){
lcd.print(" ON ");
lightRGB(setpoint, temperature);
}
else{
lcd.print("OFF ");
setColor(255, 255, 255); // white
}
}
}
else displayPid();


last_lcd_update = current_time;
}
}


// Read Iron temperature
uint16_t readTemp() {
uint16_t temp = 0;
//int tempr = thermocouple.readCelsius();
for (int i = 0; i < 10; i++)
{ int tempr = thermocouple.readCelsius();
//temp += analogRead(TEMP_PIN);
temp = tempr;
}

//temp = (EQUATION_A*temp) + EQUATION_B;
return temp;
}


uint16_t readPot() {
uint16_t pot = 0;

// Read the potentiometer three times
pot += analogRead(POT);
pot += analogRead(POT);
pot += analogRead(POT);

// Map the value read to the temperature range
pot = map(pot, 0, 3069, 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();
decreaseBrightButton.listen();
pidButton.listen();


//Button1
if(heatButton.onPress()) {
if (heater_mode == ON) heater_mode = OFF;
else heater_mode = ON;
}


//Button2
if (decreaseBrightButton.onPress()){
if (--bright < 1) bright = 10;
setBrightness(bright);
}


//Button3
if (increaseBrightButton.onPress()){
if (++bright > 10) bright = 1;
setBrightness(bright);
}


//Button4
if (pidButton.onPress()){
if (showPID == OFF){
showPID = ON;
}
else{
showPID = OFF;
EEPROM.writeInt(bright_address, bright);
}
}
}


// Display PID Constants
void displayPid() {
lcd.clear();
lcd.print("P ");
lcd.print(kp, 2);
lcd.print(" I ");
lcd.print(ki, 2);
lcd.setCursor(0, 1);
lcd.print("D ");
lcd.print(kd, 2);


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, 1, 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 = setpoint - temperature;


if (abs(diff) < 1){
if (temperature < setpoint){
lcd.print(" ");
lcd.write(byte(4));
lcd.print(" ");
}
}
else if (abs(diff) < 5){
if (temperature < setpoint){
lcd.print(" ");
lcd.write(byte(1));
lcd.write(byte(2));
lcd.write(byte(7));
lcd.print(" ");
}
else{
lcd.print(" ");
lcd.write(byte(1));
lcd.write(byte(6));
lcd.write(byte(7));
lcd.print(" ");
}
}
else if (abs(diff) < 10){
if (temperature < setpoint){
lcd.print(" ");
lcd.write(byte(1));
lcd.write(byte(2));
lcd.write(byte(3));
lcd.write(byte(6));
lcd.print(" ");
}
else{
lcd.print(" ");
lcd.write(byte(2));
lcd.write(byte(5));
lcd.write(byte(6));
lcd.write(byte(7));
lcd.print(" ");
}
}
else if (abs(diff) < 15){
if (temperature < setpoint){
lcd.write(byte(1));
lcd.write(byte(2));
lcd.write(byte(3));
lcd.write(byte(4));
lcd.print(" ");
}
else{
lcd.print(" ");
lcd.write(byte(4));
lcd.write(byte(5));
lcd.write(byte(6));
lcd.write(byte(7));
}
}
else if (abs(diff) < 20){
if (temperature < setpoint){
lcd.write(byte(2));
lcd.write(byte(3));
lcd.write(byte(4));
lcd.write(byte(4));
lcd.print(" ");
}
else{
lcd.print(" ");
lcd.write(byte(4));
lcd.write(byte(4));
lcd.write(byte(5));
lcd.write(byte(6));
}
}
else if (abs(diff) < 25){
if (temperature < setpoint){
lcd.write(byte(3));
lcd.write(byte(4));
lcd.write(byte(4));
lcd.write(byte(4));
lcd.print(" ");
}
else{
lcd.print(" ");
lcd.write(byte(4));
lcd.write(byte(4));
lcd.write(byte(4));
lcd.write(byte(5));
}
}
else if (abs(diff) < 30){
if (temperature < setpoint){
lcd.write(byte(2));
lcd.write(byte(3));
lcd.write(byte(4));
lcd.write(byte(4));
lcd.write(byte(4));
lcd.print(" ");
}
else{
lcd.print(" ");
lcd.write(byte(4));
lcd.write(byte(4));
lcd.write(byte(4));
lcd.write(byte(5));
lcd.write(byte(6));
}
}
else if (abs(diff) < 35){
if (temperature < setpoint){
lcd.write(byte(1));
lcd.write(byte(2));
lcd.write(byte(3));
lcd.write(byte(4));
lcd.write(byte(4));
lcd.write(byte(4));
lcd.print(" ");
}
else{
lcd.print(" ");
lcd.write(byte(4));
lcd.write(byte(4));
lcd.write(byte(4));
lcd.write(byte(5));
lcd.write(byte(6));
lcd.write(byte(7));
}
}
else{
if (temperature < setpoint){
lcd.print(" ");
lcd.write(byte(1));
lcd.write(byte(2));
lcd.write(byte(3));
lcd.write(byte(4));
lcd.write(byte(4));
lcd.write(byte(4));
}
else{
lcd.write(byte(4));
lcd.write(byte(4));
lcd.write(byte(4));
lcd.write(byte(5));
lcd.write(byte(6));
lcd.write(byte(7));
lcd.print(" ");
}
}
}


// Create degree character
void charSetup() {
byte therm[8] = {
0b00100,
0b01010,
0b01010,
0b01010,
0b01110,
0b11111,
0b11111,
0b01110
};
byte bar[7][8] = {
{0b00000,0b00000,0b00000,0b00000,0b00000,0b00011,0 b11011,0b11011},
{0b00000,0b00000,0b00000,0b00011,0b11011,0b11011,0 b11011,0b11011},
{0b00000,0b00011,0b11011,0b11011,0b11011,0b11011,0 b11011,0b11011},
{0b11011,0b11011,0b11011,0b11011,0b11011,0b11011,0 b11011,0b11011},
{0b00000,0b11000,0b11011,0b11011,0b11011,0b11011,0 b11011,0b11011},
{0b00000,0b00000,0b00000,0b11000,0b11011,0b11011,0 b11011,0b11011},
{0b00000,0b00000,0b00000,0b00000,0b00000,0b11000,0 b11011,0b11011}
};
lcd.createChar(0, therm);
lcd.createChar(1, bar[0]);
lcd.createChar(2, bar[1]);
lcd.createChar(3, bar[2]);
lcd.createChar(4, bar[3]);
lcd.createChar(5, bar[4]);
lcd.createChar(6, bar[5]);
lcd.createChar(7, bar[6]);
}

SProg
22-05-16, 18:52
Εαν υποθεσουμε οτι ο PID λειτουργει (υποθετω το πηρες απο site - οποτε μαλλον λειτουργει) τότε ή εχεις θεμα στην εξοδο ή στην εισοδο.

Ξανα υποθέτοντας οτι μετρας την θερμοκρασια σωστα, τοτε μαλλον εχεις θεμα στην εξοδο.


Αυτη η βιβλιοθήκη δεν θελει και ενα initialize;Δε της λες καπου την συχνοτητα που θελεις;Εκτον εαν παιρνει την προ-επιλεγμενη απο το bootloader.


Υ.Γ

Ουτε αυτος βλεπω οτι κανει initialize οποτε δεν ειναι αυτο.

Μηπως το pin που χρησιμοποιεις δεν ειναι του Timer1;

billtsig
22-05-16, 19:22
καλησπέρα σάββα σε ευχαριστώ για την προσπάθεια σου να με βοηθήσεις
το pid λειτουργεί σωστά μιας και αν αντικαταστίσω τα Pi , i & d με δικούς μου αριθμούς όλα λειτουργούν σωστά και βλέπω το feedback της θερμοκρασίας στην οθόνη μου κανονικά (άρα υποθέτω πως η συνάρτηση readtemp() μου επιστρέφει την τιμή)


το περίεργο είναι πως όταν κάνω autotune ενώ ξεκινάει το autotune δεν ολοκληρώνεται ποτέ και η έξοδος μου στέλνει ένα σήμα προφανώς με dutycycle 50%(δεν έχω παλμογράφο για να το δω αλλα τραβάει το μισό ρεύμα από ότι θα τράβαγε με pwm max ) αυτό όμως δεν μεταβάλλεται


αν αντί για το max6675 βάλω τον op amp στο pin 18 και τα δηλώσω αντίστοιχα με στην readtemp() τότε δουλεύει το autotune αλλά θέλω να γίνει με το max6675 γιατί δεν επηρεάζεται τόσο πολύ από θόρυβο


πραγματικά δεν μπορώ να καταλάβω τι γίνεται

fivosv
22-05-16, 19:25
Θα βοηθούσε να μας πεις ποιος είναι ο πρωτότυπος κώδικας πριν κάνεις τις διορθώσεις για να δουλεύει με το MAX6675.
Είναι αυτός που υπάρχει στο https://hackermagnet.com ?

Το "όλα δουλεύουν μια χαρά" τι ακριβώς σημαίνει?
Αν δεν κάνεις pid autotune, ο σταθμός δείχνει να αντιλαμβάνεται τις αλλαγές θερμοκρασίας?

Σε κάθε περίπτωση, αν συμπεριφέρεται σαν να μην αλλάζει η θερμοκρασία αυτό μάλλον σημαίνει ότι το πρόγραμμά σου δεν διαβάζει την θερμοκρασία σωστά.
Ξεκίνα δοκιμάζοντας μόνο το κομμάτι της ανάγνωσης θερμοκρασίας για να αντιμετωπίσεις το πρόβλημα τμηματικά και να μπορέσεις να κάνεις ευκολότερη διάγνωση.
Τρέξε π.χ. το παρακάτω sketch που δοκιμάζει την βιβλιοθήκη ΜΑΧ6675 και σου τυπώνει τις τιμές στο serial monitor του PC σου:
https://github.com/adafruit/MAX6675-library/blob/master/examples/lcdthermocouple/lcdthermocouple.pde
αφου βέβαια αλλάξεις κατάλληλα τα νούμερα στα παρακάτω pins:

int thermoDO = 4;
int thermoCS = 5;
int thermoCLK = 6;

Οι τιμές βαθμών Κελσίου που βλέπεις στο serial monitor αν τρέξεις το παραπάνω παράδειγμα σου φαίνονται λογικές?
Αν θερμάνεις το στοιχείο (έστω με ένα αναπτήρα αν δεν μπορείς να του δώσεις ρεύμα) βλέπεις άνοδο της θερμοκρασίας?

Αν οι τιμές είναι παλαβές, αυτό μπορεί να οφείλεται σε διάφορες αιτίες (καμένο MAX6675, λάθος συνδεσμολογία κλπ.).
=> Έλεγξε τις καλωδιώσεις σου και ξανατρέξε το παράδειγμα
=> Αν εξακολουθείς να μην παίρνεις αποτελέσματα, δοκίμασε να αλλάξεις την συνδεσμολογία σου σύμφωνα με τα pins 4, 5, 6 του παραδείγματος (χωρίς να κόβω και το κεφάλι μου, νομίζω πως το SPI interface δεν δουλεύει σε οποιαδήποτε pins, είναι συγκεκριμένα pins για κάθε μοντέλο Arduino).

ΥΓ: Αφού σου δουλέψει το παράδειγμα και αλλάξεις τον κώδικα σου ώστε να δουλεύει κι αυτός, σκέψου και την εξής αλλαγή:
Ο πρωτότυπος κώδικας ήταν:

// Read Iron temperature
uint16_t readTemp() {
uint16_t temp = 0;
for (int i = 0; i < 10; i++){
temp += analogRead(TEMP_PIN);
}
temp = temp/10;
temp = (EQUATION_A*temp) + EQUATION_B;
return temp;
}


Ο δικός σου κώδικας είναι:

// Read Iron temperature
uint16_t readTemp() {
uint16_t temp = 0;
//int tempr = thermocouple.readCelsius();
for (int i = 0; i < 10; i++)
{
int tempr = thermocouple.readCelsius();
//temp += analogRead(TEMP_PIN);
temp = tempr;
}
//temp = (EQUATION_A*temp) + EQUATION_B;
return temp;
}


Στον δικό σου κώδικα έχεις κρατήσει το loop (x10) χωρίς όμως να παίρνεις μέσο όρο των τιμών, οπότε το loop δεν έχει πια νόημα,
ή θα πετάξεις το loop και θα διαβάζεις την τιμή 1 φορά (γιατί απλώς σου προσθέτει καθυστερήσεις) ή θα κρατήσεις το loop και θα παίρνεις τον μέσο όρο.
Επισης η function readCelsius() ορίζεται ως εξής:
double readCelsius(void);
Που σημαίνει πως σου επιστρέφει τιμή double (floating point) και όχι uint16.
Αν το κρατήσεις σε uint16 τότε χάνεις τα δέκατα βαθμών Κελσίου που πιθανόν μπορεί να σου επιστρέψει.
Μια εκδοχή του κώδικα παίρνοντας υπ' όψιν όλα τα παραπάνω θα ήταν:

// Read Iron temperature
double readTemp() {
double temp = 0;
for (int i = 0; i < 10; i++)
{
// Add 10 sample values
temp += thermocouple.readCelsius();
}
// Get the average value
temp = temp / 10.0;
return temp;
}

fivosv
22-05-16, 19:39
το περίεργο είναι πως όταν κάνω autotune ενώ ξεκινάει το autotune δεν ολοκληρώνεται ποτέ και η έξοδος μου στέλνει ένα σήμα προφανώς με dutycycle 50%(δεν έχω παλμογράφο για να το δω αλλα τραβάει το μισό ρεύμα από ότι θα τράβαγε με pwm max ) αυτό όμως δεν μεταβάλλεται
Αυτή είναι άλλη μια ένδειξη ότι μάλλον η readtemp() δε σου επιτρέπει σωστή θερμοκρασία και το autotune κολλάει σε κάποιο από τα while() loops.
Βάλε μερικά Serial.print() στον κώδικά σου για να δεις τις θερμοκρασίες καθώς και σε ποια φάση βρίσκεται το autotune.
Το πιο πρόχειρο που μπορείς να κάνεις είναι να βάλεις μια Serial.print(temp) μεσα στην readtemp() να δεις μερικές θερμοκρασίες.

Fire Doger
22-05-16, 19:45
αν αντί για το max6675 βάλω τον op amp στο pin 18 και τα δηλώσω αντίστοιχα με στην readtemp() τότε δουλεύει το autotune αλλά θέλω να γίνει με το max6675 γιατί δεν επηρεάζεται τόσο πολύ από θόρυβο

πραγματικά δεν μπορώ να καταλάβω τι γίνεται
Μήπως προσπαθεί και κάπου αλλού να πάρει δείγματα απ' το Max? Αν πας κάτω από ~200ms (το datasheet το έχει 170- 220) τότε φριζάρει και δεν μεταβάλετε η θερμοκρασία που σου επιστρέφει, μένει σταθερά αυτή που είχε διαβάσει όταν είχε μείνει για πάνω από ~200ms χωρίς επικοινωνία.

Επίσης την βιβλιοθήκη που την είχα κοιτάξει δεν το προέβλεπε αυτό. Την υπερδειγματοληψία που κάνεις στα καπάκια είναι άχρηστη γιατί και οι 10 τιμές είναι ίδιες και ίσες με την πρώτη. Θέλεις delay ανάμεσα στις μετρήσεις.
https://i.imgur.com/EkNHeQ8.png

billtsig
22-05-16, 19:53
Θα βοηθούσε να μας πεις ποιος είναι ο πρωτότυπος κώδικας πριν κάνεις τις διορθώσεις για να δουλεύει με το MAX6675.
Είναι αυτός που υπάρχει στο https://hackermagnet.com ?

Το "όλα δουλεύουν μια χαρά" τι ακριβώς σημαίνει?
Αν δεν κάνεις pid autotune, ο σταθμός δείχνει να αντιλαμβάνεται τις αλλαγές θερμοκρασίας?(ναι αντιλαμβανεται κανονικα )

Σε κάθε περίπτωση, αν συμπεριφέρεται σαν να μην αλλάζει η θερμοκρασία αυτό μάλλον σημαίνει ότι το πρόγραμμά σου δεν διαβάζει την θερμοκρασία σωστά.
Ξεκίνα δοκιμάζοντας μόνο το κομμάτι της ανάγνωσης θερμοκρασίας για να αντιμετωπίσεις το πρόβλημα τμηματικά και να μπορέσεις να κάνεις ευκολότερη διάγνωση.
Τρέξε π.χ. το παρακάτω sketch που δοκιμάζει την βιβλιοθήκη ΜΑΧ6675 και σου τυπώνει τις τιμές στο serial monitor του PC σου:
https://github.com/adafruit/MAX6675-library/blob/master/examples/lcdthermocouple/lcdthermocouple.pde
αφου βέβαια αλλάξεις κατάλληλα τα νούμερα στα παρακάτω pins:

int thermoDO = 4;
int thermoCS = 5;
int thermoCLK = 6; (τιπό) (και εδώ λειτουργεί το max)

Οι τιμές βαθμών Κελσίου που βλέπεις στο serial monitor αν τρέξεις το παραπάνω παράδειγμα σου φαίνονται λογικές?
Αν θερμάνεις το στοιχείο (έστω με ένα αναπτήρα αν δεν μπορείς να του δώσεις ρεύμα) βλέπεις άνοδο της θερμοκρασίας?

Αν οι τιμές είναι παλαβές, αυτό μπορεί να οφείλεται σε διάφορες αιτίες (καμένο MAX6675, λάθος συνδεσμολογία κλπ.).
=> Έλεγξε τις καλωδιώσεις σου και ξανατρέξε το παράδειγμα
=> Αν εξακολουθείς να μην παίρνεις αποτελέσματα, δοκίμασε να αλλάξεις την συνδεσμολογία σου σύμφωνα με τα pins 4, 5, 6 του παραδείγματος (χωρίς να κόβω και το κεφάλι μου, νομίζω πως το SPI interface δεν δουλεύει σε οποιαδήποτε pins, είναι συγκεκριμένα pins για κάθε μοντέλο Arduino).

ΥΓ: Αφού σου δουλέψει το παράδειγμα και αλλάξεις τον κώδικα σου ώστε να δουλεύει κι αυτός, σκέψου και την εξής αλλαγή:
Ο πρωτότυπος κώδικας ήταν:

// Read Iron temperature
uint16_t readTemp() {
uint16_t temp = 0;
for (int i = 0; i < 10; i++){
temp += analogRead(TEMP_PIN);
}
temp = temp/10;
temp = (EQUATION_A*temp) + EQUATION_B;
return temp;
}


Ο δικός σου κώδικας είναι:

// Read Iron temperature
uint16_t readTemp() {
uint16_t temp = 0;
//int tempr = thermocouple.readCelsius();
for (int i = 0; i < 10; i++)
{
int tempr = thermocouple.readCelsius();
//temp += analogRead(TEMP_PIN);
temp = tempr;
}
//temp = (EQUATION_A*temp) + EQUATION_B;
return temp;
}


Στον δικό σου κώδικα έχεις κρατήσει το loop (x10) χωρίς όμως να παίρνεις μέσο όρο των τιμών, οπότε το loop δεν έχει πια νόημα,
ή θα πετάξεις το loop και θα διαβάζεις την τιμή 1 φορά (γιατί απλώς σου προσθέτει καθυστερήσεις) ή θα κρατήσεις το loop και θα παίρνεις τον μέσο όρο.
Επισης η function readCelsius() ορίζεται ως εξής:
double readCelsius(void);
Που σημαίνει πως σου επιστρέφει τιμή double (floating point) και όχι uint16.
Αν το κρατήσεις σε uint16 τότε χάνεις τα δέκατα βαθμών Κελσίου που πιθανόν μπορεί να σου επιστρέψει.
Μια εκδοχή του κώδικα παίρνοντας υπ' όψιν όλα τα παραπάνω θα ήταν:

// Read Iron temperature
double readTemp() {
double temp = 0;
for (int i = 0; i < 10; i++)
{
// Add 10 sample values
temp += thermocouple.readCelsius(); (πλέον έκανα έτσι τον κώδικα )
}
// Get the average value
temp = temp / 10.0;
return temp;
}


φυσικά σε ευχαριστώ για την βοήθεια σου και των χρόνο σου

billtsig
22-05-16, 20:31
Αυτή είναι άλλη μια ένδειξη ότι μάλλον η readtemp() δε σου επιτρέπει σωστή θερμοκρασία και το autotune κολλάει σε κάποιο από τα while() loops.
Βάλε μερικά Serial.print() στον κώδικά σου για να δεις τις θερμοκρασίες καθώς και σε ποια φάση βρίσκεται το autotune.
Το πιο πρόχειρο που μπορείς να κάνεις είναι να βάλεις μια Serial.print(temp) μεσα στην readtemp() να δεις μερικές θερμοκρασίες.

καλησπέρα φοιβο όταν δεν κάνω autotune οι τιμές στο serial monitor είναι σωστές όταν κάνω tuning η τιμη είναι πάντα η ίδια που είχε μόλις ξεκίνησε το tuning

fivosv
22-05-16, 21:13
Διαβάζοντας αυτά που λέει ο Στέφανος εδώ:

Μήπως προσπαθεί και κάπου αλλού να πάρει δείγματα απ' το Max? Αν πας κάτω από ~200ms (το datasheet το έχει 170- 220) τότε φριζάρει και δεν μεταβάλετε η θερμοκρασία που σου επιστρέφει, μένει σταθερά αυτή που είχε διαβάσει όταν είχε μείνει για πάνω από ~200ms χωρίς επικοινωνία.

Επίσης την βιβλιοθήκη που την είχα κοιτάξει δεν το προέβλεπε αυτό. Την υπερδειγματοληψία που κάνεις στα καπάκια είναι άχρηστη γιατί και οι 10 τιμές είναι ίδιες και ίσες με την πρώτη. Θέλεις delay ανάμεσα στις μετρήσεις.
https://i.imgur.com/EkNHeQ8.png

κι αυτό που γράφεις εσύ:

καλησπέρα φοιβο όταν δεν κάνω autotune οι τιμές στο serial monitor είναι σωστές όταν κάνω tuning η τιμη είναι πάντα η ίδια που είχε μόλις ξεκίνησε το tuning

Θα σου πρότεινα να δοκιμάσεις κάτι τέτοιο:

// Read Iron temperature
double readTemp() {
double temp = 0;
for (int i = 0; i < 10; i++)
{
// Add 10 sample values
temp += thermocouple.readCelsius();
delay(220);
}
// Get the average value
temp = temp / 10.0;
return temp;
}


ή ακόμη καλύτερα (για πιο γρήγορα γιατί το παραπάνω θα κάνει 2 sec για κάθε μέτρηση):

// Read Iron temperature
double readTemp() {
double temp = thermocouple.readCelsius();
delay(220);
return temp;
}


Επίσης αν εξακολουθεί να κάνει freeze το autotune, πρόσθεσε κάποια Serial.print() μέσα στη function
πριν από κάθε while() για να δεις σε ποιο σημείο κολλάει (κλασική μέθοδος όταν δεν έχουμε διαθέσιμο debuger).
Βλέποντας ποιο είναι το τελευταίο μήνυμα που εμφανίζεται στο serial monitor, ξέρεις σε ποιο while() μέσα έχει κολλήσει,
π.χ.:



[...]
// Heat to the setpoint, temperature will rise above it
Timer1.setPwmDuty(HEATER, duty);
Serial.println("while(readTemp() < setpoint)");
while(readTemp() < setpoint) {
// Reset the watchdog timer to prevent rebooting
wdt_reset();
}

// Wait for temperature to drop to setpoint
Timer1.setPwmDuty(HEATER, 0);
Serial.println("while(readTemp() > setpoint)");
while(readTemp() > setpoint) {
// Reset the watchdog timer to prevent rebooting
wdt_reset();
}
// Start the autotune
Serial.println("while(autotune == ON)");
while(autotune == ON) {
// Get the current temperature
[...]

billtsig
22-05-16, 22:25
τελικά η λύση στο πρόβλημα μου ήταν όντως εδώ
// Read Iron temperaturedouble readTemp() {
double temp = thermocouple.readCelsius();
delay(220);
return temp; }

σας ευχαριστώ πολύ όλους για τον χρόνο σάς και φυσικά για την πολύτιμη βοήθεια να είστε καλά!!!

leuteris107
09-07-16, 09:38
Καλημέρα στην παρέα.
Πριν από λίγο καιρό σκέφτηκα να ασχοληθώ με το Arduino και τον προγραμματισμό του.
Αγόρασα ένα Arduino Mega 2560 16AU, ένα Ethernet W5100 Network, μία οθόνη 20χ4 HD44780, έναν Sensor DHT22 , ένα RTC DS3231 AT24C32 και ένα Module 8 Relay .Ξεκινώντας τον προγραμματισμό έφτιαξα ένα πρόγραμμα για την LCD και το RTC:


#include <Wire.h>#include "ds3231.h"#include "rtc_ds3231.h"#include <LiquidCrystal.h>LiquidCrystal lcd(27, 26, 25, 24, 23, 22); //Pins for the LCD display, as taken from arduino.cc#define BUFF_MAX 128uint8_t time[8];char recv[BUFF_MAX];unsigned int recv_size = 0;unsigned long prev, interval = 1000;void setup(){Serial.begin(9600);Wire.begin();DS3231_ini t(DS3231_INTCN);memset(recv, 0, BUFF_MAX);Serial.println("GET time");lcd.begin(20, 4);lcd.clear();//Serial.println ("setting time");//parse_cmd("T100217508072016",16);}void loop(){char in;char buff[BUFF_MAX];unsigned long now = millis();struct ts t;// show time once in a whileif ((now - prev > interval) && (Serial.available() <= 0)) {DS3231_get(&t); //get timelcd.clear();lcd.setCursor(4,0);lcd.print(t.mda y);lcd.print(" ");printMonth(t.mon);lcd.print(" ");lcd.print(t.year);lcd.setCursor(5,1);lcd.print(t .hour);lcd.print(":");if (t.min<10){lcd.print("0");}lcd.print(t.min);lcd.print(":");if (t.sec<10){lcd.print("0");}lcd.print(t.sec);lcd.print(' ');prev = now;}if (Serial.available() > 0) {in = Serial.read();if ((in == 10 || in == 13) && (recv_size > 0)) {parse_cmd(recv, recv_size);recv_size = 0;recv[0] = 0;} else if (in < 48 || in > 122) {; // ignore ~[0-9A-Za-z]} else if (recv_size > BUFF_MAX - 2) { // drop lines that are too long// droprecv_size = 0;recv[0] = 0;} else if (recv_size < BUFF_MAX - 2) {recv[recv_size] = in;recv[recv_size + 1] = 0;recv_size += 1;}}}void parse_cmd(char *cmd, int cmdsize){uint8_t i;uint8_t reg_val;char buff[BUFF_MAX];struct ts t;//snprintf(buff, BUFF_MAX, "cmd was '%s' %d\n", cmd, cmdsize);//Serial.print(buff);// TssmmhhWDDMMYYYY aka set timeif (cmd[0] == 84 && cmdsize == 16) {//T355720619112011t.sec = inp2toi(cmd, 1);t.min = inp2toi(cmd, 3);t.hour = inp2toi(cmd, 5);t.wday = cmd[7] - 48;t.mday = inp2toi(cmd, 8);t.mon = inp2toi(cmd, 10);t.year = inp2toi(cmd, 12) * 100 + inp2toi(cmd, 14);DS3231_set(t);Serial.println("OK");} else if (cmd[0] == 49 && cmdsize == 1) { // "1" get alarm 1DS3231_get_a1(&buff[0], 59);Serial.println(buff);} else if (cmd[0] == 50 && cmdsize == 1) { // "2" get alarm 1DS3231_get_a2(&buff[0], 59);Serial.println(buff);} else if (cmd[0] == 51 && cmdsize == 1) { // "3" get aging registerSerial.print("aging reg is ");Serial.println(DS3231_get_aging(), DEC);} else if (cmd[0] == 65 && cmdsize == 9) { // "A" set alarm 1DS3231_set_creg(DS3231_INTCN | DS3231_A1IE);//ASSMMHHDDfor (i = 0; i < 4; i++) {time[i] = (cmd[2 * i + 1] - 48) * 10 + cmd[2 * i + 2] - 48; // ss, mm, hh, dd}uint8_t flags[5] = { 0, 0, 0, 0, 0 };DS3231_set_a1(time[0], time[1], time[2], time[3], flags);DS3231_get_a1(&buff[0], 59);Serial.println(buff);} else if (cmd[0] == 66 && cmdsize == 7) { // "B" Set Alarm 2DS3231_set_creg(DS3231_INTCN | DS3231_A2IE);//BMMHHDDfor (i = 0; i < 4; i++) {time[i] = (cmd[2 * i + 1] - 48) * 10 + cmd[2 * i + 2] - 48; // mm, hh, dd}uint8_t flags[5] = { 0, 0, 0, 0 };DS3231_set_a2(time[0], time[1], time[2], flags);DS3231_get_a2(&buff[0], 59);Serial.println(buff);} else if (cmd[0] == 67 && cmdsize == 1) { // "C" - get temperature registerSerial.print("temperature reg is ");Serial.println(DS3231_get_treg(), DEC);} else if (cmd[0] == 68 && cmdsize == 1) { // "D" - reset status register alarm flagsreg_val = DS3231_get_sreg();reg_val &= B11111100;DS3231_set_sreg(reg_val);} else if (cmd[0] == 70 && cmdsize == 1) { // "F" - custom fctreg_val = DS3231_get_addr(0x5);Serial.print("orig ");Serial.print(reg_val,DEC);Serial.print("month is ");Serial.println(bcdtodec(reg_val & 0x1F),DEC);} else if (cmd[0] == 71 && cmdsize == 1) { // "G" - set aging status registerDS3231_set_aging(0);} else if (cmd[0] == 83 && cmdsize == 1) { // "S" - get status registerSerial.print("status reg is ");Serial.println(DS3231_get_sreg(), DEC);} else {Serial.print("unknown command prefix ");Serial.println(cmd[0]);Serial.println(cmd[0], DEC);}}void printMonth(int month){switch(month){case 1: lcd.print("Jan");break;case 2: lcd.print("Feb");break;case 3: lcd.print("Mar");break;case 4: lcd.print("Apr");break;case 5: lcd.print("May");break;case 6: lcd.print("Jun");break;case 7: lcd.print("Jul");break;case 8: lcd.print("Aug");break;case 9: lcd.print("Sep");break;case 10: lcd.print("Oct");break;case 11: lcd.print("Nov");break;case 12: lcd.print("Dec");break;default: lcd.print("Err");break;}}

Επίσης έφτιαξα και ένα πρόγραμμα για την LCD και το DS22:

#include <LiquidCrystal.h>LiquidCrystal lcd(27, 26, 25, 24, 23, 22); //Pins for the LCD display, as taken from arduino.cc#include "DHT.h"#define DHTPIN 28 // what digital pin we're connected to#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321// Initialize DHT sensor.// Note that older versions of this library took an optional third parameter to// tweak the timings for faster processors. This parameter is no longer needed// as the current DHT reading algorithm adjusts itself to work on faster procs.DHT dht(DHTPIN, DHTTYPE);void setup() {Serial.begin(9600);lcd.begin(20, 4);dht.begin();}void loop() {// Wait a few seconds between measurements.delay(2000);// Reading temperature or humidity takes about 250 milliseconds!// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)lcd.setCursor(0, 2);float h = dht.readHumidity();// Read temperature as Celsius (the default)float t = dht.readTemperature();// Read temperature as Fahrenheit (isFahrenheit = true)float f = dht.readTemperature(true);// Check if any reads failed and exit early (to try again).if (isnan(h) || isnan(t) || isnan(f)) {Serial.println("Failed to read from DHT sensor!");return;}lcd.setCursor(0, 2);lcd.print("temp: ");lcd.print(t);lcd.print(" C");Serial.print("\t\t");lcd.setCursor(0, 3);lcd.print("Humidity: ");lcd.print(h);lcd.print(" %");Serial.print("\t\t");}

Και τα δυο προγράμματα αν τα τρέξω ξεχωριστά δουλεύουν και δεν έχω πρόβλημα. Θα ήθελα την βοήθεια σας για τυχόν διορθώσεις και για να τρέξω ένα πρόγραμμα με ενσωματωμένα και τα δυο. Ευχαριστώ