/* 
 A PID-es szabályozás lényege.
 https://hu.wikipedia.org/wiki/PID_szab%C3%A1lyoz%C3%B3
 A neten az alábbi linken található kapcsolásból és programból indultam ki.
 http://randomdamon.blogspot.com/2015/12/diy-hot-end-arduino-pid-control.html
 A rajz és az eredeti program a linken megtalálható. 100 Kohm termisztor + 10 Kohm soros ellenállás. (Ender 3 termisztor)
 Az a feladat adódott, hogy nagy teljesítményt, 240 Volton kellett szabályozni, szilárd test relével.
 A pontosság miatt szerettem volna a PID szabályozást bevonni. 
 Fingom sincs, hogy működik a PID függvény, de azért elég jól meghekkeltem az alap programot.
 A 3 db. magam írt program részeket megjelötem, néhány angol szót ( google fordítóval ) magyarosítottam.
 A szilárd test relé közvetlenül nem lehet PWM jelel meghajtani, mert a Arduino Uno-n a PWM pinek 3, 5, 6, 9, 10 és 11. 
 A PWM jel frekvenciája az 5. és 6. pinen körülbelül 980 Hz, a többi pinen pedig 490 Hz. A PWM érintkezők ~ jellel vannak jelölve.
 https://create.arduino.cc/projecthub/muhammad-aqib/arduino-pwm-tutorial-ae9d71
 Az eredeti programban a Pin 9 lábon jelenik meg a PWM jel a fűtés maghajtására.
 A átírt programban is, a PWM jel változatlanul megjelenik a 9 lábon. 
 A rajzon látható 3,3V - és az AREF pontot a Ardunio alaplapon vezetékkel alul előre átkötöttem.
 A rajzon látható 3,3V - és az A0 nulla pontot a Ardunio alaplapon a 10 Kohmos ellenállással alul előre átkötöttem.
 A tápfeszültség vezetékeket, is alulról forrasztottam a panelre.
 Ebben a kapcsolásban a szilárd test relé, 1 mp belüli alacsony és magas szint hosszával változtatja a fűtés teljesítményt.
 (Ha jól okoskodom akkor 1 Millihertz (mHz - Frekvencia), a frekvencia.)
 A programot úgy módosítottam, hogy a Pin 7 lábra lehet kötni a szilárd test relét.
 A Pin 5 lábra lehet kötni a fűtést jelző ledet. (Az 5,7 láb együtt működik.)
 A hőmérséklet alsó felső értékét a program 3,4 sorban kell definiálni.
 A lineáris potméter NYUJTOTT (270*) skálája a kezdő és a vég hőmérsékleten belül állítható.
 A TM1637 Display elhagyható, de akkor csak a potméter skálája a mérvadó.
 (A könnyebb hardver építés miatt, néhány lábat fel-le húztam, de nem kötelező élni vele.)
 A most aktív 3 db. sor a Serilal printen jól követhető a PID szabályozás a plotteren.
 A készüléken a nyomógomb megnyomásakor a kijelzés villog. Ekkor lehet a potmétert pontosan beállítani.
 A potmétert nyomógomb megnyomása nélkül is lehet állítani a megrajzolt skála alapján.
 Beüzemelés után tanácsos a serial printeket kivenni.
///////////////////////////////////////////////////
Arduino UNO Lábkiosztás
////////////////////////////////////////////////////////
TM1637 Displayon a pinek jobboldalt szembe
CLK
DIO
Vcc
GND
TM1637 Display meghajtás
 11  Pin DIO 
 12  Pin CLK 
/////////////////////////////////////////
 9  PWM kimenet 0-255 analog kimenet
 8  GND    LOW-ra húzva
 ///////////////////////////////////////////
 ///////////// 7 - 5 Pin együtt működik
 7  Szilárdtest relé meghajtás, HIGH vagy LOW 1 mp belül delay (0-1000, 1000 -0)
 6  GND    LOW-ra húzva
//////////////////////////////////////////////////
 ez külön kábelen megy a fedlaphoz
 5  Fűtésjező led meghajtás, HIGH vagy LOW 1 mp belül (delay (0-1000, 1000 -0))
 4  GND    LOW-ra húzva
//////////////////////////////////////////////////
thermisztor csatlakozó
 A0  thermisztor bemenet
 A1  GND  LOW-ra húzva
///////////////////////////////////
Fedlaphoz a 4 eres szalag kábel
A2  Nyomógomb bemenet. Hőmérséklet beállítás / Tényleges hőmérséklet kijelzés között.
A3  Hőmérséklet beállító potméter bemenet
    a fedlapon levő potméternek  ( + - ) 5 volt, és a nyomógombnak, illetve a ledeknek negatív pólus
    a fedlapon két led van az egyik a tápfesz a másik a fűtés aktív állapotot jelzi
A4  Vcc   A4 HIGH-re húzva
A5  GND   A5 LOW-ra húzva
*/
#include <PID_v1.h>
#include <TM1637Display.h>
/////////////////////// 270* lineáris potméternél
#define kezdo_homerseklet 85      // alsó hőmérséklet
#define maximalis_homerseklet 240 // felső hőmérséklet
/////////////////////////////
/////////////////////////////
/////////////////////////////////////////////////////////
#define PWM_kimenet_pin 9       // PWM analog kimenet 0-255
#define GND_8_Pin 8  // low
// 5, 7 Pin együtt működik
#define szilard_test_vererles 7 // digital kimenet szilárd test felé 0,1 állapot hossza 1 mp alatt
#define GND_6_Pin 6  // low
#define futes_led_jelzes 5      // digital kimenet szilárd test felé 0,1 állapot hossza 1 mp alatt
#define GND_4_Pin 4  // low
// thermistor analog pin bemenet
#define THERMISTORPIN A0
// how many samples to take and average  // hány mintát kell venni és átlagolni
#define NUMSAMPLES 5
// how long between pid/sampling // mennyi idő van a pid/mintavétel között
#define SAMPLETIME 1000 // 1 mp
//Define Variables we'll be connecting to  //Változók meghatározása, amelyekhez csatlakozni fogunk ?
double Setpoint, currentTemp, Output;
//Specify the links and initial tuning parameters  //Adja meg a hivatkozásokat és a kezdeti hangolási paramétereket
PID myPID(&currentTemp, &Output, &Setpoint,15,.3,0, DIRECT);
/////////////////////////////////////////////////////////////////////////////////
int val ;
int szilard_test_ertek1 ;
int tenyleges_homerseklet ;
int PWM_ertek ; // PWM kimenet
int szilard_test_ertek0 ; // szilárd test kimenet 1 mp belüli ki be kapcsolgatás
// delay (max 1000 - 0  vagy  min 0 - 1000)
int homerseklet_beallitas ;
boolean button_state = 1;
// TM1637 Displayt vezérlő portok beállítása
#define CLK 12  
#define DIO 11 
/////////////////////////////////
// Create display object of type TM1637Display:
TM1637Display display = TM1637Display(CLK, DIO);
// Create array that turns all segments on: // minden szegmens bekapcsol, TESZT
const uint8_t data[] = {0xff, 0xff, 0xff, 0xff};
// done = kész felirat
const uint8_t done[] = { 
  SEG_B | SEG_C | SEG_D | SEG_E | SEG_G,           // d
  SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,   // O
  SEG_C | SEG_E | SEG_G,                           // n
  SEG_A | SEG_D | SEG_E | SEG_F | SEG_G   };       // E
  // Create degree Celsius symbol: // celziusz fok jele
  const uint8_t celsius[] = { 
  SEG_A | SEG_B | SEG_F | SEG_G,};  // Circle a felső nény szegmens kőrt alkot
///////////////////////////////////////////////
///////////////////////////////////////////////
void setup() {
  Serial.begin(9600);
  analogReference(EXTERNAL); // AREF pin külső jelet fogad
  // TM1637 Displaynak  CLK 12  DIO 11 foglalt
  pinMode(PWM_kimenet_pin, OUTPUT);       // Pin 9 analog write PWM
  pinMode(GND_8_Pin, OUTPUT);             // LOW
  digitalWrite(GND_8_Pin, 0);
  pinMode(szilard_test_vererles,OUTPUT);  // Pin 7 digital write 0-1
  digitalWrite(szilard_test_vererles, 0); // digital write
  pinMode (GND_6_Pin,OUTPUT);             // GND  LOW
  digitalWrite(GND_6_Pin, 0);             // digital write LOW
  pinMode(futes_led_jelzes,OUTPUT);       // Pin 5 LOW
  digitalWrite(futes_led_jelzes , 0);  
  pinMode (GND_4_Pin,OUTPUT);            // GND  LOW
  digitalWrite(GND_4_Pin, 0);            // digital write LOW
  ///////  analog sor
  // A0 thermisztor bemenet, már fent a 9 sorban definiálva van ?
  pinMode(A1, OUTPUT);   
  digitalWrite(A1, 0);                   // GND a thermisztornak
  pinMode(A2, INPUT_PULLUP);             // fűtés beállító nyomogomb bemenet
  pinMode(A3, INPUT);                    // Hőmérséklt beállító potméter bemenet
  pinMode(A4, OUTPUT);      
  digitalWrite(A4, 1);                   // Vcc 
  pinMode(A5, OUTPUT);      
  digitalWrite(A5, 0);                   // GND   
 //turn the PID on
  myPID.SetMode(AUTOMATIC);
  myPID.SetSampleTime(SAMPLETIME);
  //pid Autotuner
  display.clear();
  display.setBrightness(7);
  display.setSegments(data);            // szegment teszt
  delay(1200) ;
  display.setSegments(done);            // done = kész felirat
  delay(1200) ;
}
void loop() {
 //////////// saját munka1 kezd
  homerseklet_beallitas = analogRead(A3);  // beállító potméter bemenet
  homerseklet_beallitas = map(homerseklet_beallitas, 1023,0, kezdo_homerseklet,maximalis_homerseklet);
  Setpoint = homerseklet_beallitas ;
  ////////////////////////////////////////////////////////////
  PWM_ertek = Output ;
  PWM_ertek = PWM_ertek * 100 / 25.5 ;
  szilard_test_ertek1 =  PWM_ertek ;
  szilard_test_ertek0 = ( 1000 - szilard_test_ertek1 ) ;
  tenyleges_homerseklet = currentTemp ;
  //////////////////////////////////////
  button_state = digitalRead(A2) ;
  if ( button_state == 0)             // kijelzés csere
  {led_print1 (); }else { led_print0 ();}
 if ( button_state == 0)              // a gyors villogás miatt a ciklus röviditése nyomógomb megnyomásakor 
 { szilard_test_ertek1 = 100 ;szilard_test_ertek0 = 100 ;}
   ///////// digitális kirás !!! Új PWM_ertek, szilard_test_ertek0 összege mindig 1000
  digitalWrite(szilard_test_vererles, 1);  // digital write
  digitalWrite(futes_led_jelzes, 1);  
  ////////////////////////////////
  if ( button_state == 0)     // kijelzés csere
    szilard_test_ertek1 = 0 ; // fütés és a fütés led letiltása nyomogom lenyomásakor
  //////////////////////////////////////////                             
  delay(szilard_test_ertek1); // 
  digitalWrite(szilard_test_vererles, 0);  // digital write
  digitalWrite(futes_led_jelzes , 0);                                    
  delay(szilard_test_ertek0); //
  // saját munka1 vége
  ////////////////////////
   if (Serial.available() > 0) {
    // get incoming byte:
    Setpoint = Serial.parseFloat();}
  uint8_t i;
  double average = 0;
  // take N samples in a row, with a slight delay
  for (i = 0; i < NUMSAMPLES; i++) {
    average += analogRead(THERMISTORPIN);// A0 bemnet
    delay(10);}
  average /= NUMSAMPLES;
  currentTemp=resistanceToC(inputToResistance(average));
  myPID.Compute();
  analogWrite(PWM_kimenet_pin, Output);
 //////////////////////////////////////////////
 // saját munka2
 // Bezüzemelés után tanácsos a serial printeket kivenni.
  //////////*  Serial print kezdete     A Serial print a program készítésekor kellett
  //Serial.print(" Szamlalo = "); // munka
  //Serial.print(szamlalo);  // munka
  //Serial.print(" SP= "); // Setpoint
  Serial.print(homerseklet_beallitas);
  Serial.print(" ");
  Serial.println(tenyleges_homerseklet);
  //Serial.println(" = T  "); // mért hőmérséklet
  //Serial.print(" PID: ");
  //Serial.print(PWM_ertek);
  //Serial.print(" ");
  //Serial.println(szilard_test_ertek0);
}  ///////////// Serial print vége saját munka2 vége
 double inputToResistance(double input) {
  // funtion to convert the input value to resistance
  // the value of the 'other' resistor
  double SERIESRESISTOR = 10000;
  input = 1023 / input - 1;
  return SERIESRESISTOR / input;}
 double resistanceToC(double resistance) {
  // funtion to convert resistance to c
  // temp/resistance for nominal
  double THERMISTORNOMINAL = 118000;
  double TEMPERATURENOMINAL = 25;
  // beta coefficent
  double BCOEFFICIENT = 3950;
  double steinhart;
  steinhart = resistance / THERMISTORNOMINAL;       // (R/Ro)
  steinhart = log(steinhart);                       // ln(R/Ro)
  steinhart /= BCOEFFICIENT;                        // 1/B * ln(R/Ro)
  steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
  steinhart = 1.0 / steinhart;                      // Invert
  steinhart -= 273.15;   // convert to C
  return steinhart;}
//////////////////////////////////////////////////////////////////////////
// saját munka3 kezdete
void led_print0 () { ////////////// 
///display.showNumberDec(tenyleges_homerseklet); }
 display.showNumberDec(tenyleges_homerseklet, false, 3, 0);
 display.setSegments(celsius, 3, 3);}
//////////////////////////////////////////
void led_print1 () { // gyorsan villog a kiírás
 display.showNumberDec(homerseklet_beallitas, false, 3, 0);
 display.setSegments(celsius, 3, 3);
 display.clear();
 delay (5) ;
 display.showNumberDec(homerseklet_beallitas, false, 3, 0);
 display.setSegments(celsius, 3, 3);}
 ////saját munka3 vége
