#include "PID_v1.h"

const int setPointPin = A0;

//Переменные для ПИД регулятора
double Setpoint, Input, Output;

//Параметры ПИД регулятора
double Kp = 40, Ki = 40, Kd = 0; // ПИ
//double Kp = 40, Ki = 40, Kd = 7; // ПИД

//Объект ПИД регулятора
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, P_ON_E, DIRECT);

void setup()
{
  Serial.begin(115200);
  myPID.SetOutputLimits(0, 255); //диапазон выхода
  //индикаторы для отладки
  Setpoint = 0; //начальное значение уставки - ноль
  myPID.SetMode(AUTOMATIC); //включение регулятора
  Input = simPlant(0.0,1.0); //внутренняя модель входного сигнала
  Serial.println("Setpoint Input Output Watts");
}

void loop()
{
  float heaterWatts = (int)Output * 20.0 / 255; //мощность нагревателя для модели
  Input = simPlant(heaterWatts,Output>0?1.0:1-Output);//моделирование нагрева

  if (myPID.Compute()) //ПИД регулятор
  {
    Setpoint = analogRead(setPointPin) / 4; // чтение уставки температуры (от 0 до 255)
  }
  report(); //вывод отладочных данных в com порт
}

/*Функция вывода результата работы ПИД-регулятора*/
void report(void)
{
  static uint32_t last = 0;
  const int interval = 100; //вывод раз в секунду
  if (millis() - last > interval)
  {
    last += interval;
    Serial.print("time:");
    Serial.print((double)last/1000);
    Serial.print(" SP:");
    Serial.print(Setpoint);
    Serial.print(" PV:");
    Serial.print(Input);
    Serial.print(" CV:");
    Serial.print(Output);
    Serial.print(' ');
    Serial.println();
  }
}

/*Функция модели нагрева
Q - мощность [Вт],
hfactor - относительный коэффициент теплопроводности*/
float simPlant(float Q,float hfactor)
{
  //Имитация алюминиевого блока размером 1x1x2 см с нагревателем и пассивным охлаждением
  float h = 5 *hfactor ; // Вт/м2K коэффициент конвекции
  float Cps = 0.89; // теплоемкость Дж/грамм°C
  float area = 1e-4; // площадь конвекции, м2
  float mass = 1 ; // масса, граммы
  float Tamb = 25; // температура окружающей среды °C
  static float T = Tamb; // текущая температура °C
  static uint32_t last = 0; // время для моделирования
  uint32_t interval = 100; // период обновления данных, мс
  if (millis() - last >= interval)
  {
    last += interval;
    T = T + Q * interval / 1000 / mass / Cps - (T - Tamb) * area * h;
  }
  return T;
}
uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
pot1:VCC
pot1:SIG
pot1:GND