/**************************************************************************
Номер контакта Наименование контакта К какому контакту Arduino необходимо подключить на NANO
Управление шаговым двигателем
ENA-D7, DIR-D3, PUL STEP-D4
Кнопки nano esp32
KN1 D2
KN2 D5
KN3 D6
KN4 D8
SD по SPI
CS D10
SLC D13
MOSI D11
MISO D12
LED A3
ЭКран по I2C
SDA A4
SCL A5
**************************************************************************/
#define DEBUG 1 // если 1 - симулятор, если 0 - рН-метр
#define KN1 2 //на эту кнопку сделать прерывание
#define KN2 5
#define KN3 6
#define KN4 8
#define pin_ENA 7 //на эту кнопку сделать прерывание
#define pin_DIR 3
#define pin_PUL 4
#define LED_PIN 17 // светодиод на А3
#define CSpin 10
/////////////////////////////// БИБЛИОТЕКИ ////////////////////////////////////////////////////
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include "GyverButton.h"
#if (DEBUG == 0)
#include <iarduino_I2C_pH.h> // Подключаем библиотеку для работы с pH-метром I2C-flash.
#endif
#include "SD.h"
#include"SPI.h"
///////////////////////////////////////////////////////////////////////////////////////////////
#if (DEBUG == 0)
iarduino_I2C_pH sensor(0x09); // Объявляем объект sensor для работы с функциями и методами библиотеки iarduino_I2C_pH, указывая адрес модуля на шине I2C.
#endif
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
GButton butt1(KN1);
GButton butt2(KN2);
GButton butt3(KN3);
GButton butt4(KN4);
///////////////////////////////// класс на таймер //////////////////////////////////////
class Timer {
public:
Timer(uint32_t nprd = 0) {
setPeriod(nprd);
}
void setPeriod(uint32_t nprd) {
prd = nprd;
}
bool ready() {
return (prd && millis() - tmr >= prd) ? (tmr = millis(), 1) : 0;
}
private:
uint32_t tmr = 0, prd = 0;
};
/////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////// ТАЙМЕРЫ //////////////////////////////////////
Timer tmr1 (50); // таймер на имерение рН
Timer tmr2 (150); // таймер на обновление цифер на экране
Timer tmr3; // для симулятора рН
Timer tmr4; // обновление значений на экране
Timer tmr5 (1000);
Timer tmr6 ; //LED on/of
Timer tmr7 (1000) ; // таймер на отсчет времени для калибровки рН
uint32_t t_0 = 0;
uint32_t s; // секунды
uint16_t t_s; // время прошло, с
uint16_t t_m; // время прошло, мин
uint16_t t_h; // время прошло, ч
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////// Структуры ////////////////////////////////////
struct Data {
float min_pH = 0; // мин рН
float max_pH = 0; //макс рН
float w_mlm = 0; // скорость прoкачки , мл/мин
float v0_ml = 0; // объем, который нужно слить, мл
float vn_ml = 0; // объем заданный при калибровке, мл
float vk_ml = 0; // объем реальный после калибровки, мл
float k_nV = 0; // количество шагов матора на 1 мл k = n/V
uint16_t w_auto = 0; // скорость прoкачки в режиме автомата , шагов
uint16_t v_auto = 0; // объем прoкачки в режиме автомата , шагов
float pH1 = 0; // точки калибровки рН
float pH2 = 0; // точки калибровки рН
uint16_t fileNBR = 0; // точки калибровки рН
};
///////////////////////////////// ПЕРЕМЕННЫЕ ДЛЯ МЕНЮ ///////////////////////////////
uint8_t lvl=1; //уровень
uint16_t nomer=1; //номер пункта меню
bool red_Flag = false; // флаг для редактирования
float v_prok = 0.00; // прокаченный объем
//////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////// ПЕРЕМЕННЫЕ //////////////////////////////////////
volatile bool intFlag = false; // флаг на прерывание
bool titrFlag = true ; // флаг, определяет титровать или нет
bool simFlag = true ; // флаг, определяет титровать или нет
bool tFlag = false; // флаг, определяет началось ли титрование
float pH_val; // значение рН
float v_kap = 0.01; // объем капли, мл
bool light = true;
String dataString =""; // строка с данными для записи на SD
Data data; //структура для записи констант в еепром
File sensorData;
//////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/*
const float min_pH PROGMEM = 7.82;
const float max_pH PROGMEM = 8.12;
const float w_mlm PROGMEM = 20.00;
const float v0_ml PROGMEM = 1.00;
const float vn_ml PROGMEM = 10.00;
const float vk_ml PROGMEM= 10.00;
const float k_nV PROGMEM= 16000;
const uint16_t w_auto PROGMEM = 1000;
const uint16_t v_auto PROGMEM = 156;
const float pH1 PROGMEM = 4.00;
const float pH2 PROGMEM= 9.18;
const uint16_t fileNBR PROGMEM= 0;
*/
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void setup() {
#if (DEBUG == 0)
EEPROM.get(0, data); // прочитать из адреса 0
#endif
pinMode( pin_ENA, OUTPUT ); // Конфигурируем вывод Arduino как выход.
pinMode( pin_DIR, OUTPUT ); // Конфигурируем вывод Arduino как выход.
pinMode( pin_PUL, OUTPUT ); // Конфигурируем вывод Arduino как выход.
pinMode( LED_PIN, OUTPUT);
pinMode(CSpin, OUTPUT);
lcd.init(); lcd.backlight(); // initialize the lcd
Serial.begin(9600);
#if (DEBUG == 0)
sensor.begin(); // Инициируем работу с pH-метром I2C-flash.
#endif
if (!SD.begin(CSpin)) {
Serial.println(F("Card failed, or not present"));
// don't do anything more:
return;
}
Serial.println(F("card initialized."));
//
//////////////////////////////////////////
#if (DEBUG == 1)
data.min_pH = 7.82;
data.max_pH = 8.12;
data.w_mlm = 20.00;
data.v0_ml = 1.00;
data.vn_ml = 10.00;
data.vk_ml =10.00;
data.k_nV = 16000;
data.w_auto = 1000;
data.v_auto = 160;
data.pH1 = 4.00;
data.pH2 = 9.18;
data.fileNBR = 0;
pH_val = 8.25;
EEPROM.put(0, data);
#endif
///////////////////////////////
/*
#if (DEBUG == 1)
data.min_pH = pgm_read_float (&min_pH);
//Serial.println(min_pH);
data.max_pH = pgm_read_float (&max_pH );
data.w_mlm = pgm_read_float (&w_mlm);
data.v0_ml = pgm_read_float (&v0_ml);
data.vn_ml = pgm_read_float (&vn_ml); ;
data.vk_ml = pgm_read_float (&vk_ml);
data.k_nV = pgm_read_float (&k_nV);
data.w_auto = pgm_read_word (&w_auto);
data.v_auto = pgm_read_word (&v_auto);
data.pH1 = pgm_read_float (&pH1);
data.pH2 = pgm_read_float (&pH2);
data.fileNBR = pgm_read_word (&fileNBR);
pH_val = 8.25;
EEPROM.put(0, data);
#endif
*/
////////////////////////////////////////////
butt2.setDebounce(80); // настройка антидребезга (по умолчанию 80 мс)
butt3.setDebounce(80); // настройка антидребезга (по умолчанию 80 мс)
// butt1.setTimeout(500); // настройка таймаута на удержание (по умолчанию 500 мс)
butt2.setClickTimeout(100); // настройка таймаута между кликами (по умолчанию 300 мс)
butt3.setClickTimeout(100); // настройка таймаута между кликами (по умолчанию 300 мс)
attachInterrupt(0, bT, FALLING);
start(); // Приветствие
menu(1); // Экран начального меню
red_Flag = false; // флаг на редактирование
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//____________________________________________________________________________________
void loop() {
butt1.tick(); // обязательная функция отработки. Должна постоянно опрашиваться
butt2.tick(); // обязательная функция отработки. Должна постоянно опрашиваться
butt3.tick(); // обязательная функция отработки. Должна постоянно опрашиваться
butt4.tick(); // обязательная функция отработки. Должна постоянно опрашиваться
if (butt1.isClick()) {Serial.println("выход"); kursorB(); }
if (butt2.isClick()) {Serial.println("вверх"); kursorV() ; znach_minus (); }
if (butt3.isClick()) {Serial.println("низ"); kursorN(); znach_plus ();}
if (butt4.isClick()) {Serial.println("вход"); kursorE(); }
//if (butt2.isPress()) Serial.println("Press"); // нажатие на кнопку (+ дебаунс)
//if (butt3.isPress()) Serial.println("Press"); // нажатие на кнопку (+ дебаунс)
// if (butt2.isHolded()) {Serial.println("Holded"); motor2(5,1000,1);}; // проверка на удержание
//if (butt3.isHolded()) Serial.println("Holded"); // проверка на удержание
if (butt2.isHold()) { znach_minus (); } // если кнопка была удержана (это для инкремента)
if (butt3.isHold()) { znach_plus (); } // если кнопка была удержана (это для инкремента)
cikl ();
//saveData(); // save to SD card
}
//_____________________________________________________________________________________
void bT() {
intFlag = true; // подняли флаг прерывания
//Serial.println(F("STOPPPPPP"));
//intFlag = false;
}
////////////////////////////////////// Вывод на экран приветствия ////////////////////////////
void start () {
lcd.setCursor(4,0);
lcd.print("PRIVET!");
delay(400);
lcd.setCursor(2,0);
lcd.print("TITRATOR OH-");
lcd.setCursor(5,1);
lcd.print("v.1.0");
delay(400); }
//////////////////////////// Функция Отрисовки меню /////////////////////////////////
void s_menu (uint8_t x1, String name1, uint8_t x2, String name2, bool st){
lcd.clear(); lcd.setCursor(x1,0); lcd.print(name1);
lcd.setCursor(x2,1); lcd.print(name2);
if (st == true) { lcd.setCursor(15,0); lcd.print(F("<")); }
}
void f_menu (bool cl, uint8_t x1, float name1, uint8_t x2, float name2, bool st){
if (cl == true) lcd.clear();
lcd.setCursor(x1,0); lcd.print(name1);
lcd.setCursor(x2,1); lcd.print(name2);
if (st == true) { lcd.setCursor(15,0); lcd.print(F("<")); }}
void u_menu (bool cl, uint8_t x1, uint16_t name1, uint8_t x2, uint16_t name2, bool st){
if (cl == true) lcd.clear();
lcd.setCursor(x1,0); lcd.print(name1);
lcd.setCursor(x2,1); lcd.print(name2);
if (st == true) { lcd.setCursor(15,0); lcd.print(F("<")); }
}
void sf_menu (bool cl, uint8_t x1, String name1, uint8_t x2, float name2, bool st){
if (cl == true) lcd.clear();
lcd.setCursor(x1,0); lcd.print(name1);
lcd.setCursor(x2,1); lcd.print(name2);
if (st == true) { lcd.setCursor(15,0); lcd.print(F("<")); }
}
void su_menu (bool cl, uint8_t x1, String name1, uint8_t x2, uint16_t name2, bool st){
if (cl == true) lcd.clear();
lcd.setCursor(x1,0); lcd.print(name1);
lcd.setCursor(x2,1); lcd.print(name2);
if (st == true) { lcd.setCursor(15,0); lcd.print(F("<")); }
}
void str_n_menu () {lcd.setCursor(15,0); lcd.print(F(" ")); lcd.setCursor(15,1); lcd.print(F("<"));}
void str_v_menu () {lcd.setCursor(15,1); lcd.print(F(" ")); lcd.setCursor(15,0); lcd.print(F("<"));}
/////////////////////////////////////////////////////////////////////////////////////
////////////////////////////Фунции вывода информации в порт ////////////////////////
void no_lvl () {
#if (DEBUG == 1)
Serial.print(nomer); Serial.print(F(" lvl "));Serial.println(lvl);
#endif
}
void Flag_show () {
#if (DEBUG == 1)
Serial.println(red_Flag);
#endif
}
/////////////////////////////////////// Menu ///////////////////////////////////////////////////
void menu (uint16_t NM) {
switch (NM){
case 1: s_menu (0, F("IZMERENIE pH"), 0, F("TITROVANIE"),true) ; break;
case 11: sf_menu (true, 6, F("pH"), 5, pH_val, false) ; break;
case 2: s_menu (0, F("PROKACHKA"), 0, F("KALIBROVKA"),true) ; break;
case 21: s_menu (0, F("RUCHNOE"), 0, F("AVTOMAT"),true) ; break;
case 211: s_menu (0, F("pH"), 0, F("V"), false) ; lcd.setCursor(9,0); lcd.print("#"); lcd.print(data.fileNBR); break;
case 3: s_menu (0, F("NASTROYKI"), 0, F(" "),true); break;
case 31: s_menu (0, F("VPERED"), 0, F("NAZAD"),true); break;
case 33: s_menu (0, F("RUCHNOE"), 0, F("NEPRERYVNO"),true); break;
case 331: sf_menu (true, 5, F("V, ml"), 5, v_prok, false); break;
case 41: s_menu (0, F("K. NASOS"), 0, F("K. pH-METR"),true); break;
case 51: s_menu (0, F("pH_min"), 0, F("pH_max"),true);
f_menu (false, 9, data.min_pH, 9, data.max_pH, false); break;
case 53: s_menu (0, F("w ml/m"), 0, F("V0 ml"),true);
f_menu (false, 9, data.w_mlm, 9, data.v0_ml, false); break;
case 55: s_menu (0, F("w n auto"), 0, F("V n auto"),true);
u_menu (false, 9, data.w_auto, 9, data.v_auto, false) ; break;
case 57: sf_menu (true, 4, F("K , n/ml"), 4, data.k_nV,true); break;
case 411: sf_menu (true, 0, F("Ustanovi V1, ml"), 5, data.vn_ml, false) ; break;
case 412: sf_menu (true, 0, F("Ustanovi V2, ml"), 5, data.vk_ml, false) ; break;
case 421: sf_menu (true, 1, F("Ustanovi pH ml"), 6, data.pH1, false) ; break;
case 424: sf_menu (true, 1, F("Ustanovi pH ml"), 6, data.pH2, false) ; break;
}}
///////////////////////////////////////////////////////////////////////////////////////////////////
void minus (){nomer--; no_lvl ();}
void lvl_minus (){lvl--; no_lvl ();}
void plus (){nomer++; no_lvl ();}
void lvl_plus (){lvl++; no_lvl ();}
/////////////////////////////////////// Курсор ///////////////////////////////////////////////////
void kursorV() {
switch (lvl){
case 1: if (nomer>1) {minus ();}
if (nomer==2) menu(1);
if (nomer==4) menu(2);
if (nomer==6) menu(3);
if (nomer%2 == 0) {str_n_menu ();}
if (nomer%2 == 1) {str_v_menu ();}
break;
case 2: if (red_Flag==false ) {
if (nomer>21 && nomer < 23) {minus ();}
if (nomer>31 && nomer < 35) {minus ();}
if (nomer>41 && nomer < 43) {minus ();}
if (nomer>51 && nomer < 58) {minus ();}
if (nomer==52) menu(51);
if (nomer==54) menu(53);
if (nomer==56) menu(55);
if (nomer==32) menu(31);
if (nomer%2 == 0 and nomer != 421) {str_n_menu ();}
if (nomer%2 == 1 and nomer != 421) {str_v_menu ();}
}
break;
}
}
void kursorN() {
switch (lvl){
case 1: if (nomer<5) {plus ();}
if (nomer==3) menu(2);
if (nomer==5) menu(3);
if (nomer%2 == 0) {str_n_menu ();}
if (nomer%2 == 1) {str_v_menu ();}
break;
case 2: if (red_Flag==false ) {
if (nomer<22 && nomer >20 && red_Flag==false) {plus ();}
if (nomer<34 && nomer >30 && red_Flag==false) {plus ();}
if (nomer<42 && nomer >40 && red_Flag==false) {plus ();}
if (nomer<57 && nomer >50 && red_Flag==false) {plus ();}
if (nomer==53 && red_Flag==false) menu(53);
if (nomer==55 && red_Flag==false) menu(55);
if (nomer==57 && red_Flag==false) menu(57);
if (nomer==33 && red_Flag==false) menu(33);
if (nomer%2 == 0 and nomer != 421) {str_n_menu ();}
if (nomer%2 == 1 and nomer != 421) {str_v_menu ();}
}
break;
}
}
void kursorE() {
switch (lvl){
case 1: if (nomer==1) {nomer=11; lvl_plus (); menu (11);}
if (nomer==2) {nomer=21; lvl_plus (); menu (21);}
if (nomer==3) {nomer=31; lvl_plus (); menu (31);}
if (nomer==4) {nomer=41; lvl_plus (); menu (41);}
if (nomer==5) {nomer=51; lvl_plus (); menu (51);}
if (nomer==6) {;}
break;
case 2: if (nomer>50 && nomer<57) {switch (red_Flag) {
case false: red_Flag = !red_Flag; Flag_show ();
if (nomer%2 == 0) {lcd.setCursor(15,0); lcd.print(F(" ")); lcd.setCursor(15,1); lcd.print(F("*"));}
if (nomer%2 == 1) {lcd.setCursor(15,1); lcd.print(F(" ")); lcd.setCursor(15,0); lcd.print(F("*"));}
break;
case true: red_Flag = !red_Flag; Flag_show (); EEPROM.put(0, data);
if (nomer%2 == 0) {lcd.setCursor(15,0); lcd.print(F(" ")); lcd.setCursor(15,1); lcd.print(F("<"));}
if (nomer%2 == 1) {lcd.setCursor(15,1); lcd.print(F(" ")); lcd.setCursor(15,0); lcd.print(F("<"));}
break;}}
if (nomer==21) {nomer=211; lvl_plus (); menu (211); red_Flag = true;}
if (nomer==22) {nomer=221; lvl_plus (); menu (211); red_Flag = true;}
if (nomer==31) {Prokachka(1); menu (31);}
if (nomer==32) {Prokachka(0); menu (31); nomer=31; }
if (nomer==33) {nomer=331; lvl_plus (); menu (331); red_Flag=true;}
if (nomer==34) {nomer=341; lvl_plus (); menu (331); red_Flag=false;}
if (nomer==41) {nomer=411; lvl_plus (); menu (411); red_Flag = true;}
if (nomer==42) {nomer=421; lvl_plus (); menu (421); red_Flag = false;}
break;
case 3: if (nomer==411) {calibr_nasos () ; nomer=412; no_lvl (); menu (412); red_Flag = true;}
else {
if (nomer==412) {nomer=41; lvl_minus (); menu (41); red_Flag = false;
data.k_nV = data.k_nV * data.vn_ml/data.vk_ml; EEPROM.put(0, data);} }
if (nomer==341){motor_nepr2 (0,data.k_nV * data.w_mlm / 60,1,1,5); }
if (nomer==211){saveData() ;} //запись рН, V и секунд в файл
if (nomer==221){nomer =222; no_lvl (); titr_auto ();} //
if (nomer==421) {nomer=422; lvl_plus (); calibr_pH1 ();}
break;
case 4: if (nomer==422) {nomer=423; lvl_plus (); menu (424); }
break;
case 5: if (nomer==423) {nomer=424; no_lvl (); calibr_pH2 (); }
break;
}
}
void kursorB() {
switch (lvl){
case 2: if (nomer==11) {nomer=1; lvl_minus (); menu (1); digitalWrite(LED_PIN, false); intFlag = false; }
if (nomer==21 or nomer ==22) {nomer=1; lvl_minus (); menu (1);}
if (nomer==41 or nomer ==42) {nomer=3; lvl_minus (); menu (2);}
if (nomer>30 and nomer < 35) {nomer=3; lvl_minus (); menu (2); v_prok = 0; }
if (nomer>=51 && nomer <58 and red_Flag==false) {nomer=5; lvl_minus (); menu (3);}
break;
case 3: if (nomer==411) {nomer=41; lvl_minus (); menu (41); red_Flag = false; EEPROM.put(0, data); intFlag = false;}
if (nomer==412) {nomer=41; lvl_minus (); menu (41); red_Flag = false;
data.k_nV = data.k_nV * data.vn_ml/data.vk_ml; EEPROM.put(0, data); intFlag = false;}
if (nomer==331) {nomer=33; lvl_minus (); menu (33); red_Flag=false; v_prok = 0; digitalWrite( pin_ENA, 1 );}
if (nomer==341) {nomer=33; lvl_minus (); menu (33); red_Flag=false; v_prok = 0; digitalWrite( pin_ENA, 1 );}
if (nomer==211 or nomer==221 or nomer == 222) {nomer=21; lvl_minus (); menu (21);
tFlag = false; red_Flag=false; v_prok = 0; digitalWrite( pin_ENA, 1 ); digitalWrite(LED_PIN, false); data.fileNBR++; EEPROM.put(0, data); }
if (nomer==421) {nomer=41; lvl_minus (); menu (41); intFlag = false;}
break;
case 4: if (nomer==422) {nomer=41; lvl=2; no_lvl (); menu (41); intFlag = false;}
break;
case 5: if (nomer==424 or nomer==424) {nomer=41; lvl=2; no_lvl (); menu (41); intFlag = false;}
break;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////// Удержание, изменение значений ///////////////////////////////
void val_delta (float &val, float delta, uint8_t x, uint8_t y ){
val = val + delta; lcd.setCursor(x,y); lcd.print(val); lcd.print(F(" "));;
}
void val_delta_uint16 (uint16_t &val, uint16_t delta, uint8_t x, uint8_t y ){
val = val + delta; lcd.setCursor(x,y); lcd.print(val); lcd.print(F(" "));;
}
void val_change (float &val, uint8_t x, uint8_t y ){
lcd.setCursor(x,y); lcd.print(val); lcd.print(F(" "));
}
void znach_minus () {
if (red_Flag==true){
switch (nomer){
case 51: val_delta (data.min_pH, -0.01, 9, 0); lcd.setCursor(15,0); lcd.print(F("*")); break;
case 52: val_delta (data.max_pH, -0.01, 9, 1);lcd.setCursor(15,1); lcd.print(F("*")); break;
case 53: val_delta (data.w_mlm, -0.1, 9, 0); lcd.setCursor(15,0); lcd.print(F("*")); break;
case 54: val_delta (data.v0_ml, -0.01, 9, 1); lcd.setCursor(15,1); lcd.print(F("*")); break;
case 55: val_delta_uint16 (data.w_auto, -10, 9, 0); lcd.setCursor(15,0); lcd.print(F("*")); break;
case 56: val_delta_uint16 (data.v_auto, -1, 9, 1);lcd.setCursor(15,1); lcd.print(F("*")); break;
case 411: val_delta (data.vn_ml, -0.01, 5, 1); break;
case 412: val_delta (data.vk_ml, -0.01, 5, 1); break;
case 331: motor_nepr (data.v_auto,data.w_auto,0,0); if (tmr2.ready()){val_change (v_prok,5,1);}; break;
case 211: tFlag = true; motor_nepr (data.v_auto,data.w_auto,0,0); if (tmr2.ready()){val_change (v_prok,3,1);}; break;
}}
}
void znach_plus () {
if (red_Flag==true){
switch (nomer){
case 51: val_delta (data.min_pH, 0.01, 9, 0); lcd.setCursor(15,0); lcd.print(F("*")); break;
case 52: val_delta (data.max_pH, 0.01, 9, 1); lcd.setCursor(15,1); lcd.print(F("*")); break;
case 53: val_delta (data.w_mlm, 0.1, 9, 0); lcd.setCursor(15,0); lcd.print(F("*")); break;
case 54: val_delta (data.v0_ml, 0.01, 9, 1); lcd.setCursor(15,1); lcd.print(F("*")); break;
case 55: val_delta_uint16 (data.w_auto, 10, 9, 0);lcd.setCursor(15,0); lcd.print(F("*")); break;
case 56: val_delta_uint16 (data.v_auto, 1, 9, 1); lcd.setCursor(15,1); lcd.print(F("*")); break;
case 411: val_delta (data.vn_ml, 0.01, 5, 1); break;
case 412: val_delta (data.vk_ml, 0.01, 5, 1); break;
case 331: motor_nepr (data.v_auto,data.w_auto,1,0); if (tmr2.ready()){ val_change (v_prok,5,1);}; break;
case 211: tFlag = true; motor_nepr (data.v_auto,data.w_auto,1,0); if (tmr2.ready()){ val_change (v_prok,3,1);}; break;
}}
}
/////////////////////////////////КАЛИБРОВКА НАСОСА //////////////////////////////////////////
void calibr_nasos () {
lcd.clear(); lcd.setCursor(1,0); lcd.print(F("KRUCHU VERCHU"));
motor_nepr2 (data.k_nV * data.vn_ml, data.k_nV * 30 / 60, 1,1,5); v_prok =0;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////Прокачка //////////////////////////////////////////////////
void Prokachka (int32_t napr) {
lcd.clear(); lcd.setCursor(1,0); lcd.print(F("KRUCHU VERCHU"));
motor_nepr2 (data.k_nV * data.v0_ml, data.k_nV * data.w_mlm / 60, napr,1,5); v_prok =0;
}
////////////////////////////////// ФУНКЦИЯ КРУЧЕНИЯ МОТРОРА ////////////////////////////////
void motor_nepr (uint32_t m_tick, float m_speed, int32_t m_dir, int8_t ena) { //указать шаги, скорость и направление
intFlag = false;
if (m_tick ==0) m_tick = -1;
int32_t count = 0;
int8_t napr;
uint8_t x;
if (m_dir ==0) napr = -1; if (m_dir ==1) napr = 1;
float f = m_speed; // Определяем частоту следования микрошагов от 1 до 200'000 Гц.
float t = 1000000/f/2; // Определяем длительность импульсов t3 и пауз t4 в мкс.
// Готовимся к движению вала: //
digitalWrite( pin_ENA, 0 ); // Разрешаем работу двигателя.
delayMicroseconds(5); // Выполняем задержку t1 (см. график STEP/DIR).
digitalWrite( pin_DIR, m_dir ); // Выбираем направление вращения.
delayMicroseconds(5); // Выполняем задержку t2 (см. график STEP/DIR). //
digitalWrite(LED_PIN, HIGH);
for(;;){ // Выполняем
digitalWrite( pin_PUL, 1 ); // Устанавливаем на выводе PUL состояние логической «1».
delayMicroseconds(t); // Выполняем задержку t3 (см. график STEP/DIR).
digitalWrite( pin_PUL, 0 ); // Устанавливаем на выводе PUL состояние логического «0».
delayMicroseconds(t); // Выполняем задержку t4 (см. график STEP/DIR).
count++;
if (intFlag == true) { intFlag = false; Serial.println(F("Interrupt!")); break;}
if (count== m_tick) {
//Serial.println(f);
break;}
}
digitalWrite( pin_ENA, ena ); // Запрещаем работу двигателя, отключаем токи в обмотках.
digitalWrite(LED_PIN, LOW);
v_prok = v_prok + count/data.k_nV*napr;
if (nomer == 222) { if (tmr2.ready()){ val_change (v_prok, 3,1);}}
//Serial.println(f);
//Serial.println(t);
}
void motor_nepr2 (uint32_t m_tick, float m_speed, int32_t m_dir, int8_t ena, uint8_t x) { //указать шаги, скорость и направление
intFlag = false;
if (m_tick ==0) m_tick = -1;
int32_t count = 0;
int8_t napr;
if (m_dir ==0) napr = -1; if (m_dir ==1) napr = 1;
float f = m_speed; // Определяем частоту следования микрошагов от 1 до 200'000 Гц.
float t = 1000000/f/2; // Определяем длительность импульсов t3 и пауз t4 в мкс.
// Готовимся к движению вала: //
digitalWrite( pin_ENA, 0 ); // Разрешаем работу двигателя.
delayMicroseconds(5); // Выполняем задержку t1 (см. график STEP/DIR).
digitalWrite( pin_DIR, m_dir ); // Выбираем направление вращения.
delayMicroseconds(5); // Выполняем задержку t2 (см. график STEP/DIR).
digitalWrite(LED_PIN, HIGH);
for(;;){ // Выполняем
digitalWrite( pin_PUL, 1 ); // Устанавливаем на выводе PUL состояние логической «1».
delayMicroseconds(t); // Выполняем задержку t3 (см. график STEP/DIR).
digitalWrite( pin_PUL, 0 ); // Устанавливаем на выводе PUL состояние логического «0».
delayMicroseconds(t); // Выполняем задержку t4 (см. график STEP/DIR).
count++;
v_prok = count/data.k_nV*napr;
if (tmr2.ready()){ val_change (v_prok, x,1);}
if (intFlag == true) { intFlag = false; Serial.println(F("Interrupt!")); break;}
if (count== m_tick) {
// Serial.println(f);
break;}
}
digitalWrite( pin_ENA, ena ); // Запрещаем работу двигателя, отключаем токи в обмотках.
digitalWrite(LED_PIN, LOW);
//Serial.println(f);
//Serial.println(t);
}
/////////////////////////////////// Симулятор рН /////////////////////////////////////////
void pH_simulator (uint16_t vremya) {
tmr3.setPeriod(vremya);
if (tmr3.ready()){
if (pH_val > data.min_pH-0.01 and simFlag == true) {pH_val = pH_val -0.03;};
if (pH_val <= data.min_pH-0.01 and simFlag == true) {simFlag = false; pH_val = pH_val + 0.01;};
if (pH_val < data.max_pH+0.01 and simFlag == false) {pH_val = pH_val + 0.01;};
if (pH_val >= data.max_pH+0.01 and simFlag == false) {simFlag = true; pH_val = pH_val - 0.03;};
//Serial.println(pH_val);
if (nomer == 11) {val_change (pH_val,5,1);}
if (nomer == 211 or nomer == 221 or nomer ==222) {val_change (pH_val,3,0);
if (tFlag==false) {t_0 = millis();}
if (tFlag==true) {sekundomer (); lcd.setCursor(11,1); lcd.print(s);;
lcd.setCursor(9,0); lcd.print(t_h);lcd.print(F(":")); lcd.print(t_m); lcd.print(F(":"));lcd.print(t_s);lcd.print(F(" "));}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////// pH-метр //////////////////////////////////////////////////
#if (DEBUG == 0)
void izm_pH (uint16_t vremya) {
tmr3.setPeriod(vremya);
if (tmr3.ready()){
pH_val = sensor.getPH() ,2;
Serial.print(F("Кислотность = " )); //
Serial.print(pH_val, 2); // Выводим водородный показатель жидкости с 2 знаком после запятой.
Serial.print(F(" pH.\r\n")); //
if (nomer == 11) {val_change (pH_val,5,1);}
if (nomer == 211 or nomer == 221 or nomer ==222) {val_change (pH_val,3,0);
if (tFlag==false) {t_0 = millis();}
if (tFlag==true) {sekundomer (); lcd.setCursor(11,1); lcd.print(s);;
lcd.setCursor(9,0); lcd.print(t_h);lcd.print(F(":")); lcd.print(t_m); lcd.print(F(":"));lcd.print(t_s);lcd.print(F(" "));}}}
led_blink (500);
}
#endif
//_____________________________________ Калибровка рН ________________________________________
void calibr_pH1 () {
#if (DEBUG == 0)
sensor.setCalibration(1, data.pH1);
#endif
tim (10); // таймер на n с
s_menu (2, F("Spolostnite"), 4, F("datchik"),false) ;
}
void calibr_pH2 () {
#if (DEBUG == 0)
sensor.setCalibration(2, data.pH2);
#endif
tim (10); // таймер на n с
s_menu (2, F("Spolostnite"), 4, F("datchik"),false) ; }
/////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// Автоматический титратор ////////////////////////////////////
void titr_auto (){
titrFlag = true;
intFlag = false;
tFlag=true; t_0 = millis();
for (;;) {
#if (DEBUG == 0)
izm_pH (333);
#endif
#if (DEBUG == 1)
pH_simulator (200);
#endif
//Serial.println(pH_val);
if (pH_val > data.min_pH +0.01 and titrFlag == true) {motor_nepr(data.v_auto,data.w_auto,1,0);};
if (pH_val <= data.min_pH +0.01 and titrFlag == true) {titrFlag = false;
//Serial.println(titrFlag);
saveData();};
if (pH_val >= data.max_pH -0.01 and titrFlag == false) {titrFlag = true;
// Serial.println(titrFlag);
};
if (intFlag == true) { intFlag = false; Serial.println("Interrupt!"); break;}
}
}
//////////////////////////////////Секундомер и таймер /////////////////////////////
void sekundomer (){
s = (millis() - t_0)/1000ul;
t_s = (s % 3600) % 60; // секунды
t_m = (s % 3600) / 60; // минуты
t_h = (s / 3600); // часы
}
void tim (uint16_t t) {
lcd.clear();
intFlag = false;
for (;;) {
led_blink (150);
if (tmr7.ready()){t--;
su_menu (false, 2, F("Kalibrovka..."), 7, t, false); lcd.print(F(" "));
if (t ==0){ break;}
if (intFlag == true){intFlag = false; Serial.println(F("Interrupt!")); break; }
}}
digitalWrite(LED_PIN, LOW);
}
////////////////////////////// LED ////////////////////////////////////////
void led_blink (uint16_t tmr_on){
tmr6.setPeriod(tmr_on);
if (tmr6.ready()){
light = !light;
digitalWrite(LED_PIN, light); }
}
///////////////////////////////////////////////////////////////////////////
///////////////////////////// В ЦИКЛЕ ////////////////////////////////////
void cikl (){
#if (DEBUG == 0)
if (nomer == 11 or nomer == 211) {izm_pH (100); led_blink (500); }
#endif
#if (DEBUG == 1)
if (nomer == 11 or nomer == 211) {pH_simulator (100); led_blink (500); }
#endif
}
////////////////////////////////////////////////////////////////////////////////
//------------------------------ SD ------------------------------------------
void saveData(){
dataString = String(s) + ";" + String(v_prok) + ";" + String(pH_val); // convert to CSV
String FName = String(data.fileNBR) + ".csv";
sensorData = SD.open(FName, FILE_WRITE);
if (sensorData){
Serial.println(F("файл открыт"));
sensorData.println(dataString);
Serial.println(dataString);
sensorData.close(); // close the file
Serial.println(F("файл закрыт"));}
else{ // иначе ...
Serial.println("не открылся");
}
if(SD.exists(FName)){ // если файл с именем "iarduino.txt" существует, то ...
Serial.println(F("файл существует"));}
}