Advertisement
Szerelo

HV AC motor speed controller

Feb 5th, 2020
302
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 16.76 KB | None | 0 0
  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.  
  9. #define GATE 6             // TRIAC gate
  10. #define BUTTON 10          // stop/start gomb
  11. #define FINE 9             // rpm egyesével való állítása kapcsoló
  12. #define RELAY 4            // relé
  13. #define CURRENT A7         // motor áram
  14. #define PULSE 2            // triac gyújtóimpulzusának a hossza, órajelciklusban
  15. #define TACHOPULSES 8      // a tacho fordulatonkénti impulzusa
  16.  
  17. unsigned int RPM;                   // mért fordulatszám
  18. unsigned int count;                 // tacho impulzus számlálója
  19. unsigned int lastcount = 0;         // a tacho impulzusainak számlálója, a fordulatszám kiszámításához szükséges
  20. unsigned long lastcounttime = 0;    // a tacho impulzusainak ideje
  21. unsigned long lasttachotime;        // a tach impulzus idejének átmeneti tárolása
  22. unsigned long lastpiddelay = 0;     // a motor lágy indításának számlálója
  23. unsigned long previousMillis = 0;   // a kijelző frissési idejének méréséhez
  24. unsigned long lastDebounceTime = 0; // a gomb pergésének idejéhaz átmeneti tároló
  25.  
  26. const int sampleRate = 1;           // A PID szabályozó minavételezési gyakorisága
  27. const int rpmcorrection = 86;       // a perc és a processzor órajele közötti korrekció
  28. const int lcdinterval = 500;        // a kijelző frissítési ideje ms-ban
  29. const int protection = 2000;        // fordulatszám túllépési hiba értéke
  30. const int debounceDelay = 50;       // a gomb pergésmentesítési ideje
  31. const int minoutputlimit = 80;      // a PID szabályozó kimeneti értékének alsó határa
  32. const int maxoutputlimit = 540;     // a PID szabályozó kimeneti értékének felső határa
  33. const int mindimminglimit = 80;     // a triac gyújtási idejének biztonsági korlátja
  34. const int maxdimminglimit = 625;    // a triac gyújtási idejének biztonsági korlátja
  35. const int minrpm = 200;             // a fordulatszám kiválasztás alsó határa
  36. const int maxrpm = 9500;            // a fordulatszám kiválasztás alsó határa
  37. const int risetime = 100;           // RPM rise time delay in microseconds (risetime x RPM)
  38.  
  39. int dimming = 540;                  // a gyújtásszög kezdeti értéke (fordított érték)
  40. int counter;                        // fordulatszám mérés számlálója
  41. int desiredRPM;                     // a PID szabályozó kívánt fordulasztám értéke
  42. int tempcounter = 100;              // a motor lágy indításához átmeneti számláló
  43.  
  44. byte currentdisplay;                // a motor áramának kijelzett értéke
  45. int current;                        // motor áramának mért értéke
  46. byte relayState = LOW;              // a relé állapota
  47. byte buttonState;                   // a gomb állapota
  48. byte lastButtonState = HIGH;        // a gomb előző állapota
  49.  
  50. bool softflag = false;              // motor lágyindításának jelzése
  51. bool startflag = false;             // motor működésének engedélyezése, triac gate jel
  52. bool runflag = false;               // motor normál működése
  53.  
  54. double Setpoint, Input, Output;       // PID változók
  55. double sKp = 0.1, sKi = 0.2, sKd = 0; // a motor lágy indításához tartozó PID értékek
  56. double rKp = 0.25, rKi = 1, rKd = 0;  // a motor normál működéséhez tartozó PID értékek
  57.  
  58. LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // az LCD I2C címe és a kijelző bekötése
  59. Rotary r = Rotary(12, 11);            // az enkóder kivezetései
  60. PID myPID(&Input, &Output, &Setpoint, sKp, sKi, sKd, DIRECT); // a PID szabályozó létrehozása
  61.  
  62. void setup() {
  63.   Serial.begin(115200);             // hibakereséshez a soros monitor
  64.   Serial.println("Start ...");      // a szabályozó elindult
  65.   lcd.begin(16,2);                  // a kijelző tipusának beállítása és a meghajtó létrehozása
  66.   pinMode(11, INPUT_PULLUP);        // az enkóder kivezetése, felhúzó ellenállással
  67.   pinMode(12, INPUT_PULLUP);        // az enkóder kivezetése, felhúzó ellenállással
  68.   pinMode(BUTTON, INPUT_PULLUP);    // a gomb, felhúzó ellenállással
  69.   pinMode(FINE, INPUT_PULLUP);      // rpm kapcsoló, felhúzó ellenállással
  70.   pinMode(RELAY, OUTPUT);           // relé kimenet
  71.   pinMode(GATE, OUTPUT);            // triac kimenet
  72.   digitalWrite(RELAY, relayState);  // relé alaphelyzet, LOW
  73.  
  74.   counter = minrpm;                 // fordulatszám beállítás kezdő értéke
  75.   Input = 200;                      // PID szabályozó kezdő értéke
  76.   Setpoint = 200;                   // PID szabályozó kezdő értéke
  77.  
  78.   myPID.SetMode(AUTOMATIC);         // PID szabályozó létrehozása
  79.   myPID.SetOutputLimits(minoutputlimit, maxoutputlimit);
  80.   myPID.SetSampleTime(sampleRate);  // és értékek beállítása
  81.  
  82.   OCR1A = 100;                      // timer1 komparátor beállítása
  83.   TIMSK1 = 0x03;                    // timer1 A komparátor és a túlcsordulás megszakítások beállítása
  84.   TCCR1A = 0x00;                    // timer1 normál működés beállítása
  85.   TCCR1B = 0x00;                    // timer1 normál működés beállítása
  86.  
  87.   attachInterrupt(0, tacho, FALLING);   // a tacho jeléhez megszakítás beállítása, 2-es kivezetés
  88.   attachInterrupt(1, ZCD, RISING);  //a nullaátmenet detektor jeléhez megszakítás beállítása, 3-as kivezetés
  89.  
  90.   lcd.backlight();                  // kijelző háttér világításának bekapcsolása
  91.  
  92.   RPMset_display();
  93.   motorStateStop();
  94. }
  95.  
  96. void ZCD() {                      // megszakítás a nullaátmenet detektorhoz
  97.   TCCR1B = 0x04;                  // timer1 elősztó 256-ra állítása
  98.   TCNT1 = 0;                      // timer1 értékének nullázása
  99.   OCR1A = dimming;                // timer1 A komparátor értékének beállítása
  100. }
  101.  
  102. ISR(TIMER1_COMPA_vect) {          // timer1 A komparátor megszakítás (Interrupt Service Routin)
  103.   if (startflag == true) {        // motor működés engedélyezés ellenőrzése
  104.     digitalWrite(GATE, HIGH);     // triac bekapcsolása
  105.     TCNT1 = 65536 - PULSE;        // triac gyújtóimpulzus hosszának a beállítása
  106.   }
  107. }
  108.  
  109. ISR(TIMER1_OVF_vect) {         // timer1 túlcsordulás, letelt a gyújtóimpulzus hossza
  110.   digitalWrite(GATE, LOW);     // triac gate kikapcsolása. a triac nem kapcsol ki ettől!
  111.   TCCR1B = 0x00;               // timer1 normál működés
  112. }
  113.  
  114. void tacho() {                 // tach impulzus megszakítás. fordulatszám kiszámítása
  115.   count++;
  116.   unsigned long tachotime = micros() - lasttachotime;   // két impulzus közötti idő
  117.   float time_in_sec  = ((float)tachotime + rpmcorrection) / 1000000;  // átszámítás másodpercre
  118.   float prerpm = 60 / time_in_sec;                      // átszámítás percre
  119.   RPM = prerpm / TACHOPULSES;                           // és elosztva a fordulatonkénti tacho impulzusok számával
  120.   lasttachotime = micros();                             // időpont tárolása
  121. }
  122.  
  123. void loop() {
  124.   desiredRPM = counter;         // a kívánt fordulatszám beállítása
  125.   int reading = digitalRead(BUTTON); // gomb állapotának beolvasása
  126.   if (reading != lastButtonState) {  // ha vátozott az előző állapothoz képest,
  127.     lastDebounceTime = millis();     // akkor pergésmentestés számlálójának nullázása
  128.   }
  129.   if ((millis() - lastDebounceTime) > debounceDelay) {  // a pergésmentesítési idő leteltének ellenőrzése
  130.     if (reading != buttonState) {     // a gomb előző állapotához képest történt-e változás
  131.       buttonState = reading;          // ha történt, akkor az állapotjelző frissítése
  132.       if (buttonState == LOW) {       // a gomb megnyomott állapotának ellenőrzése
  133.         relayState = !relayState;     // ha igen, akkor gombnyomás történt, relé állapotának ellenkezőre váltása
  134.         if (relayState == HIGH) {     // ha a reléállapot be van kapcsolva,
  135.           softflag = true;            // lágyindítás bekapcsolása
  136.           digitalWrite(RELAY, relayState); // relé bekapcsolása
  137.           delay (300);                // a relé kontaktusok záródására várakozás, relé típustól függ
  138.           startflag = true;           // motor működés engedélyezése, triac
  139.           RPM=0;                      // álló motornál kezdő fordulatszám nulla. nincs ellenőrizve, hogy tényleg áll-s a motor
  140.         }
  141.         if (relayState == LOW) {      // motor kikapcsolása
  142.           Setpoint = 200;             // PID érték alaphelyzetbe állítása
  143.           Input = 200;                // PID érték alaphelyzetbe állítása
  144.           runflag = false;            // motor normál működését jelző kikapcsolása
  145.           startflag = false;          // motor működését engedélyező jelző kikapcsolása
  146.           delay (300);                // várakozás a motor áram megszűnésére, a relé kontaktusának a kímélése miatt
  147.           digitalWrite(RELAY, relayState); // relé kikapcsolása
  148.           motorStateStop();           //
  149.         }
  150.       }
  151.     }
  152.   }
  153.   lastButtonState = reading;          // a gomb utolsó állapotának a tárolása
  154.  
  155.   unsigned char result = r.process();  // enkóder kezelés
  156.   int tmp;                            // átmeneti tároló a megváltoztatandő érték változásának nagyságához
  157.   if (result == DIR_CW) {             // ha jobbra történt a forgatás,
  158.     tmp=20;                           // a változtatás kezdő értéke
  159.     if (counter >= 500) tmp=50;       // ha nagyobb az érték, akkor sávosan nagyobb lesz a változtatás mértéke is
  160.     if (counter >=1500) tmp=100;
  161.     if (digitalRead(BUTTON)==LOW) tmp=1;  // ha lépésenkénti állítás
  162.     counter+=tmp;                     // az új érték kiszámítása
  163.     if (counter >= maxrpm) {          // elérte-e vagy meghaladta a maximális értéket
  164.       counter = maxrpm;               // ha igen, akkor az érték a maximum lesz
  165.     }
  166.     RPMset_display();                 // az új érték kijelzése
  167.   }
  168.   else if (result == DIR_CCW) {       // ha balra történt a forgatás,
  169.     tmp=20;                           // a változtatás kezdő értéke
  170.     if (counter >= 500) tmp=50;       // ha nagyobb az érték, akkor sávosan nagyobb lesz a változtatás mértéke is
  171.     if (counter >=1500) tmp=100;
  172.     if (digitalRead(BUTTON)==LOW) tmp=1;  // ha lépésenkénti állítás
  173.     counter-=tmp;                     // az új érték kiszámítása
  174.     if (counter <= minrpm) {          // elérte-e vagy kisebb-e a minimális értéknél
  175.       counter = minrpm;               // ha igen, akkor az érték a minimum lesz
  176.     }
  177.     RPMset_display();                 // az új érték kijelzése
  178.   }
  179.   if (softflag == true) {             // lágyindítás kell-e
  180.     myPID.SetTunings(sKp, sKi, sKd);  // PID szabályozó lágyindításhoz szükséges értékeinek a beállítása
  181.     int i = (desiredRPM - tempcounter); // a kívánt fordulatszámmal arányos számú szabályozási hurok meghatározása
  182.     for (int j = 1; j <= i; j++) {    // a szabályozási hurok
  183.       Input = RPM;                    // PID szabályozó bemenete a tényleges fordulatszám
  184.       Setpoint = tempcounter;         // PID szabályozó állításához tartozó érték
  185.       myPID.Compute();                // PID szbályozó számítás
  186.       dimming = map(Output, minoutputlimit, maxoutputlimit, maxoutputlimit, minoutputlimit); // a PID szabályoző és a triac gyújtásának az ideje fordított
  187.       dimming = constrain(dimming, mindimminglimit, maxdimminglimit);     // ellenőrzés, hogy a megfelelő tartományba esik-e az érték
  188.       tempcounter++;                  // a PID szabályozó állítási értékének a növelése
  189.       delayMicroseconds (risetime);   // feléledési idő a PID szabályozónak
  190.     }
  191.     if (tempcounter >= desiredRPM) {  // ha elérte a kívánt értéket az átmeneti beállítási érték
  192.       lastcounttime = millis();       // akkor átváltás normál működésre engedélyezés
  193.       lastpiddelay = millis();        // és a hozzá tartozó értékek és jelzők beállítása
  194.       softflag = false;
  195.       runflag = true;
  196.       tempcounter = 100;              // átmeneti indító számláló alaphelyzetbe állítása
  197.     }
  198.   }
  199.  
  200.   if (relayState == HIGH && softflag == false) {  // ha nincs lágyindítás,
  201.     unsigned long piddelay = millis();  // időpont olvasása
  202.     if ((piddelay - lastpiddelay) > 1000) { // a lágyindítás engedélyezése óta eltelt-e már 1000ms
  203.       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
  204.       lastpiddelay = millis();              // az utolsó időpont olvasása
  205.     }
  206.     Input = RPM;                        // a PID szabályozó bemeneti értéke a tényleges fordulatszám
  207.     Setpoint = desiredRPM;              // a PID szabályozó beállítási értéke a kívánt fordulatszám
  208.     myPID.Compute();                    // PID szabályozó kimeneti értékének a számítása
  209.     dimming = map(Output, minoutputlimit, maxoutputlimit, maxoutputlimit, minoutputlimit); // a PID szabályoző és a triac gyújtásának az ideje fordított
  210.     dimming = constrain(dimming, mindimminglimit, maxdimminglimit);     // ellenőrzés, hogy a megfelelő tartományba esik-e az érték
  211.   }
  212.  
  213.   unsigned long counttime = millis();   // időpont tárolása
  214.   if (counttime - lastcounttime >= 2000) {  // az utolsó tachotól érkezett jeltől eltelt-e már 2000 ms
  215.     if (count == 0 && relayState == HIGH && runflag == true) {  // ha igen, akkor hiba, de csak akkor, ha menet közben történt
  216.       startflag = false;               // motor engedélyezés kikapcsolása
  217.       delay (300);                     // várakozás a motor feszültség mentes állapotára
  218.       digitalWrite(RELAY, LOW);        // motor relé kikapcsolása
  219.       relayState = LOW;                // relé állapot kikapcsolása
  220.       stuckerror();                    // nincs tach jel hiba jelzése
  221.     }
  222.     lastcount = count;                 // tacho jel számláló tárolása
  223.     count = 0;                         // tacho jel számláló nullázása
  224.     lastcounttime = millis();          // időpont tárolása az eltelt idő méréséhez
  225.   }
  226.  
  227.   if (count == 0 && relayState == LOW) { // ha a motor megállt,
  228.     RPM = 0;                           // akkor a tényleges fordulatszám nullára állítása
  229.   }
  230.  
  231.   if (relayState == HIGH && 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
  232.     startflag = false;            // ha igen, akkor motor kikapcsolása
  233.     delay (300);                  // várakozás a motor feszültségmentes állapotára
  234.     digitalWrite(RELAY, LOW);     // relé kikapcsolás
  235.     relayState = LOW;             // relé állapotjelző kikapcsolása
  236.     exceederror();                // túlzott fordulatszám hiba jelzése
  237.   }
  238.   // real RPM display
  239. //  if (relayState == HIGH && range != 0) {
  240.   unsigned long currentMillis = millis();
  241.   if (currentMillis - previousMillis >= lcdinterval) {
  242.     previousMillis = currentMillis;
  243. //    Serial.println(dimming);
  244.     //int rpmdisplay = RPM;
  245.     lcd.setCursor(0, 0);
  246.     lcd.print("RPM: ");
  247.     if (counter < 1000) lcd.print(" ");
  248.     lcd.print(counter);
  249.     lcd.print(" /");
  250.     lcd.setCursor(12, 0);
  251.     if (RPM < 1000) lcd.print(" ");
  252.     if (RPM < 100) lcd.print(" ");
  253.     if (RPM < 10) lcd.print(" ");
  254.     lcd.print(RPM);
  255.     if (relayState == HIGH) {
  256.       lcd.setCursor(0, 1);
  257.       lcd.print("                ");
  258.       lcd.setCursor(0, 1);
  259.       current=analogRead(A7)-511;
  260.       if (current<0) current=0;
  261.       currentdisplay=current/3.75;
  262.       for (byte i=1;i<currentdisplay;i++) {
  263.         lcd.print("*");
  264.       }
  265.     }
  266.     else {
  267.       lcd.setCursor(0, 1);
  268.       lcd.print ("  Press  START  ");
  269.     }
  270.   }
  271. }
  272.  
  273. void range0() {
  274.   lcd.setCursor(0, 0);
  275.   lcd.print(" Please  select ");
  276.   lcd.setCursor(0, 1);
  277.   lcd.print(" the RPM range! ");
  278. }
  279.  
  280. void motorStateStop() {
  281.   lcd.setCursor(0, 1);
  282.   lcd.print ("  Press  START  ");
  283. }
  284.  
  285. void RPMset_display() {
  286.   lcd.setCursor(0, 0);
  287.   lcd.print("RPM: ");
  288.   if (counter < 1000) lcd.print(" ");
  289.   lcd.print(counter);
  290.   lcd.print(" /");
  291.   lcd.setCursor(12, 0);
  292.   if (RPM < 1000) lcd.print(" ");
  293.   if (RPM < 100) lcd.print(" ");
  294.   if (RPM < 10) lcd.print(" ");
  295.   lcd.print(RPM);
  296. }
  297.  
  298. void exceederror() {
  299.   lcd.clear();
  300.   while (1) {
  301.     lcd.setCursor(5, 0);
  302.     lcd.print("ERROR!");
  303.     lcd.setCursor(2, 1);
  304.     lcd.print("TRIAC DAMAGE");
  305.   }
  306. }
  307.  
  308. void stuckerror() {
  309.   lcd.clear();
  310.   while (1) {
  311.     lcd.setCursor(5, 0);
  312.     lcd.print("ERROR!");
  313.     lcd.setCursor(2, 1);
  314.     lcd.print("MOTOR STUCK!");
  315.   }
  316. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement