// Мои переменные и дефайны
#include <Arduino.h>
#include <EEPROM.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
//#include "LCD_1602_RUS.h"
//LCD_1602_RUS lcd(0x27, 20, 4); //адрес 0x27 или 0x3f
LiquidCrystal_I2C lcd(0x27, 20, 4); // адрес 0x27 или 0x3f
//#include "GyverPID.h"
#include <GyverNTC.h>
#include <GyverTimers.h> // библиотека таймера
#include "GyverEncoder.h"
#include "EmonLib.h" // для сети 220 считываем значения
EnergyMonitor emon1;
//GyverPID regulator(5, 1, 0.01, 1000); // коэф. П, коэф. И, коэф. Д, период дискретизации dt (мс)
#define r_kub 9900 //10000 //9900 // номинальное сопротивление резистора
#define r_kolonna 9900 //10000 //9900 // номинальное сопротивление резистора
#define r_tsa 9850 //10000 //9900 // номинальное сопротивление резистора
#define ZERO_PIN 3 // пин детектора нуля < указать 3 для платы темной с PCB или 4 для плат с Зеленограда>
#define INT_NUM 1 // соответствующий ему номер прерывания 0 либо 1 < указать 1 для платы темной с PCB>
#define pause_menu 5 // тайм-аут нахождения в меню, сек
#define startEEPROM 900 // ячёйка для внесения начальных значений в память
#define KEY_First_start 20 // ключ первого запуска. на выбор 0-220
#define Pin_Upravlenija_Simistorom_PWM 4 // плавное управление. без контроля синусойды через 0 Pin_Power_PWM_Vihod_220 = Pin_Upravlenija_Simistorom_PWM
#define k 0.01 // коэффициент для температуры
#define MY_PERIOD 1000 // период в мс
// ниже блок Для считывания напряжения сети
#define PinReadVoltage A2 // для считывания напряжения сети
int Uk = 151;
int i = 0,S_online;
float tenvals = 0.0;
float minval = 1000;
float maxval = 0.0;
float Useti=0, Pset=0;
// закончен бок переменных напряжения сети
GyverNTC NTC_A0(0, 10000, 3435, 25, r_kub); // Датчик Куб
GyverNTC NTC_A1(1, 10000, 3435, 25, r_kolonna); // Датчик Колонны
GyverNTC NTC_A2(2, 10000, 3435, 25, r_tsa); // Датчик ТСА
float NTC_Temp_Kolonna = 0; // переменная опроса датчика температуры Колонны
float NTC_Temp_Kub = 0; // переменная опроса датчика температуры Куба
float NTC_Temp_TSA = 0; // переменная опроса датчика температуры ТСА
// переменные для хранения режима работы пинов
byte Pin_Upravlenija_Relay = 5; // Pin_Power_Relay_220 = Pin_Upravlenija_Relay
byte Pin_BEEP = 11;
// переменные для хранения времени работы реле в сек.
uint32_t sec = 0; // полное количество секунд
int timeHours = 0; // часы
int timeMins = 0; // минуты
int timeSecs = 0; // секунды
int PWN_Signal_na_Simistor = 0; // Power_na_220 = PWN_Signal_na_Simistor
float Vidavaemaja_Power = 0;
float PWN = 0;
bool flag = false;
bool Stop_Start_flag = false;
// Мои переменные и дефайны закончились
#define LINES 4 // количество строк дисплея
#define SETTINGS_AMOUNT 11 // количество настроек
#define FAST_STEP 30 // скорость изменения при быстром повороте
// пины энкодера
#define CLK 2//2 вниз 2- для моделирования
#define DT 3//3 вверх 3 - для моделирования
#define SW 6//4 кнопка 6 - для моделирования
Encoder enc(CLK, DT, SW); // для работы c кнопкой
float vals[SETTINGS_AMOUNT]; // массив параметров
int8_t arrowPos = 0;
bool controlState = 0; // клик
const char name1[] PROGMEM = "TEH HArPy3. ";// vals[0]MO-CTb.
const char name2[] PROGMEM = "ABTOPA3rOH ";// vals[1]
const char name3[] PROGMEM = "T.ABTOPA3-HA";// vals[2]Ky6a
const char name4[] PROGMEM = "T.CPA6AT.K. ";// vals[3]K-HA
const char name5[] PROGMEM = "OCTAHOB BP. ";// vals[4]PA6
const char name6[] PROGMEM = "OCTAHOB TCA ";// vals[5]TCA
const char name7[] PROGMEM = "OCTAHOB t K.";// vals[6]Ky6a
const char name8[] PROGMEM = "3AKP.K.HO/H3";// vals[7]
const char name9[] PROGMEM = "rUCTEPE3UC ";// vals[8]
const char name10[]PROGMEM = "M.PA3rOHA K.";// vals[9]Ky6A
const char name11[]PROGMEM = "R.TEHA B Om ";// vals[10]OMAX
//const char name12[]PROGMEM = "KOPPEK.U CETu";// vals[10]
// объявляем таблицу ссылок
const char* const names[] PROGMEM = {
name1, name2, name3, name4, name5, name6, name7, name8, name9, name10, name11, //name12, // vals[n+1]
};
int Power_Vihoda_na_Ten =10;//= EEPROM.get(2, vals[0]); //vals[0]; Power_Vihoda_na_Ten = Power_Vihoda_na_220
int avtorejim =0;//= EEPROM.get(6, vals[1]); //vals[1];
int Temp_V_Kube_razgon =70;//= EEPROM.get(10, vals[2]); //vals[2];
float Temp_Work_Rele =60;//= EEPROM.get(14, vals[3]); //vals[3]; Temp_Open_Rele_220 = Temp_Work_Rele
int Vremja_Raboti_Bolshe_Chem =10;//= EEPROM.get(18, vals[4]); //vals[4];
int Temp_V_TSA_Bolshe_Chem =30;//= EEPROM.get(22, vals[5]); //vals[5];
int Temp_V_Kube_Bolshe_Chem =35;//= EEPROM.get(26, vals[6]); //vals[6];
int Tip_Rele_NO_NZ =1;//= EEPROM.get(30, vals[7]); //vals[7]; Rejim_Raboti_Rele_220 = Tip_Rele_NO_NZ
float gisterezis =1;//= EEPROM.get(34, vals[8]); //vals[8];
int Avtorazgon_Power_Tena =30;//= EEPROM.get(38, vals[9]); //vals[9];
int R_tena =16;//= EEPROM.get(42, vals[10]); //vals[10];
//int Uk = EEPROM.get(32, vals[11]); //vals[11];
void setup() {
lcd.init();
lcd.backlight();
emon1.voltage(PinReadVoltage, Uk, 1.7); //считывание напряжения где 150 (uk) поправочный коэффичиент
//regulator.setDirection(NORMAL); // направление регулирования (NORMAL/REVERSE). ПО УМОЛЧАНИЮ СТОИТ NORMAL
NTC_Temp_Kub = (NTC_A0.getTemp());
NTC_Temp_Kolonna = (NTC_A1.getTempAverage());
NTC_Temp_TSA = (NTC_A2.getTemp());
pinMode(ZERO_PIN, INPUT_PULLUP);
pinMode(Pin_Upravlenija_Simistorom_PWM, OUTPUT);
attachInterrupt(INT_NUM, isr, RISING); // для самодельной схемы ставь FALLING CHANGE изначально - RISING
Timer2.enableISR();
Serial.begin(9600);
enc.setType(TYPE2);
enc.setFastTimeout(250);
printGUI();
}
void loop() {
enc.tick();
// EEPROM.put(2, 100); EEPROM.put(6, 1); EEPROM.put(10, 50);EEPROM.put(14, 68.0);EEPROM.put(18, 14);EEPROM.put(22, 45);EEPROM.put(26, 96);EEPROM.put(30, 1);EEPROM.put(34, 0.1);EEPROM.put(38, 90);EEPROM.put(42, 16);
time(); // работает всегда. время с момента включения.
timing_menu();
vibor_logiki();
//analogWrite(pin, computePID(sensorRead, 30, 1.0, 2.0, 3.0, 0.02, 0, 255));
}
void glavMEHU (){
enc.tick();
// смена контроля
if (enc.isClick()) {
flag = true;
controlState = !controlState;
printGUI();
}
if (enc.isTurn()) {
Stop_Start_flag = false;
flag = true;
float increment = 0; // локальная переменная направления
// получаем направление
if (!controlState) {
if (enc.isRight()) increment = 1;
if (enc.isLeft()) increment = -1;
arrowPos += increment; // двигаем курсор
arrowPos = constrain(arrowPos, 0, SETTINGS_AMOUNT - 1); // ограничиваем
}
increment = 0; // обнуляем инкремент
if ((arrowPos==0 && controlState && enc.isRight()) || enc.isRightH()) increment = 50;
if ((arrowPos==0 && controlState && enc.isLeft()) || enc.isLeftH()) increment = -50;
if ((arrowPos==1 && controlState && enc.isRight()) || enc.isRightH()) vals[1] =1;
if ((arrowPos==1 && controlState && enc.isLeft()) || enc.isLeftH()) vals[1] =0;
if ((arrowPos==2 && controlState && enc.isRight()) || enc.isRightH()) increment = 1;
if ((arrowPos==2 && controlState && enc.isLeft()) || enc.isLeftH()) increment = -1;
if ((arrowPos==3 && controlState && enc.isRight()) || enc.isRightH()) increment = 0.1;
if ((arrowPos==3 && controlState && enc.isLeft()) || enc.isLeftH()) increment = -0.1;
if ((arrowPos==4 && controlState && enc.isRight()) || enc.isRightH()) increment = 1;
if ((arrowPos==4 && controlState && enc.isLeft()) || enc.isLeftH()) increment = -1;
if ((arrowPos==5 && controlState && enc.isRight()) || enc.isRightH()) increment = 1;
if ((arrowPos==5 && controlState && enc.isLeft()) || enc.isLeftH()) increment = -1;
if ((arrowPos==6 && controlState && enc.isRight()) || enc.isRightH()) increment = 1;
if ((arrowPos==6 && controlState && enc.isLeft()) || enc.isLeftH()) increment = -1;
if ((arrowPos==7 && controlState && enc.isRight()) || enc.isRightH()) vals[7] =1;
if ((arrowPos==7 && controlState && enc.isLeft()) || enc.isLeftH()) vals[7] =0;
if ((arrowPos==8 && controlState && enc.isRight()) || enc.isRightH()) increment = 0.1;
if ((arrowPos==8 && controlState && enc.isLeft()) || enc.isLeftH()) increment = -0.1;
if ((arrowPos==9 && controlState && enc.isRight()) || enc.isRightH()) increment = 1;
if ((arrowPos==9 && controlState && enc.isLeft()) || enc.isLeftH()) increment = -1;
if ((arrowPos==10 && controlState && enc.isRight()) || enc.isRightH()) increment = 1;
if ((arrowPos==10 && controlState && enc.isLeft()) || enc.isLeftH()) increment = -1;
// if ((controlState && enc.isRight()) || enc.isRightH()) increment = 1;
// if ((controlState && enc.isLeft()) || enc.isLeftH()) increment = -1;
if (controlState && enc.isFastR()) increment = FAST_STEP;
if (controlState && enc.isFastL()) increment = -FAST_STEP;
vals[arrowPos] += increment; // меняем параметры
//
//float i = 220/R_tena; float Pras_ten=(220*i)+100;
vals[0] = constrain (vals[0], 0, 3100); //u=i*r p=u*i i=u/r Pras_ten
vals[1] = constrain (vals[1], 0, 1);
vals[2] = constrain (vals[2], 0, 100);
vals[3] = constrain (vals[3], 0, 100);
vals[4] = constrain (vals[4], 1, 18);
vals[5] = constrain (vals[5], 25, 100);
vals[6] = constrain (vals[6], 25, 100);
vals[7] = constrain (vals[7], 0, 1);
vals[8] = constrain (vals[8], 0, 5);
vals[9] = constrain (vals[9], 5, 100);
vals[10] = constrain (vals[10], 1, 1200);
//vals[11] = constrain (vals[11], 100, 200);
Power_Vihoda_na_Ten = vals[0]; EEPROM.put (2, vals[0]);
avtorejim = vals[1]; EEPROM.put (6, vals[1]);
Temp_V_Kube_razgon = vals[2]; EEPROM.put (10, vals[2]);
Temp_Work_Rele = vals[3]; EEPROM.put (14, vals[3]);
Vremja_Raboti_Bolshe_Chem = vals[4]; EEPROM.put (18, vals[4]);
Temp_V_TSA_Bolshe_Chem = vals[5]; EEPROM.put (22, vals[5]);
Temp_V_Kube_Bolshe_Chem = vals[6]; EEPROM.put (26, vals[6]);
Tip_Rele_NO_NZ = vals[7]; EEPROM.put (30, vals[7]);
gisterezis = vals[8]; EEPROM.put (34, vals[8]);
Avtorazgon_Power_Tena = vals[9]; EEPROM.put (38, vals[9]);
R_tena = vals[10]; EEPROM.put (50, vals[10]);
//int Uk = vals[11]; EEPROM.put (32, vals[11]);
//
printGUI();
}
}
void Infomenu(){
enc.tick(); if (enc.isTurn() && enc.isClick() ) { flag = true; glavMEHU(); }
lcd.setCursor(0, 0); lcd.print((String("TEM.KO-HA:") + String(NTC_Temp_Kolonna, 1))); lcd.write(223); lcd.print("C");
lcd.setCursor(0, 1); lcd.print((String("TEM.B TCA:") + String(NTC_Temp_TSA, 1))); lcd.write(223); lcd.print("C");
lcd.setCursor(0, 2); lcd.print((String("TEM.B Ky6:") + String(NTC_Temp_Kub, 1))); lcd.write(223); lcd.print("C");
lcd.setCursor(0, 3); lcd.print((String("U=") + String(Useti, 0))); lcd.print("B");
if (avtorejim == 1) {
lcd.setCursor(7, 3); lcd.print((String("P=") + String((Avtorazgon_Power_Tena/100) * vals[0]))); lcd.print("Bm ");
}
if (avtorejim == 0) {
lcd.setCursor(7, 3); lcd.print((String("P=") + String(S_online,0))); lcd.print("Bm "); // 203c242
}
lcd.setCursor(16, 3); lcd.print(String(PWN,0) ); lcd.print("%");
if (avtorejim == 1) {
lcd.setCursor(17, 0);
lcd.print("[A]");
}
if (avtorejim == 0) {
lcd.setCursor(17, 0);
lcd.print(" ");
}
}
void timing_menu() {
glavMEHU();
static byte g;
static int count;
static uint32_t pause;
uint32_t vremja = millis() / 1000ul;
if (pause - vremja >= 1 && g != 1) { // изменения
pause = vremja;
count++;
}
if (flag == true && count < pause_menu ) {
glavMEHU();
count = 0;
flag = false;
g=0;
}
if (count >= pause_menu) {
flag = false;
count = 0;
lcd.clear();
g=1;
}
if (g >=1 && flag == false && NTC_Temp_Kub <= Temp_V_Kube_Bolshe_Chem && NTC_Temp_TSA <= Temp_V_TSA_Bolshe_Chem && timeHours <= Vremja_Raboti_Bolshe_Chem )//&& Stop_Start_flag == false
{
Infomenu();
voltage ();
}
}
void read_temp() {
NTC_Temp_Kolonna += (NTC_A1.getTemp() - NTC_Temp_Kolonna) * k;
//NTC_Temp_Kolonna += (NTC_A1.getTempAverage() - NTC_Temp_Kolonna) * k;
NTC_Temp_TSA += (NTC_A2.getTemp() - NTC_Temp_TSA) * k;
NTC_Temp_Kub += (NTC_A0.getTemp() - NTC_Temp_Kub) * k;
/*
Температура будет немного “шуметь”, несмотря на чтение с усреднением.
Для более точных измерений можно использовать простейший фильтр – экспоненциальное скользящее среднее,
которое реализуется так: filt_val += (new_val - filt_val) * k, где k – число от 0.0 до 1.0.
Фильтр даёт плавное изменение, что позволяет получать максимально точное значение с течением времени.
Результат работы данной программы лучше наблюдать во встроенном плоттере графиков:
*/
}
void Logik_Work() {
read_temp();
PWN_Signal_na_Simistor = PWN;
//______________________ Клапан 220 НО и NTC > t срабатывания клапана
if (NTC_Temp_Kolonna >= Temp_Work_Rele && Tip_Rele_NO_NZ == 0) {
pinMode(Pin_Upravlenija_Relay, OUTPUT);
digitalWrite(Pin_Upravlenija_Relay, HIGH);
}
//______________________ Клапан 220 НО и NTC < t срабатывания клапана
if (NTC_Temp_Kolonna <= (Temp_Work_Rele - gisterezis) && Tip_Rele_NO_NZ == 0 ) {
digitalWrite(Pin_Upravlenija_Relay, LOW);
pinMode(Pin_Upravlenija_Relay, INPUT);
}
//______________________ Клапан 220 НЗ и NTC > t срабатывания клапана
if (Tip_Rele_NO_NZ == 1 && NTC_Temp_Kolonna >= Temp_Work_Rele) {
digitalWrite(Pin_Upravlenija_Relay, LOW);
pinMode(Pin_Upravlenija_Relay, INPUT);
}
//______________________ Клапан 220 НЗ и NTC < t срабатывания клапана
if (Tip_Rele_NO_NZ == 1 && NTC_Temp_Kolonna <= (Temp_Work_Rele - gisterezis)) {
pinMode(Pin_Upravlenija_Relay, OUTPUT);
digitalWrite(Pin_Upravlenija_Relay, HIGH);
}
if (NTC_Temp_TSA >= Temp_V_TSA_Bolshe_Chem) {
pinMode(Pin_Upravlenija_Simistorom_PWM, INPUT);
pinMode(Pin_BEEP, OUTPUT);
STOP_TCA();
Stop_Start_flag = true;
}
if (timeHours >= Vremja_Raboti_Bolshe_Chem) {
pinMode(Pin_Upravlenija_Simistorom_PWM, INPUT);
pinMode(Pin_BEEP, OUTPUT);
STOP_Time();
Stop_Start_flag = true;
}
if (NTC_Temp_Kub >= Temp_V_Kube_Bolshe_Chem) {
pinMode(Pin_Upravlenija_Simistorom_PWM, INPUT);
pinMode(Pin_BEEP, OUTPUT);
STOP_Kyb();
Stop_Start_flag = true;
}
//Stop_Start_flag== true
while (Stop_Start_flag && NTC_Temp_TSA < Temp_V_TSA_Bolshe_Chem){
STOP_TCA();
enc.tick();
Serial.println(Stop_Start_flag);
if ( enc.isTurn()) {
//enc.tick(); // ========================================================
pinMode(Pin_BEEP, INPUT);
lcd.clear();
Infomenu();
Stop_Start_flag = false;
pinMode(Pin_Upravlenija_Simistorom_PWM, OUTPUT);
Serial.println(Stop_Start_flag);
//break;
}
}
}
void avtorazgon_logik() {
bool flag_1;
read_temp();
if (avtorejim == 1 && NTC_Temp_Kub <= Temp_V_Kube_razgon) {
PWN_Signal_na_Simistor = map(Avtorazgon_Power_Tena, 100, 0, 500, 9300);
if (NTC_Temp_Kolonna >= Temp_Work_Rele && Tip_Rele_NO_NZ == 0 ) {
pinMode(Pin_Upravlenija_Relay, OUTPUT);
digitalWrite(Pin_Upravlenija_Relay, HIGH); // температура выше установленной! закрываем
}
//______________________ Клапан 220 НО и NTC < t срабатывания клапана
if (NTC_Temp_Kolonna <= (Temp_Work_Rele - gisterezis) && Tip_Rele_NO_NZ == 0 ) {
digitalWrite(Pin_Upravlenija_Relay, LOW); // температура ниже установленной! открываем
pinMode(Pin_Upravlenija_Relay, INPUT);
}
//______________________ Клапан 220 НЗ и NTC > t срабатывания клапана
if (Tip_Rele_NO_NZ == 1 && NTC_Temp_Kolonna >= Temp_Work_Rele) {
digitalWrite(Pin_Upravlenija_Relay, LOW);
pinMode(Pin_Upravlenija_Relay, INPUT);
}
//______________________ Клапан 220 НЗ и NTC < t срабатывания клапана
if (Tip_Rele_NO_NZ == 1 && NTC_Temp_Kolonna <= (Temp_Work_Rele - gisterezis)) {
pinMode(Pin_Upravlenija_Relay, OUTPUT);
digitalWrite(Pin_Upravlenija_Relay, HIGH);
}
if (NTC_Temp_Kub >= Temp_V_Kube_Bolshe_Chem) {
pinMode(Pin_Upravlenija_Simistorom_PWM, INPUT);
pinMode(Pin_BEEP, OUTPUT);
STOP_Kyb();
Stop_Start_flag = true;
}
if (NTC_Temp_TSA >= Temp_V_TSA_Bolshe_Chem) {
pinMode(Pin_Upravlenija_Simistorom_PWM, INPUT);
pinMode(Pin_BEEP, OUTPUT);
STOP_TCA();
Stop_Start_flag = true;
}
if (timeHours >= Vremja_Raboti_Bolshe_Chem) {
pinMode(Pin_Upravlenija_Simistorom_PWM, INPUT);
pinMode(Pin_BEEP, OUTPUT);
STOP_Time();
Stop_Start_flag = true;
}
if (NTC_Temp_TSA <= Temp_V_TSA_Bolshe_Chem && Stop_Start_flag == true) {
STOP_TCA () ;
flag_1 = true;
pinMode(Pin_BEEP, INPUT);
}
if (flag_1 == true && Stop_Start_flag == true) {
lcd.clear();
Infomenu();
//Stop_Start_flag = false;
pinMode(Pin_Upravlenija_Simistorom_PWM, OUTPUT);
flag_1 = false;
}
}
if (avtorejim == 1 && NTC_Temp_Kub >= Temp_V_Kube_razgon) {
PWN_Signal_na_Simistor = PWN;
avtorejim = 0;
}
}
void voltage () {
static unsigned long tStart;
int tEnd = 2000;
if(millis() - tStart > tEnd) {
emon1.calcVI(20,500);
float Vrms = (emon1.Vrms);
tenvals += Vrms;
// Serial.print("Avg: "); Serial.print(tenvals/10); Serial.print(" ("); Serial.print(Vrms); Serial.print(") Min: "); Serial.print(minval); Serial.print(" Max: "); Serial.println(maxval);
Useti=tenvals;
tenvals = 0;
Pset = (Useti*Useti)/R_tena;
PWN = (1-(Pset - Power_Vihoda_na_Ten)/Pset)*100;
S_online = (PWN*Pset)/100;
if (PWN >100){ PWN =100; }
tStart += tEnd;
}
}
void vibor_logiki() {
if (avtorejim == 1) {
avtorazgon_logik();
}
if (avtorejim == 0) {
Logik_Work();
}
}
void STOP_TCA(){
signal();
static uint32_t tmr;
if (millis() - tmr >= 1000) {
tmr = millis();
lcd.clear();
}
lcd.setCursor(2, 1);
lcd.print("CTOП пo t TCA");
}
void STOP_Kyb(){
signal();
static uint32_t tmr;
if (millis() - tmr >= 1000) {
tmr = millis();
lcd.clear();
}
lcd.setCursor(2, 1);
lcd.print("CTOП пo t Ky6A");
}
void STOP_Time(){
signal();
static uint32_t tmr;
if (millis() - tmr >= 1000) {
tmr = millis();
lcd.clear();
}
lcd.setCursor(2, 1);
lcd.print("CTOП пo BPEMEHИ");
}
void printGUI() {
static int8_t screenPos = 0; // номер "экрана"
static int8_t lastScreen = 0; // предыдущий номер "экрана"
screenPos = arrowPos / LINES; // ищем номер экрана (0..3 - 0, 4..7 - 1)
if (lastScreen != screenPos) lcd.clear(); // если экран сменился - очищаем
lastScreen = screenPos;
for (byte i = 0; i < LINES; i++) { // для всех строк
lcd.setCursor(0, i); // курсор в начало
// если курсор находится на выбранной строке
smartArrow(arrowPos == LINES * screenPos + i); // рисуем стрелку или пробел
// если пункты меню закончились, покидаем цикл for
if (LINES * screenPos + i == SETTINGS_AMOUNT) break;
// выводим имя и значение пункта меню
printFromPGM(&names[LINES * screenPos + i]);
lcd.print(F(":"));
lcd.print(vals[LINES * screenPos + i],1);
lcd.print(F(" ")); // пробелы для очистки
if (arrowPos >=0 && arrowPos <=3 && vals[1] ==1) {lcd.setCursor(14, 1); lcd.print("BK.");} if (arrowPos >=0 && arrowPos <=3 && vals[1] ==0) {lcd.setCursor(14, 1); lcd.print("OTK");}
if (arrowPos >=4 && arrowPos <=7 && vals[7] ==1) {lcd.setCursor(14, 3); lcd.print("Н/3");}if (arrowPos >=4 && arrowPos <=7 && vals[7] ==0) {lcd.setCursor(14, 3); lcd.print("Н/O");}
}
}
// очень хитрая функция для печати из PROGMEM
void printFromPGM(int charMap) {
uint16_t ptr = pgm_read_word(charMap); // получаем адрес из таблицы ссылок
while (pgm_read_byte(ptr) != NULL) { // всю строку до нулевого символа
lcd.print(char(pgm_read_byte(ptr))); // выводим в монитор или куда нам надо
ptr++; // следующий символ
}
}
void smartArrow(bool state) { // рисует стрелку, галку или пробел
lcd.write(state ? (controlState ? 62 : 126) : 32);//62 : 126)
}
void time() {
sec = millis() / 1000ul; // полное количество секунд
timeHours = (sec / 3600ul); // часы
timeMins = (sec % 3600ul) / 60ul; // минуты
timeSecs = (sec % 3600ul) % 60ul; // секунды
}
int computePID(float input, float setpoint, float kp, float ki, float kd, float dt, int minOut, int maxOut) {
float err = setpoint - input;
static float integral = 0, prevErr = 0;
integral = constrain(integral + (float)err * dt * ki, minOut, maxOut);
float D = (err - prevErr) / dt;
prevErr = err;
return constrain(err * kp + integral + D * kd, minOut, maxOut);
}
void signal() {
uint32_t Global_timer = millis() / 1000ul; // полное количество секунд
if (Global_timer % 2 == 0) {
digitalWrite(Pin_BEEP, 1);
} else {
digitalWrite(Pin_BEEP, 0);
}
}
ISR (TIMER2_A) {
digitalWrite(Pin_Upravlenija_Simistorom_PWM, 1); // включаем симистор
Timer2.stop(); // останавливаем таймер
}
void isr() {
static int lastDim;
digitalWrite(Pin_Upravlenija_Simistorom_PWM, 0); // выключаем симистор
if (lastDim != PWN_Signal_na_Simistor) Timer2.setPeriod(lastDim = PWN_Signal_na_Simistor);
else Timer2.restart();
}