新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 51單片機PID的算法實現程序C語言

        51單片機PID的算法實現程序C語言

        作者: 時間:2016-11-19 來源:網絡 收藏
        /*
        用整型變量來實現PID算法,由于是用整型數來做的,所以也不是很精確,但是對于很多的使用場合,這個精度也夠了,
        關于系數和采樣電壓全部是放大10倍處理的.所以精度不是很高. 但是也不是那么低,大部分的場合都夠了. 實在覺得精度不夠,
        可以再放大10倍或者100倍處理,但是要注意不超出整個數據類型的范圍就可以了.本程序包括PID計算和輸出兩部分.
        當偏差>10度全速加熱,偏差在10度以內為PID計算輸出. 具體的參考代碼參見下面:
        */
        //================================================================
        // pid.H
        // Operation about PID algorithm procedure
        // C51編譯器 Keil 7.08
        //================================================================
        // All rights reserved.
        //================================================================




        #include
        #include
        typedef unsigned char uint8;
        typedef unsigned int uint16;
        typedef unsigned long int uint32;
        /函數聲明/
        void PIDOutput ();
        void PIDOperation ();
        /*/
        typedef struct PIDValue
        {
        uint32 Ek_Uint32[3]; //差值保存,給定和反饋的差值
        uint8 EkFlag_Uint8[3]; //符號,1則對應的為負數,0為對應的為正數
        uint8 KP_Uint8;
        uint8 KI_Uint8;
        uint8 KD_Uint8;
        uint16 Uk_Uint16; //上一時刻的控制電壓
        uint16 RK_Uint16; //設定值
        uint16 CK_Uint16; //實際值
        }PIDValueStr;


        PIDValueStr PID;
        uint8 out ; // 加熱輸出
        uint8 count; // 輸出時間單位計數器
        /*
        PID = Uk + KP*[E(k)-E(k-1)]+KI*E(k)+KD*[E(k)-2E(k-1)+E(k-2)];(增量型PID算式)
        函數入口: RK(設定值),CK(實際值),KP,KI,KD
        函數出口: U(K)
        //PID運算函數
        /
        void PIDOperation (void)
        {
        uint32 Temp[3]; //中間臨時變量
        uint32 PostSum; //正數和
        uint32 NegSum; //負數和
        Temp[0] = 0;
        Temp[1] = 0;
        Temp[2] = 0;
        PostSum = 0;
        NegSum = 0;

        if( PID.RK_Uint16 > PID.RK_Uint16 ) //設定值大于實際值否?
        {
        if( PID.RK_Uint16 - PID.RK_Uint16 >10 ) //偏差大于10否?
        {
        PID.Uk_Uint16 = 100; //偏差大于10為上限幅值輸出(全速加熱)
        }
        else
        {
        Temp[0] = PID.RK_Uint16 - PID.CK_Uint16; //偏差<=10,計算E(k)
        PID.EkFlag_Uint8[1]=0; //E(k)為正數
        //數值移位
        PID.Ek_Uint32[2] = PID.Ek_Uint32[1];
        PID.Ek_Uint32[1] = PID.Ek_Uint32[0];
        PID.Ek_Uint32[0] = Temp[0];
        //
        if( PID.Ek_Uint32[0] >PID.Ek_Uint32[1] ) //E(k)>E(k-1)否?
        {
        Temp[0]=PID.Ek_Uint32[0] - PID.Ek_Uint32[1]; //E(k)>E(k-1)
        PID.EkFlag_Uint8[0]=0; //E(k)-E(k-1)為正數
        }
        else
        {
        Temp[0]=PID.Ek_Uint32[0] - PID.Ek_Uint32[1]; //E(k)PID.EkFlag_Uint8[0]=1; //E(k)-E(k-1)為負數
        }
        //
        Temp[2]=PID.Ek_Uint32[1]*2 ; // 2E(k-1)
        if( (PID.Ek_Uint32[0]+ PID.Ek_Uint32[2])>Temp[2] ) //E(k-2)+E(k)>2E(k-1)否?
        {
        Temp[2]=(PID.Ek_Uint32[0]+ PID.Ek_Uint32[2])-Temp[2]; //E(k-2)+E(k)>2E(k-1)
        PID.EkFlag_Uint8[2]=0; //E(k-2)+E(k)-2E(k-1)為正數
        }
        else
        {
        Temp[2]=Temp[2]-(PID.Ek_Uint32[0]+ PID.Ek_Uint32[2]); //E(k-2)+E(k)<2E(k-1)
        PID.EkFlag_Uint8[2]=1; //E(k-2)+E(k)-2E(k-1)為負數
        }
        //
        Temp[0] = (uint32)PID.KP_Uint8 * Temp[0]; // KP*[E(k)-E(k-1)]
        Temp[1] = (uint32)PID.KI_Uint8 * PID.Ek_Uint32[0]; // KI*E(k)
        Temp[2] = (uint32)PID.KD_Uint8 * Temp[2]; // KD*[E(k-2)+E(k)-2E(k-1)]




        /*以下部分代碼是講所有的正數項疊加,負數項疊加*/
        /KP*[E(k)-E(k-1)]/
        if(PID.EkFlag_Uint8[0]==0)
        PostSum += Temp[0]; //正數和
        else
        NegSum += Temp[0]; //負數和
        /* KI*E(k)/
        if(PID.EkFlag_Uint8[1]==0)
        PostSum += Temp[1]; //正數和
        else
        ; //空操作,E(K)>0
        /KD*[E(k-2)+E(k)-2E(k-1)]/
        if(PID.EkFlag_Uint8[2]==0)
        PostSum += Temp[2]; //正數和
        else
        NegSum += Temp[2]; //負數和
        /*U(K)*/
        PostSum += (uint32)PID.Uk_Uint16;

        if(PostSum > NegSum ) // 是否控制量為正數
        {
        Temp[0] = PostSum - NegSum;
        if( Temp[0] < 100 ) //小于上限幅值則為計算值輸出
        PID.Uk_Uint16 = (uint16)Temp[0];
        else
        PID.Uk_Uint16 = 100; //否則為上限幅值輸出
        }
        else //控制量輸出為負數,則輸出0(下限幅值輸出)
        PID.Uk_Uint16 = 0;
        }
        }
        else
        {
        PID.Uk_Uint16 = 0;
        }
        }




        /*
        函數入口: U(K)
        函數出口: out(加熱輸出)
        //PID運算植輸出函數
        /
        void PIDOutput (void)
        {
        static int i;
        i=PID.Uk_Uint16;
        if(i==0)
        out=1;
        else out=0;
        if((count++)==5)//如定時中斷為40MS,40MS*5=0.2S(輸出時間單位),加熱周期20S(100等份)
        { //每20S PID運算一次
        count=0;
        i--;
        }

        }

        本文引用地址:http://www.104case.com/article/201611/318566.htm


        關鍵詞: 51單片機PID的算

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 三门峡市| 友谊县| 共和县| 望城县| 温宿县| 许昌市| 怀来县| 宜章县| 泾源县| 宁城县| 遂宁市| 丁青县| 黎城县| 宜章县| 郴州市| 邛崃市| 田阳县| 芦山县| 林州市| 濮阳县| 浦江县| 太和县| 兴安盟| 碌曲县| 凭祥市| 新郑市| 锡林郭勒盟| 盐山县| 大渡口区| 商城县| 峨山| 樟树市| 报价| 宁乡县| 津南区| 寿宁县| 尼玛县| 农安县| 钦州市| 韩城市| 彰化县|