Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- -Project name:
- Regulator (Demonstation by Kvascev & Todorov & Marjanovic)
- -Description:
- This program demonstrates simple control of temperature
- and air levitation using the basic knowledge about PI regulators
- -Test configuration:
- MCU: P18F4520
- Dev.Board: EasyPIC4
- SW: mikroC PRO v5.6.1
- Oscillator: HS, 08.0000 MHz
- Ext. Modules: D/A Converter
- Date: 20.11.2012.
- */
- const char _CHIP_SELECT = 1;
- unsigned int timerTicks;
- // custom...
- char sample_flag = 0x00;
- float u_man = 0; // manual control signal
- // PI regulator signals and parameters u_pi = Kp*e + u_i, u_i = Kp/Ti*integral(e(t))
- float ref = 25; // reference signal
- float u_i = 0; // integral control signal
- float Kp = 1; // proportional gain
- float Ti = 10; // integral time constant
- float Ts = 0.02;
- float u, y;
- // button configuration (PORTB)
- unsigned char incButton = 0; // increment button
- unsigned char decButton = 2; // decrement button
- unsigned char autoButton = 6; // switch to AUTO mode
- unsigned char manualButton = 7; // switch to MANUAL mode
- unsigned char prevIncBtn = 0;
- unsigned char prevDecBtn = 0;
- unsigned char prevAutoBtn = 0;
- unsigned char prevManBtn = 0;
- // mode type definition
- typedef enum {MANUAL, MAN2AUTO, AUTO, AUTO2MAN} mode_t;
- mode_t currentMode = MANUAL;
- mode_t previousMode = MANUAL;
- mode_t nextMode = MANUAL;
- void init();
- void updateLCD(); // writes current MODE, HEIGHT and REFERENCE/CONTROL to LCD
- float pi_reg(); // returns control signal in auto mode 0-100%
- int percent2dac(float per); // converts 0-100% to integer for DAC
- float adc2percent(int adc); // converts integer ADC measuerement to 0-100% range
- void DAC_Output(unsigned int valueDAC);
- void handleButtons(); // handles user input from buttons on PORTB
- // Lcd pinout settings
- sbit LCD_RS at RD2_bit;
- sbit LCD_EN at RD3_bit;
- sbit LCD_D7 at RD7_bit;
- sbit LCD_D6 at RD6_bit;
- sbit LCD_D5 at RD5_bit;
- sbit LCD_D4 at RD4_bit;
- // Pin direction
- sbit LCD_RS_Direction at TRISD2_bit;
- sbit LCD_EN_Direction at TRISD3_bit;
- sbit LCD_D7_Direction at TRISD7_bit;
- sbit LCD_D6_Direction at TRISD6_bit;
- sbit LCD_D5_Direction at TRISD5_bit;
- sbit LCD_D4_Direction at TRISD4_bit;
- void main() {
- init(); // initialization code...
- while(1) // control loop
- {
- currentMode = nextMode;
- if(sample_flag)
- {
- y = adc2percent(Adc_Read(3));
- switch(currentMode)
- {
- case MANUAL:
- u = u_man;
- nextMode = MANUAL;
- break;
- case MAN2AUTO:
- // bumpless
- u_i = u_man - Kp*(ref-y);
- ref = y;
- nextMode = AUTO;
- break;
- case AUTO:
- // pi
- u = pi_reg();
- nextMode = AUTO;
- break;
- case AUTO2MAN:
- // bumpless
- u_man = Kp*(ref-y) + u_i;
- nextMode = MANUAL;
- break;
- }
- DAC_Output(percent2dac(u));
- updateLCD();
- sample_flag = 0x00;
- }
- handleButtons();
- }
- // AD i DA konverzija
- // y_int = Adc_Read(3); // citanje sa AD konvertora, kanal 3 (vraca vrednost u opsegu 0-1023)
- // DAC_Output(u_int); // upis na DA konvertor (0-4095)
- }
- void handleButtons()
- {
- previousMode = currentMode;
- if(Button(&PORTB, incButton, 1, 1))
- prevIncBtn = 1;
- if(prevIncBtn && Button(&PORTB, incButton, 1, 0))
- {
- // INCREMENT button action
- switch(currentMode)
- {
- case MANUAL:
- u_man += 0.5; // %
- if(u_man>100)
- u_man = 100;
- break;
- case AUTO:
- ref += 0.5; // %
- if(ref>100)
- ref = 100;
- break;
- }
- prevIncBtn = 0;
- }
- if(Button(&PORTB, decButton, 1, 1))
- prevDecBtn = 1;
- if(prevDecBtn && Button(&PORTB, decButton, 1, 0))
- {
- // DECREMENT button action
- switch(currentMode)
- {
- case MANUAL:
- u_man -= 0.5; // %
- if(u_man<0)
- u_man = 0;
- break;
- case AUTO:
- ref -= 0.5; // %
- if(ref<0)
- ref = 0;
- break;
- }
- prevDecBtn = 0;
- }
- if(Button(&PORTB, autoButton, 1, 1))
- prevAutoBtn = 1;
- if(prevAutoBtn && Button(&PORTB, autoButton, 1, 0))
- {
- // AUTO button action
- if(currentMode == MANUAL)
- nextMode = MAN2AUTO;
- prevAutoBtn = 0;
- }
- if(Button(&PORTB, manualButton, 1, 1))
- prevManBtn = 1;
- if(prevManBtn && Button(&PORTB, manualButton, 1, 0))
- {
- // MANUAL button action
- if(currentMode == AUTO)
- nextMode = AUTO2MAN;
- prevManBtn = 0;
- }
- }
- int percent2dac(float per) // converts 0-100% to integer for DAC
- {
- return (int) per/100.0*4095;
- }
- float adc2percent(int adc) // converts integer ADC measuerement to 0-100% range
- {
- return (float) (adc-116)/1023.0*100.0/88.7*100.0;
- }
- // Timed Interrupt on 0.02 sec
- void interrupt() {
- timerTicks++;
- TMR1H = 99; // 40000 counts until overflow 40000=65535-(99*256+192)
- TMR1L = 192; // 40000/2000000=0.02sec on 8MHz, 2000000=8MHz/4
- T1CON = 0x01; // TMR1ON: Timer1 On bit 1 = Enables Timer1
- PIR1.TMR1IF= 0; // Clear interrupt request bit
- PIE1 = 1; // TMR1IE: TMR1 Overflow Interrupt Enable bit, 1 = Enables
- INTCON = 0xC0; // Interrupts enable
- sample_flag = 0x01; // set flag to 0x01 every 20ms
- }
- float pi_reg() // returns control signal in auto mode 0-100%
- {
- float u_ret = 0;
- float e;
- e = ref - y;
- u_i = u_i + Kp/Ti*e*Ts;
- u_ret = Kp*e + u_i;
- if(u_ret > 100.0)
- u_i = 100.0 - Kp*e; // anti-windup
- if(u_ret<0.0)
- u_i = -Kp*e;
- if(u_ret < 0)
- u_ret = 0;
- if(u_ret > 100)
- u_ret = 100;
- return u_ret;
- }
- // DAC increments (0..4095) --> output voltage (0..5V)
- void DAC_Output(unsigned int valueDAC) {
- char temp;
- PORTC &= ~(_CHIP_SELECT); // ClearBit(PORTC,CHIP_SELECT);
- // Prepare for data transfer
- temp = (valueDAC >> 8) & 0x0F; // Prepare hi-byte for transfer
- temp |= 0x30; // It's a 12-bit number, so only
- SPI1_write(temp); // lower nibble of high byte is used
- temp = valueDAC; // Prepare lo-byte for transfer
- SPI1_write(temp);
- PORTC |= _CHIP_SELECT; // SetBit(PORTC,CHIP_SELECT);
- }
- void updateLCD()
- {
- char buff[10];
- sprintf(buff,"h=%03.1f",y);
- Lcd_Out(1,1,buff);
- switch(currentMode)
- {
- case MANUAL:
- sprintf(buff,"u=%03.1f",u);
- break;
- case AUTO:
- sprintf(buff,"r=%03.1f",ref);
- break;
- }
- Lcd_Out(2,1,buff);
- }
- void init()
- {
- // Inicijalizacija portova i periferija
- ADCON1 = 0x0F; // Turn off A/D converters on PORTB
- TRISA = 0xFF; // Set PORTA pins as input pins(to work with A/D converter)
- TRISB = 0xFF; // Set PORTB pins as input pins(to work with keybord)
- TRISC &= ~(_CHIP_SELECT); // SPI ClearBit(TRISC,CHIP_SELECT);
- TRISD = 0x00; // Set PORTD pins as output pins(to work with LCD display)
- SPI1_init(); // Initialisation of SPI communication
- // inicijalizacija interapt rutine
- timerTicks = 0;
- TMR1H = 99; // 40000 counts until overflow 40000=65535-(99*256+192)
- TMR1L = 192; // 40000/2000000=0.02sec on 8MHz, 2000000=8MHz/4
- T1CON = 0x01; // TMR1ON: Timer1 On bit 1 = Enables Timer1
- PIR1.TMR1IF= 0; // Clear interrupt request bit
- PIE1 = 1; // TMR1IE: TMR1 Overflow Interrupt Enable bit, 1 = Enables
- INTCON = 0xC0; // Interrupts enable
- // inicijalizacija i brisanje display-a
- Lcd_Init();
- Lcd_Cmd(_LCD_CLEAR);
- Lcd_Cmd(_LCD_CURSOR_OFF);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement