Ещё один богомпроклятый дозатор воды...
- Войдите на сайт для отправки комментариев
Чт, 02/11/2017 - 21:01
Добрый день уважаемые, представляю Вашему благочестивому вниманию скетч на дозатор жидкости...
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);
}
}
Мысль простая: не заниматься онанизмом, а посадить вход с датчика на пины с внешними прерываниями (2 и 3), и по смене фронта считать импульсы. Смотреть attachInterrupt, и после просветления окажется, что никакой проблемы 50 Герц для подсчёта кол-ва импульсов в секунду - не существует, проблема только в неправильно выбранном текущем подходе.
Может датчик на прерывание посадить?
godForgottenBe посмотри исходники тахометров, и тут и в интернете хватает