Csandriel

Untitled

Mar 17th, 2026
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.75 KB | None | 0 0
  1. //06.07.25
  2. //Двустворчатые ворота с засовом.
  3. //
  4. //коммандные пины;
  5. #define IDLEpin 2     //прекратить, что бы ни происходило
  6. #define OPENingPin 3  //открыть
  7. #define CLOSingPin 4  //закрыть
  8. //пины состояния концевиков
  9. #define LOTpin 5   //левый открыт?
  10. #define ROTpin 6   //ппавый открыт?
  11. #define LCTpin 7   //левый закрыт?
  12. #define RCTpin 8   //правый закрыт?
  13. #define BOTpin 9   //засов открыт?
  14. #define BCTpin 10  //засов закрыт?
  15. //пины состояния реле
  16. #define LORpin 11  //открыть левый
  17. #define RORpin 12  //открыть правый
  18. #define LCRpin 13  //закрыть левый
  19. #define RCRpin 14  //закрыть правый
  20. #define BORpin 15  //открыть засов
  21. #define BCRpin 16  //закрыть засов
  22.  
  23.  
  24. // Флаги состояния концевиков
  25. bool LOT = 0;  // LeftOPENingTerminal
  26. bool LCT = 0;  // LeftCLOSingTerminal
  27. bool ROT = 0;  // RightOPENingTerminal
  28. bool RCT = 0;  // RightCLOSingTerminal
  29. bool BOT = 0;  // BoltOPENingTerminal
  30. bool BCT = 0;  // BoltCLOSingTerminal
  31.  
  32. // Флаги состояния реле
  33. bool LOR = 0;  // LeftOPENingRelay
  34. bool LCR = 0;  // LeftCLOSingRelay
  35. bool ROR = 0;  // RightOPENingRelay
  36. bool RCR = 0;  // RightCLOSingRelay
  37. bool BOR = 0;  // BoltOPENingRelay
  38. bool BCR = 0;  // BoltCLOSingRelay
  39.  
  40. //Глобальная задача. Новый тип данных, выражается через int.
  41. enum State {
  42.   IDLE = 0,
  43.   OPEN = 1,
  44.   CLOSE = 2
  45. };
  46.  
  47.  
  48. State currentState;  //Глобальный флаг текущей задачи.
  49. int PDelay;          //Время разбежки между створками.
  50.  
  51. /*
  52. Старт открытия/закрытия створок. Левая внахлест, --  должна начать открываться раньше,
  53. а закрываться позже. OPENingPlates() и CLOSingPlates() вычислют разницу старта опираясь на moveStarted
  54. */
  55. unsigned long moveStarted;  //время начала работы, для OPENingPlates() и CLOSingPlates().
  56. /*Чтобы каждый раз не прогонять OPENingPlates() полностью,
  57. мы будем в самом ее начале проверять, идет ли движение обеих створок и тут же выходить на новый цикл, если да.
  58. */
  59. bool LMove;  //левая створка двигается?
  60. bool RMove;  //правая створка двигается?
  61.  
  62. /*Переменные антидребезга кнопок и концевиков*/
  63.  
  64. int DBDelay = 100;  //DeBounce Dalay
  65. int LBState;  //Last Button State, прошлое положение кнопки.
  66. long LBTime;  //Last Button Time. прошлое время срабатывания.
  67.  
  68.  
  69. void setup() {
  70.   PDelay = 4000;
  71.   DBDelay = 100;
  72.   LBState = HIGH;
  73.   currentState = IDLE;
  74.   //Инициализация пинов кнопок.
  75.   pinMode(IDLEpin, INPUT_PULLUP);
  76.   pinMode(OPENingPin, INPUT_PULLUP);
  77.   pinMode(CLOSingPin, INPUT_PULLUP);
  78.   //Инициализация пинов концевиков.
  79.   pinMode(LOTpin, INPUT);
  80.   pinMode(LCTpin, INPUT);
  81.   pinMode(ROTpin, INPUT);
  82.   pinMode(RCTpin, INPUT);
  83.   pinMode(BOTpin, INPUT);
  84.   pinMode(BCTpin, INPUT);
  85.   //Инициализация пинов реле.
  86.   pinMode(LORpin, OUTPUT);
  87.   pinMode(LCRpin, OUTPUT);
  88.   pinMode(RORpin, OUTPUT);
  89.   pinMode(RCRpin, OUTPUT);
  90.   pinMode(BORpin, OUTPUT);
  91.   pinMode(BCRpin, OUTPUT);
  92.  
  93.  
  94.   Serial.begin(9600);
  95.   Serial.println("Setup executed");
  96. }
  97.  
  98. int checkErrors() {
  99.   /* Проверяет конфликты состояния датчиков/кнопок.
  100.      В случае конфликта сбрасывает состояние в IDLE
  101.      и сигнализирует об ошибке.
  102.  
  103.       Например, датчики "открыто" и "закрыто"
  104.      работают одновременно для левой
  105.      или правой половины ворот, или для
  106.      засова:
  107.  */
  108.  
  109.   if (ROT == RCT || LOT == LCT || BOT == BCT) {
  110.     int ERROR = 1;  //пока пример: одновременное срабатывание взаимоислючающих концевиков.
  111.     // blinkError(ERROR); //сигнал характера ошибки.
  112.     Serial.println("ERROR:"+String(ERROR));
  113.     return ERROR;
  114.   }
  115.   return 0;
  116. }
  117. void halt() {  //остановка всего, по тревоге или штатно
  118.                //работает в простое, вместо подтяжки реле.
  119.                //Кнопки подтянем к земле лапками.
  120.   digitalWrite(LORpin, LOW);
  121.   digitalWrite(LCRpin, LOW);
  122.   digitalWrite(RORpin, LOW);
  123.   digitalWrite(RCRpin, LOW);
  124.   digitalWrite(BORpin, LOW);
  125.   digitalWrite(BCRpin, LOW);
  126.   LOR = 0;
  127.   LCR = 0;
  128.   ROR = 0;
  129.   RCR = 0;
  130.   BOR = 0;
  131.   BCR = 0;
  132.     moveStarted = 0;
  133.   currentState = IDLE;
  134. }
  135.  
  136. bool OPENingBolt() {             //открываем засов
  137.   if (!BOT) {                //если концевик открытия не замкнут
  138.     BOR = 1;                     //выставляем флаг открытия
  139.     digitalWrite(BORpin, HIGH);  //двигаем реле открытия
  140.     return false;                // болт не открыт. Возвращаем ложь в функции движения.
  141.   } else if (BOT == 1) {
  142.     if(BOR){moveStarted = millis();}// запоминаем время старта открытия створок,
  143.     BOR = 0;                            //чтобы обеспечить разбежку створок.
  144.  
  145.     digitalWrite(BORpin, LOW);
  146.     return true;  // болт открыт. Сигналим об этом.
  147.   }
  148. }
  149.  
  150. bool CLOSingBolt() {
  151.   if (!BCT) {
  152.     BCR = 1;
  153.     digitalWrite(BCRpin, HIGH);
  154.     return false;
  155.   } else if (BCT == 1) {
  156.    
  157.  
  158.     digitalWrite(BCRpin, LOW);
  159.     return true;
  160.   }
  161. }
  162.  
  163. void OPENingPlates() {
  164.   /*открывает створки ворот
  165.   левая должна открываться раньше,
  166.   закрываться позже*/
  167.      if (LOT) {              //Официальное открытие левой створки свершилось.
  168.       LMove = false;
  169.       digitalWrite(LORpin, LOW);
  170.   }
  171.  
  172.      if (ROT) {                                 //Официальное откытие правой створки.
  173.       RMove = false;                                  //Левая теперь двиагается одна, через проверку концевика.
  174.       digitalWrite(RORpin, LOW);
  175.     }
  176.    
  177.   if (LMove && RMove) {
  178.     digitalWrite(LORpin, HIGH);
  179.     digitalWrite(RORpin, HIGH);
  180.     return;  //если ворота уже двигаются, продолжаем движение, идем на следующий цикл.
  181.              //выходим из процедуры открытия. Флаги на месте. Cбрасываются они либо
  182.              //концевиками в loop(), либо halt().
  183.   }
  184.  
  185.   if (!OPENingBolt()) {
  186.     return;  //Если засов не открыт, ждем пока откроется
  187.              //идем на следующий цикл.
  188.   } else {   //Если засов открыт, доходим до начала движения ворот.
  189.    
  190.  
  191.     if ((millis() - moveStarted) > PDelay && !ROT) {  //Если после первого цикла функции прошло более 4 сек
  192.       digitalWrite(RORpin, HIGH);                     //и не открыто полностью, -- начинаем двигать левую створку,
  193.       RMove = true;                                   //о чем выставляем флаг.
  194.     }
  195.  
  196.     if (!LOT) {                    //если не замкнут концевик левой створки
  197.       digitalWrite(LORpin, HIGH);  //двигаем.
  198.       LMove = true;                //о чем выставляем флаг.
  199.     }
  200.  
  201.      if (LOT && ROT) {  //Если обе створки открыты
  202.    
  203.         currentState = IDLE;                   //Отдыхаем.
  204.       halt();
  205.     }
  206.   }
  207. }
  208.  
  209.  
  210. void CLOSingPlates() {  //закрываем ворота
  211.   if (!BOT){ //Если засов е открыт
  212.     return; //не пытаемся закрыть ворота.
  213.    
  214.             }
  215.  
  216.     if(LCT){
  217.     LMove = false;
  218.     digitalWrite(LCRpin, LOW);
  219.   }
  220.   if(RCT){
  221.     RMove = false;
  222.     digitalWrite(RCRpin, LOW);
  223.     }
  224.    
  225.   if (LMove && RMove) {
  226.     digitalWrite(LCRpin, HIGH);
  227.     digitalWrite(RCRpin, HIGH);
  228.     return;  //если  створки уже двигаются, продлжаем цикл.
  229.   }
  230.   if (millis() - moveStarted > PDelay && !LCT) {  //начинаем двигать левую створку после паузы.
  231.     digitalWrite(LCRpin, HIGH);
  232.     LMove = true;
  233.   }
  234.  
  235.   if (!RCT) {  //Правая стартует она без задержки
  236.     RMove = true;
  237.     digitalWrite(RCRpin, HIGH);
  238.   }
  239.  
  240.   if (RCT && LCT) {        //Если обе створки закрыты,
  241.     if (!CLOSingBolt()) {  //но засов не закрыт
  242.       return;              //идем на следующий цикл, где засов продолжает двигаться.
  243.     } else {               //Створки закрыты и засов тоже.
  244.  
  245.          halt();              //Ок. Стоп.
  246.     }
  247.   }
  248. }
  249.  
  250. int dbRead(int PIN) {
  251.  
  252.   int CBState = digitalRead(PIN);
  253.   if (CBState != LBState) {             // Положение кнопки изменилось,
  254.     LBTime = millis();                  // запускаем таймер.
  255.     LBState = CBState;                  // Обновляем глобальный флаг последнего положения.
  256.   } else if (LBState == CBState) {      // Это новый цикл. Все еще не изменилось?
  257.     if (millis() - LBTime > DBDelay) {  // Замеряем длительность нажатия
  258.         Serial.println("dbRead("+String(PIN)+","+String(CBState)+")");
  259.         return CBState;
  260.     }
  261.   }
  262. }
  263.  
  264. int dtRead(int PIN) {  // Антидребезг концевиков. Это не кнопки.
  265.                        // Здесь является штатным одновременное состояние многих.
  266.                        // поэтому антидребезг каждому.
  267.   static bool LOTlast = LOW;
  268.   static long LOTtime = 0;
  269.  
  270.   static bool LCTlast = LOW;
  271.   static long LCTtime = 0;
  272.  
  273.   static bool ROTlast = LOW;
  274.   static long ROTtime = 0;
  275.  
  276.   static bool RCTlast = LOW;
  277.   static long RCTtime = 0;
  278.  
  279.   static bool BOTlast = LOW;
  280.   static long BOTtime = 0;
  281.  
  282.   static bool BCTlast = LOW;
  283.   static long BCTtime = 0;
  284.  
  285.   switch (PIN) {
  286.     case LOTpin:
  287.       {
  288.         int CTState = digitalRead(LOTpin);
  289.         if (LOTlast != CTState) {                   // Состояние изменилось
  290.           LOTtime = millis();                       // Запускаем таймер
  291.           LOTlast = CTState;                        // Обновляем состояние
  292.         } else if (millis() - LOTtime > DBDelay) {  // Состояние не изменилось. Проверка задержки
  293.           return CTState;                           // Возвращаем состояние
  294.         }
  295.         break;  // Для этого пина завершили. ИИ четко реплицировал остальные кейсы,
  296.                 // вежливо проигнорировал просьбу кадрировать switch,
  297.                 // и молча добавил инициацию статиков, дав всю функцию целиком.
  298.                 //
  299.       }
  300.     case LCTpin:
  301.       {
  302.         int CTState = digitalRead(LCTpin);
  303.         if (LCTlast != CTState) {
  304.           LCTtime = millis();
  305.           LCTlast = CTState;
  306.         } else if (millis() - LCTtime > DBDelay) {
  307.           return CTState;
  308.         }
  309.         break;
  310.       }
  311.     case ROTpin:
  312.       {
  313.         int CTState = digitalRead(ROTpin);
  314.         if (ROTlast != CTState) {
  315.           ROTtime = millis();
  316.           ROTlast = CTState;
  317.         } else if (millis() - ROTtime > DBDelay) {
  318.           return CTState;
  319.         }
  320.         break;
  321.       }
  322.     case RCTpin:
  323.       {
  324.         int CTState = digitalRead(RCTpin);
  325.         if (RCTlast != CTState) {
  326.           RCTtime = millis();
  327.           RCTlast = CTState;
  328.         } else if (millis() - RCTtime > DBDelay) {
  329.           return CTState;
  330.         }
  331.         break;
  332.       }
  333.     case BOTpin:
  334.       {
  335.         int CTState = digitalRead(BOTpin);
  336.         if (BOTlast != CTState) {
  337.           BOTtime = millis();
  338.           BOTlast = CTState;
  339.         } else if (millis() - BOTtime > DBDelay) {
  340.           return CTState;
  341.         }
  342.         break;
  343.       }
  344.     case BCTpin:
  345.       {
  346.         int CTState = digitalRead(BCTpin);
  347.         if (BCTlast != CTState) {
  348.           BCTtime = millis();
  349.           BCTlast = CTState;
  350.         } else if (millis() - BCTtime > DBDelay) {
  351.           return CTState;
  352.         }
  353.         break;
  354.       }
  355.     default:
  356.       return LOW;  // Для любых неподдерживаемых пинов
  357.   }
  358.  
  359.   return LOW;  // Возвращаем LOW, если ничего не изменилось
  360. }
  361.  
  362.  
  363.  
  364. void checkSensors() {
  365.  
  366.   if (dbRead(OPENingPin) == HIGH) {  //обрабатывая кнопку, мы выставляем флаг,
  367.                                      //и время нажатия кнопки.
  368.  
  369.     Serial.println("OPENingPlates:HIGH");
  370.     if (currentState != OPEN) {  // это первый цикл вызова функции?
  371.       currentState = OPEN;       // время пошло. Обратно флаг будет снят кнопкой либо концевиками.
  372.       OPENingPlates();
  373.     }
  374.  
  375.    
  376.   }
  377.  
  378.   if (dbRead(CLOSingPin) == HIGH) {
  379.         Serial.println("CLOSingPlates:HIGH");
  380.       if(currentState !=CLOSE){ //Это первый вызов функции?
  381.       moveStarted = millis();   //Значит стартуем таймер.
  382.       currentState = CLOSE;     //Выставляем глобальную задачу.
  383.       CLOSingPlates();
  384.       }
  385.     }
  386.  
  387.  
  388.   if (dbRead(IDLEpin) == HIGH) {  //обрабатывая кнопку, мы лишь выставляем флаг.
  389.     currentState = IDLE;
  390.     Serial.println("IDLEpin:HIGH");
  391.     halt();
  392.   }
  393.  
  394.  
  395.   /*пробегаемся по концевикам, устанавливаем соответствующие флаги*/
  396.   LOT = dtRead(LOTpin);
  397.   LCT = dtRead(LCTpin);
  398.   ROT = dtRead(ROTpin);
  399.   RCT = dtRead(RCTpin);
  400.   BOT = dtRead(BOTpin);
  401.   BCT = dtRead(BCTpin);
  402.  
  403. }  //конец checkSensors()
  404.  
  405. void loop() {  // Генеральная линия Партии.
  406.    
  407.     checkSensors();  //мацаем кнопки, концевики, возможно другие сигналы
  408.  
  409.     switch (currentState) {
  410.       case IDLE:
  411.         halt();
  412.         break;
  413.       case OPEN:
  414.          //официальное начало OPENingPlates().
  415.         OPENingPlates();
  416.         if (LOT && ROT) {
  417.           currentState = IDLE;  //официальное завершение OPENingPlates().
  418.         }
  419.         break;
  420.       case CLOSE:
  421.         //Официальное начало CLOSingPlates();
  422.         CLOSingPlates();          //ныряем в функцию в цикле
  423.         if (LCT && RCT && BCT) {  //пока все гештальты не закрыты.
  424.           currentState = IDLE;
  425.         }
  426.         break;
  427.       default:
  428.         break;
  429.     }
  430.       Serial.println("currentState:" +String(currentState));
  431. }
  432.  
Advertisement
Add Comment
Please, Sign In to add comment