Szerelo

AC motor contlorrel with real time adjust PID setting

Sep 27th, 2021
1,352
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //#include <avr/wdt.h> // Watchdog timer
  2. #include <avr/io.h>
  3. #include <avr/interrupt.h>
  4. #include <Wire.h>
  5. #include <LiquidCrystal_I2C.h>
  6. #include <Rotary.h>
  7. #include <PID_v1.h>
  8. #include <EEPROM.h>
  9.  
  10. #define GATE 6             // TRIAC gate
  11. #define encButton 10          // stop/start gomb
  12. #define FINE 9  // rpm egyesével való állítása kapcsoló
  13. #define FINE10 8  //
  14. #define LED 13             //
  15. #define RELAY 4            // relé
  16. #define CURRENT A7         // motor áram
  17. #define PULSE 2            // triac gyújtóimpulzusának a hossza, órajelciklusban
  18. #define TACHOPULSES 8      // a tacho fordulatonkénti impulzusa
  19.  
  20. unsigned int RPM;                   // mért fordulatszám
  21. unsigned int count;                 // tacho impulzus számlálója
  22. unsigned int lastcount = 0;         // a tacho impulzusainak számlálója, a fordulatszám kiszámításához szükséges
  23. unsigned long lastcounttime = 0;    // a tacho impulzusainak ideje
  24. unsigned long lasttachotime;        // a tach impulzus idejének átmeneti tárolása
  25. unsigned long lastpiddelay = 0;     // a motor lágy indításának számlálója
  26. //unsigned long previousMillis = 0;   // a kijelző frissési idejének méréséhez
  27. //unsigned long lastDebounceTime = 0; // a gomb pergésének idejéhez átmeneti tároló
  28.  
  29. const int sampleRate = 1;           // A PID szabályozó minavételezési gyakorisága
  30. const int rpmcorrection = 86;       // a perc és a processzor órajele közötti korrekció
  31. const int lcdinterval = 500;        // a kijelző frissítési ideje ms-ban
  32. const int protection = 2000;        // fordulatszám túllépési hiba értéke
  33. //const int debounceDelay = 50;       // a gomb pergésmentesítési ideje
  34. const int minoutputlimit = 80;      // a PID szabályozó kimeneti értékének alsó határa
  35. const int maxoutputlimit = 540;     // a PID szabályozó kimeneti értékének felső határa
  36. const int mindimminglimit = 80;     // a triac gyújtási idejének biztonsági korlátja
  37. const int maxdimminglimit = 625;    // a triac gyújtási idejének biztonsági korlátja
  38. const int minrpm = 200;             // a fordulatszám kiválasztás alsó határa
  39. const int maxrpm = 9500;            // a fordulatszám kiválasztás alsó határa
  40. const int risetime = 100;           // RPM rise time delay in microseconds (risetime x RPM)
  41.  
  42. int dimming = 540;                  // a gyújtásszög kezdeti értéke (fordított érték)
  43. int counter;                        // fordulatszám mérés számlálója
  44. int desiredRPM;                     // a PID szabályozó kívánt fordulasztám értéke
  45. int tempcounter = 100;              // a motor lágy indításához átmeneti számláló
  46.  
  47. byte currentdisplay;                // a motor áramának kijelzett értéke
  48. int current;                        // motor áramának mért értéke
  49. //byte relayState = LOW;              // a relé állapota
  50. //byte buttonState;                   // a gomb állapota
  51. //byte lastButtonState = HIGH;        // a gomb előző állapota
  52.  
  53. bool softflag = false;              // motor lágyindításának jelzése
  54. bool startflag = false;             // motor működésének engedélyezése, triac gate jel
  55. bool runflag = false;               // motor normál működése
  56.  
  57. double Setpoint, Input, Output;       // PID változók
  58. double sKp = 0.1, sKi = 0.2, sKd = 0; // a motor lágy indításához tartozó PID értékek
  59. double rKp = 0.25, rKi = 1, rKd = 0;  // a motor normál működéséhez tartozó PID értékek
  60. //double Kp=25, Ki=1, Kd=0;
  61.  
  62. unsigned long lastDebounceTime = 0,lastDebounceTime1 = 0;
  63. unsigned long debounceDelay = 50;
  64. unsigned long longPressDelay = 1000;
  65. unsigned long buttonCounter,buttonCounter1;
  66. unsigned long currentMillis;
  67. unsigned long previousMillis;
  68. bool readingButton,readingButton1;
  69. bool buttonShort=false,buttonShort1=false;
  70. bool buttonLong=false,buttonLong1=false;
  71. bool buttonShortPress=false,buttonShortPress1=false;
  72. bool buttonLongPress=false,buttonLongPress1=false;
  73. bool reading,reading1;
  74.  
  75. bool PIDset;
  76. byte menu;
  77. bool buttonOK=true;
  78. unsigned int buttonCountOK;
  79. unsigned int buttonCount=20000;
  80.  
  81.  
  82. //LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // az LCD I2C címe és a kijelző bekötése
  83. LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display
  84. Rotary r = Rotary(12, 11);            // az enkóder kivezetései
  85. PID myPID(&Input, &Output, &Setpoint, sKp, sKi, sKd, DIRECT); // a PID szabályozó létrehozása
  86.  
  87. void setup() {
  88.   for(int i = 0, j=400; i < 256; i++, j>>=1){
  89.    
  90.   }
  91.   Serial.begin(115200);             // hibakereséshez a soros monitor
  92.   Serial.println("Start ...");      // a szabályozó elindult
  93.   //lcd.begin(16,2);                  // a kijelző tipusának beállítása és a meghajtó létrehozása
  94.   pinMode(11, INPUT_PULLUP);        // az enkóder kivezetése, felhúzó ellenállással
  95.   pinMode(12, INPUT_PULLUP);        // az enkóder kivezetése, felhúzó ellenállással
  96.   pinMode(encButton, INPUT_PULLUP);    // a gomb, felhúzó ellenállással
  97.   pinMode(FINE, INPUT_PULLUP);      // rpm kapcsoló, felhúzó ellenállással
  98.   pinMode(FINE10, INPUT_PULLUP);      // rpm kapcsoló, felhúzó ellenállással
  99.   pinMode(RELAY, OUTPUT);           // relé kimenet
  100.   pinMode(GATE, OUTPUT);            // triac kimenet
  101.   pinMode(LED, OUTPUT);             //
  102.   digitalWrite(RELAY, LOW);  // relé alaphelyzet, LOW
  103.   digitalWrite(LED,HIGH);
  104.  
  105.   counter = minrpm;                 // fordulatszám beállítás kezdő értéke
  106.   Input = 200;                      // PID szabályozó kezdő értéke
  107.   Setpoint = 200;                   // PID szabályozó kezdő értéke
  108.  
  109.   myPID.SetMode(AUTOMATIC);         // PID szabályozó bekapcsolása
  110.   myPID.SetOutputLimits(minoutputlimit, maxoutputlimit);
  111.   myPID.SetSampleTime(sampleRate);  // és értékek beállítása
  112.  
  113.   OCR1A = 100;                      // timer1 komparátor beállítása
  114.   TIMSK1 = 0x03;                    // timer1 A komparátor és a túlcsordulás megszakítások beállítása
  115.   TCCR1A = 0x00;                    // timer1 normál működés beállítása
  116.   TCCR1B = 0x00;                    // timer1 normál működés beállítása
  117.  
  118.   attachInterrupt(0, tacho, FALLING);   // a tacho jeléhez megszakítás beállítása, 2-es kivezetés
  119.   attachInterrupt(1, ZCD, RISING);  //a nullaátmenet detektor jeléhez megszakítás beállítása, 3-as kivezetés
  120.   lcd.init();
  121.   lcd.backlight();                  // kijelző háttér világításának bekapcsolása
  122.  
  123.   disp();
  124.   motorStateStop();
  125.   //save();     // ******************************************* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ***************************************
  126.   EEPROM.get(0, rKp);
  127.   EEPROM.get(8, rKi);
  128.   EEPROM.get(16, rKd);
  129.   menu=0;
  130.   //myPID.SetTunings(rKp, rKi, rKd);      // a motor normál működéséhez tartozo PID szablyozó értékeinek a beállítása
  131. }
  132.  
  133. void ZCD() {                      // megszakítás a nullaátmenet detektorhoz
  134.   TCCR1B = 0x04;                  // timer1 elősztó 256-ra állítása
  135.   TCNT1 = 0;                      // timer1 értékének nullázása
  136.   OCR1A = dimming;                // timer1 A komparátor értékének beállítása
  137. }
  138.  
  139. ISR(TIMER1_COMPA_vect) {          // timer1 A komparátor megszakítás (Interrupt Service Routin)
  140.   if (startflag == true) {        // motor működés engedélyezés ellenőrzése
  141.     digitalWrite(GATE, HIGH);     // triac bekapcsolása
  142.     TCNT1 = 65536 - PULSE;        // triac gyújtóimpulzus hosszának a beállítása
  143.   }
  144. }
  145.  
  146. ISR(TIMER1_OVF_vect) {         // timer1 túlcsordulás, letelt a gyújtóimpulzus hossza
  147.   digitalWrite(GATE, LOW);     // triac gate kikapcsolása. a triac nem kapcsol ki ettől!
  148.   TCCR1B = 0x00;               // timer1 normál működés
  149. }
  150.  
  151. void tacho() {                 // tach impulzus megszakítás. fordulatszám kiszámítása
  152.   count++;
  153.   unsigned long tachotime = micros() - lasttachotime;   // két impulzus közötti idő
  154.   float time_in_sec  = ((float)tachotime + rpmcorrection) / 1000000;  // átszámítás másodpercre
  155.   float prerpm = 60 / time_in_sec;                      // átszámítás percre
  156.   RPM = prerpm / TACHOPULSES;                           // és elosztva a fordulatonkénti tacho impulzusok számával
  157.   lasttachotime = micros();                             // időpont tárolása
  158. }
  159.  
  160. void loop() {
  161.   if (runflag==true) {
  162.     //myPID.Compute();     // PID szbályozó számítás
  163.   }
  164.  
  165.   currentMillis = millis();
  166.   if (currentMillis - previousMillis >= 500) {   // Timer every 1 second due to display refresh
  167.     previousMillis = currentMillis;
  168.     disp();
  169.   }
  170.   pressButton();
  171.   //pressButton1();
  172.   digitalWrite(LED,!digitalRead(FINE));
  173.   desiredRPM = counter;              // a kívánt fordulatszám beállítása
  174.  
  175.   if (buttonLong==true){    // Long press on the encoder button, enter the time setting menu
  176.     reading=false;
  177.     buttonLong=false;
  178.     Serial.println("Long Press Normal");   // The button has been pressed long time
  179.     if (PIDset==false) {
  180.       PIDset=true;
  181.       menu=1;
  182.     } else {
  183.       PIDset=false;
  184.       menu=0;
  185.       save();
  186.     }
  187.     disp();
  188.   }
  189.   if (buttonShort==true and readingButton==HIGH){   // Short press of encoder button, current timer START
  190.     reading=false;
  191.     buttonShort=false;
  192.     Serial.println("Short Press Normal");    // The button has been pressed short time  
  193.     if (runflag == false){
  194.       myPID.SetMode (AUTOMATIC);
  195.       runflag=true;
  196.       softflag = true;            // lágyindítás bekapcsolása
  197.       digitalWrite(RELAY, HIGH); // relé bekapcsolása
  198.       delay (300);                // a relé kontaktusok záródására várakozás, relé típustól függ
  199.       startflag = true;           // motor működés engedélyezése, triac
  200.       RPM=0;                      // álló motornál kezdő fordulatszám nulla. Nincs ellenőrizve, hogy tényleg áll-e a motor
  201.     } else {
  202.       //myPID.SetMode (MANUAL);
  203.       Setpoint = 200;             // PID érték alaphelyzetbe állítása
  204.       Input = 200;                // PID érték alaphelyzetbe állítása
  205.       runflag = false;            // motor normál működését jelző kikapcsolása
  206.       startflag = false;          // motor működését engedélyező jelző kikapcsolása
  207.       delay (300);                // várakozás a motor áram megszűnésére, a relé kontaktusának a kímélése miatt
  208.       digitalWrite(RELAY, LOW); // relé kikapcsolása
  209.       motorStateStop();           //
  210.     }
  211.   }
  212.  
  213.   if (buttonLong1==true){    // Long press on the encoder button, enter the time setting menu
  214.     reading1=false;
  215.     buttonLong1=false;
  216.     Serial.println("Long1 Press Normal");   // The button has been pressed long time
  217.   }
  218.   if (buttonShort1==true and readingButton1==HIGH){   // Short press of encoder button, current timer START
  219.     reading1=false;
  220.     buttonShort1=false;
  221.     Serial.println("Short1 Press Normal");    // The button has been pressed short time  
  222.   }
  223.  
  224.  
  225.   unsigned char result = r.process(); // enkóder kezelés
  226.   int tmp;                            // átmeneti tároló a megváltoztatandó érték változásának nagyságához
  227.   if (PIDset==false){
  228.     if (result == DIR_CW) {             // ha jobbra történt a forgatás,
  229.       tmp=20;                           // a változtatás kezdő értéke
  230.       if (counter >= 500) tmp=50;       // ha nagyobb az érték, akkor sávosan nagyobb lesz a változtatás mértéke is
  231.       if (counter >=1500) tmp=100;
  232.       if (digitalRead(FINE)==LOW) tmp=1;  // ha lépésenkénti állítás
  233.       if (digitalRead(FINE10)==LOW) tmp=10;  // ha lépésenkénti állítás
  234.       counter+=tmp;                     // az új érték kiszámítása
  235.       if (counter >= maxrpm) {          // elérte-e vagy meghaladta a maximális értéket
  236.         counter = maxrpm;               // ha igen, akkor az érték a maximum lesz
  237.       }
  238.       disp();                 // az új érték kijelzése
  239.     }
  240.     else if (result == DIR_CCW) {       // ha balra történt a forgatás,
  241.       tmp=20;                           // a változtatás kezdő értéke
  242.       if (counter >= 500) tmp=50;       // ha nagyobb az érték, akkor sávosan nagyobb lesz a változtatás mértéke is
  243.       if (counter >=1500) tmp=100;
  244.       if (digitalRead(FINE)==LOW) tmp=1;// ha lépésenkénti állítás
  245.       if (digitalRead(FINE10)==LOW) tmp=10;  // ha lépésenkénti állítás
  246.       counter-=tmp;                     // az új érték kiszámítása
  247.       if (counter <= minrpm) {          // elérte-e vagy kisebb-e a minimális értéknél
  248.         counter = minrpm;               // ha igen, akkor az érték a minimum lesz
  249.       }
  250.       disp();                 // az új érték kijelzése
  251.     }
  252.   } else {
  253.     if (result == DIR_CW) {             // ha jobbra történt a forgatás,
  254.       setplus();
  255.       myPID.SetTunings(rKp,rKi,rKd);
  256.       disp();
  257.     }
  258.     if (result == DIR_CCW) {             // ha jobbra történt a forgatás,
  259.       setminus();
  260.       myPID.SetTunings(rKp,rKi,rKd);
  261.       disp();
  262.     }
  263.     if (digitalRead(FINE10)==LOW and menu>1 and buttonOK==true) {
  264.       buttonCountOK=buttonCount;
  265.       buttonOK=false;
  266.       menu--;
  267.       disp();
  268.     }
  269.     if (digitalRead(FINE)==LOW and menu<3 and buttonOK==true) {
  270.       buttonCountOK=buttonCount;
  271.       buttonOK=false;
  272.       menu++;
  273.       disp();
  274.     }
  275.   }
  276.   if (softflag == true) {             // lágyindítás kell-e
  277.     myPID.SetTunings(sKp, sKi, sKd);  // PID szabályozó lágyindításhoz szükséges értékeinek a beállítása
  278.     int i = (desiredRPM - tempcounter); // a kívánt fordulatszámmal arányos számú szabályozási hurok meghatározása
  279.     for (int j = 1; j <= i; j++) {    // a szabályozási hurok
  280.       Input = RPM;                    // PID szabályozó bemenete a tényleges fordulatszám
  281.       Setpoint = tempcounter;         // PID szabályozó állításához tartozó érték
  282.       myPID.Compute();                // PID szbályozó számítás
  283.       dimming = map(Output, minoutputlimit, maxoutputlimit, maxoutputlimit, minoutputlimit); // a PID szabályoző és a triac gyújtásának az ideje fordított
  284.       dimming = constrain(dimming, mindimminglimit, maxdimminglimit);     // ellenőrzés, hogy a megfelelő tartományba esik-e az érték
  285.       tempcounter++;                  // a PID szabályozó állítási értékének a növelése
  286.       delayMicroseconds (risetime);   // feléledési idő a PID szabályozónak
  287.     }
  288.     if (tempcounter >= desiredRPM) {  // ha elérte a kívánt értéket az átmeneti beállítási érték
  289.       lastcounttime = millis();       // akkor átváltás normál működésre engedélyezés
  290.       lastpiddelay = millis();        // és a hozzá tartozó értékek és jelzők beállítása
  291.       softflag = false;
  292.       runflag = true;
  293.       tempcounter = 100;              // átmeneti indító számláló alaphelyzetbe állítása
  294.     }
  295.   }
  296.  
  297.  
  298.   if (runflag == HIGH && softflag == false) {  // ha nincs lágyindítás,
  299.     unsigned long piddelay = millis();  // időpont olvasása
  300.     if ((piddelay - lastpiddelay) > 1000) { // a lágyindítás engedélyezése óta eltelt-e már 1000ms
  301.       myPID.SetTunings(rKp, rKi, rKd);      // ha igen, akkor a motor normál működéséhez tartozo PID szablyozó értékeinek a beállítása
  302.       lastpiddelay = millis();              // az utolsó időpont olvasása
  303.     }
  304.     Input = RPM;                        // a PID szabályozó bemeneti értéke a tényleges fordulatszám
  305.     Setpoint = desiredRPM;              // a PID szabályozó beállítási értéke a kívánt fordulatszám
  306.     myPID.Compute();                    // PID szabályozó kimeneti értékének a számítása
  307.     dimming = map(Output, minoutputlimit, maxoutputlimit, maxoutputlimit, minoutputlimit); // a PID szabályoző és a triac gyújtásának az ideje fordított
  308.     dimming = constrain(dimming, mindimminglimit, maxdimminglimit);     // ellenőrzés, hogy a megfelelő tartományba esik-e az érték
  309.   }
  310.  
  311.  
  312.   unsigned long counttime = millis();   // időpont tárolása
  313.   if (counttime - lastcounttime >= 5000) {  // az utolsó tachotól érkezett jeltől eltelt-e már 2000 ms
  314.     if (count == 0 && runflag == true) {  // ha igen, akkor hiba, de csak akkor, ha menet közben történt
  315.       startflag = false;               // motor engedélyezés kikapcsolása
  316.       delay (300);                     // várakozás a motor feszültség mentes állapotára
  317.       digitalWrite(RELAY, LOW);        // motor relé kikapcsolása
  318.       runflag = LOW;                // relé állapot kikapcsolása
  319.       stuckerror();                    // nincs tacho jel hiba jelzése
  320.     }
  321.     lastcount = count;                 // tacho jel számláló tárolása
  322.     count = 0;                         // tacho jel számláló nullázása
  323.     lastcounttime = millis();          // időpont tárolása az eltelt idő méréséhez
  324.   }
  325.  
  326.   if (count == 0 && runflag == LOW) { // ha a motor megállt,
  327.     RPM = 0;                           // akkor a tényleges fordulatszám nullára állítása
  328.   }
  329.  
  330.   if (runflag == true && RPM > desiredRPM + protection) {  // a motor működése közben meghaladja-e a tényleges fordulatszám a beállított fordulatszámot a biztonsági értékkel
  331.     startflag = false;            // ha igen, akkor motor kikapcsolása
  332.     //delay (300);                  // várakozás a motor feszültségmentes állapotára
  333.     digitalWrite(RELAY, LOW);     // relé kikapcsolás
  334.     runflag = false;             // relé állapotjelző kikapcsolása
  335.     digitalWrite(RELAY, LOW);        // motor relé kikapcsolása
  336.     exceederror();                // túlzott fordulatszám hiba jelzése
  337.   }
  338.  
  339.   if (buttonCountOK!=0) {
  340.     buttonCountOK--;
  341.     if (buttonCountOK==0) {
  342.       buttonOK=true;
  343.     }
  344.   }
  345. }
  346.  
  347. void motorStateStop() {
  348.   lcd.setCursor(0, 1);
  349.   lcd.print ("  Press  START  ");
  350. }
  351.  
  352. void disp() {
  353.   if (menu==0) {  
  354.     lcd.setCursor(0, 0);
  355.     lcd.print("RPM: ");
  356.     if (counter < 1000) lcd.print(" ");
  357.     lcd.print(counter);
  358.     lcd.print(" /");
  359.     lcd.setCursor(12, 0);
  360.     if (RPM < 1000) lcd.print(" ");
  361.     if (RPM < 100) lcd.print(" ");
  362.     if (RPM < 10) lcd.print(" ");
  363.     lcd.print(RPM);
  364.     if (runflag == HIGH) {
  365.       lcd.setCursor(0, 1);
  366.       lcd.print("                ");
  367.       lcd.setCursor(0, 1);
  368.     }
  369.     else {
  370.       lcd.setCursor(0, 1);
  371.       lcd.print ("  Press  START  ");
  372.     }
  373.   }
  374.   if (menu==1) {
  375.     lcd.setCursor(0, 1);
  376.     lcd.print("                ");
  377.     lcd.setCursor(3, 1);
  378.     lcd.print("Kp: ");
  379.     lcd.print(rKp);
  380.   }
  381.   if (menu==2) {
  382.     lcd.setCursor(0, 1);
  383.     lcd.print("                ");
  384.     lcd.setCursor(3, 1);
  385.     lcd.print("Ki: ");
  386.     lcd.print(rKi);
  387.   }
  388.   if (menu==3) {
  389.     lcd.setCursor(0, 1);
  390.     lcd.print("                ");
  391.     lcd.setCursor(3, 1);
  392.     lcd.print("Kd: ");
  393.     lcd.print(rKd);
  394.   }
  395. }
  396.  
  397. void exceederror() {
  398.   lcd.clear();
  399.   while (1) {
  400.     lcd.setCursor(5, 0);
  401.     lcd.print("ERROR!");
  402.     lcd.setCursor(2, 1);
  403.     lcd.print("TRIAC DAMAGE");
  404.   }
  405. }
  406.  
  407. void stuckerror() {
  408.   lcd.clear();
  409.   lcd.setCursor(5, 0);
  410.   lcd.print("ERROR!");
  411.   lcd.setCursor(2, 1);
  412.   lcd.print("MOTOR STUCK!");
  413.   delay(1000);
  414.   while (digitalRead(encButton)) {
  415.   }
  416.   delay(500);
  417.   while (!digitalRead(encButton)) {
  418.   }
  419.   delay(500);
  420. }
  421.  
  422. void pressButton() {
  423.   readingButton = digitalRead(encButton);
  424.   if (readingButton==LOW and reading==true) {
  425.     buttonCounter++;
  426.     if ((millis() - lastDebounceTime) > debounceDelay) {  // Is the prell time out?
  427.       buttonShort=true;
  428.     }
  429.     if ((millis() - lastDebounceTime) > longPressDelay) {
  430.       buttonLong=true;
  431.       buttonShort=false;
  432.     }
  433.   }
  434.   if (readingButton==HIGH) {
  435.     lastDebounceTime=millis();
  436.     buttonCounter=0;
  437.     reading=true;
  438.   }
  439. }
  440.  
  441. void pressButton1() {
  442.   readingButton1 = digitalRead(FINE);
  443.   if (readingButton1==LOW and reading1==true) {
  444.     buttonCounter1++;
  445.     if ((millis() - lastDebounceTime1) > debounceDelay) {  // Letelt-e a prell idő
  446.       buttonShort1=true;
  447.     }
  448.     if ((millis() - lastDebounceTime1) > longPressDelay) {  //
  449.       buttonLong1=true;
  450.       buttonShort1=false;
  451.     }
  452.   }// else {
  453.   if (readingButton1==HIGH) {
  454.     lastDebounceTime1=millis();
  455.     buttonCounter1=0;
  456.     reading1=true;
  457.   }
  458. }
  459.  
  460. void setplus() {    // Increase value
  461.   Serial.print(menu);
  462.   Serial.print(" ");
  463.   Serial.println(rKp);
  464.   if (menu==1) {
  465.     rKp=rKp+0.01;
  466.     if (rKp>10) rKp=10;
  467.   }
  468.   if (menu==2) {
  469.     rKi=rKi+0.01;
  470.     if (rKi>10) rKi=10;
  471.   }
  472.   if (menu==3) {
  473.     rKd=rKd+0.01;
  474.     if (rKd>10) rKd=10;
  475.   }
  476. }
  477.  
  478. void setminus() {   // Decrease value
  479.   if (menu==1) {
  480.     rKp=rKp-0.01;
  481.     if (rKp<0) rKp=0;
  482.   }
  483.   if (menu==2) {
  484.     rKi=rKi-0.01;
  485.     if (rKi<0) rKi=0;
  486.   }
  487.   if (menu==3) {
  488.     rKd=rKd-0.01;
  489.     if (rKd<0) rKd=0;
  490.   }
  491. }
  492.  
  493. void save() {
  494.   EEPROM.put(0,rKp);
  495.   EEPROM.put(8,rKi);
  496.   EEPROM.put(16,rKd);
  497. }
  498.  
  499. /*
  500. #include<avr/wdt.h> // Header for watchdog timers in AVR
  501.  
  502. void setup() {
  503.   Serial.begin(9600); // Define baud rate for serial communication
  504.   Serial.println("Watchdog Demo Starting");
  505.   pinMode(13, OUTPUT);
  506.   wdt_disable();  // Disable the watchdog and wait for more than 2 seconds
  507.   delay(3000);  // Done so that the Arduino doesn't keep resetting infinitely in case of wrong configuration
  508.   wdt_enable(WDTO_2S);  /* Enable the watchdog with a timeout of 2 seconds
  509. }
  510.  
  511. void loop() {
  512.   for(int i = 0; i<20; i++) // Blink LED for some time  
  513.   {
  514.     digitalWrite(13, HIGH);
  515.     delay(100);
  516.     digitalWrite(13, LOW);
  517.     delay(100);
  518.     wdt_reset();  // Reset the watchdog
  519.   }
  520.   while(1); // Infinite loop. Will cause watchdog timeout and system reset.
  521. } */
RAW Paste Data