//VAL2 17.1.2004 //VAL3 17.1.2004 rešeni problemi z pretvorbo ad v stopinje (težave je delal float in long ki je unsigned // rešene težave z irq (setup_time_0) //val4 18.1 napisan in nepreizkusen regulator;napiši š4 hitri inkrment in vpis vEE //val5 20.1 pripravi še vpis Kp in Ki v EE //val6 22.1 poskus hitri incr //val7 EE je rešen , hitri incr pa še ne //val8 22.1 upam da je hitr incr OK #include <16f873.H> #device ADC=10 #use delay(clock=4000000) #fuses XT,NOWDT,PUT,BROWNOUT,NOPROTECT,NOLVP #zero_ram //*********************************** // RUTINE ZA LCD //----------------------------------- struct lcd_pin_map { // This structure is overlayed int unused : 2; // be pin B0. BOOLEAN rs; //RS na B2 BOOLEAN enable; //E na B3 int data : 4; // zgornji çtirje biti so podatkovni za LCD } lcd; #byte lcd = 6 //PORTB #define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines #define lcd_line_two 0x40 // LCD RAM address for the second line byte const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6}; // These bytes need to be sent to the LCD // to start it up. //BYTE const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xf, 1, 6}; //utripa in je viden 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; // while ( bit_test(lcd_read_byte(),7) ) ; izloźeno ker iz LCD ni mo§no brati delay_ms(1); lcd.rs = address; delay_cycles(1); delay_cycles(1); lcd.enable = 0; lcd_send_nibble(n >> 4); lcd_send_nibble(n & 0xf); delay_ms(1); /* poźakaj da se znak izpiçe */ } /*******************/ /* L C D _ I N I T */ /*******************/ BYTE const Ini_LCD_znaki[8*8] = { 0x0A, 0x04, 0x0E, 0x10, 0x10, 0x11, 0x0E, 0x00, /*Znak 'ź',č */ 0x0A, 0x04, 0x0F, 0x10, 0x0E, 0x01, 0x1E, 0x00, /* Znak 'ç'š */ 0x0A, 0x04, 0x1F, 0x02, 0x04, 0x08, 0x1F, 0x00 /* Znak '§'ž */ 0x02, 0x04, 0x0E, 0x10, 0x10, 0x11, 0x0E, 0x00, /* Znak ''c' */ 0x02, 0x07, 0x02, 0x0E, 0x12, 0x12, 0x0E, 0x00, /* Znak 'dj' */ 0x04, 0x0E, 0x1F, 0x04, 0x04, 0x04, 0x0E, 0x00, /* Znak '' */ 0x0E, 0x04, 0x04, 0x04, 0x1F, 0x0E, 0x04, 0x00 /* Znak '' */ 0x11, 0x1F, 0x1F, 0x1F, 0x0E, 0x04, 0x04, 0x0E /* Kozarec (poln - źrno)*/ }; //REZERVA // 0x0E, 0x0E, 0x04, 0x0E, 0x1B, 0x11, 0x11, 0x1F /* Steklenica */ // 0x11, 0x11, 0x11, 0x11, 0x0E, 0x04, 0x04, 0x0E /* Kozarec (prazen) */ // 0x11, 0x1F, 0x11, 0x11, 0x0E, 0x04, 0x04, 0x0E /* Kozarec (poln - źrta)*/ void lcd_init() { BYTE i; lcd.rs = 0; lcd.enable = 0; delay_ms(100); /* po vklopu, da se lcd pripravi */ 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]); /*************************** znaki źç§ -------------- */ lcd_send_byte(0,0x40); /* set - vpisovanje uporabnisko definiranih znakov */ for (i=0;i<8*8;i++) { lcd_send_byte(1,Ini_LCD_znaki[i]); /* poçlje definicije po vrsti */ } lcd_send_byte(0,0x01); delay_ms(5); /* brisanje displeja */ } void lcd_gotoxy( int x, int y) { int address; if(y!=1) address=lcd_line_two; else address=0; address+=x-1; lcd_send_byte(0,0x80|address); } void lcd_putc( char c) { switch (c) { case '\f' : lcd_send_byte(0,1); /* brisanje displeja */ delay_ms(2); /* 2ms */ // lcd_send_byte (0,0x0C); /* Izklop kurzorja */ break; case '\n' : lcd_gotoxy(1,2); break; //v novo vrstico case '\r' : lcd_gotoxy(1,1); break; //v novo vrstico case '\b' : lcd_send_byte(0,0x10); break; //pomik kurzorjaza 1 levo default : //izpis znaka switch (c) { /* Slovenska + hrvaçka verzija tekstov*/ /* V YU_ASCI ali SLO_WIN naboru znakov*/ //yu_asci // case '^': // case '~': //slo_win // case '¬': // case 'ź': //win -XP case 'Č': case 'č': c = 0; break; //yu_asci // case '[': // case '{': //slo_win // case 'ć': // case 'ç': //win -XP case 'Š': case 'š': c = 1; break; //yu_asci // case '¦': // case '§': //slo_win // case '@': // case '`': //win -XP case 'Ž': case 'ž': c = 2; break; //yu_asci // case 'Ź': // case '†': //slo_win // case ']': // case '}': //win -XP case 'Ć': case 'ć': c = 3; break; //yu_asci // case 'Ń': // case 'Đ': //slo_win // case '\\': // case '|': //win -XP case 'Đ': case 'đ': c = 4; break; } lcd_send_byte(1,c); } } //*********************************** // KONEC RUTIN ZA LCD //----------------------------------- //*********************************** // RUTINE ZA EEPROM //----------------------------------- //-------------- //lokacije v EE #define SPOMIN1 0 #define SPOMIN2 2 #define SPOMIN3 4 void Write_2bajta_eeprom(int ee_lokacija,long stevilo_tmp) { write_eeprom(ee_lokacija,(BYTE) (stevilo_tmp)); write_eeprom(++ee_lokacija,(BYTE) (stevilo_tmp >> 8)); } long Read_2bajta_eeprom(int ee_lokacija) { long stevilo_tmp; stevilo_tmp = read_eeprom(ee_lokacija+1); stevilo_tmp<<=8; //šifta levo za osem mest stevilo_tmp += read_eeprom(ee_lokacija); return (stevilo_tmp); } void Write_float_eeprom(int ee_lokacija,float stevilo_tmp) { write_eeprom(ee_lokacija,*(int)(&stevilo_tmp)); write_eeprom(ee_lokacija+1,*(int)(&stevilo_tmp+1)); write_eeprom(ee_lokacija+2,*(int)(&stevilo_tmp+2)); write_eeprom(ee_lokacija+3,*(int)(&stevilo_tmp+3)); } float Read_float_eeprom(int ee_lokacija) { float stevilo_tmp; *(int)(&stevilo_tmp) = read_eeprom(ee_lokacija); *(int)(&stevilo_tmp+1) = read_eeprom(ee_lokacija+1); *(int)(&stevilo_tmp+2) = read_eeprom(ee_lokacija+2); *(int)(&stevilo_tmp+3) = read_eeprom(ee_lokacija+3); return (stevilo_tmp); } //*********************************** // KONEC RUTIN ZA EEPROM //----------------------------------- //*********************************** // RUTINE ZA TIPKE //----------------------------------- #define TIPKA_GOR PIN_C6 #define TIPKA_DOL PIN_C4 int Ti_sp_gor,Ti_sp_dol; int Timer_tipka_spuscena,Timer_tipka_pritisnjena; /*****************/ /* S C A N K E Y */ /*****************/ #define ZAPISI_V_EE 10 /*desetink sekunde*/ #define ZACNI_HITRI_INKREMENT 10 /*desetink sekunde*/ #define _PLUS_ 28 #define _MINUS_ 8 //#define _ESC_ 27 BYTE Scankey(void) { BYTE tmp = 0; #if 1 if (!Ti_sp_gor && Ti_sp_dol) tmp =_PLUS_; else if (Ti_sp_gor && !Ti_sp_dol) tmp =_MINUS_; if (tmp) Timer_tipka_spuscena = ZAPISI_V_EE; else Timer_tipka_pritisnjena = ZACNI_HITRI_INKREMENT; return(tmp); // if (!Ti_sp_gor && !Ti_sp_dol) return(_ESC_); #endif } BYTE Newkey(void) { static BYTE old_scan; BYTE new_scan; new_scan = Scankey(); if (old_scan == new_scan) new_scan=0; else old_scan = new_scan; return(new_scan); } //*********************************** // KONEC RUTIN ZA TIPKE //----------------------------------- //*********************************** // RUTINE ZA AD //----------------------------------- long read_adc_30x() { long vsota,povprecje; int i; vsota=0; for(i=0;i<30;++i) { delay_ms(6); vsota += read_adc(); } povprecje =vsota/30; return(povprecje); } float iz_ad_v_stopinje_celzija(long ad_vrednost) { float stopinje_c; float stop_nad_25; stop_nad_25=((float)ad_vrednost-536.0)/20; //536 je AD pri 2000 ohmov=25 stopinj (stmina 20 ad/stopinjo) if (stop_nad_25>0) stop_nad_25=stop_nad_25*1.03; //nad 25 stopinj se strmina krvulje poveča za 3% stopinje_c=stop_nad_25+25.0; // printf(lcd_putc,"\r%3.3f;\n%ld; ",stopinje_c,ad_vrednost); return(stopinje_c); } float meri_stopinje_c() { return(iz_ad_v_stopinje_celzija(read_adc_30x())); } //*********************************** // KONEC RUTIN ZA AD //----------------------------------- int moc_grelci; int Timer_regulator; int timer_50ms; /***********/ /* M A I N */ /***********/ main(void) { /* začetek programa */ int i; int tipka,tipka_last; int a,b,c,d; int flag_st_cilj_spremenjena; float stopinje_c_merjeno,stopinje_c_cilj,epsilon; signed long izhod_regulatorja; signed long izhod_proporcionalnega_reg; float izhod_integralnega_reg; //INICIALIZACIJA //ANALOGNO DIGITALNI PRETVORNIK set_tris_a(0b11111111); setup_adc_ports( ALL_ANALOG ); setup_adc( ADC_CLOCK_INTERNAL ); set_adc_channel( 0 ); //DISPLEJ set_tris_b(0b00000011); lcd_init(); //PORT C set_tris_c(0b11010011); setup_timer_0 (RTCC_INTERNAL); enable_interrupts(INT_TIMER0); enable_interrupts(GLOBAL); //stopinje_c_cilj=26.0; //ZA POSKUS KI BO VKLJUČIL RAGULATOR stopinje_c_cilj = Read_float_eeprom(SPOMIN1); if (stopinje_c_cilj > 50.0 || stopinje_c_cilj < 0) stopinje_c_cilj=25.0; while (1) { /* v neskončni zanki */ tipka = newkey(); //ko prvič pritisnem if (tipka) tipka_last=tipka; if (Timer_tipka_pritisnjena == 0 && flag_st_cilj_spremenjena == 1 && scankey()) { //ko držim več kot 1s tipka = tipka_last; } if (tipka==_PLUS_) { stopinje_c_cilj=stopinje_c_cilj+0.1; flag_st_cilj_spremenjena=1; } if (tipka==_MINUS_) { stopinje_c_cilj=stopinje_c_cilj-0.1; flag_st_cilj_spremenjena=1; } if (Timer_tipka_spuscena==0 && flag_st_cilj_spremenjena == 1) { Write_float_eeprom(SPOMIN1,stopinje_c_cilj); flag_st_cilj_spremenjena=0; } /* if (Timer_tipka_pritisnjena ==0 && timer_50ms == 0) { //ko držim več kot 1s in je od prejšnjega inkr minilo več kot 50ms tipka = scankey(); timer_50ms = 25; //po 2ms } */ /****************/ //regulator PI /****************/ #define CAS_ITERACIJE 10 /* 10*0.1s=1s*/ if (Timer_regulator == 0) { //EPSILON stopinje_c_merjeno = meri_stopinje_c(); epsilon=stopinje_c_cilj - stopinje_c_merjeno; #define Kp 20 izhod_proporcionalnega_reg=epsilon*Kp; #define Ki 0.1 izhod_integralnega_reg = izhod_integralnega_reg + Ki*epsilon; //omejitev izhoda integralnega 0-100 if( izhod_integralnega_reg >100) { izhod_integralnega_reg=100; //0-100% } else if (izhod_integralnega_reg < 0) { izhod_integralnega_reg=0; //0-100% } izhod_regulatorja=izhod_proporcionalnega_reg + (long)izhod_integralnega_reg; //skupni izhod //omejitev izhoda 0-100 if (izhod_regulatorja > 100) { izhod_regulatorja=100; //0-100% } else if (izhod_regulatorja < 0) { izhod_regulatorja=0; //0-100% } moc_grelci=izhod_regulatorja; Timer_regulator=CAS_ITERACIJE; } a=*(int)(&stopinje_c_cilj); b=*(int)(&stopinje_c_cilj+1); c=*(int)(&stopinje_c_cilj+2); d=*(int)(&stopinje_c_cilj+3); // printf(lcd_putc,"\r%2.1f%ld\n%2.1f;%ld; ",epsilon,izhod_proporcionalnega_reg,izhod_integralnega_reg,izhod_regulatorja); // printf(lcd_putc,"\rT=%2.2fC\n%2.1f;%2x; ",stopinje_c_merjeno,stopinje_c_cilj+0.001,Timer_tipka_pritisnjena); printf(lcd_putc,"\r%2x%2x%2x%2x\n%2.1f;%2x; ",a,b,c,d,stopinje_c_cilj+0.001,Timer_tipka_pritisnjena); // printf(lcd_putc,"\rT=%2.2fC\n%2.1f;%ld; ",stopinje_c_merjeno,stopinje_c_cilj+0.001,read_adc_30x()); //printf(lcd_putc,"\rT=%5f\n;%ld; ",meri_stopinje_c(),read_adc_30x()); } /* konec while zanke */ } /* konec funkcije main */ /*************************************/ /* P R E K I N I T E V _ T I M E R 0 */ /*************************************/ #define PWM_TRIAC PIN_C3 long interrupt_counter; int pwm_counter; int hec; #INT_RTCC void Prekinitev_timer0(void) { // KVARC == 4 vsakih 1us*256 = 256us se izvaja rutina //PREBERI TIPKE // if (interrupt_counter & 0x001f == 0) {// vsakih 32*256us=8.192ms if(--hec==0) { // vsakih 12*256us=2ms shift_left(&Ti_sp_gor,1,input(TIPKA_GOR)); shift_left(&Ti_sp_dol,1,input(TIPKA_DOL)); if(timer_50ms!=0) timer_50ms--;// 0.002 sek hec=20; } //TIMERJI ZA PROCESE if (interrupt_counter==0) {// vsakih 100ms if(Timer_tipka_spuscena!=0) Timer_tipka_spuscena--;// 0.1 sek if(Timer_tipka_pritisnjena!=0) Timer_tipka_pritisnjena--;// 0.1 sek if(Timer_regulator!=0) Timer_regulator--;// 0.1 sek interrupt_counter=390; //390*256us je 99.84ms = 1/10 sek } else interrupt_counter--; //PWM if (++pwm_counter == 101) pwm_counter=1; //preskoźi 0 ,da pri moc_grelci==0 sploh ne vklopi if (pwm_counter <= moc_grelci) { //generiraj impulz output_low(PWM_TRIAC); //negiran izhod } else { //generiraj pavzo output_high(PWM_TRIAC); //negiran izhod } }