Re: Бортовой компьютер мотоцикла
	
	
		Сегодня убил пол дня на освоение OLED дисплея, проблема заключалась в обновлении дисплея... если при обновлении каждый раз делать reset функцией из библиотеки - то он начинал противно мигать. 
Спустя некоторые время, присмотрелся к стандартному примеру, оказалось на пример, что бы после цифры 1 написать 2, перед выводом 2, "печатаем" на дисплее 1 в черном цвете.
Вот-то, что успел сделать, это самый главный "дисплей" при включении он будет всегда первым.
с лева на право - индикатор включенной передачи, температура за бортом, уровень топлива.
Пока коряво ... прогресс бар не правильно обновляется на уменьшение, под температурой будет снежинка при минусе ;) ...
http://youtu.be/smmmO8h7gsM
	PHP код:
	
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h> 
#include <Adafruit_SSD1306.h> 
Adafruit_SSD1306 display(4); //OLED_RESET
#define LINE 20 // отступ линии от левого края
#define W_PRBAR 15 // ширина элемента прогресс бара
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B11111111, B11111111,
  B11111111, B11111111,
  B11111111, B11111111,
  B11111111, B11111111,
  B11111111, B11111111,
  B11111111, B11111111,
  B11111111, B11111111,
  B11111111, B11111111,
  B11111111, B11111111,  
  B11111111, B11111111,};
int temp[3];
void setup(){           
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); 
  display.clearDisplay(); // Очистить буфер.
  display.setTextColor(WHITE); // Цвет текста.
  _display_add_fuel(70);
  display.display();
}
void loop() {
 _display_add_temp(random(-40, 45));
 _display_add_gear(random(0, 5));
 _display_add_fuel(random(0, 70)); 
 delay(2000);
}
int _display_add_fuel(int a){ //,display.height()display.width()
  if (a < temp[0]){
    for (int f=0; f< a; f+=5) {
    display.drawBitmap(display.width() - W_PRBAR, f , logo16_glcd_bmp, W_PRBAR, 4, BLACK);
   display.display();
  }
  }
  
  for (int f=0; f< a; f+=5) {
  display.drawBitmap(display.width() - W_PRBAR, display.height() - f , logo16_glcd_bmp, W_PRBAR, 4, WHITE);
  }
  display.drawLine(display.width() - LINE, display.height(),display.width() - LINE , 0, WHITE); // линия
  display.display();
  temp[0] = a;
 
}
int _display_add_temp(int b){
  display.setTextSize(2);
  display.setTextColor(BLACK);
  display.setCursor(50,0);
  display.println(temp[1]);  
  display.display();
  display.setTextColor(WHITE);
  display.setCursor(50,0);
  display.println(b);
  temp[1] = b;
  display.display();
}
int _display_add_gear(int c){
  display.setTextSize(8);
  display.setTextColor(BLACK);
  display.setCursor(0,0);
  display.println(temp[2]);
  display.display();
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println(c);
  temp[2] = c;
  display.display();  
} 
 
	 
	
	
	
		Re: Бортовой компьютер мотоцикла
	
	
		С дисплеем разобрался никаких миганий, для обновления не надо ничего зарисовывать черным шрифтом, я случайно поставил функции не в той последовательности. Всю голову сломал с выводом меню, в таблицу не умещаются дисплей мелкий ... получилась примерно следующее.
http://youtu.be/qSfM5BxvRUM
	 
	
	
	
		Re: Бортовой компьютер мотоцикла
	
	
		Вчера прицепил RTC модуль реального времени на базе DS1307, собственно пытался уже давно но ничего не получалось ... вначале была проблема связи модуля с ардуиной, дата и время были премерно следующие "2165/165/165 165:165:85", потом таймер каждый раз начинался заново при отключении питания, ну и в заключении долго пытался найти как синхронизировать время.
Видео- http://youtu.be/reKBAI_8LaI 
В начале обязательно подтягиваем шину I2С к +5В через резисторы 10к, даже если устройство на шине одно, без резисторов работать не будет.
Библиотеки из примера http://zelectro.cc/Media/Default/%D0...%8B/RTClib.zip
http://zelectro.cc/Media/Default/%D0...D1%8B/Time.zip
Заливаем в ардуино скетч:
	PHP код:
	
#include <Wire.h>
#include "RTClib.h"
#include <Time.h>
RTC_DS1307 RTC;
void setup () {
    Serial.begin(9600);
    Wire.begin();
    RTC.begin();
}
void loop () {
    time_t curTime = 0;
    // На Serial поступит время в формате unixtime
    if (Serial.available() > 0)
    {
      int eps = millis();
      time_t coef = 1000000000;
      while (coef > 0)
      {
         byte b = Serial.read();
         if (b == 255)
         {
            continue; 
         }
         curTime += coef*(b-'0');
         coef /= 10;
      }
      // Устанавливаем считанное по байтам время в RTC
      RTC.adjust(curTime + (millis()-eps)/1000);
    }
} 
 Открываем окно терминала, далее переходим по ссылке http://www.bl2.ru/programing/timestamp.html, быстро копируем Текущее Unix время,например: 1423495561, и так же быстро вставляем текст в окно терминала комбинацией клавиш Ctrl + v, нажимаем отправить! Всё! время выставлено, проверяем:
	PHP код:
	
#include <Wire.h>
#include "RTClib.h"
RTC_DS1307 RTC;
void setup () {
    Serial.begin(9600);
    Wire.begin();
    RTC.begin();
}
void loop () {
    // Определяем время
    DateTime now = RTC.now();
    
    // Выводим время в монитор порта
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
 
    delay(1000);
} 
 
	 
	
	
	
		Re: Бортовой компьютер мотоцикла
	
	
		Oleg_33, у ds1302 (SPI) и ds1307 (I2C) с точностью хода зачастую проблемы. Будь готов подводить часы на 5-10сек каждый день. В идеале лучше использовать DS3231.
Думал также готовый модуль использовать, потом посмотрел по обвязке и решил отдельно прикупить микруху и осциллятор, чтобы распаять самому и сэкономить место.
	 
	
	
	
		Re: Бортовой компьютер мотоцикла
	
	
		да да я зметил модуль врёт, за 3 дня убежал секунд на 30 ... я ведь хотел DS3231 сразу заказать, но что то меня остановило :)
	 
	
	
	
		Re: Бортовой компьютер мотоцикла
	
	
		Где то читал, что можно analogRead, digitalWrite ... заменить на код прямого доступа, тем самым с экономить память и увеличить быстродействие, где можно прочитать  про это ?
Я к чему веду, библиотека дисплея, меню и прочая ерунда =) сожрала 70% памяти ... а ещё нужно кое что добавить, вот сижу оптимизирую код, убираю лишние функции, операторы ...
	 
	
	
	
		Re: Бортовой компьютер мотоцикла
	
	
		Oleg_33, да, можно заменить. Почитать можно здесь (один из самых популярных манов, но мне не сильно понравилось).
Я бы не рекомендовал заниматься оптимизацией, когда еще надобности не возникло. Разумеется когда подключаешь библиотеки, память будет отжираться и казаться, что вот-вот она кончится.
Однако забить все 30Кб (2Кб отожрет загрузчик Arduino) на atmega328 сложновато, если не подключать все подряд.
Самый простой вариант сократить объем занимаемой памяти - выкинуть неиспользуемый код из библиотек, удалив его или окружив комментариями. 
Свой код можно особо не оптимизировать - даже 10Кб своего кода - это весьма много текста. Лучше постараться избежать г0внокода, когда заглянув через месяц в свой файл, не поймешь чего имел в виду.
По быстродействию я бы сильно также не парился - это не то место, где оно нужно. Имхо достаточно просто delay и совсем идиотские конструкции не использовать и всё.
Я думаю стоит прислушаться к мнению автора серии книг "Искусство программирования" ;)
	Цитата:
	
		
		
			Преждевременная оптимизация — корень всех (или большинства) проблем в программировании.
			
		
	
 
	 
	
	
	
		Re: Бортовой компьютер мотоцикла
	
	
		Всё таки не соглашусь, почему бы и не оптимизировать если код станет меньше (возможно сложнее  в понимании -  насчёт этого вообще не парюсь, всегда можно прикоментировать разъяснительные аннотации :rolleyes: ) 
С библиотеками все не просто, например убрав часть кода с инициализации SPI интерфейса и поддержки дисплея меньшего размера  ... в Adafruit_SSD1306, удалось увеличить память на 5%, а вот из библиотеки MFRC522 какие бы функции я не убирал размер не меняется , получается  компилятор сам берёт на себя эту функцию.
	 
	
	
	
		Re: Бортовой компьютер мотоцикла
	
	
		Oleg_33, разумеется компилятор что-то выкидывает, но он также не всемогущ.
По мне писать кучу комментариев, если это не обучающий код, - дурной тон. В идеале код должен вообще не содержать комментариев, т.е. быть само-документированным.
В твоем случае, я бы, например, создал наследника класса Adafruit_SSD1306 (аналогично с ds1307, но там можно и просто либу поправить под нужны), добавил ему методы init(), temperature(val), gear(val) и прочие. 
Тогда main будет проще читать и поддерживать. 
При выборе размер-скорость-простота кода я выбираю простоту кода, потом скорость, а уж потом место. С местом парился бы только в случае, если реально оно вдруг кончилось.
Пример инициализации портов для attiny13 (аля pinMode(..., INPUT))
	Код:
	
        ADCSRA |= (1<<ADPS2)|(1<<ADPS1);
        ADCSRA |= (1<<ADEN); 
        DDRB |= (1<<PB3);
        PORTB &= ~(1<<PB3);
        
        DDRB |= (1<<PB0);
        panel.mux = 2;
        panel.muxgnd = 3;
        panel.port = &PORTB;
        panel.portmask = (1<<PB4);
        PORTB |= (1<<PB0);
 Поддерживать такое можно только постоянно занимаясь программированием под МК и потому помня какие константы и где используются. 
Для тех, у кого МК хобби, т.е. большинство владельцев Arduino, такой код лучше избегать, поскольку уже через месяц не вспомнишь что он делает.
	 
	
	
	
		Re: Бортовой компьютер мотоцикла
	
	
		Ладно по экспериментирую потом с портами, вот такая структура получается, дальше пока не могу писать, тк нет полной обвязки от ардуино.
Осторожно много букф :D
	PHP код:
	
#include <MFRC522.h>
#include <OneWire.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h> 
#include <Adafruit_SSD1306.h> 
#include "RTClib.h"
#include <TimerOne.h> 
#include <EEPROM.h>
#define INTERRUPT__INT 0                       // 0 Внешнее прерывание
//#define Spare                                // 1
#define TEMP_DS18B20__DIGITAL_PIN 2            // 2 Цифровой датчик температуры
//#define Scl                                  // 3
#define GEAR_NEITRAL__DIGITAL_PIN 10           // 4 Минус при включении нейтрали
#define FAN_CONTROL_RUN__DIGITAL_PIN 5         // 5 Минус при включении вентилятора
#define FUELPOMP_CONTROL_RUN__DIGITAL_PIN 6    // 6 Минус при включении насоса
//#define Spare                                // 7
//#define Spare                                // 8
#define RST_PIN 9                              // 9 RFID
#define SS_PIN 10                              // 10 RFID
#define FUELPOMP_RELAY__DIGITAL_PIN 11         // 11 Включение реле топливного насоса
#define FAN_RELAY__DIGITAL_PIN 12              // 12 Включение реле вентилятора охлаждения
#define LED_ERROR__DIGITAL_PIN 13              // 13 Светодиод неисправности
#define FUEL_LEVEL__ANALOG_PIN 0               // 0 Датчик уровня топлива
#define TEMP_RESISTOR__ANALOG_PIN 1            // 1 Датчик температуры охлаждающей жидкости
//#define Spare                                // 2
//#define Spare                                // 3
#define GEAR_SWITCH__ANALOG_PIN 4              // 4 Номер передачи
#define IGN_ON__ANALOG_PIN 5                   // 5 Плюс при включении зажигания
//FAN ==========================================================================================================
// Глобальные переменные
int RELAY_CURENT; // Текущее состояние реле
int TEMP_CURENT_ANALOG; // Показания с АЦП 
byte flag_FAN_CYRENT = 0;
// Константы 
#define   LOW_COLING_FAN 2
#define  HIGH_COLING_FAN 3
#define ERROR_COLING_FAN 4
//_Timer()
int Timer = LOW;
unsigned long currentTime;
unsigned long loopTime;
int TEMP_ARRAY_FAN[4] = {88,110,120, 25}; // напряжение [отключение, включение, перегрев, по температуре окр. воздуха]
//SVITCH GEAR====================================================================================================
// Константы
#define UP_GEAR 300 // Делитель напряжения GEAR_SWITCH__ANALOG_PIN
#define DOWN_GEAR 550 // Делитель напряжения GEAR_SWITCH__ANALOG_PIN
// Глобальные переменные
int GEAR_CURENT;
//
int gear, neital;
int u, g;
boolean flag_gearH = false, flag_gearL = false;
//OUT_TEMP=======================================================================================================
OneWire  ds(TEMP_DS18B20__DIGITAL_PIN);
// Глобальные переменные
int OUT_TEMP_CORECTION = 10; // 0 - 20
int OUT_TEMP_CURENT =+ (OUT_TEMP_CORECTION - 10);
//DS1307 RTC =======================================================================================================
RTC_DS1307 RTC;
char ch_time[11]; 
int time_one = 70, timer_go;
//RFID=======================================================================================================
// Константы 
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.
// Глобальные переменные
unsigned long KEY1 = 2910087621;
unsigned long KEY2 = 4124219933;
unsigned long uidDec, uidDecTemp;  // Для отображения номера карточки в десятичном формате.
int KEY_OK;
//OLED Display=======================================================================================================
Adafruit_SSD1306 display(4); //OLED_RESET
#define LINE 20 // отступ линии от левого края
#define W_PRBAR 15 // ширина элемента прогресс бара
static const unsigned char PROGMEM logo16_glcd_bmp[] = 
{B11111111, B11111111, 
B11111111, B11111111,
B11111111, B11111111,
B11111111, B11111111,
B11111111, B11111111};
// Константы 
#define M_SERVIS 1
  #define SUB_TO2 10
  #define SUB_TO3 11
  #define SUB_OIL 12
  #define SUB_CHAIN 13
  
#define M_OPTION_FAN 2
  #define SUB_ERROR 21
  #define SUB_SET_TEMP 22
  #define SUB_T_OUT 23
  #define SUB_FAN_OFF 24
  
#define M_FAN 3
  #define SUB_STATUS 30
  #define SUB_AKTIV 31
  #define SUB_CORECT_OUT 32 
  #define SUB_CORECT_ENGIN 33
  
#define M_SPEED 4
  #define SUB_CORECT 40
  #define SUB_SPEED 41
#define M_ERROR1 5
#define M_RROR2 6
#define MAIN_MENU_MAIN 111
#define MAIN_MENU_ERROR 222
#define MAIN_MENU_TAIM 333
#define MAIN_MENU_KEY 444
int servis_Limit[4] = {12000, 6000, 3000, 1000};
//_______________________________________________________________________________________________________________
void setup()
{
  //Serial.begin(9600); 
/*  
  pinMode(FAN_RELAY__DIGITAL_PIN, OUTPUT);
  pinMode(GEAR_NEITRAL__DIGITAL_PIN, INPUT);  
  digitalWrite(GEAR_NEITRAL__DIGITAL_PIN, HIGH);
attachInterrupt(INTERRUPT__INT, blnk, FALLING);            // 0 Внешнее прерывание
pinMode(GEAR_NEITRAL__DIGITAL_PIN, INPUT);                 // 4 Минус при включении нейтрали
  digitalWrite(GEAR_NEITRAL__DIGITAL_PIN, HIGH);
pinMode(FAN_CONTROL_RUN__DIGITAL_PIN, INPUT);              // 5 Минус при включении вентилятора
  digitalWrite(FAN_CONTROL_RUN__DIGITAL_PIN, HIGH);
pinMode(FUELPOMP_CONTROL_RUN__DIGITAL_PIN, INPUT);         // 6 Минус при включении насоса
  digitalWrite(FUELPOMP_CONTROL_RUN__DIGITAL_PIN, HIGH);
pinMode(FUELPOMP_RELAY__DIGITAL_PIN, OUTPUT);              // 11 Включение реле топливного насоса
pinMode(FAN_RELAY__DIGITAL_PIN, OUTPUT);                   // 12 Включение реле вентилятора охлаждения
pinMode(LED_ERROR__DIGITAL_PIN, OUTPUT);                   // 13 Светодиод неисправности
*/
 Wire.begin();
 display.begin(SSD1306_SWITCHCAPVCC, 0x3C); 
 display.setTextColor(WHITE); 
 SPI.begin();   
 mfrc522.PCD_Init(); // Init MFRC522 card  
 RTC.begin(); 
 display.clearDisplay();
 _DispleyAddMenu(MAIN_MENU_KEY,0); // Надпись на дисплее "KEY ?"
 display.display();
}
 
void loop()
{
  if (_Timer(100, 5000) == 10) // Считываем температуру каждые 5 сек
  {
    TEMP_CURENT_ANALOG = analogRead(TEMP_RESISTOR__ANALOG_PIN); // Температуру двигателя
    _Out_Temp();  // Температуру наружного воздуха
  }
  _TempMonitoring(TEMP_CURENT_ANALOG);
  _Gear_Switch_Neutral();
  DateTime now = RTC.now();// Определяем время
  if (time_one == 70)  time_one = now.second() - 2;
  if (now.second() > time_one){timer_go = now.second() - time_one;}
  else {timer_go ++;}
  sprintf (ch_time,"%02i:%02i:%02i",now.hour(),now.minute(), timer_go);
  if (KEY_OK == 0){
    unsigned long tk = _ReadKeyRFID();
    if (tk == KEY1 || tk == KEY2) KEY_OK = 1;
    display.clearDisplay();
  }
  if (KEY_OK == 1){
  _DispleyAddMenu(MAIN_MENU_MAIN,0);
  
    display.display();
    display.clearDisplay();
    delay(1000);
  }
  
}
//________________________________________________________________________________________________________________
//FUNC ***********************************************************************************************************
unsigned long _ReadKeyRFID(){
 if ( !mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) return 0;
  for (byte i = 0; i < mfrc522.uid.size; i++) 
  {
    uidDecTemp = mfrc522.uid.uidByte[i];
    uidDec = uidDec*256+uidDecTemp;  
  }  
  return uidDec;
}
int _DispleyAddMenu(int fun, int str){ // номер функции, строка функции
      char* myStrings[]={"TO2", "TO3", "Oil","Chain", "Err Temp", "Temp On", "t out>30", "Temp Off"};
      char charBufVar[50];
      String stringVar;
      int iii;
      
  switch (fun) 
  {
   case M_SERVIS: // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      __dis(0, 0, 2, WHITE, 0);
      display.println(fun + String(">Servis"));
      if (str == SUB_TO2){ iii = servis_Limit[0]; stringVar = myStrings[0];}
      if (str == SUB_TO3){ iii = servis_Limit[1]; stringVar = myStrings[1];}
      if (str == SUB_OIL){ iii = servis_Limit[2]; stringVar = myStrings[2];}
      if (str == SUB_CHAIN){ iii = servis_Limit[3]; stringVar = myStrings[3];}
       __dis(0, 20, 2, WHITE, 0);
       stringVar.toCharArray(charBufVar, 50);
       display.println(charBufVar);
       __dis(0, 42, 3, WHITE, 1);
       display.println(iii); 
       break; // --- >
      
   case M_OPTION_FAN: // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      __dis(0, 0, 2, WHITE, 0);
      display.println(fun + String(">Opt Fan"));
      if (str == SUB_ERROR){ iii = TEMP_ARRAY_FAN[2]; stringVar = myStrings[4];}
      if (str == SUB_SET_TEMP){ iii = TEMP_ARRAY_FAN[1]; stringVar = myStrings[5];}
      if (str == SUB_T_OUT){ iii = TEMP_ARRAY_FAN[3]; stringVar = myStrings[6];}
      if (str == SUB_FAN_OFF){ iii = TEMP_ARRAY_FAN[0]; stringVar = myStrings[7];}
       __dis(0, 20, 2, WHITE, 0);
       stringVar.toCharArray(charBufVar, 50);
       display.println(charBufVar);
       __dis(0, 42, 3, WHITE, 1);
       display.println(iii); 
       break; // --- >
  case M_FAN: // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      __dis(0, 0, 2, WHITE, 0);
      display.println(fun + String(">Fan"));
          switch (str)
          {
          case SUB_STATUS:
              __dis(0, 20, 2, WHITE, 0);
              display.println("Status");
              __dis(0, 42, 3, WHITE, 0);
             if (flag_FAN_CYRENT == 1) display.println("ON");
             else display.println("OFF");
              break; // --- >
          
          case SUB_AKTIV:
              __dis(0, 20, 2, WHITE, 0);
               display.println("Activation");
              __dis(0, 42, 3, WHITE, 1);
              display.println("---"); 
              break; // --- >
               
          case SUB_CORECT_OUT:
              __dis(0, 20, 2, WHITE, 0);
               display.println("Out tem +-");
              __dis(0, 42, 3, WHITE, 1);
              display.println(OUT_TEMP_CORECTION + String("c")); 
              break; // --- >
              
          case SUB_CORECT_ENGIN:
              __dis(0, 20, 2, WHITE, 0);
               display.println("Eng tem +-");
              __dis(0, 42, 3, WHITE, 1);
              display.println(OUT_TEMP_CORECTION + String("c")); 
              break; // --- >              
          }   
 
      break; // --- >MAIN_MENU_TAIM
   case MAIN_MENU_TAIM: // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>      
      __dis(0, 0, 2, WHITE, 0);
      display.println("Time");
       __dis(0, 20, 2, WHITE, 0);
       display.println(ch_time);
       break; // --- >
   case MAIN_MENU_MAIN: // Главный экран
      __dis(0, 0, 8, WHITE, 0); // Номер передачи
      if (GEAR_CURENT == 0) display.println("N");
      display.println(GEAR_CURENT);
   
      __dis(50, 0, 2, WHITE, 0); // Температура за бортом
      display.println( String(OUT_TEMP_CURENT, DEC));
      for (int f=0; f< random(0, 65); f+=5) {
        display.drawBitmap(128 - W_PRBAR, 64 - f , logo16_glcd_bmp, W_PRBAR, 4, WHITE);
      }
      display.drawLine(128 - LINE, 64,128 - LINE , 0, WHITE); // линия
      break; // --- >
      
    case MAIN_MENU_KEY: // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
     __dis(0, 0, 4, WHITE, 0);
    display.println("NOKEY");
     __dis(0, 40, 1, WHITE, 0);
    display.println("Honda Varadero");
     __dis(0, 50, 1, WHITE, 0);
    display.println("computer v15.02.15");    
    break; // --- > 
  }
   display.display(); 
}
          
int __dis(int pos_s, int pos, int siz, int color, int flag){ // 1 позиция с лева, 2 с верху, 3 размер шрифта, 4 цвет 
  display.setTextSize(siz);
  display.setCursor(pos_s,pos);
 display.setTextColor(color);
  if (flag == 1)display.setTextColor(BLACK, WHITE); //Инверсия
}
int _Out_Temp() // Температура наружного воздуха
{
  byte i,present = 0,type_s,data[12],addr[8];
  float celsius;
  if ( !ds.search(addr)) ds.reset_search();
  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1);  
  present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);
  for ( i = 0; i < 9; i++) data[i] = ds.read();
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s){raw = raw << 3;if (data[7] == 0x10) raw = (raw & 0xFFF0) + 12 - data[6];}
  OUT_TEMP_CURENT = (float)raw / 16.0;
}  
int _Timer(int l, int h) // Возвращет 5 после времени 'l' и 10 после времени 'h'
  {
  currentTime = millis();                      
  if(currentTime >= (loopTime + l) && (Timer != HIGH)){loopTime = currentTime;Timer = HIGH;return 5;}
  if(currentTime >= (loopTime + h) && (Timer = HIGH)){loopTime = currentTime;Timer = LOW;return 10;}
}
int _TempMonitoring(int adc) // Считываем ацп указанного вывода, включаем или выключаем реле.
{
  if (adc > 150 ){_RelayColingFan(ERROR_COLING_FAN);return ERROR_COLING_FAN;} // Перегрев
  if (adc > 130){_RelayColingFan(HIGH_COLING_FAN);return HIGH_COLING_FAN;}    // Включаем
  if (adc <  80){_RelayColingFan(LOW_COLING_FAN);return LOW_COLING_FAN;}      // Выключаем
}
int _RelayColingFan(int atr) // Включение реле согласно принятому значению температуры
{
  switch (atr)
  {
    case LOW_COLING_FAN: // 80C
      digitalWrite(FAN_RELAY__DIGITAL_PIN, HIGH); // Выключено
      RELAY_CURENT = digitalRead(FAN_RELAY__DIGITAL_PIN);
      break;
 
    case HIGH_COLING_FAN: // 100C 
      digitalWrite(FAN_RELAY__DIGITAL_PIN, LOW); // Включено
      RELAY_CURENT = digitalRead(FAN_RELAY__DIGITAL_PIN);
      break; 
    
    case ERROR_COLING_FAN: // Перегрев
      break;
    
    default: //
    //
    break;
  }
}
int _Gear_Switch_Neutral()
{
  int anread = analogRead(GEAR_SWITCH__ANALOG_PIN);
  if (anread > DOWN_GEAR) {_Gear_Set(anread,DOWN_GEAR);gear = DOWN_GEAR;} // Если напряжение на делителе "равно" константе (замкнут геркон DOWN) то передаём в функцию напряжение и константу
    else if (anread > UP_GEAR) {_Gear_Set(anread,UP_GEAR);gear = UP_GEAR;} // Замкнут геркон UP
  if (anread == 0 && gear == DOWN_GEAR) {_Gear_Set(0,DOWN_GEAR);gear = 0;} // Передам в функцию ноль, геркон отключен
  if (anread == 0 && gear == UP_GEAR) {_Gear_Set(0,UP_GEAR);gear = 0;} //
  
  //if ( digitalRead(GEAR_NEITRAL__DIGITAL_PIN)== LOW ) {lcd.setCursor(0, 0); lcd.print("Neitral        "); GEAR_CURENT = 1;} //Если нейтраль то номер передачи равен одному
}
int _Gear_Set(int abc, int gear1)// Счётчик скоростей в переменной GEAR_CURENT / напряжение ацп, up или down.
{
  u = abc, g = gear1;
  if (u > g) {flag_gearL = true;}
  if (u == 0 && flag_gearL == true) {flag_gearH = true;}
  if (flag_gearH == true && flag_gearL == true)
  {
    flag_gearH = false; 
    flag_gearL = false; 
    if (g == UP_GEAR && GEAR_CURENT < 5) GEAR_CURENT++; //Ограничиваем наивысшую пердачу на 5
    if (g == DOWN_GEAR && GEAR_CURENT > 1) GEAR_CURENT--;//Ограничиваем низшую пердачу на 1
   }
}