Тема: ПИД терморегулятор DS18B20
Основная статья - http://rcl-radio.ru/?p=131968
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include <OneWire.h> // http://rcl-radio.ru/wp-content/uploads/2018/07/OneWire.zip
LiquidCrystal_I2C lcd(0x27,16,2); // Устанавливаем дисплей
OneWire ds(8); // Вход датчика 18b20
int nagrev,set,up,dw;
float temper,t,kpp = 1,kii = 0,kdd = 0;
unsigned long times,times1;
bool w;
void setup() {
lcd.init();lcd.backlight();lcd.clear();
Serial.begin(9600);
pinMode(9,OUTPUT);
cli();TCCR1A = 0;TCCR1B = 0;TCNT1 = 0;
TCCR1A = 1 << COM1A1 |1 << WGM11;
TCCR1B = 1 << WGM13 |1 << WGM12 |1 << CS12 | 1 << CS10;
TIMSK1 |= (1 << OCIE1A);
ICR1 = 5120;
OCR1A = 0; sei();
pinMode(2,INPUT_PULLUP);// UP
pinMode(3,INPUT_PULLUP);// DW
pinMode(4,INPUT_PULLUP);// SET
if(EEPROM.read(100)!=0){for(int i=0;i<101;i++){EEPROM.update(i,0);}}
t=EEPROM.read(1);
kpp = EEPROM.read(0);if(kpp==0){kpp=1;}
EEPROM.get(10, kii);
EEPROM.get(20, kdd);
delay(200);
}
void loop() {
if(digitalRead(4)==LOW){set++;if(set>3){set=0;}}
if(digitalRead(2)==LOW && set==0){if(up>10){t+=5;}else{t++;}up++;w=1;times1=millis();}
if(digitalRead(3)==LOW && set==0){if(dw>10){t-=5;}else{t--;}dw++;w=1;times1=millis();}
if(digitalRead(2)==HIGH){up=0;}if(digitalRead(3)==HIGH){dw=0;}
if(t<0){t=0;}if(t>100){t=100;}
if(digitalRead(2)==LOW && set==1){kpp++;;w=1;times1=millis();}
if(digitalRead(3)==LOW && set==1){kpp--;if(kpp<1){kpp=1;};w=1;times1=millis();}
if(digitalRead(2)==LOW && set==2){kii+=0.01;;w=1;times1=millis();}
if(digitalRead(3)==LOW && set==2){kii-=0.01;if(kii<0){kii=0;};w=1;times1=millis();}
if(digitalRead(2)==LOW && set==3){kdd++;;w=1;times1=millis();}
if(digitalRead(3)==LOW && set==3){kdd--;if(kdd<0){kdd=0;};w=1;times1=millis();}
delay(50);// период измерения dt
lcd.setCursor(0, 0);lcd.print("T=");
lcd.print(temper,1);lcd.print((char)223);lcd.print("C ");
lcd.setCursor(10, 0);lcd.print("P=");lcd.print(100.00/512.00*float(nagrev),0);;lcd.print("% ");
lcd.setCursor(0, 1);lcd.print("t=");lcd.print(t,0);lcd.print((char)223);lcd.print("C ");
lcd.setCursor(8, 1);
if(set==0){lcd.print(" PID ");}
if(set==1){lcd.print("kp=");lcd.print(kpp,0);lcd.print(" ");}
if(set==2){lcd.print("ki=");lcd.print(kii,2);lcd.print(" ");}
if(set==3){lcd.print("kd=");lcd.print(kdd,0);lcd.print(" ");}
if(millis()-times1>10000 && w==1){w=0;EEPROM.update(0,kpp);EEPROM.update(1,t);EEPROM.put(10, kii);EEPROM.put(20, kdd);
lcd.setCursor(8, 1);lcd.print(" SAVE ");delay(300);
}
}
ISR(TIMER1_COMPA_vect){
_delay_ms(50);temper = dsRead(0);_delay_ms(50);
nagrev = computePID(temper, t, kpp, kii, kdd, 0.3, 0, 512);
OCR1A = nagrev*10;
}
int computePID(float currentpoint, float setpoint, float kp, float ki, float kd, float dt, int minOut, int maxOut) {
static float last_error;
float P;
float D;
static float I;
signed int PID;
P = (setpoint - currentpoint);
I = (I + (setpoint - currentpoint) * dt);
if(I>511){I=511;}if(I<-511){I=-511;}
D = (((setpoint - currentpoint) - last_error) / dt);
last_error = setpoint - currentpoint;
PID = (kp * P) + (ki * I) + (kd * D);
return constrain(PID, minOut, maxOut);
}
float dsRead(byte x) {
byte data[2], addr[8][8], kol = 0;
while (ds.search(addr[kol])) { // поиск датчиков, определение адреса и кол-ва датчиков
kol++;
}
ds.reset_search(); // Сброс поиска датчика
ds.reset(); // Инициализация, выполняется сброс шины
ds.select(addr[x]); // Обращение к датчику по адресу
ds.write(0x44, 0); // Измерение температуры с переносом данных в память
ds.reset(); // Инициализация, выполняется сброс шины
ds.select(addr[x]); // Обращение к датчику по адресу
ds.write(0xBE); // Обращение памяти
data[0] = ds.read();// Чтение памяти byte low
data[1] = ds.read();// Чтение памяти byte high
float value = ((data[1] << 8) | data[0]) / 16.0; return (float)value; // Расчет температуры и вывод
}