|
[ bogdan.kecman @ 12.08.2010. 05:16 ] @
| 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 :)
 |
[ veselinovic @ 12.08.2010. 11:01 ] @
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.
[ bogdan.kecman @ 12.08.2010. 15:08 ] @
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"
[ veselinovic @ 12.08.2010. 17:18 ] @
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.
[ bogdan.kecman @ 12.08.2010. 20:20 ] @
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 :)
[ grabik @ 13.08.2010. 07:18 ] @
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.
[ veselinovic @ 13.08.2010. 07:34 ] @
Bogdane, veceras dobijas kompletan rad sa sve formulama.
Ovo sto sam radio je digitalni regulator sa samopodesavajucim parametrima, i minimum trajanja prelaznog procesa.
[ grabik @ 13.08.2010. 13:11 ] @
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;
[ bogdan.kecman @ 13.08.2010. 22:36 ] @
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 ..
[ grabik @ 14.08.2010. 10:05 ] @
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.
[ bogdan.kecman @ 14.08.2010. 18:22 ] @
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
[ veselinovic @ 17.08.2010. 16:26 ] @
Saljem citav rad samo daj mail.
[ bogdan.kecman @ 17.08.2010. 16:56 ] @
bogdan.kecman [na] sun.com
[ bogdan.kecman @ 30.08.2010. 10:12 ] @
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
}
}
[ grabik @ 01.09.2010. 07:04 ] @
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?
[ plc @ 01.09.2010. 09:10 ] @
[ bogdan.kecman @ 01.09.2010. 13:33 ] @
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)
[ veselinovic @ 02.09.2010. 17:00 ] @
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.
[ bogdan.kecman @ 02.09.2010. 17:35 ] @
[ bogdan.kecman @ 02.09.2010. 18:07 ] @
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)
[ grabik @ 02.09.2010. 21:00 ] @
Hvala na dokumentu, u redu je ovako u pdf.
[ veselinovic @ 03.09.2010. 18:40 ] @
Citat: bogdan.kecman: 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)
Autor se slaze. To je javni rad, nema tu nista epohalno, samo malko slozene kockice.
Poz.
[ bogdan.kecman @ 03.09.2010. 19:03 ] @
nice podignucu veceras i .doc na isto mesto
Copyright (C) 2001-2025 by www.elitesecurity.org. All rights reserved.
|