#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
const byte averageFactor = 7;  // коэффициент сглаживания показаний (0 = не сглаживать)
// что можно настраивать
const float LineLimit = 5;              // предел шкалы, бар
const float WarnLow = 0.1;              // нижний предел по давлению, Бар
const float WarnHigh = 9.0;             // верхний предел по давлению, Бар
const int WarnZummerCounterLimit = 60;  // ограничение по количеству вяков для пищалки
const int pToneDefault = 1300;          // начальный тон для пищалки, Гц
// чем выше, тем больше "инерционность"
// точки аппроксимаци
const float U1 = 0.5;                   // напряжение 1, В
const float P1 = 0;                     // давление 1, Бар
const float U2 = 4.5;                   // напряжение 2, В
const float P2 = 10.34;                 // давление 2, Бар
const int lightPin = 2;     // пин, контролирующий подсветку
const int piezoPin = 3;     // пин, к которому подключен пьезодинамик
const int sensorPin = A0;   // пин, к которому подключен датчик давления
int lightStateCounter = 0;  
int lightState = 0;         
int lastLightState = LOW;     
unsigned long lastDebounceTime = 0;  
unsigned long debounceDelay = 50;    
int sensorValue = 0;                    
int i = 0;
int j = 0;
float sValue = 0;
float uValue = 0;
float Vcc = 5.0;                        // опорное напряжение АЦП, для пересчета в напряжение
float pValue = 0;
int WarnBlinkCounter = 0;
int WarnZummerCounter = 1;
int pTone;                              // тон для пищалки
float dX = 0;
float x1, y1, x2, y2, k, b;
#define LOGO_HEIGHT   16
#define LOGO_WIDTH    44
const unsigned char logo_bmp [] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x7f, 0x03, 0xc0, 0x00,
  0x00, 0x00, 0x61, 0xc1, 0x80, 0x00, 0x0f, 0x00, 0x60, 0xe1, 0x80, 0x00, 0xf9, 0x80, 0x78, 0x7f,
  0xfc, 0x0f, 0xe0, 0xc0, 0x1f, 0xc0, 0x07, 0xfd, 0xc0, 0x00, 0x03, 0xc0, 0x03, 0xc1, 0x80, 0x00,
  0x00, 0xc0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0x00, 0x06, 0x00, 0x40, 0x00, 0x40, 0x00, 0x0e,
  0x00, 0x40, 0x00, 0x40, 0x00, 0x1c, 0x00, 0x60, 0x00, 0x40, 0x00, 0x18, 0x00, 0xe0, 0x00, 0x7f,
  0xff, 0xf0, 0x00, 0xf0, 0x00, 0xff, 0xff, 0xe0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
void setup()
{
   
  pinMode(lightPin, INPUT);   // initialize the light control pin as a input:
  digitalWrite(lightPin, 1);
  delay(1000);                // пауза перед включением
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  // определение коэффициентов линейного полинома напряжение-давление
  y1 = P1;
  y2 = P2;
  x1 = U1 / Vcc * 1024;
  x2 = U2 / Vcc * 1024;
  k = (y1 - y2) / (x1 - x2);
  b = y2 - k * x2;
  pTone = pToneDefault;
  
  // отрисовка масленки
  display.drawBitmap(
    (display.width()  - LOGO_WIDTH ) / 2,
    (display.height() - LOGO_HEIGHT) / 2,
    logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
  display.display();
  //  display.dim(false);           // снижение яркости
  delay(2000);
  // Clear the buffer
  display.clearDisplay();
  // смещение масленки вниз за пределы экрана
  for (i = ((display.height() - LOGO_HEIGHT) / 2);
       i < (display.height() + LOGO_HEIGHT / 2);
       i += 2 )
  {
    display.drawBitmap(
      (display.width()  - LOGO_WIDTH ) / 2,
      i,
      logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
    display.display();
    delay(50);
    display.clearDisplay();
  }
//  display.fadeout();
}
void loop()
{
  lightState = digitalRead(lightPin);
  if (averageFactor > 0)        // усреднение показаний для устранения "скачков" барометра
  {
    int oldsensorValue = sensorValue;
    sensorValue = analogRead(sensorPin);
    sensorValue = (oldsensorValue * (averageFactor - 1) + sensorValue) / averageFactor;
  }
  display.setTextColor(WHITE);
  sValue = sensorValue;
  pValue = k * sValue + b;  // давление в Барах
  display.setCursor(5, 0);
  // исключение отрицательного давления
  if (pValue < 0)
  {
    pValue = 0;
  }
  display.setTextSize(3);
  display.print(pValue);
  display.setTextSize(2);
  display.setCursor(85, 0);  //80,8
  display.print("ba");
     if (lightState == HIGH) 
      {
        display.print("1");
      }
      else
      {
        display.print("0");
      }
  // сигнал низкого или высокого давления
  if ((pValue <= WarnLow) or (pValue >= WarnHigh))
  {
    // моргаем дисплеем
    if (WarnBlinkCounter <= 10)
    {
      display.invertDisplay(false);
      noTone(piezoPin); // Остановили звучание
      ++WarnBlinkCounter;
    }
    else
    {
      display.invertDisplay(true);
      noTone(piezoPin);
      pTone = pTone * 1.25;
      if (WarnZummerCounter > 0)
      {
        tone(piezoPin, pTone); // Запустили звучание
        ++WarnZummerCounter;
        if (WarnZummerCounter > WarnZummerCounterLimit * 2)
        {
          WarnZummerCounter = 0;
        }
      }
      ++WarnBlinkCounter;
      if (WarnBlinkCounter >= 13)
      {
        WarnBlinkCounter = 0;
        pTone = pToneDefault;
      }
    }
  }
  else
  {
    display.invertDisplay(false);
    noTone(piezoPin); // Остановили звучание
    WarnBlinkCounter = 0;
    pTone = pToneDefault;
    WarnZummerCounter = 1;
  }
  // рисуем полоску
  dX = (display.width() - 6) / LineLimit;
  for (j = 2; j < 6; j++)
  {
    display.drawLine (0, display.height() - j , pValue * dX, display.height() - j , 1);
  }
  for (j = 0; j < (display.width() - 1); j += round(dX))
  {
    display.setCursor(j, display.height() - 7);
    display.setTextColor(1, 0);
    // символ размером 5x7 пикселей.
    display.setTextSize(1);
    display.print(round(j / dX));
  }
  display.display();
  delay(50);
  // Clear the buffer
  display.clearDisplay();
}