#include <tools.h> объявляет время работы, преобразование диапазонов, random() и PID. Заголовок использует uint32_t и bool из других заголовков: подключайте перед ним <dev.h> либо <stdint.h> и <stdbool.h>.

millis

  uint32_t millis(void);
  

Миллисекунды sysTime. Значение uint32_t оборачивается примерно через 49,7 суток. Для интервала используйте (uint32_t)(millis() - start); интервал должен быть короче полного оборота счётчика.

timePowerOff

  uint32_t timePowerOff(void);
  

Длительность предыдущего отключения питания в секундах. UINT32_MAX означает, что пригодная длительность не была определена. Значение вычисляется при запуске прошивки по сохранённой календарной метке; оно не равно uptime.

convInt

  int convInt(int in, int inMin, int inMax, int outMin, int outMax);
  

Линейно отображает входной диапазон [inMin, inMax] в выходной [outMin, outMax]. Используйте возрастающий входной диапазон. Значения за границами насыщаются: in <= inMin даёт outMin, in >= inMax даёт outMax. При равных входных границах возвращается outMax. Выходной диапазон может быть обратным. Расчёт не переполняет int32 на полном диапазоне аргументов. Дробная часть промежуточного смещения от outMin отбрасывается до сложения; это важно при обратном выходном диапазоне.

convFloat

  float convFloat(float in, float inMin, float inMax, float outMin, float outMax);
  

Линейно отображает входной диапазон [inMin, inMax] в выходной [outMin, outMax]. Используйте возрастающий входной диапазон. Значения за границами насыщаются: in <= inMin даёт outMin, in >= inMax даёт outMax. При равных входных границах возвращается outMax. Выходной диапазон может быть обратным. Передавайте конечные аргументы. Специальной проверки NaN, Inf и некорректного порядка входных границ нет.

convDouble

  double convDouble(double in, double inMin, double inMax, double outMin, double outMax);
  

Линейно отображает входной диапазон [inMin, inMax] в выходной [outMin, outMax]. Используйте возрастающий входной диапазон. Значения за границами насыщаются: in <= inMin даёт outMin, in >= inMax даёт outMax. При равных входных границах возвращается outMax. Выходной диапазон может быть обратным. Передавайте конечные аргументы. Специальной проверки NaN, Inf и некорректного порядка входных границ нет.

random

  uint32_t random(uint32_t start, uint32_t stop);
  

Возвращает uint32_t в полуинтервале [start, stop): start включён, stop исключён. Требуется start < stop; функция сама не проверяет порядок и пустой диапазон. Это отдельный механизм от rand()/srand(); не используйте его как криптографическую гарантию.

PID-регулятор

  typedef struct {
  bool     useLimits;
  float    min;
  float    max;
  float    kP;
  float    kI;
  float    kD;
  float    integral;
  float    lastError;
  float    lastOutput;
  uint32_t lastTime;
} pid_t;
  

Объект pid_t хранится у вызывающего кода. На один независимый регулятор нужен отдельный объект. Проверка указателя на NULL не выполняется.

pidInit

  void pidInit(pid_t * pid, float kP, float kI, float kD, float min, float max);
  

Записывает kP/kI/kD, min/max и вызывает pidReset(). Ограничения выхода включаются при min < max; при min >= max не применяются. Поле useLimits в текущей реализации не используется: не рассчитывайте на переключение ограничений через него.

pidReset

  void pidReset(pid_t * pid);
  

Сбрасывает интеграл, предыдущую ошибку и выход, помечает объект как ещё не выполнявшийся. Коэффициенты и min/max сохраняются.

pidStep

  float pidStep(pid_t * pid, float measurement, float setPoint);
  

Ошибка равна setPoint-measurement. Первый вызов возвращает пропорциональную составляющую с учётом min/max. Далее dt вычисляется по millis(): при dt < 50 мс возвращается предыдущий выход, при dt > 5 минут состояние сбрасывается и возвращается 0. Интеграл учитывает секунды, производная — изменение ошибки за секунду. При включённых границах ограничиваются интеграл и итоговый выход. Это не гарантия отсутствия интегрального насыщения во всех режимах.

Пример расчёта без изменения выходов

  #include <dev.h>
#include <tools.h>
#include <stdio.h>

int main(void) {
    pid_t regulator;
    pidInit(&regulator, 2.0f, 0.1f, 0.0f, 0.0f, 100.0f);
    float result = pidStep(&regulator, 18.0f, 20.0f);
    printf("PID: %.2f; map: %d\n", (double)result, convInt(50, 0, 100, 0, 1000));
    return 0;
}