ПИ регулятор отопления
Страница 1 из 1
Чего нехватает?
ПИ регулятор отопления
Представляю ПИ терморегулятор на микроконтроллере ATMega8. Прошивка написана в среде Ардуино и залита через Arduino ISP. В качестве датчика температуры использован NTC терморезистор на 10кОм при 20 градусах цельсия. Регулятор имеет релейный выход, выбор реле осуществляеться по необходимой мощности нагревателя. Регулятор можно использовать как с электроконвекторами так и с другими нагревательными приборами. Регулятор может выдавать мощность с точностью до 1% (в связи с тем что выход релейный а продолжительность минимального управляющего воздействия 500мс минимальная мощность ограничена 4%-2сек.). По сути организован медленный ШИМ с периодом 500мс.
Небольшая особенность представленной схемы в том что питание на терморезистор подаеться только в момент измерения, что помогает избежать саморазогрев терморезистора. На схеме не указан LCD но из скетча должно быть понятно к каким выводам он подключен.
- Код:
//кнопки А0, реле 13,12 подсветка 10
#include <LiquidCrystal.h>
#define key_in analogRead(0)//вход аналоговых кнопок
#define T_Sensor_OFF digitalWrite(16,LOW)//отключить термистор
#define T_Sensor_ON digitalWrite(16,HIGH)//включить термистор
#define HI_OFF digitalWrite(13,LOW)//отключить реле HI
#define HI_ON digitalWrite(13,HIGH)//включить реле HI
//#define LO_OFF digitalWrite(12,LOW)//отключить реле LO
//#define LO_ON digitalWrite(12,HIGH)//включить реле LO
#define n_f 10.0//температура по умолчанию
#define p_s 50//частота обновления экрана
#define t_pwm 600//период ШИМ
#define t_time 1000//период опроса температуры
//для ПИ регулятора
float p,i;
LiquidCrystal lcd(7,6,5,4,3,2);
long time;//интервал замера температуры
long lcd_time;//интервал отрисовки экрана
long on_time;//для периода ШИМ
int zad=0;
int k_b[]={
512,683,768};//аналоговые кнопки SET + -
float temp=0.0;//текущее значение температуры
float pre_temp=0.0;//предыдущее значение температуры
int w=0;
float ust=n_f;//termostate
int c=0;//пройденые циклы мощности
float addr[25][2] = {
{
0,32.0
}
,
{
5,25.5
}
,
{
10,20.0
}
,
{
15,15.7
}
,
{
20,12.62
}
,
{
25,10.0
}
,
{
30,8.24
}
,
{
35,6.63
}
,
{
40,5.41
}
,
{
45,4.41
}
,
{
50,3.62
}
,
{
55,2.99
}
,
{
60,2.48
}
,
{
65,2.08
}
,
{
70,1.75
}
,
{
75,1.47
}
,
{
80,1.258
}
,
{
85,1.063
}
,
{
90,0.905
}
,
{
95,0.776
}
,
{
100,0.669
}
,
{
105,0.581
}
,
{
110,0.505
}
,
{
115,0.442
}
,
{
120,0.387
}
,
};
byte cel[] =
{
0b01000,
0b10100,
0b01000,
0b00111,
0b01000,
0b01000,
0b00111
};
void setup(){
// Serial.begin(9600);
pinMode(13,OUTPUT);//реле HI
// pinMode(12,OUTPUT);//реле LO
pinMode(16,OUTPUT);//питание термистора
T_Sensor_OFF;
HI_OFF;//отключить реле HI
// LO_OFF;//отключить реле LO
lcd.begin(16, 2);
analogWrite(10,250);//подсветка
time = millis();
lcd_time = time;
on_time = time;
lcd.createChar(1, cel);
}
void loop(){
key();//опрос кнопок
if (time>millis()){//защита от переполнения
time=millis();
lcd_time=time;
on_time=time;
}
//---------------чтение температуры---------------
if ((millis()-time)>=t_time){
time=millis();
temp=getTemp();
temp=(pre_temp*0.2)+(temp*0.8);//фильтр
// w=abs((ust-temp)*(pre_temp-temp));//время выхода на уставку
pre_temp=temp;
PIctl();//расчет мощности
}
//-------------------вывод на экран----------------
if ((millis()-lcd_time)>=p_s){//вывод на экран
lcd_time=millis();
Screen_print();
}
//---------------------управление мощностью--------------------------
//выдаем мощность
if (millis()>3000){
if((millis()-on_time)>=t_pwm){//период ШИМ
on_time=millis();
if(c<zad){
HI_ON;
}
else{
if (zad != 100){
HI_OFF;
}
}
c=c+1;
if(c==100){
c=0;
//PIctl();
}
}
}
}
void PIctl()
{
if(temp>(ust-0.5)&&temp<(ust+0.5))//зона нечувствительности +-0,5C
{
zad=i;
}
else
{
float e;
e=(ust-temp);
// расчет выходной мощности:
p=130.0*e;//130 коффициент пропорциональности
if (p<0.0)
{
p=0.0;//ограничение P
}
i=(i+(e*0.014));//0.7
if (i>100.0)
{
i=100.0;//ограничение I
}
if (i<-100.0)
{
i=-100.0;//ограничение I
}
//расчет выходной мощности
zad=p+i;
}
//ограничение управляющего сигнала
//для исключения частого переключения реле
//если твердотельное реле, можно не ограничивать
if (zad<4){
zad=0;
}
if (zad>96){
zad=100;
}
//корректировка при отклонении температуры более чем на +-2С
//для быстрого выхода на уставку
if (temp<(ust-2.0))//если темп < уст на 2С
{
zad=100;//то мощность 100%
i=0;
}
if (temp>(ust+2.0))//если темп > уст на 2С
{
zad=0;//то мощность 0%
i=0;
}
}
//----------------опрос клавиш-------------------------------
void key(){
int x;
x = key_in;
if (x>k_b[0]-5 && x<k_b[0]+5){//МЕНЮ
UP_butt();
key_m(0);
}
if (x>k_b[1]-5 && x<k_b[1]+5){// +
UP_butt();
key_m(1);
}
if (x>k_b[2]-5 && x<k_b[2]+5){// -
UP_butt();
key_m(2);
}
}
//---------------проверка отпускания кнопки-----------------
void UP_butt(){
while (key_in<1010){//ждем отпускания кнопки
}
}
//------------------замер температуры----------------------
double getTemp()
{
T_Sensor_ON;
delay(10);//задержка при подаче питания терморезистора
int t;
t=0;
for (int i=0; i <= 15; i++){
//for (int i=0; i <= 4; i++){
t = t + analogRead(1);
}
// T_Sensor_OFF;
t=t/4;
//t=t/5;
float R;
R=getR(t);
int i=0;
while (addr[i][1] >R)
{
i++;
}
double result;
result=(R-addr[i][1])*(addr[i-1][0]-addr[i][0])/(addr[i-1][1]-addr[i][1])+addr[i][0];
return result;
}
float getR(float V)
{
float result;
result=-10*V/(V-4096);
//result=-10*V/(V-1024);
T_Sensor_OFF;
return result;
}
//-----------------обработка кнопок-------------------------
void key_m(int x){
// lcd.clear();
switch (x){
case 0://menu
ust=10;
break;
case 1://кнопка +
ust++;
if (ust>35){
ust=35;
}
break;
case 2://кнопка -
ust--;
if (ust<5){
ust=5;
}
break;
}
}
int oversempling(){
T_Sensor_ON;
delay(10);//задержка при подаче питания терморезистора
int o;
o=0;
for (int i=0; i <= 15; i++){//оверсемплинг до 4096
//for (int i=0; i <= 4; i++){
o = o + analogRead(1);
}
T_Sensor_OFF;
o=o/4;
//t=t/5;
return o;
}
void Screen_print()
{
byte a=0;
byte b=0;
tempPrint(temp,0,0);
tempPrint(ust,0,1);
lcd.setCursor(6, 0);
lcd.print(zad);
lcd.print("% ");
varPrint(i,"I ",6,1);
// lcd.print("I ");
lcd.setCursor(12, 0);
lcd.print(c);
lcd.print("m ");
a=digitalRead(13);
b=digitalRead(12);
if (a==1 && b==0){
lcd.setCursor(12, 1);
lcd.print("HI ");
}
if (a==0 && b==1){
lcd.setCursor(12, 1);
lcd.print("LO ");
}
if (a==0 && b==0){
lcd.setCursor(12, 1);
lcd.print("OFF");
}
}
//-------------вывод температуры----------------------------
void tempPrint(double t, int x, int y){
lcd.setCursor(x, y);
lcd.print(t);
lcd.setCursor(x+4, y);
lcd.print(char(1));//вывод градусов
}
//---------------вывод переменной-------------------------
void varPrint (double v, char* t, int x, int y){
lcd.setCursor(x, y);
lcd.print(v);
lcd.print(t);
}
Страница 1 из 1
Права доступа к этому форуму:
Вы не можете отвечать на сообщения
|
|