Sziasztok!
Idén végzős egyetemistaként írom szakdolgozatomat. Témám egy hőkezelő kemence automatizálásának megvalósítása melyet egy atmega 328p-pu csippel végzek és ehhez terveztem és készítettem egy egyedi áramkört, hogy ne kelljen beleépítenem az egész arduino UNO boardot. Azonban felmerült néhány probléma miután beüzemeltem a rendszert az egyedi nyákkal. A program egy menürendszerrel kezdődik ahol be tudok állítani különböző értékeket és paramétereket 3 gomb segítségével (up/down/select). A probléma az, hogy ha lenyomok egy gombot akkor valamilyen oknál fogva a másik gombhoz rendelt funkció reagál. Pl: select gomb feladata a továbblépés de valamiért az up gomb funkciója teljesül. A programban input pullup beállítást használtam a bemenetekre. Olvastam, hogy a csipben beépített ellenállások vannak melyeket ezzel a funkcióval tudok aktiválni ezért nem kell külön a nyákra építenem, ebben nem tévedek? Valamint ugyan ilyen problémák vannak az SD kártya olvasóval ami az arduino UNO boardban tökéletesen funkcionált. Nem tudom, hogy elképzelhető-e, hogy az adott bekötő vezetékekhez közel elhaladó hálózati kábel e a probléma? Időnként a MAX31855 K típusú hőszondákhoz való áramkör se olvas ki jelet. Kicsit tanácstalan vagyok és kezdek kifutni az időből ezért számítok a segítségetekre.
Előre is köszönöm!
Ui.: Képként feltöltöm a nyák kapcsolási rajzát illetve a programot (kicsit átláthatatlan mert még nem szerkesztettem de hátha segít).
A kód:
#include <LiquidCrystal_I2C.h>
#include <LiquidCrystal.h> // LCD display library
#include <max6675.h> // Thermocouple card library
#include <PID_v2.h> // PID temp control library
#include <SPI.h> // Serial Peripheral Interface library
#include <SD.h> // SD memory card library (SPI is required)
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27,20,4);
#include "Adafruit_MAX31855.h"
File saveFile;
//NE VÁLTOZTASD MEG
const int upPin = 2;
const int downPin = 3;
const int selectPin = 4;
int optionNum = 0;
boolean segPhase = 0;
const int lcdRefresh = 2500; // Refresh rate to update screen when running (ms)
const int maxTemp = 1600; // Maximum temperature (degrees). If reached, will shut down.
const int numZones = 1; // Number of heating element + thermostat zones (max of 3)
const int pidCycle = 2500; // Time for a complete PID on/off cycle for the heating elements (ms)
double pidInput[1]; // Input array for PID loop (actual temp reading from thermocouple). Don't change.
double pidOutput[1]; // Output array for PID loop (relay for heater). Don't change.
double pidSetPoint[1]; // Setpoint array for PID loop (temp you are trying to reach). Don't change.
PID pidCont[1] = {PID(&pidInput[0], &pidOutput[0], &pidSetPoint[0], 800, 47.37, 4.93, DIRECT)}; // PID controller array for each zone. Set arguments 4/5/6 to the Kp, Ki, Kd values after tuning.
const long saveCycle = 15000; // How often to save current temp / setpoint (ms)
const int tempOffset[1] = {0}; // Array to add a temp offset for each zone (degrees). Use if you have a cold zone in your kiln or if your thermocouple reading is off. This gets added to the setpoint.
const int tempRange = 2; // This is how close the temp reading needs to be to the set point to shift to the hold phase (degrees). Set to zero or a positive integer.
const char tempScale = 'C';
int screenNum = 0; //4 ha vége
int i = 0;
double rampHours;
unsigned long rampStart;
unsigned long saveStart;
unsigned long schedStart;
unsigned long holdStart;
unsigned long lcdStart;
unsigned long pidStart;
int segNum;
int segHold;
int segRamp;
int segTemp;
const int heaterPin = 9;
String schedDesc1;
double calcSetPoint;
int lastTemp;
MAX6675 thermo[1] = {MAX6675(5, 6 ,7)};
void setup() {
Serial.begin(9600);
pinMode(heaterPin, OUTPUT);
pinMode(selectPin, INPUT_PULLUP);
pinMode(downPin, INPUT_PULLUP);
pinMode(upPin, INPUT_PULLUP);
pidInput[0] = 0;
lcd.begin(20, 4);
lcd.init();
lcd.backlight();
segRamp = 1000;
segTemp = 50;
segHold = 10; //percben!
SD.remove("temps.txt");
lcd.backlight();
lcd.clear();
lcd.print(F("Parameter beallit:"));
lcd.setCursor(0, 1);
lcd.print(F("Temp: "));
lcd.print(segTemp);
lcd.print((char)223);
lcd.print("C");
lcd.setCursor(0, 2);
lcd.print(F("Ramp: "));
lcd.print(segRamp);
lcd.print((char)223);
lcd.print("C/hr");
lcd.setCursor(0, 3);
lcd.print(F("Hold: "));
lcd.print(segHold);
lcd.print("min");
delay(100);
}
void loop() {
//Fel gomb
if(digitalRead(upPin) == LOW && screenNum == 0) {
if (optionNum == 0) {
segTemp = segTemp + 10;
}
if (optionNum == 1) {
segRamp = segRamp + 10;
}
if (optionNum == 2) {
segHold = segHold + 10;
}
updateLCD();
btnBounce(upPin);
}
//Le gomb
if(digitalRead(downPin) == LOW && screenNum == 0) {
if (optionNum == 0) {
segTemp = segTemp - 10;
}
if (optionNum == 1) {
segRamp = segRamp - 10;
}
if (optionNum == 2) {
segHold = segHold - 10;
}
updateLCD();
btnBounce(downPin);
}
//select gomb
if(digitalRead(selectPin) == LOW && screenNum == 0) {
if (optionNum == 0 || optionNum == 1 || optionNum == 2) {
optionNum = optionNum + 1;
}
if (optionNum == 3) {
setupPIDs();
segNum = 1;
screenNum = 1;
lcdStart = millis();
pidStart = millis();
rampStart = millis();
schedStart = millis();
updateLCD();
btnBounce(selectPin);
}
updateLCD();
btnBounce(selectPin);
}
//###############
//program elindítása
//###############
// if (digitalRead(selectPin) == LOW) {
// setupPIDs();
// segNum = 1;
// screenNum = 1;
// lcdStart = millis();
// pidStart = millis();
// rampStart = millis();
// schedStart = millis();
// updateLCD();
// btnBounce(selectPin);
// }
//############
//futás közben
//############
if (segNum >= 1) {
// Update PID's / turn on heaters / update segment info
if (screenNum < 4) {
if (millis() - pidStart >= pidCycle) {
pidStart = millis();
updatePIDs();
}
htrControl();
updateSeg();
}
// Refresh the LCD
if (millis() - lcdStart >= lcdRefresh) {
updateLCD();
lcdStart = millis();
}
// Save the temps to a file on SD card
if (millis() - saveStart >= saveCycle && pidInput[0] > 0 && screenNum < 4) {
saveFile = SD.open("temps.txt", FILE_WRITE);
saveFile.print((millis() - schedStart) / 60000.0); // Save in minutes
for (i = 0; i < numZones; i++) {
saveFile.print(",");
saveFile.print(pidInput[i]);
}
saveFile.print(",");
saveFile.println(pidSetPoint[0]);
saveFile.close();
saveStart = millis();
}
}
}
//################
//LCD frissítése
//################
void updateLCD() {
if (screenNum == 0) {
lcd.backlight();
lcd.clear();
lcd.print(F("Parameter beallit:"));
lcd.setCursor(0, 1);
lcd.print(F("Temp: "));
lcd.print(segTemp);
lcd.print((char)223);
lcd.print("C");
lcd.setCursor(0, 2);
lcd.print(F("Ramp: "));
lcd.print(segRamp);
lcd.print((char)223);
lcd.print("C/hr");
lcd.setCursor(0, 3);
lcd.print(F("Hold: "));
lcd.print(segHold);
lcd.print("min");
delay(100);
}
if (screenNum == 1){
if (segPhase == 0) {
lcd.backlight();
lcd.clear();
lcd.print(F("Felfutes: "));
lcd.setCursor(1, 1);
lcd.print(F("Sensor1:"));
lcd.setCursor(1, 2);
lcd.print(F("Rdg: "));
lcd.print((int)pidInput[0]);
lcd.print(char(223));
lcd.print("C");
lcd.setCursor(1, 3);
lcd.print(F("Set: "));
lcd.print((int)pidSetPoint[0]);
lcd.print((char)223);
lcd.print("C");
}
if (segPhase == 1) {
lcd.backlight();
lcd.clear();
lcd.print(F("Hontartas: "));
lcd.setCursor(1, 1);
lcd.print(F("Sensor1:"));
lcd.setCursor(1, 2);
lcd.print(F("Rdg: "));
lcd.print((int)pidInput[0]);
lcd.print((char)223);
lcd.print("C");
lcd.setCursor(1, 3);
lcd.print(F("Set: "));
lcd.print((int)pidSetPoint[0]);
lcd.print((char)223);
lcd.print("C");
lcd.setCursor(12, 1);
lcd.print(F("Hold: "));
lcd.setCursor(12, 2);
lcd.print(F("Now: "));
lcd.print((millis() - holdStart) / 60000);
lcd.print("m");
lcd.setCursor(12, 3);
lcd.print(F("Set: "));
lcd.print(segHold);
lcd.print("m");
}
}
if (screenNum == 4)
{
readTemps();
lcd.backlight();
lcd.clear();
lcd.print(F("Holepcsok kesz!"));
lcd.setCursor(0, 1);
lcd.print(F("Varj a lehulesre!"));
lcd.setCursor(0, 2);
lcd.print(F("Sensor1: "));
lcd.print((int)pidInput[0]);
lcd.print((char)223);
lcd.print("C");
}
}
//################
//PID beállítása
//################
void setupPIDs() {
pidCont[0].SetSampleTime(pidCycle);
pidCont[0].SetOutputLimits(0, pidCycle);
pidCont[0].SetMode(AUTOMATIC);
}
//################
//duplaklikk elkerülése
//################
void btnBounce (int btnPin) {
while (digitalRead(btnPin) == LOW);
delay(40);
}
//################
//szám karakterszámának meghatározása
//################
int intLenght(int myInt) {
myInt = abs(myInt);
if (myInt >= 10000) {
return 5;
}
else if (myInt >= 1000) {
return 4;
}
else if (myInt >= 100) {
return 3;
}
else if (myInt >= 10) {
return 2;
}
else {
return 1;
}
}
//##############
//hőmérséklet kiolvasása
//################
void readTemps() {
pidInput[0] = thermo[0].readCelsius();
}
//#############
//PID frissítés
//##############
void updatePIDs() {
// Get the last target temperature
if (segNum == 1) { // Set to room temperature for first segment
lastTemp = 24;
}
// Calculate the new setpoint value. Don't set above / below target temp
if (segPhase == 0) {
rampHours = (millis() - rampStart) / 3600000.0; //megadja mennyi ideje megy a ramp
calcSetPoint = lastTemp + (segRamp * rampHours);// kiszámolja a ramp időt és ezt beszorozva a fokot
if (segRamp >= 0 && calcSetPoint >= segTemp) {
calcSetPoint = segTemp;
}
if (segRamp < 0 && calcSetPoint <= segTemp) {
calcSetPoint = segTemp;
}
}
else {
calcSetPoint = segTemp; // Hold
}
// Read the temperatures
readTemps();
// Loop thru all PID controllers
// Set the target temp. Add any offset.
pidSetPoint[0] = calcSetPoint + tempOffset[0];
Serial.println(pidSetPoint[0]);
// Update the PID based on new variables
pidCont[0].Compute();
}
//###########
//fűtés be/ki
//#############
void htrControl() {
if (pidOutput[0] >= millis() - pidStart) {
digitalWrite(heaterPin, HIGH);
}
else {
digitalWrite(heaterPin, LOW);
}
Serial.println(pidOutput[0]);
}
//felfűtési fázis és szegmens frissítése
void updateSeg() {
// Start the hold phase
if ((segPhase == 0 && segRamp < 0 && pidInput[0] <= (segTemp + tempRange)) ||
(segPhase == 0 && segRamp >= 0 && pidInput[0] >= (segTemp - tempRange))) {
segPhase = 1;
holdStart = millis();
}
// Go to the next segment
if (segPhase == 1 && millis() - holdStart >= segHold * 60000) {
digitalWrite(heaterPin, LOW);
screenNum = 4;
}
}