Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //#include <avr/wdt.h> // Watchdog timer
- #include <avr/io.h>
- #include <avr/interrupt.h>
- #include <Wire.h>
- #include <LiquidCrystal_I2C.h>
- #include <Rotary.h>
- #include <PID_v1.h>
- #define GATE 6 // TRIAC gate
- #define BUTTON 10 // stop/start gomb
- #define FINE 9 // rpm egyesével való állítása kapcsoló
- #define RELAY 4 // relé
- #define CURRENT A7 // motor áram
- #define PULSE 2 // triac gyújtóimpulzusának a hossza, órajelciklusban
- #define TACHOPULSES 8 // a tacho fordulatonkénti impulzusa
- unsigned int RPM; // mért fordulatszám
- unsigned int count; // tacho impulzus számlálója
- unsigned int lastcount = 0; // a tacho impulzusainak számlálója, a fordulatszám kiszámításához szükséges
- unsigned long lastcounttime = 0; // a tacho impulzusainak ideje
- unsigned long lasttachotime; // a tach impulzus idejének átmeneti tárolása
- unsigned long lastpiddelay = 0; // a motor lágy indításának számlálója
- unsigned long previousMillis = 0; // a kijelző frissési idejének méréséhez
- unsigned long lastDebounceTime = 0; // a gomb pergésének idejéhaz átmeneti tároló
- const int sampleRate = 1; // A PID szabályozó minavételezési gyakorisága
- const int rpmcorrection = 86; // a perc és a processzor órajele közötti korrekció
- const int lcdinterval = 500; // a kijelző frissítési ideje ms-ban
- const int protection = 2000; // fordulatszám túllépési hiba értéke
- const int debounceDelay = 50; // a gomb pergésmentesítési ideje
- const int minoutputlimit = 80; // a PID szabályozó kimeneti értékének alsó határa
- const int maxoutputlimit = 540; // a PID szabályozó kimeneti értékének felső határa
- const int mindimminglimit = 80; // a triac gyújtási idejének biztonsági korlátja
- const int maxdimminglimit = 625; // a triac gyújtási idejének biztonsági korlátja
- const int minrpm = 200; // a fordulatszám kiválasztás alsó határa
- const int maxrpm = 9500; // a fordulatszám kiválasztás alsó határa
- const int risetime = 100; // RPM rise time delay in microseconds (risetime x RPM)
- int dimming = 540; // a gyújtásszög kezdeti értéke (fordított érték)
- int counter; // fordulatszám mérés számlálója
- int desiredRPM; // a PID szabályozó kívánt fordulasztám értéke
- int tempcounter = 100; // a motor lágy indításához átmeneti számláló
- byte currentdisplay; // a motor áramának kijelzett értéke
- int current; // motor áramának mért értéke
- byte relayState = LOW; // a relé állapota
- byte buttonState; // a gomb állapota
- byte lastButtonState = HIGH; // a gomb előző állapota
- bool softflag = false; // motor lágyindításának jelzése
- bool startflag = false; // motor működésének engedélyezése, triac gate jel
- bool runflag = false; // motor normál működése
- double Setpoint, Input, Output; // PID változók
- double sKp = 0.1, sKi = 0.2, sKd = 0; // a motor lágy indításához tartozó PID értékek
- double rKp = 0.25, rKi = 1, rKd = 0; // a motor normál működéséhez tartozó PID értékek
- LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // az LCD I2C címe és a kijelző bekötése
- Rotary r = Rotary(12, 11); // az enkóder kivezetései
- PID myPID(&Input, &Output, &Setpoint, sKp, sKi, sKd, DIRECT); // a PID szabályozó létrehozása
- void setup() {
- Serial.begin(115200); // hibakereséshez a soros monitor
- Serial.println("Start ..."); // a szabályozó elindult
- lcd.begin(16,2); // a kijelző tipusának beállítása és a meghajtó létrehozása
- pinMode(11, INPUT_PULLUP); // az enkóder kivezetése, felhúzó ellenállással
- pinMode(12, INPUT_PULLUP); // az enkóder kivezetése, felhúzó ellenállással
- pinMode(BUTTON, INPUT_PULLUP); // a gomb, felhúzó ellenállással
- pinMode(FINE, INPUT_PULLUP); // rpm kapcsoló, felhúzó ellenállással
- pinMode(RELAY, OUTPUT); // relé kimenet
- pinMode(GATE, OUTPUT); // triac kimenet
- digitalWrite(RELAY, relayState); // relé alaphelyzet, LOW
- counter = minrpm; // fordulatszám beállítás kezdő értéke
- Input = 200; // PID szabályozó kezdő értéke
- Setpoint = 200; // PID szabályozó kezdő értéke
- myPID.SetMode(AUTOMATIC); // PID szabályozó létrehozása
- myPID.SetOutputLimits(minoutputlimit, maxoutputlimit);
- myPID.SetSampleTime(sampleRate); // és értékek beállítása
- OCR1A = 100; // timer1 komparátor beállítása
- TIMSK1 = 0x03; // timer1 A komparátor és a túlcsordulás megszakítások beállítása
- TCCR1A = 0x00; // timer1 normál működés beállítása
- TCCR1B = 0x00; // timer1 normál működés beállítása
- attachInterrupt(0, tacho, FALLING); // a tacho jeléhez megszakítás beállítása, 2-es kivezetés
- attachInterrupt(1, ZCD, RISING); //a nullaátmenet detektor jeléhez megszakítás beállítása, 3-as kivezetés
- lcd.backlight(); // kijelző háttér világításának bekapcsolása
- RPMset_display();
- motorStateStop();
- }
- void ZCD() { // megszakítás a nullaátmenet detektorhoz
- TCCR1B = 0x04; // timer1 elősztó 256-ra állítása
- TCNT1 = 0; // timer1 értékének nullázása
- OCR1A = dimming; // timer1 A komparátor értékének beállítása
- }
- ISR(TIMER1_COMPA_vect) { // timer1 A komparátor megszakítás (Interrupt Service Routin)
- if (startflag == true) { // motor működés engedélyezés ellenőrzése
- digitalWrite(GATE, HIGH); // triac bekapcsolása
- TCNT1 = 65536 - PULSE; // triac gyújtóimpulzus hosszának a beállítása
- }
- }
- ISR(TIMER1_OVF_vect) { // timer1 túlcsordulás, letelt a gyújtóimpulzus hossza
- digitalWrite(GATE, LOW); // triac gate kikapcsolása. a triac nem kapcsol ki ettől!
- TCCR1B = 0x00; // timer1 normál működés
- }
- void tacho() { // tach impulzus megszakítás. fordulatszám kiszámítása
- count++;
- unsigned long tachotime = micros() - lasttachotime; // két impulzus közötti idő
- float time_in_sec = ((float)tachotime + rpmcorrection) / 1000000; // átszámítás másodpercre
- float prerpm = 60 / time_in_sec; // átszámítás percre
- RPM = prerpm / TACHOPULSES; // és elosztva a fordulatonkénti tacho impulzusok számával
- lasttachotime = micros(); // időpont tárolása
- }
- void loop() {
- desiredRPM = counter; // a kívánt fordulatszám beállítása
- int reading = digitalRead(BUTTON); // gomb állapotának beolvasása
- if (reading != lastButtonState) { // ha vátozott az előző állapothoz képest,
- lastDebounceTime = millis(); // akkor pergésmentestés számlálójának nullázása
- }
- if ((millis() - lastDebounceTime) > debounceDelay) { // a pergésmentesítési idő leteltének ellenőrzése
- if (reading != buttonState) { // a gomb előző állapotához képest történt-e változás
- buttonState = reading; // ha történt, akkor az állapotjelző frissítése
- if (buttonState == LOW) { // a gomb megnyomott állapotának ellenőrzése
- relayState = !relayState; // ha igen, akkor gombnyomás történt, relé állapotának ellenkezőre váltása
- if (relayState == HIGH) { // ha a reléállapot be van kapcsolva,
- softflag = true; // lágyindítás bekapcsolása
- digitalWrite(RELAY, relayState); // relé bekapcsolása
- delay (300); // a relé kontaktusok záródására várakozás, relé típustól függ
- startflag = true; // motor működés engedélyezése, triac
- RPM=0; // álló motornál kezdő fordulatszám nulla. nincs ellenőrizve, hogy tényleg áll-s a motor
- }
- if (relayState == LOW) { // motor kikapcsolása
- Setpoint = 200; // PID érték alaphelyzetbe állítása
- Input = 200; // PID érték alaphelyzetbe állítása
- runflag = false; // motor normál működését jelző kikapcsolása
- startflag = false; // motor működését engedélyező jelző kikapcsolása
- delay (300); // várakozás a motor áram megszűnésére, a relé kontaktusának a kímélése miatt
- digitalWrite(RELAY, relayState); // relé kikapcsolása
- motorStateStop(); //
- }
- }
- }
- }
- lastButtonState = reading; // a gomb utolsó állapotának a tárolása
- unsigned char result = r.process(); // enkóder kezelés
- int tmp; // átmeneti tároló a megváltoztatandő érték változásának nagyságához
- if (result == DIR_CW) { // ha jobbra történt a forgatás,
- tmp=20; // a változtatás kezdő értéke
- if (counter >= 500) tmp=50; // ha nagyobb az érték, akkor sávosan nagyobb lesz a változtatás mértéke is
- if (counter >=1500) tmp=100;
- if (digitalRead(BUTTON)==LOW) tmp=1; // ha lépésenkénti állítás
- counter+=tmp; // az új érték kiszámítása
- if (counter >= maxrpm) { // elérte-e vagy meghaladta a maximális értéket
- counter = maxrpm; // ha igen, akkor az érték a maximum lesz
- }
- RPMset_display(); // az új érték kijelzése
- }
- else if (result == DIR_CCW) { // ha balra történt a forgatás,
- tmp=20; // a változtatás kezdő értéke
- if (counter >= 500) tmp=50; // ha nagyobb az érték, akkor sávosan nagyobb lesz a változtatás mértéke is
- if (counter >=1500) tmp=100;
- if (digitalRead(BUTTON)==LOW) tmp=1; // ha lépésenkénti állítás
- counter-=tmp; // az új érték kiszámítása
- if (counter <= minrpm) { // elérte-e vagy kisebb-e a minimális értéknél
- counter = minrpm; // ha igen, akkor az érték a minimum lesz
- }
- RPMset_display(); // az új érték kijelzése
- }
- if (softflag == true) { // lágyindítás kell-e
- myPID.SetTunings(sKp, sKi, sKd); // PID szabályozó lágyindításhoz szükséges értékeinek a beállítása
- int i = (desiredRPM - tempcounter); // a kívánt fordulatszámmal arányos számú szabályozási hurok meghatározása
- for (int j = 1; j <= i; j++) { // a szabályozási hurok
- Input = RPM; // PID szabályozó bemenete a tényleges fordulatszám
- Setpoint = tempcounter; // PID szabályozó állításához tartozó érték
- myPID.Compute(); // PID szbályozó számítás
- dimming = map(Output, minoutputlimit, maxoutputlimit, maxoutputlimit, minoutputlimit); // a PID szabályoző és a triac gyújtásának az ideje fordított
- dimming = constrain(dimming, mindimminglimit, maxdimminglimit); // ellenőrzés, hogy a megfelelő tartományba esik-e az érték
- tempcounter++; // a PID szabályozó állítási értékének a növelése
- delayMicroseconds (risetime); // feléledési idő a PID szabályozónak
- }
- if (tempcounter >= desiredRPM) { // ha elérte a kívánt értéket az átmeneti beállítási érték
- lastcounttime = millis(); // akkor átváltás normál működésre engedélyezés
- lastpiddelay = millis(); // és a hozzá tartozó értékek és jelzők beállítása
- softflag = false;
- runflag = true;
- tempcounter = 100; // átmeneti indító számláló alaphelyzetbe állítása
- }
- }
- if (relayState == HIGH && softflag == false) { // ha nincs lágyindítás,
- unsigned long piddelay = millis(); // időpont olvasása
- if ((piddelay - lastpiddelay) > 1000) { // a lágyindítás engedélyezése óta eltelt-e már 1000ms
- 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
- lastpiddelay = millis(); // az utolsó időpont olvasása
- }
- Input = RPM; // a PID szabályozó bemeneti értéke a tényleges fordulatszám
- Setpoint = desiredRPM; // a PID szabályozó beállítási értéke a kívánt fordulatszám
- myPID.Compute(); // PID szabályozó kimeneti értékének a számítása
- dimming = map(Output, minoutputlimit, maxoutputlimit, maxoutputlimit, minoutputlimit); // a PID szabályoző és a triac gyújtásának az ideje fordított
- dimming = constrain(dimming, mindimminglimit, maxdimminglimit); // ellenőrzés, hogy a megfelelő tartományba esik-e az érték
- }
- unsigned long counttime = millis(); // időpont tárolása
- if (counttime - lastcounttime >= 2000) { // az utolsó tachotól érkezett jeltől eltelt-e már 2000 ms
- if (count == 0 && relayState == HIGH && runflag == true) { // ha igen, akkor hiba, de csak akkor, ha menet közben történt
- startflag = false; // motor engedélyezés kikapcsolása
- delay (300); // várakozás a motor feszültség mentes állapotára
- digitalWrite(RELAY, LOW); // motor relé kikapcsolása
- relayState = LOW; // relé állapot kikapcsolása
- stuckerror(); // nincs tach jel hiba jelzése
- }
- lastcount = count; // tacho jel számláló tárolása
- count = 0; // tacho jel számláló nullázása
- lastcounttime = millis(); // időpont tárolása az eltelt idő méréséhez
- }
- if (count == 0 && relayState == LOW) { // ha a motor megállt,
- RPM = 0; // akkor a tényleges fordulatszám nullára állítása
- }
- 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
- startflag = false; // ha igen, akkor motor kikapcsolása
- delay (300); // várakozás a motor feszültségmentes állapotára
- digitalWrite(RELAY, LOW); // relé kikapcsolás
- relayState = LOW; // relé állapotjelző kikapcsolása
- exceederror(); // túlzott fordulatszám hiba jelzése
- }
- // real RPM display
- // if (relayState == HIGH && range != 0) {
- unsigned long currentMillis = millis();
- if (currentMillis - previousMillis >= lcdinterval) {
- previousMillis = currentMillis;
- // Serial.println(dimming);
- //int rpmdisplay = RPM;
- lcd.setCursor(0, 0);
- lcd.print("RPM: ");
- if (counter < 1000) lcd.print(" ");
- lcd.print(counter);
- lcd.print(" /");
- lcd.setCursor(12, 0);
- if (RPM < 1000) lcd.print(" ");
- if (RPM < 100) lcd.print(" ");
- if (RPM < 10) lcd.print(" ");
- lcd.print(RPM);
- if (relayState == HIGH) {
- lcd.setCursor(0, 1);
- lcd.print(" ");
- lcd.setCursor(0, 1);
- current=analogRead(A7)-511;
- if (current<0) current=0;
- currentdisplay=current/3.75;
- for (byte i=1;i<currentdisplay;i++) {
- lcd.print("*");
- }
- }
- else {
- lcd.setCursor(0, 1);
- lcd.print (" Press START ");
- }
- }
- }
- void range0() {
- lcd.setCursor(0, 0);
- lcd.print(" Please select ");
- lcd.setCursor(0, 1);
- lcd.print(" the RPM range! ");
- }
- void motorStateStop() {
- lcd.setCursor(0, 1);
- lcd.print (" Press START ");
- }
- void RPMset_display() {
- lcd.setCursor(0, 0);
- lcd.print("RPM: ");
- if (counter < 1000) lcd.print(" ");
- lcd.print(counter);
- lcd.print(" /");
- lcd.setCursor(12, 0);
- if (RPM < 1000) lcd.print(" ");
- if (RPM < 100) lcd.print(" ");
- if (RPM < 10) lcd.print(" ");
- lcd.print(RPM);
- }
- void exceederror() {
- lcd.clear();
- while (1) {
- lcd.setCursor(5, 0);
- lcd.print("ERROR!");
- lcd.setCursor(2, 1);
- lcd.print("TRIAC DAMAGE");
- }
- }
- void stuckerror() {
- lcd.clear();
- while (1) {
- lcd.setCursor(5, 0);
- lcd.print("ERROR!");
- lcd.setCursor(2, 1);
- lcd.print("MOTOR STUCK!");
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement