element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Embedded and Microcontrollers
  • Technologies
  • More
Embedded and Microcontrollers
Embedded Forum How to convert PID output into meaningful result to feed into controller
  • Blog
  • Forum
  • Documents
  • Quiz
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Embedded and Microcontrollers to participate - click to join for free!
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • Replies 7 replies
  • Subscribers 470 subscribers
  • Views 1098 views
  • Users 0 members are here
  • pid controller
Related

How to convert PID output into meaningful result to feed into controller

chrischristian14
chrischristian14 over 5 years ago

Hi, I am creating a pressure controller with PIC micro that is controlling the heating coil and a pocketbeagle that is running a PID loop. The PIC micro takes commands from pocketbeagle over UART.

PIC responds to 0 to 9, with 9 being heating coil switched off and 1 being full on.The PID loop outputs numbers up to 10000000, depending upon what is the difference between the measured pressure and the desired pressure, and I am really struggling to convert this PID output (0 to 10 million ) to a range of 0 to 9 and not killing the PID functionality - i.e. keeping it PID and not making it like a normal code. I managed to have a few range of loop, and each range is a PID loop on its own, but that is not an ideal solution. Below is the code I tried, int_diff is the (int) PID output. Can anyone pelase help ? I have a feeling I might be over complicating things but don't know how.

Just to explain, in below code, each range sends 0 to 9 numbers to PIC micro, so the problem arises when the difference between set pressure and measured pressure is low and it just need to go up by a little, but the output (int_diff) switches range and suddenly it goes to 0 (heating coil full on) and then on next measurement (after about a second) it goes to 9 (heating coil off), while it should be moving from 8 to 9. This kind of movement (0 to 9) causes overshoot, and the reverse is also true, causing very slow rise in temperature or undershoot.

I hope I am making sense. Thanks

if(0<int_diff && int_diff<99)
{
value = diff/10; //(gives 1 to 9)
closer =1;
}
#if 1
else if(99<int_diff && int_diff<999)
{


value = diff/100;
closer =1;
}




else if (999<int_diff && int_diff<9999)
{
value = diff/1000;
closer =1;
}
else if (9999<int_diff && int_diff<99999)
{
value = diff/10000;
closer =1;
}




else if (99999<int_diff && int_diff<999999)
{
value = diff/100000;
closer =1; 
}
else if (999999<int_diff && int_diff<9999999)
{
value = diff/1000000;
closer =1;
//value = 0;
}




if(closer==1)
{


if(value>=0)
{
value= 9-(int)value;
}
else if(value<0)
{
value=9;
}


}
else
{
value = 0;
}

  • Sign in to reply
  • Cancel

Top Replies

  • chrischristian14
    chrischristian14 over 5 years ago in reply to michaelkellett +3
    Thanks Michael, I am not new to this embedded stuff, I have about 10 years of experience in electronics and maintain an RTOS product as part of my full time work, what I am not good at is explaining things…
  • michaelkellett
    michaelkellett over 5 years ago +2
    Not making much sense ! This doesn't look like all your code ! You would do much better to have it all in one place either on the PIC or the Beagle. Steps of only 0 to 9 is quite possibly not fine enough…
  • michaelkellett
    michaelkellett over 5 years ago in reply to chrischristian14 +2
    I get the feeling you are new to all this embedded stuff. My first bit of advice is that you should never leave an unexplained observation to fester. You say that the triac turns on and then turns off…
Parents
  • chrischristian14
    chrischristian14 over 5 years ago

    Thanks you all, the reason I have PIC an pocketbeagle is because, PIC handles ZeroCross detection and creates software PWM according to the value supplied by pocketbeagle, which handles PID. I need to have USB,WiFI n LCD display and embedded webserver functionality that's why I chose poketbeagle and since it can't handle zero cross detection or any real time processing (unless I dive into PRU codes, which is a bit of a learning curve that I would want like to avoid at this stage), I moved the ZCD code to PIC. Unfortunately I can't post all the code here because it belongs to the company.

    I fought with the PIC code for it to accept a string and then change that string to integer, I am doing the same at the moment but just for a single character instead of a string. If I can get a string and then itoa(str) then, I can have a bigger resolution instead of just 0 to 9  and that may solve the problem. For some reason the PIC halts or at least it stops activating the tirac used to switch coil. It always stops the coil and never gets stuck in ON position. Here is my PIC code.

     

    #include <xc.h>
     #include <stdlib.h>
    #include <math.h>
    #include <stdint.h>
    #include "main.h"
    #include "UART.h"
    
    
    // BEGIN CONFIG
    #pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
    #pragma config PWRTE = OFF       // Power-up Timer Enable bit (PWRT enabled)
    #pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
    #pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
    #pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)
    #pragma config FEXTOSC = OFF    // External Oscillator mode selection bits (Oscillator not enabled)
    #pragma config RSTOSC = HFINT1  // Power-up default value for COSC bits (HFINTOSC (1MHz))
    //END CONFIG
    int i=0;
    int my_delay = 10000;
    int t, value=0;
    char zc;
    char result[2];
    char foo, buffer[3] ; // 10(0x0D))
    char counter=0; 
    
    
    void interrupt ISR(void)
    {
        if(INTF) // check if RA2/INT interrupt is triggered.
            INTF=0;
             GIE=0;
            zc = 1;
            if(INTEDG)
                INTEDG =0;
            else
                INTEDG =1;
            GIE =1;
    }
    
    
    setup(void)
    {
        TRISA4 = 0; //Set as output 
        TRISAbits.TRISA2 =1;
        ANSELAbits.ANSA2 =0;
        INLVLAbits.INLVLA2 = 1;
        INTPPS = 0x02;
        INTE =1;
        INTF = 0;
        INTEDG = 1;
        
        zc = 0; 
    
    
        PEIE =1;
        GIE=1;          //Enable Global Interrupt
        
       delay_ms(500);
    }
    
    
    delay_ms(unsigned int ms)
    {
        while(ms > 0)
        {
            __delay_ms(1);
            ms--;
        }
    }
    void delay_10us(unsigned int us_count)
     {
        while(us_count!=0)
          {
            for(int i=0;i<11;i++)
            {
             __delay_us(1)  ;
    us_count--;
            }
       }
       }
    
    
    
    
    
    
    ser_process()
    {
       char str[8];
       {
       UART_Read_Text(str,8);
       delay_ms(200);
       UART_send_string(str);
        }
    
    
    #if 0 
        if(RC1IF)
        {
    
    
       foo = UART_get_char();
       buffer[counter]=foo;
       counter++;
       if(foo==0x0D)
       {
       buffer[counter]=0x00; // remove 0x0D
       my_delay = atoi(buffer);
       if(my_delay>9) // make sure not to overshoot
           my_delay=9;
       UART_send_string(buffer);
       itoa(result,my_delay,10);
       
       for(int i=0;i<3;i++)
       {
           buffer[i] =0x00;
          
       }
        counter = 0;
       
       }
                 }
    
    
    #endif
                
    }
    void main(void) 
    {
      
        OSCCON1bits.NDIV = 0; // necessary 
        OSCFRQbits.HFFRQ = 0b011; // 8MHz
        
        Initialize_UART();
        setup();
        my_delay = 1;
    
    
            while(1)
                
            {
    
    
    #if 1
                while(zc==0);
                
                {     
                delay_ms(0);  //THIS IS WHERE THE VALUE FROM PID SHOULD GO
                RA4 = 1;
                }
                __delay_us(500);
                RA4 = 0;
                zc = 0; 
    #endif
    
    
              ser_process();
        
        
    
            }
    
    
        
        return;
    }

    I played around with it and found that even if I try to receive individual characters, it can't handle more than than three characters and then it gets stuck, the code still responds to UART but the heating coil stays off. In the above code I have hard coded for it to stay on (delay_ms(0)), and still it goes off, and  this is where I would want to use __delay_us instead, to get higher resolution, so I can send inputs e.g 34587, instead of just 3. So the question is why above code would suddenly turn the heating coil off ? while continue to respond to UART. Thanks

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
  • genebren
    genebren over 5 years ago in reply to chrischristian14

    Chris,

     

    In looking at your interrupt function:

    void interrupt ISR(void)  
    {  
        if(INTF) // check if RA2/INT interrupt is triggered.  
            INTF=0;  
             GIE=0;  
            zc = 1;  
            if(INTEDG)  
                INTEDG =0;  
            else  
                INTEDG =1;  
            GIE =1;  
    } 

    I am not sure if the initial 'if(INTF) is intended to qualify all of the remaining code, or if the indention is unintentional.  Without braces '{}' the only statement that is dependent on the 'if(INTF) statement is 'INTF=0', all the remaining statements are executed on any interrupt, which might be causing your code to set zc to one unexpectedly.

     

    Not sure if this is part of your problem, or just me getting confused by the indention.

     

    Good luck!

    Gene

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
Reply
  • genebren
    genebren over 5 years ago in reply to chrischristian14

    Chris,

     

    In looking at your interrupt function:

    void interrupt ISR(void)  
    {  
        if(INTF) // check if RA2/INT interrupt is triggered.  
            INTF=0;  
             GIE=0;  
            zc = 1;  
            if(INTEDG)  
                INTEDG =0;  
            else  
                INTEDG =1;  
            GIE =1;  
    } 

    I am not sure if the initial 'if(INTF) is intended to qualify all of the remaining code, or if the indention is unintentional.  Without braces '{}' the only statement that is dependent on the 'if(INTF) statement is 'INTF=0', all the remaining statements are executed on any interrupt, which might be causing your code to set zc to one unexpectedly.

     

    Not sure if this is part of your problem, or just me getting confused by the indention.

     

    Good luck!

    Gene

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
Children
No Data
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube