Advertisement
Guest User

Untitled

a guest
Dec 13th, 2019
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.30 KB | None | 0 0
  1. /*
  2.     -Project name:
  3.            Regulator (Demonstation by Kvascev & Todorov & Marjanovic)
  4.     -Description:
  5.            This program demonstrates simple control of temperature
  6.            and air levitation using the basic knowledge about PI regulators
  7.     -Test configuration:
  8.      MCU:             P18F4520
  9.      Dev.Board:       EasyPIC4
  10.      SW:              mikroC PRO v5.6.1
  11.      Oscillator:      HS, 08.0000 MHz
  12.      Ext. Modules:    D/A Converter
  13.      Date:            20.11.2012.
  14. */
  15. const char _CHIP_SELECT = 1;
  16.  
  17. unsigned int  timerTicks;
  18.  
  19. // custom...
  20. char sample_flag = 0x00;
  21.  
  22. float u_man = 0;  // manual control signal
  23. // PI regulator signals and parameters   u_pi = Kp*e + u_i, u_i = Kp/Ti*integral(e(t))
  24. float ref = 25;  // reference signal
  25. float u_i = 0;  // integral control signal
  26. float Kp = 1;   // proportional gain
  27. float Ti = 10;  // integral time constant
  28. float Ts = 0.02;
  29. float u, y;
  30.  
  31. // button configuration (PORTB)
  32. unsigned char incButton = 0; // increment button
  33. unsigned char decButton = 2; // decrement button
  34. unsigned char autoButton = 6; // switch to AUTO mode
  35. unsigned char manualButton = 7; // switch to MANUAL mode
  36. unsigned char prevIncBtn = 0;
  37. unsigned char prevDecBtn = 0;
  38. unsigned char prevAutoBtn = 0;
  39. unsigned char prevManBtn = 0;
  40.  
  41.  
  42. // mode type definition
  43. typedef enum {MANUAL, MAN2AUTO, AUTO, AUTO2MAN} mode_t;
  44.  
  45. mode_t currentMode = MANUAL;
  46. mode_t previousMode = MANUAL;
  47. mode_t nextMode = MANUAL;
  48.  
  49. void init();
  50.  
  51. void updateLCD(); // writes current MODE, HEIGHT and REFERENCE/CONTROL to LCD
  52. float pi_reg(); // returns control signal in auto mode 0-100%
  53. int percent2dac(float per); // converts 0-100% to integer for DAC
  54. float adc2percent(int adc); // converts integer ADC measuerement to 0-100% range
  55. void DAC_Output(unsigned int valueDAC);
  56. void handleButtons(); //  handles user input from buttons on PORTB
  57.  
  58.  
  59. // Lcd pinout settings
  60. sbit LCD_RS at RD2_bit;
  61. sbit LCD_EN at RD3_bit;
  62. sbit LCD_D7 at RD7_bit;
  63. sbit LCD_D6 at RD6_bit;
  64. sbit LCD_D5 at RD5_bit;
  65. sbit LCD_D4 at RD4_bit;
  66.  
  67. // Pin direction
  68. sbit LCD_RS_Direction at TRISD2_bit;
  69. sbit LCD_EN_Direction at TRISD3_bit;
  70. sbit LCD_D7_Direction at TRISD7_bit;
  71. sbit LCD_D6_Direction at TRISD6_bit;
  72. sbit LCD_D5_Direction at TRISD5_bit;
  73. sbit LCD_D4_Direction at TRISD4_bit;
  74.  
  75. void main() {
  76.      init(); // initialization code...
  77.  
  78.      while(1) // control loop
  79.      {
  80.       currentMode = nextMode;
  81.       if(sample_flag)
  82.       {
  83.         y = adc2percent(Adc_Read(3));
  84.         switch(currentMode)
  85.         {
  86.             case MANUAL:
  87.                 u = u_man;
  88.                 nextMode = MANUAL;
  89.             break;
  90.            
  91.             case MAN2AUTO:
  92.             // bumpless
  93.             u_i = u_man - Kp*(ref-y);
  94.             ref = y;
  95.             nextMode = AUTO;
  96.             break;
  97.            
  98.             case AUTO:
  99.             // pi
  100.                 u = pi_reg();
  101.                 nextMode = AUTO;
  102.             break;
  103.            
  104.             case AUTO2MAN:
  105.             // bumpless
  106.             u_man = Kp*(ref-y) + u_i;
  107.             nextMode = MANUAL;
  108.             break;
  109.         }
  110.         DAC_Output(percent2dac(u));
  111.         updateLCD();
  112.         sample_flag = 0x00;
  113.       }
  114.       handleButtons();
  115.      }
  116. // AD i DA konverzija
  117. //     y_int = Adc_Read(3);             // citanje sa AD konvertora, kanal 3 (vraca vrednost u opsegu 0-1023)
  118. //     DAC_Output(u_int);               // upis na DA konvertor (0-4095)
  119. }
  120. void handleButtons()
  121. {
  122.     previousMode = currentMode;
  123.     if(Button(&PORTB, incButton, 1, 1))
  124.         prevIncBtn = 1;
  125.     if(prevIncBtn && Button(&PORTB, incButton, 1, 0))
  126.     {
  127.      // INCREMENT button action
  128.      switch(currentMode)
  129.      {
  130.       case MANUAL:
  131.         u_man += 0.5; // %
  132.         if(u_man>100)
  133.             u_man = 100;
  134.       break;
  135.       case AUTO:
  136.         ref += 0.5; // %
  137.         if(ref>100)
  138.             ref = 100;
  139.       break;
  140.      }
  141.      prevIncBtn = 0;
  142.     }
  143.  
  144.     if(Button(&PORTB, decButton, 1, 1))
  145.         prevDecBtn = 1;
  146.     if(prevDecBtn && Button(&PORTB, decButton, 1, 0))
  147.     {
  148.      // DECREMENT button action
  149.      switch(currentMode)
  150.      {
  151.       case MANUAL:
  152.         u_man -= 0.5; // %
  153.         if(u_man<0)
  154.             u_man = 0;
  155.       break;
  156.       case AUTO:
  157.         ref -= 0.5; // %
  158.         if(ref<0)
  159.             ref = 0;
  160.       break;
  161.      }
  162.      prevDecBtn = 0;
  163.     }
  164.    
  165.     if(Button(&PORTB, autoButton, 1, 1))
  166.         prevAutoBtn = 1;
  167.     if(prevAutoBtn && Button(&PORTB, autoButton, 1, 0))
  168.     {
  169.      // AUTO button action
  170.      if(currentMode == MANUAL)
  171.         nextMode = MAN2AUTO;
  172.  
  173.      prevAutoBtn = 0;
  174.     }
  175.  
  176.     if(Button(&PORTB, manualButton, 1, 1))
  177.         prevManBtn = 1;
  178.     if(prevManBtn && Button(&PORTB, manualButton, 1, 0))
  179.     {
  180.      // MANUAL button action
  181.      if(currentMode == AUTO)
  182.         nextMode = AUTO2MAN;
  183.      prevManBtn = 0;
  184.     }
  185. }
  186.  
  187. int percent2dac(float per)  // converts 0-100% to integer for DAC
  188. {
  189.     return (int) per/100.0*4095;
  190. }
  191. float adc2percent(int adc)  // converts integer ADC measuerement to 0-100% range
  192. {
  193.  
  194.     return (float) (adc-116)/1023.0*100.0/88.7*100.0;
  195. }
  196. // Timed Interrupt on 0.02 sec
  197. void interrupt() {
  198.      timerTicks++;
  199.      TMR1H      =   99;               // 40000 counts until overflow 40000=65535-(99*256+192)
  200.      TMR1L      =   192;              // 40000/2000000=0.02sec on 8MHz, 2000000=8MHz/4
  201.      T1CON      =   0x01;             // TMR1ON: Timer1 On bit 1 = Enables Timer1
  202.      PIR1.TMR1IF=   0;                // Clear interrupt request bit
  203.      PIE1       =   1;                // TMR1IE: TMR1 Overflow Interrupt Enable bit, 1 = Enables
  204.      INTCON     =   0xC0;             // Interrupts enable
  205.      sample_flag = 0x01; // set flag to 0x01 every 20ms
  206. }
  207.  
  208. float pi_reg()  // returns control signal in auto mode 0-100%
  209. {
  210.     float u_ret = 0;
  211.     float e;
  212.     e = ref - y;
  213.     u_i = u_i + Kp/Ti*e*Ts;
  214.     u_ret = Kp*e + u_i;
  215.  
  216.  
  217.     if(u_ret > 100.0)
  218.         u_i = 100.0 - Kp*e; // anti-windup
  219.    
  220.     if(u_ret<0.0)
  221.         u_i = -Kp*e;
  222.        
  223.  
  224.    
  225.     if(u_ret < 0)
  226.         u_ret = 0;
  227.     if(u_ret > 100)
  228.         u_ret = 100;
  229.        
  230.     return u_ret;
  231. }
  232. // DAC increments (0..4095) --> output voltage (0..5V)
  233. void DAC_Output(unsigned int valueDAC) {
  234. char temp;
  235.   PORTC &= ~(_CHIP_SELECT);           // ClearBit(PORTC,CHIP_SELECT);
  236.                                       // Prepare for data transfer
  237.   temp = (valueDAC >> 8) & 0x0F;      // Prepare hi-byte for transfer
  238.   temp |= 0x30;                       // It's a 12-bit number, so only
  239.   SPI1_write(temp);                   //   lower nibble of high byte is used
  240.   temp = valueDAC;                    // Prepare lo-byte for transfer
  241.   SPI1_write(temp);
  242.  
  243.   PORTC |= _CHIP_SELECT;              // SetBit(PORTC,CHIP_SELECT);
  244. }
  245.  
  246. void updateLCD()
  247. {
  248.     char buff[10];
  249.     sprintf(buff,"h=%03.1f",y);
  250.     Lcd_Out(1,1,buff);
  251.  
  252.     switch(currentMode)
  253.     {
  254.       case MANUAL:
  255.          sprintf(buff,"u=%03.1f",u);
  256.       break;
  257.       case AUTO:
  258.          sprintf(buff,"r=%03.1f",ref);
  259.       break;
  260.     }
  261.     Lcd_Out(2,1,buff);
  262.  
  263. }
  264.  
  265. void init()
  266. {
  267.      // Inicijalizacija portova i periferija
  268.      ADCON1 = 0x0F;                    // Turn off A/D converters on PORTB
  269.      TRISA  = 0xFF;                    // Set PORTA pins as input pins(to work with A/D converter)
  270.      TRISB  = 0xFF;                    // Set PORTB pins as input pins(to work with keybord)
  271.      TRISC &= ~(_CHIP_SELECT);         // SPI ClearBit(TRISC,CHIP_SELECT);
  272.      TRISD  = 0x00;                    // Set PORTD pins as output pins(to work with LCD display)
  273.      SPI1_init();                      // Initialisation of SPI communication
  274.  
  275.      // inicijalizacija interapt rutine
  276.      timerTicks =   0;
  277.      TMR1H      =   99;               // 40000 counts until overflow 40000=65535-(99*256+192)
  278.      TMR1L      =   192;              // 40000/2000000=0.02sec on 8MHz, 2000000=8MHz/4
  279.      T1CON      =   0x01;             // TMR1ON: Timer1 On bit 1 = Enables Timer1
  280.      PIR1.TMR1IF=   0;                // Clear interrupt request bit
  281.      PIE1       =   1;                // TMR1IE: TMR1 Overflow Interrupt Enable bit, 1 = Enables
  282.      INTCON     =   0xC0;             // Interrupts enable
  283.      // inicijalizacija i brisanje display-a
  284.      Lcd_Init();
  285.      Lcd_Cmd(_LCD_CLEAR);
  286.      Lcd_Cmd(_LCD_CURSOR_OFF);
  287. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement