Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.

termostat - obicni (digitalni sa ntc-om i rotary encoderom)

[es] :: Elektronika :: Mikrokontroleri :: termostat - obicni (digitalni sa ntc-om i rotary encoderom)

Strane: 1 2

[ Pregleda: 9745 | Odgovora: 22 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

bogdan.kecman
Bogdan Kecman
"specialist"
Oracle
srbistan

Član broj: 201406
Poruke: 15887
*.31.24.217.adsl2.beograd.com.

Sajt: mysql.rs


+2377 Profil

icon termostat - obicni (digitalni sa ntc-om i rotary encoderom)12.08.2010. u 05:16 - pre 165 meseci
budzio sam ovaj moj kontroler za vrucu platformu za stampanje da bi umesto dva tastera stavio rotary enkoder i da bi napravio malo bolju kontrolu temperature posto mi je sa obicnim on/off zbog termalne inercije prebacivao po 10-15 stepeni zadatu temperaturu (ja ga ugasim na 170C a on se onda u narednih 5-6 minuta dobaci do 185 pa tek onda krene da se hladi) ... i dalje nema pravi PID vec sam "seljackom metodom" pravio "low frequency pwm" (600ms perioda) i to 5%, 25%, 50% i 75% duty cycle i switchujem izmedju njih (i 0 i 100% naravno) tako da kada se priblizim zadatoj temperaturi krenem da ga grejem samo sa 5% ....

posto grejem sa AC (~70V) preko moc-a sa cross over detection-om i nekog triaka nisam hteo da vucem na pic da radim tamo detekciju nule pa da radim 180 stepeni kontrolu pwm-om vec sam isao na ovaj "low frequency" pwm tako da nemam gadan sum na zici (koji bi imao u slucaju da secem deo periode) a kako je termalna inercija povelika 600ms je vise nego dovoljno ... prostom promenom prescalera za timer1 ova vrednost moze da se promeni :)


Prikačeni fajlovi
 
Odgovor na temu

veselinovic
Jovan Veselinovic
Ist. Sarajevo

Moderator
Član broj: 7761
Poruke: 3860
adsl-218-3.teol.net.



+333 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)12.08.2010. u 11:01 - pre 165 meseci
Bogdane, rekoh ti ja, kad tad ces morati preci na neki normalan zakon upravljanja ( mozda ne PID nego PI).
Ti sad imas neki nelinearan P reulator.
Ja se jos uvijek nudim da se proba moj diplomski rad.
 
Odgovor na temu

bogdan.kecman
Bogdan Kecman
"specialist"
Oracle
srbistan

Član broj: 201406
Poruke: 15887
*.31.24.217.adsl2.beograd.com.

Sajt: mysql.rs


+2377 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)12.08.2010. u 15:08 - pre 165 meseci
video si source ... radi prilicno dobro (i super jednostavno) ...

elem sto se diplomskog tice, ako imas source i mozemo da ga uglavimo na ovaj HW, daj da probam ... ako mora neki drugi hw i to je moguce samo nece biti "odma"
 
Odgovor na temu

veselinovic
Jovan Veselinovic
Ist. Sarajevo

Moderator
Član broj: 7761
Poruke: 3860
62.101.128.94



+333 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)12.08.2010. u 17:18 - pre 165 meseci
Eh, nemam ispravan source, ali postoji svega par formulica ( racunanja).
HW je OK ako radi,
izlaz iz formulica je 0-1 ili bilo koja skalirana vrijednost, mozes zakaciti 4-20 mA, mozes PWM, mozes 0-10V, ma moze sta oces.
 
Odgovor na temu

bogdan.kecman
Bogdan Kecman
"specialist"
Oracle
srbistan

Član broj: 201406
Poruke: 15887
*.31.24.217.adsl2.beograd.com.

Sajt: mysql.rs


+2377 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)12.08.2010. u 20:20 - pre 165 meseci
pazi .. ja imam

1. prethodnu temperaturu (iz prethodog merenaj)
2. sadasnju temperaturu (izracunatu kao (prethodna*3+sadaizmerena)/4 ili (prethodna+sadaizmerena*3)/4 zavisi sta hocu da izveedm)
3. zadatu temperaturu

kao izlaz mi treba
- upali grejac / ugasi grejac

jel tebi izlaz od 0 do 1 (0, 0.1, 0.2 ... 0.9, 1) ili 0/1 ?
pwm nad AC signalom nije bas tako jednostavan, ja sam napravio ovaj PWM frekvencije 1.6Hz .. to se ne bi nazvalo PWM zato sam ga i podelio u par segmenata a ne 0-100%


daj formule pa da probamo :)
 
Odgovor na temu

grabik

Član broj: 32507
Poruke: 311
*.adsl.net.t-com.hr.



+7 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)13.08.2010. u 07:18 - pre 165 meseci
Citat:
bogdan.kecman: video si source ... radi prilicno dobro (i super jednostavno) ...

elem sto se diplomskog tice, ako imas source i mozemo da ga uglavimo na ovaj HW, daj da probam ... ako mora neki drugi hw i to je moguce samo nece biti "odma"


Pravio sam prije termostat za inkubator sa PID regulacijom i imao je manje linija u C kodu nego ovaj tvoj, pretpostavljam da je kompajliran kod sa PID mnogo duzi od tvog:)

Ja sam radio sa 18F i drzao je temperaturu prakticno "zaglavljenu" na 0,1C.

Kako se radi o racunanju sa pokretnim zarezom PIC16F bas i nisu neki dobar izbor mc-a, kompajlira se dosta veliki hex ali kako je regulacija temperature prilicno spor proces moguce da ga i 16F moze odraditi ako uspje da stane u memoriju pica.

A sto se tice koda za PID imas na elektrodi nekoliko primjera a ima i atmelov kod u c-u koji ne koristi racunanje decimalama, isto radi jako dobro. Ako ne uspjes naci prekopacu ja po mom kompu pa cu ti postati kod za PID.

Da bi izvukao maksimum iz PI ili PID regulacije moras ubaciti dobre PID koeficijente.

Da li si probao bez vanjskog smit kola ,trebalo bi da pic vec to ima ja sam koristio opticke enkodere bez, mehanici trebaju kondenzatore zbog istitravanja kontakata.
 
Odgovor na temu

veselinovic
Jovan Veselinovic
Ist. Sarajevo

Moderator
Član broj: 7761
Poruke: 3860
adsl-205-240.teol.net.



+333 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)13.08.2010. u 07:34 - pre 165 meseci
Bogdane, veceras dobijas kompletan rad sa sve formulama.
Ovo sto sam radio je digitalni regulator sa samopodesavajucim parametrima, i minimum trajanja prelaznog procesa.
 
Odgovor na temu

grabik

Član broj: 32507
Poruke: 311
*.adsl.net.t-com.hr.



+7 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)13.08.2010. u 13:11 - pre 165 meseci
PID kod. Nemam momentalno vremena za objasnjavanje , PID koeficijenti bi trebalo da budu manji od 1.

Code:

 // Get the current temperature value 
   Temperature_measured_G = PID_Temperature_read_curent();
    // Get the desired temperature value 
   Temperature_required_G = (float) temperatura;
     // Difference between required and actual temperature 
   Error = (float)Temperature_required_G - Temperature_measured_G;
    if(PID_PROPORTIONAL){
   // Proportional term
   Control_i = (float)((Error * PID_PROPORTIONAL));
    }
   // Integral term [SET TO 0 IF NOT REQUIRED]
   if (PID_INTEGRAL)
      {
      Sum_G += Error;
      Control_i +=(float) ((Sum_G * PID_INTEGRAL));
      }
   // Differential term [SET TO 0 IF NOT REQUIRED]
   if (PID_DIFFERENTIAL)
      {
      Control_i += (float)((PID_DIFFERENTIAL ) * (Error - Old_error_G));
      // Store error value
      Old_error_G = Error;
      }
   // Adjust to 100%
    if (Control_i > 100)
      {
      Control_i = 100;
      Sum_G -= Error;  // Windup protection
      }
   if (Control_i <= 0)
     {
     Control_i = 0;
      Sum_G -= Error;  // Windup protection
     }
    PWM=Control_i;

 
Odgovor na temu

bogdan.kecman
Bogdan Kecman
"specialist"
Oracle
srbistan

Član broj: 201406
Poruke: 15887
*.31.24.217.adsl2.beograd.com.

Sajt: mysql.rs


+2377 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)13.08.2010. u 22:36 - pre 165 meseci
veselinovic, kad posaljes probacemo

grabik, znam ja kako sljaka pid kontrola generalno, video i gomilu primera i slicno, takodje cuvam temperaturu kao *100 vrednost (ako si gledao kod znas) da ne bi morao da radim sa float vrednostima (16F nije bas za float racunicu). sto se kontrole tamo tice ne vidim "mnogo linija" (nije da se broj linija racuna kao neki validan pokazatelj bilo cega)?

Code:

void pid(){ 
  static int8 DC = 0;
  if (current >= target) {
    h_off();    
    DC = 0;
  } else if (current > (target -  700)) {
    if (DC != 5){
      h_5();
      DC = 5;
    }
  } else if (current > (target - 1300)) {
    if (DC != 25){
      h_25();
      DC = 25;
    }
  } else if (current > (target - 2000)) {
    if (DC != 50){
      h_50();
      DC = 50;
    }
  } else if (current > (target - 2500)) {
    if (DC != 75){
      h_75();
      DC = 75;
    }
  } else  {
    h_on();
    DC = 100;
  }  
}


iliti skraceno:

Code:

void pid(){ 
  if (current >= target) {
    PWM=0;
  } else if (current > (target -  700)) {
    PWM=0.05;
  } else if (current > (target - 1300)) {
    PWM=0.25;
  } else if (current > (target - 2000)) {
    PWM=0.5
  } else if (current > (target - 2500)) {
    PWM=0.75
  } else  {
    PWM=1;
  }  
}


fora je sto ja ne mogu da gadjam ac signal obicnim pwm-om kao sto bi radio sa DC signalom no taj deo je valjda jasan ... teoretski mogu da promenim h_##() u h(0-100) ali sam za pocetak prvo pravio ovako posto iskreno nisam nikada ranije radio ovakav PWM (1.6Hz !!) pa sam prvo hteo da vidim "dal ce to uopste da radi" i kako ce se ponasati ova alu ploca ...

elem sto se "pravog" pid-a tice (proporcionalno/integralno/diferecialne kontrole), zakacio sam neki "poskupi" pid kontroler na plocu i vristao od smeha - usaglasio je on temperaturu i drzao je na +-0.1C ali posle ~45minuta :D ovaj seljacki kod mi drzi na +-3 stepena al dodje tu za 5 min i "odma" je stabilan :) .. sve u svemu, laganica, sada kada "radi" lako ga je dalje budziti ..
 
Odgovor na temu

grabik

Član broj: 32507
Poruke: 311
*.adsl.net.t-com.hr.



+7 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)14.08.2010. u 10:05 - pre 165 meseci
Neznam kakav je to PID kontroler bio mozda kineski ili sa losim PID koeficijentima, ja sam isprobao omron i watlov i to radi vise nego dobro, prvi jos ima auto namjestanje PID vrijednosti, kad mu ukljucis auto setovanje treba mu malo vremena ali to se ionako radi jednom.

Tvoj kod je pojednostavljena proporcionalna regulacija nesto slicno sam i ja koristio dok nisam skopcao kako pravilno namjestiti PID regulaciju.

Najbolju regulaciju temperature sam dobijao da ne koristim klasicni PWM vec uzmem recimo period od 5 sekundi i sa PID regulatorom odredjujem trajanje ukljucenja grijaca, recimo uzmem da je minimum vremena ukljucenja nekoliko ms a max 5000ms i dobijam vecu rezoluciju regulacije nego sa 10bitnim PWM koji je u PIC-u, zbog termicke inercije takva regulacija radi vrlo dobro, normalno moras naci i korektno vrijeme za osvjezavanje PID kalkulacija ne valja ako je prebrzo a ni presporo.

 
Odgovor na temu

bogdan.kecman
Bogdan Kecman
"specialist"
Oracle
srbistan

Član broj: 201406
Poruke: 15887
*.31.24.217.adsl2.beograd.com.

Sajt: mysql.rs


+2377 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)14.08.2010. u 18:22 - pre 165 meseci
ja sam napravio "pwm" sa 1.6Hz (dakle 600ms mi je perioda) posto sa integrisanim pwm-om nema svrhe raditi (koja poenta udaranja 10KHz pwm-a po 50Hz signalu)... mogu da probam da napravim jos sporije ali mislim da nema potrebe, doduse pitanje i kako bi se ponasalo na duze, posto imam 0.5KW grejac koji greje 1kg alu plocu izolovanu sa 5 strana ... imam nekad i 5-6C/sec promenu temperature sto bi reklo da sa 5s dok on svati da treba da ga ugasi imam 20C overshoot

komercijalni pid kontroler je neki "talijan" .. LAE AC1-5 ... radi extra u nekoj pecki, isto u nekim ormarima za hladjenje .. drzi temperaturu zakucanu .. nemam pojma sto je kod mene pravio problem, mozda ga nisam dobro nasetovao ..

sve u svemu ova "budzevina" sada radi 1/1 ... ako veselinovic posalje ono njegovo - probacemo, ako uvatim koji minut probacu i ovaj tvoj kod ... sve u svemu, samo da izdrzim do kraja septembra i onda mi se kolicina slobodnog vremena opet drasticno povecava pa cu moci kao covek da se igram :D
 
Odgovor na temu

veselinovic
Jovan Veselinovic
Ist. Sarajevo

Moderator
Član broj: 7761
Poruke: 3860
62.101.128.94



+333 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)17.08.2010. u 16:26 - pre 165 meseci
Saljem citav rad samo daj mail.
 
Odgovor na temu

bogdan.kecman
Bogdan Kecman
"specialist"
Oracle
srbistan

Član broj: 201406
Poruke: 15887
*.com
Via: [es] mailing liste

Sajt: mysql.rs


+2377 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)17.08.2010. u 16:56 - pre 165 meseci
bogdan.kecman [na] sun.com
 
Odgovor na temu

bogdan.kecman
Bogdan Kecman
"specialist"
Oracle
srbistan

Član broj: 201406
Poruke: 15887
*.31.24.217.adsl2.beograd.com.

Sajt: mysql.rs


+2377 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)30.08.2010. u 10:12 - pre 165 meseci
uh bre .. ovo je mnogo komplikovanije nego sto deluje ... elem, 18F2423 mcu je dosao umesto ovog 16F, najvise zato sto mi je zafalilo flash-a a zafalio mi je i jedan pin za jos jedan NTC a kako je ovo bio najmanji sledeci pic po fiokama ...

novosti
- dodat je output na rs232 port (ispisuje: prosecnu temperaturu ploce \t temperaturu na NTC1 *100 \t temperaturu na NTC2 *100 \t target temperatur *100 \t trenutnu vrednost PWM-a u % \t broj gresaka na RS232 portu
- RS232 izlaz moze da se iskljuci (zakomentarisati define __rs232__)
- LCD (2x16) moze da se iskljuci (zakomentarisati define)
- cita temperaturu sa 1 ili sa 2 NTC-a, u eepromu je tabela za RT16 i GT204 za 10bitno i 12bitno konvertovanje
- PID koeficijenti su u eepromu (zadnjih 12 bajtova)
- moguce je odabrati "autotuning" mod pravljen uz ogromnu Jovanovu pomoc (covek mi je poslao ceo diplomski rad, sazvakan + je izgubio cudo vremena pokusavajuci da mi objasni kako to sve radi i kako se koristi prokleti matlab da se to izsimulira i pronadju pravi koeficijenti) .. na zalost taj deo jos nije gotov potpuno posto ja nisam bas sve skapirao kako treba (davno sam ucio matematiku, a na ovim "business administration" fakultetima ne uce racun uopste :( ) ... sve u svemu, provalicu ja to (uz jos malo smaranja Jovana) pa ce i to da proradi :)
- temperatura sa ADC-a (oba) se "uprosecuje" pa se vuce kroz NF filter
- temperatura "srednja" se vadi kao prosek sa ADC-ova (jednog ili dva zavisi od define-ova) pa se vuce opet kroz NF (i to malo jaci) kako bi se uklonilo smece koga obicno ima (izlaz je ovde sada idealno gladak)
- temperatura se sampluje jednom u sekundi (moze i 2 puta ako ima potrebe)
- kontrolna funkcija (PID ili AutoTune) se poziva svakih 4.x sekundi (moze bez promene oscilatora na 8sec da se podigne) iz RTCC interrupta
- PWM ima rezoluciju od 0.2xsec (moze da se smanji step rezolucije po potrebi, ovo je najveci step koji moze sa ovim oscilatorom) i kontrolise signal u periodi od 20*0.2xsec (oko 4sec), to je lako promeniti u define-u i naravno radi u interruptu

toliko za sada .. kad nabudzim ovaj auto tuning javljam se sa novim sorsom :D

ako neko ima nekih ideja, slusam :)

(joj sto ruzno izgleda ovaj sors na crnom skinu, ko je pravio css mogao bi to da "opravi")

Code (c):

/***************************************************
 * Project: Hot Bed controller with 18F2423
 * Author: Bogdan Kecman <arhimed [at] gmail [dot] com>
 * Licence: GPL
 *
 * $Revision: 18 $
 *
 ***************************************************/


#case
#TYPE SIGNED
#include <18F2423.h> // \\192.168.89.1\public\Dokumenti\Elektronika\PIC18\PIC18F2423-2523-4423-4523.PDF
#device adc=12
#use fast_io (B)
#include <math.h>

#define BUTTON1 PIN_B0
#define BUTTON2 PIN_B1
#define HEATER_PIN PIN_C2

#define HEATER_ON  output_low(HEATER_PIN)
#define HEATER_OFF output_high(HEATER_PIN)

//how many bits for adc
#define __ADC12__
//#define __ADC10__

//use self tuning controller
//#define __selftuning__
 
//use encoder
#define __encoder__

//be i2c slave
#define __i2cslave__

//log temperature on serial port
#define __rs232__

//use LCD
#define __USELCD__

//use thermistor GT204 (200K)
#define __GT204__

//use thermistor 135-104LAG-J01 (100K)
#define __RT16__

#ifdef __GT204__
  #define TEMPS_start_gt 2
  #define TEMPS_gt 28
  #define ADCCH_gt 0
#endif

#ifdef __RT16__
  #define TEMPS_start_rt 0x3A
  #define TEMPS_rt 30
  #define ADCCH_rt 1
#endif



//#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES NOWDT
#FUSES INTRC_IO                 //Internal RC Osc, no CLKOUT
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOBROWNOUT                 //Reset when brownout detected
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOCPD                    //No EE protection
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES NOIESO                   //Internal External Switch Over mode disabled
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES NOPBADEN                 //PORTB pins are configured as digital I/O on RESET
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB                  //Boot block not protected from table reads
#FUSES NOCPB                    //No Boot Block code protection
#FUSES NOLPT1OSC                //Timer1 configured for high-power operation
#FUSES MCLR                    
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled

#use delay(internal=8M, RESTART_WDT)

#ifdef __rs232__
  #use rs232(baud=19200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,restart_wdt,ERRORS,DISABLE_INTS)
#endif

#ifdef __i2cslave__
  #use i2c(Slave,Fast,sda=PIN_C4,scl=PIN_C3,restart_wdt,force_hw,address=0xBE)
#endif

volatile unsigned int8 j;
volatile unsigned int16 adc_raw;
volatile unsigned int16 adc_avg_rt;
volatile unsigned int16 adc_avg_gt;
volatile unsigned int16 target;
volatile float current;
volatile float current_rt;
volatile float current_gt;
volatile float temp_filtered;

//EEPROM (256 bytes)
#ROM int8 0xF00000 ={
  //target temp (80C)
  0x40, 0x1F,

#ifdef __ADC10__
  //2
  //204-GT thermistor with 10K in voltage divider
  0x7F,0xFF, 0x03,0xE7, 0x03,0xD8, 0x03,0xC2, 0x03,0xA3, 0x03,0x78, 0x03,0x42, 0x02,0xFF, 0x02,0xB3, 0x02,0x61,    //0-90 //0==1009
  0x02,0x0E, 0x01,0xBE, 0x01,0x74, 0x01,0x33, 0,252, 0,206, 0,168, 0,136, 0,111, 0,91,                             //100-190
  0,75, 0,62, 0,51, 0,43, 0,36, 0,30, 0,26, 0,22,                                                                  //  200-270
 
  //135-104LAG-J01 thermistor with 10K in voltage divider
  //0x3A
  0xFF,0, 0x03,0xCE, 0x03,0xB3, 0x03,0x8E, 0x03,0x5D, 0x03,0x21, 0x02,0xDA, 0x02,0x8B, 0x02,0x3A, 0x01,0xEA,       //0-90 //0==1009
  0x01,0x9E, 0x01,0x5A, 0x01,0x1F, 0,237, 0,195, 0,160, 0,132, 0,111, 0,90, 0,77,                                  //100-190
  0,63, 0,54, 0,45, 0,39, 0,33, 0,28, 0,24, 0,21, 0,18, 0,16,                                                      //  200-290
#endif

#ifdef __ADC12__
  //2
  //204-GT thermistor with 10K in voltage divider
  0x3F,0xFF, 0x0F,0xA0, 0x0F,0x64, 0x0F,0x0C, 0x0E,0x8D, 0x0D,0xE3, 0x0D,0x09, 0x0B,0xFF, 0x0A,0xCE, 0x09,0x86,   //0-90
  0x08,0x38, 0x06,0xF8, 0x05,0xD2, 0x04,0xCF, 0x03,0xF1, 0x03,0x37, 0x02,0x9F, 0x02,0x22, 0x01,0xBE, 0x01,0x6D,   //100-190
  0x01,0x2C, 0x00,0xF8, 0x00,0xCE, 0x00,0xAC, 0x00,0x91, 0x00,0x7A, 0x00,0x67, 0x00,0x58,                          //200-270                                                                
 
  //135-104LAG-J01 thermistor with 10K in voltage divider
  //0x3A
  0x3F,0xFF, 0x0F,0x3B, 0x0E,0xCF, 0x0E,0x3B, 0x0D,0x78, 0x0C,0x85, 0x0B,0x69, 0x0A,0x2F, 0x08,0xE9, 0x07,0xA8,   //0-90
  0x06,0x7A, 0x05,0x69, 0x04,0x7B, 0x03,0xB3, 0x03,0x0B, 0x02,0x80, 0x02,0x10, 0x01,0xBD, 0x01,0x69, 0x01,0x33,   //100-190
  0x00,0xFC, 0x00,0xD8, 0x00,0xB3, 0x00,0x9B, 0x00,0x82, 0x00,0x71, 0x00,0x61, 0x00,0x55, 0x00,0x49, 0x00,0x41,   //200-290
#endif


  //0x76
  'H','E','A','T',' ','B','E','D',' ','C','O','N','T','R','O','L',
 
  //0x86
  ' ',' ',' ',' ',' ','v','5','.','0',
#ifdef __encoder__
  'e',
#else
  ' '
#endif  
#ifdef __selftuning__
  ' ',' ','A','U','T','O',
#else
  ' ',' ',' ','P','I','D',
#endif  
  //0x96
  'T','a','r','g','e','t',':',' ',' ',' ','0','0','.','0','0','C',
  //0xA6
  'C','u','r','r','e','n','t',':',' ',' ','0','0','.','0','0','C',
  //0xB6
  0,0,
 
  //B8
  0,0,0,0,
  0,0,0,0,
 
  //C0
  0,0,0,0,
  0,0,0,0,
 
  //C8
  0,0,0,0,
  0,0,0,0,
 
  //D0
  0,0,0,0,
  0,0,0,0,
 
  //D8
  0,0,0,0,
  0,0,0,0,
 
  //E0
  0,0,0,0,
  0,0,0,0,
 
  //E8
  0,0,0,0,
  0,0,0,0,
 
  //F0
  0,0,0,0,
  0x7A,0x4C,0xCC,0xCD, //Pid (0.05)
 
  //F8
  0x73,0x51,0xB7,0x17, //pId (0.0004)
  0x71,0x51,0xB7,0x17  //piD (0.0001)
}
#define init1 0x76
#define init2 0x86
#define gen1  0x96
#define gen2  0xA6
#define Paddr 0xF4
#define Iaddr 0xF8
#define Daddr 0xFC

//pwm period in timer1 ticks
#define PWM_PERIOD 20

volatile float pwm=0;

#INT_TIMER1 //~0.2sec
void TIMER1_isr(){
  static unsigned int16 PWM_POS=0;  
 
  if (PWM_POS < PWM_PERIOD * pwm){
    HEATER_ON;
  } else {
    HEATER_OFF;
  }
 
  if (++PWM_POS > PWM_PERIOD) PWM_POS = 0;
}



//Timer 0 (RTCC) overflow //~4.19424
// CONTROLLER

#ifdef __selftuning__
//AUTO TUNING CONTROLLER WITH OBSERVER
//made using theory and examples from
//"Design of unconventional thermal process
// digital regulator with observer and with
//  minimal process transition time" by Jovan Veselinovic

// NOT WORKING ATTM (I'm still trying to figure out
// how it should work)

//coefficients calculated by matlab script
  #define p  0.7083
  #define Ki 3.4287
  #define K4 -1.9124
  #define g1 0.2868
  #define g2 0.2080
  #define g3 0.1474
  #define g4 0.1044
#int_RTCC
void controler(){
  static float x_kapa_0_1  = 0.0;
  static float x_kapa_0_2  = 0.0;
  static float x_kapa_0_3  = 0.0;
  static float x_kapa_0_4  = 0.0;
 
  float x_kapa_1;
  float x_kapa_2;
  float x_kapa_3;
  float x_kapa_4;

  static float Uint, U;
  float current_temperature, target_temperature, error, temp;

  current_temperature = temp_filtered / 100.0;
  target_temperature  = target / 100.0;
 
  //not sure why is error calculated like this
  //paper talks about r(k) - c(k) but the example
  //calculates the error like this
  error = 1 - current_temperature / target;
 
  //this might be the proper way to calculate error
  //error = target - current_temperature;
 
  temp = current_temperature - x_kapa_0_1;
 
  //observer coefficients
  x_kapa_1 = current_temperature;      //What is the point, this one is never used
  x_kapa_2 = x_kapa_0_2 + p * temp;
  x_kapa_3 = x_kapa_0_3 + p*p * temp;
  x_kapa_4 = x_kapa_0_4 + p*p*p * temp;
 
  //control value (U defines how "strong" you need to drive the target)
  Uint = Uint + Ki * error;
  U    = Uint - Ki * ( x_kapa_2 + x_kapa_3) - K4*x_kapa_4;
 
  //estimate future changes / fix coefficients
  x_kapa_0_1 = x_kapa_2+g1*U;
  x_kapa_0_2 = x_kapa_3+g2*U;
  x_kapa_0_3 = x_kapa_4+g3*U;
  x_kapa_0_4 = p*x_kapa_4+g4*U;
 
  //wind up (there's no force cooling so negative value is not usable
  //and we calculate with maximum U value of 3)
  if (U > 3) U = 3;
  if (U < 0) U = 0;
 
  pwm = U / 3.0; //PWM value (heater control) is in 0-1 range so scale U
}

#else

  float Pf; //0.0500
  float If; //0.0004
  float Df; //0.0001
#int_RTCC
void pid(){
   float error;
   float derivative;
   
   static float error_sum  =0;
   static float error_prev =0;  
   
   //P
   error          = target/100.0 - temp_filtered/100.0 ;
   //I
   error_sum     += error;
   //D
   derivative     = error - error_prev;  
   
   pwm            = error * Pf + error_sum * If  + derivative * Df;
   error_prev     = error;
 
   //engolf it between 0 and 1
   if (pwm < 0){
     pwm = 0;
     error_sum -= error;
   } else if (pwm > 1){
     pwm = 1;
     error_sum -= error;
   }
}
#endif



#ifdef __encoder__
volatile int8 encoder;

//External interrupt
#int_ext
void detect_rb0_change() {
  encoder = 1;
  if (input(BUTTON1) == input(BUTTON2) ) {
      if(target < 27000) target += 50;
  } else {
      if(target > 1500) target -= 50;
  }
}
#endif



#ifdef __i2cslave__
BYTE incoming, state;
BYTE address;
BYTE buffer[4]; //[0] + [1]<<8 = TARGET TEMP; [2] + [3]<<8 = CURRENT TEMP
BYTE changed;

#int_SSP
void  SSP_isr(void) {
  state = i2c_isr_state();
  if(state == 1){  
    incoming = i2c_read();
    address = incoming;
    if (address > 3) address = 0;
  }

  if(state == 2){  
    incoming = i2c_read();
    if (address > 1) address = 0; //only 0 and 1 are writable
    buffer[address] = incoming;
    if (address == 1) changed = 1;
  }

  if(state == 0x80){
    i2c_write (buffer[address]);
  }
}
#endif


float eeprom_read_float(unsigned int16 addr)
{
      float result;
      unsigned int8 *ptr=&result;
      unsigned int8 i;
     
      for (i=0;i<4;i++)
          *(ptr++)=read_eeprom(addr++);
 
      return result;
}
 
void eeprom_write_float(unsigned int16 addr, float data)
{
      unsigned int8 *ptr=&data;
      unsigned int8 i;
     
      for (i=0;i<4;i++)
            write_eeprom(addr++,*(ptr++));
}



#ifdef __USELCD__
struct lcd_pin_map {                
  BOOLEAN analog1;          
  BOOLEAN analog2;
  BOOLEAN rs;            
  BOOLEAN enable;    
  int     data : 4;
} lcd;

#locate lcd = getenv("sfr:PORTA")
#define set_tris_lcd(x) set_tris_a(x)

#define lcd_type 2
#define lcd_line_two 0x40

BYTE const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6};

struct lcd_pin_map const LCD_WRITE = {1, 0,0,0,0x00}; // For write mode all pins are out
//struct lcd_pin_map const LCD_READ  0,0,0x0F}; // For read mode data pins are in

void lcd_send_nibble( BYTE n ) {
      lcd.data = n;
      delay_cycles(1);
      lcd.enable = 1;
      delay_us(2);
      lcd.enable = 0;
}

void lcd_send_byte( BYTE address, BYTE n ) {
      lcd.rs = 0;      
      delay_us(100); //DELAY until LCD is ready
      lcd.rs = address;
      delay_cycles(1);
      delay_cycles(1);
      lcd.enable = 0;
      lcd_send_nibble(n >> 4);
      lcd_send_nibble(n & 0xf);
}

void lcd_init() {
    BYTE i;
    set_tris_lcd(LCD_WRITE);
    lcd.rs = 0;
    lcd.enable = 0;
    delay_ms(15);
    for(i=1;i<=3;++i) {
       lcd_send_nibble(3);
       delay_ms(5);
    }
    lcd_send_nibble(2);
    for(i=0;i<=3;++i)
       lcd_send_byte(0,LCD_INIT_STRING[i]);
}

#endif


//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
// MEASURE TEMPERATURE
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////

float getTemp(){
  unsigned int16 tempVal;
  unsigned int16 lowValue;
  unsigned int16 highValue;
  unsigned int16 dataValue;
  unsigned int16 range;
 
  unsigned int16 max;
  unsigned int16 min;
  unsigned int32 adc_temp;
  unsigned int8  probes;
 
  float tmptemp;
 
  tmptemp = 0;
  probes = 0;
 
 
#ifdef __GT204__
  max      = 0;
  min      = 0;
  adc_temp = 0;
  set_adc_channel(ADCCH_gt);
  delay_ms(1);
  for(j=0;j<34;j++){
    adc_raw = read_adc();
    if (min > adc_raw) min = adc_raw;
    if (max < adc_raw) max = adc_raw;
    adc_temp += adc_raw;  
    delay_ms(1);
  }    
  adc_raw    = (adc_temp - min - max)  >> 5;   //drop min and max read and get average from other 32    
  adc_avg_gt = (adc_avg_gt + adc_raw ) >> 1;   //rudimentary low pass filter

  for(j=1; j<TEMPS_gt; ++j){
    tempVal = read_eeprom(TEMPS_start_gt + (j*2) );
    tempVal = tempVal << 8;
    tempVal = tempVal + read_eeprom(TEMPS_start_gt + (j*2) +1);
    if (adc_avg_gt > tempVal){
      restart_wdt();
      lowValue = tempVal;    
      highValue = read_eeprom(TEMPS_start_gt +(j-1)*2 );
      highValue = highValue << 8;
      highValue = highValue + read_eeprom(TEMPS_start_gt +(j-1)*2+1);
      range = highValue - lowValue;
      dataValue = adc_avg_gt - lowValue;
         
      current_gt =  j*1000.0 - dataValue * 1000.0 / (float)range;
      tmptemp += current_gt;
      probes++;
      break;
    }
  }
#endif

#ifdef __RT16__
  max      = 0;
  min      = 0;
  adc_temp = 0;
  set_adc_channel(ADCCH_rt);
  delay_ms(1);
  for(j=0;j<34;j++){
    adc_raw = read_adc();
    if (min > adc_raw) min = adc_raw;
    if (max < adc_raw) max = adc_raw;
    adc_temp += adc_raw;  
    delay_ms(1);
  }    
  adc_raw    = (adc_temp - min - max)  >> 5;   //drop min and max read and get average from other 32    
  adc_avg_rt = (adc_avg_rt + adc_raw ) >> 1;   //rudimentary low pass filter

  for(j=1; j<TEMPS_rt; ++j){
    tempVal = read_eeprom(TEMPS_start_rt + (j*2) );
    tempVal = tempVal << 8;
    tempVal = tempVal + read_eeprom(TEMPS_start_rt + (j*2) +1);
    if (adc_avg_rt > tempVal){
      restart_wdt();
      lowValue = tempVal;    
      highValue = read_eeprom(TEMPS_start_rt +(j-1)*2 );
      highValue = highValue << 8;
      highValue = highValue + read_eeprom(TEMPS_start_rt +(j-1)*2+1);
      range = highValue - lowValue;
      dataValue = adc_avg_rt - lowValue;
         
      current_rt = j*1000.0 - dataValue * 1000.0 / (float)range;
      tmptemp += current_rt;
      probes++;
      break;
    }
  }  
#endif

  if (probes > 0) return tmptemp / probes;
  return (55555); //error
}

void print_temp(int8 line, unsigned int16 temp){  // temperature is *100
#ifdef __USELCD__
  unsigned int8 x;

  //hundreds
  x = (temp / 10000)%10;
  if (x == 0) {
    lcd_send_byte(0,0x80|(9+lcd_line_two*line));
    lcd_send_byte(1,' ');
  } else {
    x = x + 48;
    lcd_send_byte(0,0x80|(9+lcd_line_two*line));
    lcd_send_byte(1, x);
  }
  restart_wdt();

  //tens
  x = ((temp / 1000 ) % 10) + 48;
  lcd_send_byte(0,0x80|(10+lcd_line_two*line));
  lcd_send_byte(1, x);
  restart_wdt();

  //ones
  x = ((temp / 100 ) % 10) + 48;
  lcd_send_byte(0,0x80|(11+lcd_line_two*line));
  lcd_send_byte(1, x);
  restart_wdt();

  // 1/10
  x = ((temp / 10 ) % 10) + 48;
  lcd_send_byte(0,0x80|(13+lcd_line_two*line));
  lcd_send_byte(1, x);
  restart_wdt();

  // 1/100
  x = (temp  % 10) + 48;
  lcd_send_byte(0,0x80|(14+lcd_line_two*line));
  lcd_send_byte(1, x);
  restart_wdt();
#endif

#ifdef __rs232__
  printf("Current:\t%f\t%f\t%f\tTarget:\t%Lu\tPWM:\t%f\tERR:\t%i\r\n", current/100, current_gt, current_rt, target, pwm*100.0, rs232_errors);
#endif
}


#ifndef __encoder__
void menu(){
  delay_ms(15);
  if (!input(BUTTON1)) if(target<27000) target += 50;
  if (!input(BUTTON2)) if(target>49) target -= 50;
 
  if (!input(BUTTON1) && !input(BUTTON2)){
    write_eeprom(0, target & 0x00ff);
    write_eeprom(1, target >> 8 );
  }
  print_temp(0, target);
  delay_ms(15);
}
#endif


void setup(){
   setup_oscillator(OSC_8MHZ|OSC_INTRC|OSC_31250|OSC_PLL_OFF);
   setup_adc_ports(AN0_TO_AN1|VSS_VDD);
   setup_adc(ADC_CLOCK_DIV_4|ADC_TAD_MUL_20);
   
   //set_tris_a(0xff);
   set_tris_b(0xff);
   //set_tris_c(0xff);
   //set_tris_d(0xff);
   
   //setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);  // 1sec = (Fosc/4)/256 ticks; 1interrupt = 65545 ticks; 1interrupt = 65536 / (Fosc/1024) =  (4MHz) 16.77696sec; (8MHz) 8.38848sec
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128);  // 1sec = (Fosc/4)/128 ticks; 1interrupt = 65545 ticks; 1interrupt = 65536 / (Fosc/512)  =  (4MHz) 8.38848sec; (8MHz) 4.19424sec
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);     // 1sec = (Fosc/4)/8   ticks; 1interrupt = 65545 ticks; 1interrupt = 65536 / (Fosc/32)   =  (4MHz)  0.52428sec; (8MHz) 0.26214sec
   setup_timer_2(T2_DISABLED,0,1);
   setup_timer_3(T3_DISABLED);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   enable_interrupts(INT_RTCC);
   enable_interrupts(INT_TIMER1);

#ifdef __encoder__
   enable_interrupts(INT_EXT);
   encoder = 0;
#endif

#ifdef __i2cslave__
   enable_interrupts(INT_SSP);
#endif

#ifdef __USELCD__
   lcd_init();
#endif

   set_tris_b(0x33);
   HEATER_OFF;
   set_adc_channel(0);
   enable_interrupts(GLOBAL);  
}

/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
//                     MAIN                        //
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////

void main()
{
   setup();
#ifdef __selftuning__
  //read initial coefficient's from eeprom
#else
  //read PID coefficients from eeprom
   Pf = eeprom_read_float(Paddr);
   If = eeprom_read_float(Iaddr);
   Df = eeprom_read_float(Daddr);
#endif
   
   target = read_eeprom(1);
   target = target << 8;
   target |= read_eeprom(0);
   if (target > 30000) target = 7000;
   current = 0;
   temp_filtered = 0;
   adc_raw = 0;
   adc_avg_gt = 0;
   adc_avg_rt = 0;

#ifdef __i2cslave__
   changed = 0;
   buffer[0]=buffer[1]=buffer[2]=buffer[3]=0;
   address = 0;
#endif


#ifdef __USELCD__
   for (j=0;j<16;j++){
     lcd_send_byte(0,0x80|j);
     lcd_send_byte(1,read_eeprom(init1 +j));

     lcd_send_byte(0,0x80|(j+lcd_line_two));
     lcd_send_byte(1,read_eeprom(init2 +j));
   }

   delay_ms(1000);

   for (j=0;j<16;j++){
     lcd_send_byte(0,0x80|j);
     lcd_send_byte(1,read_eeprom(gen1 +j));

     lcd_send_byte(0,0x80|(j+lcd_line_two));
     lcd_send_byte(1,read_eeprom(gen2 +j));
   }

   print_temp(0, target);
#endif
   output_high(PIN_C0);
   while (TRUE){
     output_toggle(PIN_C0);
     restart_wdt();
     current = getTemp();
     //filter temperature value for the PID controller (basic LF)
     temp_filtered = ( temp_filtered*2.0 + current ) / 3.0;
   
     print_temp(1, current);  
     delay_ms(855); //1sec "tuned"

#ifdef __encoder__
     if(encoder){
        print_temp(0, target);
        encoder = 0;
        //store target value to eeprom
        write_eeprom(0, target & 0x00ff);
        write_eeprom(1, target >> 8 );
     }
#else
     if (!input(PIN_B0) || !input(PIN_B5)) menu();
#endif

#ifdef __i2cslave__
     if (changed){ //something came via I2C
        target = buffer[1];
        target = target << 8;
        target |= buffer[0];
        print_temp(0, target);
        changed = 0;        
     }
     //write data into buffer for I2C read
     buffer[2] = (int16) floor(current) & 0x00ff;
     buffer[3] = (int16) floor(current) / 256;
#endif    
   }
}

 

 
Odgovor na temu

grabik

Član broj: 32507
Poruke: 311
*.adsl.net.t-com.hr.



+7 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)01.09.2010. u 07:04 - pre 165 meseci
Nisi rekao najvaznije, da li ovaj novi kod regulira preciznije temperaturu ili onaj tvoj stari kod:)

Znaci float matematika pojela programsku memoriju pica:)

@veselinovic, da li mogu i ja da dobijem tvoj diplomski o digitalnoj regulaciji?

 
Odgovor na temu

plc
vladislav
Velika Plana

Član broj: 266870
Poruke: 107
*.dynamic.isp.telekom.rs.

Sajt: www.industrijasrbije.rs


+1 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)01.09.2010. u 09:10 - pre 165 meseci
http://www.microchipc.com/sour...ike_Pearces_heater_project.zip


mozda pomogne.
 
Odgovor na temu

bogdan.kecman
Bogdan Kecman
"specialist"
Oracle
srbistan

Član broj: 201406
Poruke: 15887
*.31.24.217.adsl2.beograd.com.

Sajt: mysql.rs


+2377 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)01.09.2010. u 13:33 - pre 165 meseci
Citat:
grabik: Nisi rekao najvaznije, da li ovaj novi kod regulira preciznije temperaturu ili onaj tvoj stari kod:)


pid, radi mnogo bolje, posebno bolje radi kada se ovako mnogo isfiltrira sum sa ntc-a

Citat:

Znaci float matematika pojela programsku memoriju pica:)


onaj prvi je bio bas bas bas malecan tako da nije bilo cudo da ga je float pojeo .. dodatno, nemam pojma koliko je picc tu uopste dobar kompajler (koliko on to pametno resava) .. vidim da su mu fload 4 bajtne varijable... ali nisam bas gledao kod koji je generisao, iskreno, mnogo mi je jeftinije da stavim veci pic :D nego da gubim vreme.. (da ne spominjem da ovaj pic kosta isto koliko i onaj)


 
Odgovor na temu

veselinovic
Jovan Veselinovic
Ist. Sarajevo

Moderator
Član broj: 7761
Poruke: 3860
62.101.128.94



+333 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)02.09.2010. u 17:00 - pre 165 meseci
Citat:
grabik: Nisi rekao najvaznije, da li ovaj novi kod regulira preciznije temperaturu ili onaj tvoj stari kod:)

Znaci float matematika pojela programsku memoriju pica:)

@veselinovic, da li mogu i ja da dobijem tvoj diplomski o digitalnoj regulaciji?


Grabik,
moze brate, sam ces biti kriv, to je preko 130 stranica teksta, ali ajde da zamolimo Bogdana da ga okaci negdje.
Ili daj mail da saljem.
Poz.
 
Odgovor na temu

bogdan.kecman
Bogdan Kecman
"specialist"
Oracle
srbistan

Član broj: 201406
Poruke: 15887
*.com
Via: [es] mailing liste

Sajt: mysql.rs


+2377 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)02.09.2010. u 17:35 - pre 165 meseci
no frks, evo ga ovde:

http://elco.crsndoo.com/files/veselinovic_diplomski.pdf

uzdravlje
b.
 
Odgovor na temu

bogdan.kecman
Bogdan Kecman
"specialist"
Oracle
srbistan

Član broj: 201406
Poruke: 15887
*.31.24.217.adsl2.beograd.com.

Sajt: mysql.rs


+2377 Profil

icon Re: termostat - obicni (digitalni sa ntc-om i rotary encoderom)02.09.2010. u 18:07 - pre 165 meseci
btw, imam i original .doc ali se (meni) ne otvara kako treba u open office-u pa mi je covek napravio pdf. u .doc-u su copy/paste objekti iz matlab-a i simulinka tako da ako nemas isti ne znam na sta ce da ti izgleda doc - mozda u ms office-u i radi, u open office-u se ne vidi nista (a pare za ms office ne da dam). No, ako treba, nije problem da upnem i .doc (ako se autor slozi)


 
Odgovor na temu

[es] :: Elektronika :: Mikrokontroleri :: termostat - obicni (digitalni sa ntc-om i rotary encoderom)

Strane: 1 2

[ Pregleda: 9745 | Odgovora: 22 ] > FB > Twit

Postavi temu Odgovori

Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.