Ещё один богомпроклятый дозатор воды...

godForgottenBeginner
Offline
Зарегистрирован: 12.09.2017
Добрый день уважаемые, представляю Вашему благочестивому вниманию скетч на дозатор жидкости...
 
3 Месяца я пытался понять в чём проблема этого диавольского устройства, в итоге после подключения генератора сигналов (и осциллографа для надёжности) я выяснил что после того как значения с датчика превышает 50 герц, программа перестаёт правильно сопоставлять количества входящих импульсов с количеством налитой воды... т.е. до 50 импульсов в секунду программа считает к примеру 9 импульсов за 0.1 литра, когда частота подачи импульсов (со счетчика) превышает 50 импульсов то программа как бы не успевает подсчитывать их и переводить в литры, т.е. скорость набора переменной отвечающей за 0.1 литра после 50-70 герц (импульсов в секунду со счётчика) не меняется от количества этих импульсов... Если у кого есть мысли об этом предлагаю поделиться.
 
========================================================================*/

#include <TM74HC595Display.h>          // Библиотека Семисегментного дисплея "НОВАЯ"
#include "TimerOne.h"                  // Библиотека таймера
#include "sav_button.h"                // Библиотека опроса кнопок
SButton button1(2,50,0,0,500);         // Пуск (пин 2, задержка 50)
SButton button2(3,50,1000,0,500);      // Больше (пин 3, задержка 50, время удержания 1сек для перехода в быстрый режим
SButton button3(4,50,1000,0,500);
 
SBUTTON_CLICK button_state1 = SB_NONE;  // Обнуление данных по кнопкам
SBUTTON_CLICK button_state2 = SB_NONE;
SBUTTON_CLICK button_state3 = SB_NONE;
// ------------------------------------
int Rele = 13;                       // выход на реле пуска воды
int Datchik = 8;                     // Датчик воды           
int SCLK = 5;                        // Дисплей
int RCLK = 6;                        // Дисплей
int DIO = 7;                         // Дисплей
int valBut = 0;                      // Задаем переменную, для счетчика 
int valBut_Min = 0;                  // Задаем переменную, для счетчика
float n = 0;                         // Рабочие
int m = 0;                           //     переменные
float Water_P = 1;                   // Переменная наполнения насосом
float Water_R = 10;                  // Переменная наполнения оператором
float Water_Rv = 1;                  // Переменная выставленного значения 
long previousMillis = 0;             // Зададим начальное значение для счетчика millis
long TimePush = 500;                 // Время нажатия на кнопку
int LedVal = LOW;                    // устанавливаем начальное состояние светодиода
int nm = 0;                          // переменная для команды STOP

//-------------------------------------
 TM74HC595Display disp(SCLK, RCLK, DIO); // Подключение дисплея
unsigned char LED_0F[29];
//--------------------------------------------------------------------------------------------------
                        
// Callback функция по таймеру
  void timerIsr()
   {
   disp.timerIsr();
   button_state1 = button1.Loop();
   button_state2 = button2.Loop();
   button_state3 = button3.Loop();  
   }
 
void setup()
{
  //-------------------------------------------------------------------------------------------------
  LED_0F[0] = 0xC0; //0
  LED_0F[1] = 0xF9; //1
  LED_0F[2] = 0xA4; //2
  LED_0F[3] = 0xB0; //3
  LED_0F[4] = 0x99; //4
  LED_0F[5] = 0x92; //5
  LED_0F[6] = 0x82; //6
  LED_0F[7] = 0xF8; //7
  LED_0F[8] = 0x80; //8
  LED_0F[9] = 0x90; //9
  LED_0F[10] = 0x88; //A
  LED_0F[11] = 0x83; //b
  LED_0F[12] = 0xC6; //C
  LED_0F[13] = 0xA1; //d
  LED_0F[14] = 0x86; //E
  LED_0F[15] = 0x8E; //F
  LED_0F[16] = 0xC2; //G
  LED_0F[17] = 0x89; //H
  LED_0F[18] = 0xF9; //I
  LED_0F[19] = 0xF1; //J
  LED_0F[20] = 0xC3; //L
  LED_0F[21] = 0xA9; //n
  LED_0F[22] = 0xC0; //O
  LED_0F[23] = 0x8C; //P
  LED_0F[24] = 0x98; //q
  LED_0F[25] = 0x92; //S
  LED_0F[26] = 0xC1; //U
  LED_0F[27] = 0x91; //Y
  LED_0F[28] = 0xBF; //Минус или 191 в десятичной системе
  LED_0F[29] = 0x7F;// Точка  или 127
//--------------------------------------------
  
   Serial.begin(115200);
  Serial.println("Test smart button ...");
//--------------------------------------------
    
// Инициация кнопок 
   button1.begin();
   button2.begin();
   button3.begin();
// Инициализация таймера
  Timer1.initialize(1500);  
  Timer1.attachInterrupt( timerIsr );

  //-----------------------------------------
  //  Проверка дисплея
  //-----------------------------------------
  disp.clear();
  delay(1500);  
  for (int i = 1111; i <= 9999; )
  {
    disp.digit4(i);
    delay(200);
    disp.clear();
    delay(200);
    i = i + 1111;
  }
  delay(1000);  
  disp.set(LED_0F[22], 0);    
  delay(2);
  disp.set(LED_0F[20], 1);    
  delay(2);
  disp.set(LED_0F[14], 2);   
  delay(2);
  disp.set(LED_0F[17], 3);    
  
//-------------------------------------------
  
  delay(2000);                                // очистка дисплея
  disp.clear();
  delay(1000);   
  disp.dispFloat((Water_R/10), 1);            // Индикация установленных литров   
}

//==========================================
void loop(){
   if( button_state1 != SB_NONE ){
      //Serial.print("Press button 1 mode ");
      //Serial.println(button_state1);
      Water_Rv = Water_R;                        // Присваение значения "установлено набрать"
      button_state1 = SB_NONE;
      digitalWrite(Rele, HIGH);                  // Включить реле  
      n = 0;                                     //  Обнуление рабочей переменной  
      Water_P = 0;                               // Установка начального значения счетчика 
      Pusk();                                    // Пуск  
      digitalWrite(Rele, LOW);                   // отключение реле по окончанию налива     
       
  
   }
   //--------------------------------------------
   if( button_state2 != SB_NONE ){
      //Serial.print("Press button 2 mode ");
      //Serial.println(button_state2);
      if (button_state2 == 1)                    // если нажата кнопка "больше" (короткое нажатие)
      {
        Water_R = Water_R + 1;                   // Увеличиваем на 0.1 литра
        disp.clear();                            // очистка дисплея 
        disp.dispFloat((Water_R/10), 1);         // Индикация набранных литров
        delay(20);
         if ( Water_R >= 1000)                   // Ограничение по максимуму 
            {
            Water_R = 1000;
            }  
      }
      else
      {
        nabor_Max();                             // если длинное нажатие. Перейти на у скоренный набор
      }
      button_state2 = SB_NONE;                   //  сброст переменной опроса кнопки
   
   }
   //------------------------------------------
   if( button_state3 != SB_NONE ){
      //Serial.print("Press button 3 mode ");
      //Serial.println(button_state3);
      if (button_state3 == 1)                     //   если нажата кнопка "меньше"
      {
        if ( Water_R >= 1)                        // Избавляемся от мерцания "минуса"
          {                                                              
         Water_R = Water_R - 1;                   // уменьшаем на 0.1 литра
         disp.clear();                            // очистка дисплея         
         disp.dispFloat((Water_R/10), 1);         // Индикация набранных литров
         delay(20);
              if ( Water_R <= 0)                   // Ограничение по минимуму
             {
                Water_R = 0;
             } 
         }  
      }
      else
   {
    Nabor_Min();                                    //  при длительном нажатии перейти в ускоренный набор
   }
      button_state3 = SB_NONE;                      // сброс переменной опроса кнопки 
     
   }
     
}
//===========================
//=========================== 
void nabor_Max()
   {
  while(digitalRead(3) == LOW)                      // если кнопка еще нажата
   {
           Water_R = Water_R + 1;
           Water_R = abs( Water_R);                  // Увеличение на 1 литр (временная строка - заменить переменную)          
       if ( Water_R >= 1000)                         // Ограничение по максимуму
       {
        Water_R = 1000;
       }
       disp.clear();                                 // очистка дисплея 
      disp.dispFloat((Water_R/10), 1);               // Индикация набранных литров
          delay(40);                                 // скорость набора
   }
 }
//===========================
void Nabor_Min()
       {
  while(digitalRead(4) == LOW)                       // если кнопка еще нажата
   {
       Water_R = Water_R - 1;                        // Уменьшение на 1 литр (временная строка - заменить переменную)
       Water_R = abs( Water_R);
       
      if (Water_R <= 1)                              // ограничение по минимуму
      {  
       Water_R = 1;
      }
      disp.clear();                                  // очистка дисплея 
      disp.dispFloat((Water_R/10), 1);               // Индикация набранных литров
      delay(40);                                     //  скорость набора
   }
 }

//===========================
void Pusk()
    { 
       nm = 0;                                         // Обнуление счетчика STOP
      float n = 0;                                                 
       disp.clear();                                   // очистка дисплея 
            disp.dispFloat((Water_P/10), 1);           // Индикация набранных литров (Старт)
            delay(20); 
      int flag = 0;
             
        while(Water_P < Water_Rv)
        {

 //=================================================
 //      Модуль установки и регулировки колличества 
 //=================================================
          if (digitalRead(Datchik) == HIGH  && flag == 0)
               {
                 
                flag=1;
                  n = n + 1;                                    //  Увеличение рабочей переменной
                  Serial.println(n); 
                   if (n == 40)                                  // Провека набранного 0.1 литра                         
                     {  
                       Water_P = Water_P + 1;                   // Увеличение "набрано"
                        Serial.println(Water_P/10); 
                       disp.clear();                            // очистка дисплея 
                       disp.dispFloat((Water_P/10), 1);         // Индикация набранных литров
                       delay(1); 
                      // Serial.println(n); 
                       n = 0;                                   //  Сброс рабочей переменной
                       nm = 0;                                  // Счетчик аварийного отключения
                     } 
           
               }
 //----------------------------          
          if (nm == 6000)                                       // модуль аварийного отключения
                  {                                             // (установка паузы до выхода в аварийный режим)
                    STOP();                                     // аварийное отключение
                  }
                  nm = nm + 1;
                  delay(5);         
          
 //------------------------------
             if (digitalRead(Datchik) == LOW  && flag == 1)
                 {
                  flag=0; 
                 }
//==================================================
//==================================================               
            }
  
        }
//===================================================
   void STOP()
{
digitalWrite(Rele, LOW);            // отключение реле
int Stop = 0; 
while(Stop <= 20)
{                                   // индикация аварии
  disp.set(LED_0F[23], 0);    
  delay(2);
  disp.set(LED_0F[20], 1);    
  delay(2);
  disp.set(LED_0F[14], 2);   
  delay(2);
  disp.set(LED_0F[17], 3);    
  delay(1000);
  disp.clear();
  delay(500);  
}
}

 

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

godForgottenBeginner пишет:

Если у кого есть мысли об этом предлагаю поделиться.
 

Мысль простая: не заниматься онанизмом, а посадить вход с датчика на пины с внешними прерываниями (2 и 3), и по смене фронта считать импульсы. Смотреть attachInterrupt, и после просветления окажется, что никакой проблемы 50 Герц для подсчёта кол-ва импульсов в секунду - не существует, проблема только в неправильно выбранном текущем подходе.

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Может датчик на прерывание посадить?

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

godForgottenBe посмотри исходники тахометров, и тут и в интернете хватает