當前位置:首頁 » 操作系統 » 單片機控制演算法

單片機控制演算法

發布時間: 2023-08-12 02:57:58

❶ 單片機pid演算法控制步進電機的電路圖和程序

//P1.1(T0):Count They Distance
//P0.4:Tx
//P0.5:Rx
#include <C8051F310.h> //SFR declarations
#include <stdio.h> //Standard I/O definition file
#include <math.h> //Math library file
#include <Intrins.h>
#include <absacc.h>

unsigned int j,i;
char a=0;
unsigned int t=0;

//sbit led=P0^2;
//P0.0(PWM0):給定左輪速度.
sbit vls=P0^4; //P0.4(GPIO):給定左輪方向.
sbit vlf=P0^6; //P0.6(T0) :反饋左輪速度.
sbit dlf=P1^0; //P1.0(GPIO):反饋左輪方向.

//P0.2(PWM0):給定右輪速度.
sbit vrs=P0^5; //P0.5(GPIO):給定右輪方向.
sbit vrf=P0^7; //P0.7(T0) :反饋右輪速度.
sbit drf=P1^1; //P1.1(GPIO):反饋右輪方向.

int ol; //左輪給定值
int len;
int len_1,len_2;
int lyn_1,lyn_2;
int vl1,vl2; //反饋左輪速度值(取樣周期內的方波數)
int lfz; //運算後賦給PWM的值

int lyn,lynn;
int lun=0,lun_1=0; //偏差校正值 即校正PWM輸出
int lunp,luni,lund; //PID 校正值

int or; //右輪給定值
int ren;
int ren_1,ren_2;
int ryn_1,ryn_2;
int vr1,vr2; //反饋右輪速度值(取樣周期內的方波數)
int rfz; //運算後賦給PWM的值

int ryn,rynn;
int run=0,run_1=0; //偏差校正值 即校正PWM輸出
int runp,runi,rund; //PID 校正值

float kp=2.0; //比例系數1.8
float kd=0.2; //微分系數0.4
float lki; //積分系數

void pio_init(void);
void sys_init(void);
void t01_init(void);
void TIME3_INT(void);
void PID(void);
void interrupt_init(void);
void delay(unsigned int x);
void pwm1_1(void);

void main(void)
{
PCA0MD &= ~0x40; //關閉
pio_init(); //P11為測距輸入端
sys_init();
t01_init();
pwm1_1();
TIME3_INT();
interrupt_init();

vls=1;vrs=0;
while(1)
{

ol=50;
or=50;
delay(1000);

ol=100;
or=100;
delay(1000);

ol=-50;
or=50;
delay(1000);

}

}

void PID(void)
{
/****************左輪PID調節******************/
if(dlf==1)
{
lyn=(vl2*256+vl1); //dlf是左輪反饋方向,0表示向前 vl=TL0
}
else
{
lyn=-(vl2*256+vl1); //dlf=1表示是向後退,速度應該為負值
}

len=ol-lyn; //誤差=給定速度-反饋速度(取樣周期內的方波數)

if(abs(len)<8)//30
{
lki=1.4; //ki值的確定1.4
}
else
{
lki=0.05; //積分系數:如果 | 給定值-反饋值 | 太大
} //則就可以不引入積分,或者引入的很小0.05

lunp=kp*(len-len_1); //比例校正
luni=lki*len; //積分校正
lund=kd*(len-2*len_1+len_2); //微分校正

lun=lunp+luni+lund+lun_1; //總校正

/*************新舊數據更新*************************/
len_2=len_1;
len_1=len; //len:當前取樣周期內出現的速度偏差;len_1:上次取樣周期內出現的速度偏差
lun_1=lun; //lun:當前取樣周期內得出的PWM校正值;lun_1:上次取樣周期內得出的PWM校正值
/*************新舊數據更新*************************/

if(lun>255)
{
lun=255; //正速度
}
if(lun<-255)
{
lun=-255; //負速度
}
if(lun<0)

{
vls=1;
PCA0CPH0=-lun;
}

if(lun>=0)
{
vls=0;
PCA0CPH0=lun;
}

/****************右輪PID調節******************/
if(drf==0)
{
ryn=(vr2*256+vr1); //drf是右輪反饋方向,0表示向前 vl=TL0
}
else
{
ryn=-(vr2*256+vr1); //dlf=1表示是向後退,速度應該為負值
}

ren=or-ryn; //誤差=給定速度-反饋速度(取樣周期內的方波數)

if(abs(ren)<8)//30
{
lki=1.4; //ki值的確定1.4
}
else
{
lki=0.05; //積分系數:如果 | 給定值-反饋值 | 太大
} //則就可以不引入積分,或者引入的很小0.05

runp=kp*(ren-ren_1); //比例校正
runi=lki*ren; //積分校正
rund=kd*(ren-2*ren_1+ren_2); //微分校正

run=runp+runi+rund+run_1; //總校正

/*************新舊數據更新*************************/
ren_2=ren_1;
ren_1=ren; //len:當前取樣周期內出現的速度偏差;len_1:上次取樣周期內出現的速度偏差
run_1=run; //lun:當前取樣周期內得出的PWM校正值;lun_1:上次取樣周期內得出的PWM校正值
/*************新舊數據更新*************************/

if(run>255)
{
run=255; //正速度
}
if(run<-255)
{
run=-255; //負速度
}
if(run<0)

{
vrs=1;
PCA0CPH1=-run;
}

if(run>=0)
{
vrs=0;
PCA0CPH1=run;
}
//因為這里的PCA0CPH0越大,對應的電機速度越小,所以要255來減一下
}

void pio_init(void)
{
XBR0=0x00; //0000 0001
XBR1=0x72; //0111 0010 時能弱上拉 T0T1連接到腳口P06、P07 CEX0、CEX1連接到腳口P00、P01

P0MDIN=0xff; //模擬(0);數字(1) 1111 0011
P0MDOUT=0xc3;//開漏(0);推挽(1) 1111 1111
P0SKIP=0x3c; //0011 1100

P1MDIN=0xff; //1111 1111
P1MDOUT=0xfc;//
P1SKIP=0x00; //1111 1111

}

void sys_init(void) //12MHz
{
OSCICL=0x43;
OSCICN=0xc2;
CLKSEL=0x00;

}

void pwm1_1(void) //PWM的初始化
{
PCA0MD=0x08; //PCA時鍾為12分頻

PCA0CPL0=200; //左輪
PCA0CPM0=0x42; //設置左輪為8位PWM輸出
PCA0CPH0=200;

PCA0CPL1=200; //平衡校正
PCA0CPM1=0x42; //設置為8位PWM輸出
PCA0CPH1=200;

PCA0CN=0x40; //允許PCA工作
}

void t01_init(void)
{
TCON=0x50; //計數器1、2允許
TMOD=0x55; //定時器1、2採用16位計數功能
CKCON=0x00;

TH1=0x00; //用於採集左輪的速度
TL1=0x00;

TH0=0x00; //用於採集右輪的速度
TL0=0x00;
}

void TIME3_INT(void)
{
TMR3CN = 0x00; //定時器3為16位自動重載
CKCON &= ~0x40;

TMR3RLL = 0xff;
TMR3RLH = 0xd7;
TMR3L = 0xff;
TMR3H = 0xd7;

TMR3CN |= 0x04;
}

void T3_ISR() interrupt 14 //定時器3中斷服務程序
{
//led=~led;
EA=0;
TCON &=~0x50; //關閉計數器0、1

vl1=TL0; //取左輪速度值
vl2=TH0;

vr1=TL1; //取右輪速度值
vr2=TH1;

TH1=0x00;
TL1=0x00;

TH0=0x00;
TL0=0x00;

PID(); //PID處理

TMR3CN &=~0x80; //清中斷標志位
TCON |=0x50; //重新開計數器0、1
EA=1;
}
void interrupt_init(void)
{ IE=0x80;
IP=0x00;
EIE1|=0x80;
EIP1|=0x80;

}

void delay(unsigned int m) //延時程序
{
for(i=0;i<2000;i++)
{
for(j=0;j<m;j++){_nop_(); _nop_();}
}
}

❷ 單片機中的PID演算法是什麼意思啊,有什麼用途呢謝謝!

pid就是比例積分微分演算法

❸ pic單片機pid控制演算法參數整定

我這有51的

#include <stdlib.h>

#include "global_varible.h"

/****************************************************************************
* 模塊名: PID
* 描述: PID調節子程序
* 採用PID-PD演算法。在偏差絕對值大於△e時,用PD演算法,以改善動態品質。
* 當偏差絕對值小於△e時,用PID演算法,提高穩定精度。
* PIDout=kp*e(t)+ki*[e(t)+e(t-1)+...+e(1)]+kd*[e(t)-e(t-1)]
*============================================================================
* 入口: 無
* 出口: 無
* 改變: PID_T_Run=加熱時間控制
*****************************************************************************/
void PID_Math(void)
{
signed long ee1; //偏差一階
//signed long ee2; //偏差二階
signed long d_out; //積分輸出

if(!Flag_PID_T_OK)
return;
Flag_PID_T_OK=0;

Temp_Set=3700; //溫度控制設定值37.00度

PID_e0 = Temp_Set-Temp_Now; //本次偏差
ee1 = PID_e0-PID_e1; //計算一階偏差
//ee2 = PID_e0-2*PID_e1+PID_e2; //計算二階偏差
if(ee1 > 500) //一階偏差的限制范圍
ee1 = 500;
if(ee1 < -500)
ee1 = -500;
PID_e_SUM += PID_e0; //偏差之和
if(PID_e_SUM > 200) //積分最多累計的溫差
PID_e_SUM = 200;
if(PID_e_SUM < -200)
PID_e_SUM = -200;

PID_Out = PID_kp*PID_e0+PID_kd*ee1; //計算PID比例和微分輸出
if(abs(PID_e0) < 200) //如果溫度相差小於1.5度則計入PID積分輸出
{
if(abs(PID_e0) > 100) //如果溫度相差大於1度時積分累計限制
{
if(PID_e_SUM > 100)
PID_e_SUM = 100;
if(PID_e_SUM < -100)
PID_e_SUM = -100;
}
d_out = PID_ki*PID_e_SUM; //積分輸出
if(PID_e0 < -5) //當前溫度高於設定溫度0.5度時積分累計限制
{
if(PID_e_SUM > 150)
PID_e_SUM = 150;

if(PID_e_SUM > 0) //當前溫度高於設定溫度0.5度時削弱積分正輸出
d_out >>= 1;
}
PID_Out += d_out; //PID比例,積分和微分輸出
}
else
PID_e_SUM=0;

PID_Out/=100; //恢復被PID_Out系數放大的倍數
if(PID_Out > 200)
PID_Out=200;
if(PID_Out<0)
PID_Out=0;

if(PID_e0 > 300) //當前溫度比設定溫度低3度則全速加熱
PID_Out=200;
if(PID_e0 < -20) //當前溫度高於設定溫度0.2度則關閉加熱
PID_Out=0;

Hot_T_Run=PID_Out; //加熱時間控制輸出

PID_e2 = PID_e1; //保存上次偏差
PID_e1 = PID_e0; //保存當前偏差
}
////////////////////////////////////////////////////////////void PID_Math() end.

❹ 用單片機做PID演算法控制問題

1.可以直接套用PID公式,無論增量還是絕對的。PID演算法是根據誤差來控制的演算法,不依賴系統的模型,故不用算系統的傳遞函數。有的書提到傳遞函數,一般是用於理論建模模擬,從而直接用Matlab一類的模擬軟體進行PID參數調試。得到的參數可以為實際應用提供一定參考價值。

2.PID參數整定有一套原則。首先要了解各個參數的作用。具體的整定方法,隨便找本自控原理的書都會提到,我不太記得了,大致是有一個倍數關系。但實際操作,一般不會是用這個數,是需要根據系統的反應,改變各個參數來試的。盡信書不如無書啊~
另外,不同系統的參數肯定不一樣。就算同一個系統,稍微有一些改變,可能最好的那組參數就會變化。因此衍生了很多先進PID演算法,如神經PID、專家PID、模糊PID等等。

❺ 單片機是怎麼用PID控制演算法實現對電加熱

那要看你計算出來的是什麼了,如果直接是一個電流,那麼直接用它來驅動加熱爐就行,如果是一個誤差值(理想值與真實值之差),那麼就要先計算出要是電爐達到理想溫度的電流值是多少,再用計算出的電流來驅動。希望能對你有幫助。

❻ stm32單片機能寫復雜控制演算法么

1.PID原理
1.1 P I D三個參數簡單理解
1.2 P I D
1.3 PI PD PID適用系統
2.串級PID原理
3.PID代碼
3.1 單級PID
3.1.1 初始化PID結構體
3.1.2 單級PID計算
3.1.3PID初始化
3.1.4 清空PID
3.2 串級PID
3.2.1 初始化串級PID結構體
3.2.2 串級PID計算
4.PID的使用
4.1 定義PID結構體並初始化
4.2 定義電機速度函數
4.3 在檢測霍爾碼盤時發送速度給電機
4.4 實驗效果
1.PID原理
PID是什麼,P,I,D的分別功能

你和PID調參大神之間,就差這篇文章!

1.1 P I D三個參數簡單理解
P(比例): 簡單來說,P就是涼了加熱水,熱了加涼水。比目標值小,我就增加一點,比目標值大,我就減小一點。(現在)
P可能出現的問題: 1.P太小,達到目標值需要花費很長的時間,而且會有穩態誤差。2.P太大,達到目標值時可能會一直震盪。

I(積分): 將一段時間內的誤差累積起來加到輸出上,可以消除歷史誤差對當前實際曲線的影響,提高系統的穩定性。 (過去)
I可能出現的問題: 1.I太小,可以消除穩態誤差,但太慢了,對於某些需要很快響應的系統,顯然不能滿足要求。2.I太大,累計誤差佔比過大,就會出現抖動現象,難以收斂。

D(微分): 減小最大超調量。(下圖中③就是最大超調量。) 可以有效減小震動的幅度。讓曲線收斂更快 (未來)
D可能出現的問題: 1.D太小,作用小,時間長。2.D太大,為了減小超調量,補償的過多,導致震盪很久。
在這里插入圖片描述

1.2 P I D
先調P,逐漸增加P直到系統出現震盪,將當前值乘0.7就是較為合適的值。
再調I,將穩態誤差逐漸降低。
後調D,將最大超調量降到最低。

1.3 PI PD PID適用系統
PI:響應速度要求不那麼高的系統。
PD:大慣性系統。超調量太大。
PID:都可以。

網上將PID原理太多太多了,我的理解也都是參見上面的內容。認真看肯定有收獲。

2.串級PID原理
【串級PID】淺談串級PID作用及意義——快速理解串級PID結構優勢

這里個人理解就是,單機PID就是穩定速度。而需要帶位置和角度的就要用串級PID了。常用於平衡車,板球系統等。
而轉速閉環稱為串級PID的內環,位置 (角度) 閉環稱為串級PID的外環。其實也很好理解,位移是速度的積分,只有速度慢慢穩定,位置才能確定。

3.PID代碼
3.1 單級PID
3.1.1 初始化PID結構體
typedef struct _PID
{
float kp,ki,kd;
float error,lastError;//誤差、上次誤差
float integral,maxIntegral;//積分、積分限幅
float output,maxOutput;//輸出、輸出限幅
}PID;
1
2
3
4
5
6
7
1
2
3
4
5
6
7
3.1.2 單級PID計算
#define LIMIT(x,min,max) (x)=(((x)<=(min))?(min):(((x)>=(max))?(max):(x)))

//單級pid計算
void PID_SingleCalc(PID *pid,float reference,float feedback)
{
//更新數據
pid->lastError=pid->error;
pid->error=reference-feedback;
//計算微分
pid->output=(pid->error-pid->lastError)*pid->kd;
//計算比例
pid->output+=pid->error*pid->kp;
//計算積分
pid->integral+=pid->error*pid->ki;
LIMIT(pid->integral,-pid->maxIntegral,pid->maxIntegral);//積分限幅
pid->output+=pid->integral;
//輸出限幅
LIMIT(pid->output,-pid->maxOutput,pid->maxOutput);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
3.1.3PID初始化
void PID_Init(PID *pid,float p,float i,float d,float maxI,float maxOut)
{
pid->kp=p;
pid->ki=i;
pid->kd=d;
pid->maxIntegral=maxI;
pid->maxOutput=maxOut;
}
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
3.1.4 清空PID
//清空一個pid的歷史數據
void PID_Clear(PID *pid)
{
pid->error=0;
pid->lastError=0;
pid->integral=0;
pid->output=0;
}
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
3.2 串級PID
3.2.1 初始化串級PID結構體
typedef struct _CascadePID
{
PID inner;//內環
PID outer;//外環
float output;//串級輸出,等於inner.output
}CascadePID;
1
2
3
4
5
6
1
2
3
4
5
6
3.2.2 串級PID計算
//串級pid計算
void PID_CascadeCalc(CascadePID *pid,float angleRef,float angleFdb,float speedFdb)
{
PID_SingleCalc(&pid->outer,angleRef,angleFdb);//計算外環(角度環)
PID_SingleCalc(&pid->inner,pid->outer.output,speedFdb);//計算內環(速度環)
pid->output=pid->inner.output;
}
1
2
3
4
5
6
7
1
2
3
4
5
6
7
4.PID的使用
STM32應用(九)編碼器及其測速原理、L298N電機驅動控制編碼器電機

在這篇博客的配置下,只需要修改部分代碼。以單級PID為例子。

4.1 定義PID結構體並初始化
PID pid;

void Motor_Init(void)
{
PID_Init(&pid,10,0,0,1000,1000);
HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL); //開啟編碼器定時器
__HAL_TIM_ENABLE_IT(&htim1,TIM_IT_UPDATE); //開啟編碼器定時器更新中斷,防溢出處理
HAL_TIM_Base_Start_IT(&htim6); //開啟10ms定時器中斷
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //開啟PWM
__HAL_TIM_SET_COUNTER(&htim1, 10000); //編碼器定時器初始值設定為10000
motor.loopNum = 0; //防溢出
}
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
4.2 定義電機速度函數
void Motor_Send()
{
float output = 0;
PID_SingleCalc(&pid, motor.targetSpeed, motor.speed);
output = pid.output;
if(output > 0) //正轉
{
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, (uint32_t)output);
IN1(1);
IN2(0);
}
else //反轉
{
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, (uint32_t)(-output));
IN1(0);
IN2(1);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
4.3 在檢測霍爾碼盤時發送速度給電機
if(htim->Instance==htim6.Instance) //10ms中斷
{
int16_t pluse = COUNTERNUM - RELOADVALUE/2;
motor.totalAngle = pluse + motor.loopNum * RELOADVALUE/2;
motor.speed = (float)(motor.totalAngle - motor.lastAngle)/(4*13*RR)*6000; //進行速度計算,根據前文所說的,4倍頻,編碼器13位,減速比30,再乘以6000即為每分鍾輸出軸多少轉
motor.lastAngle = motor.totalAngle; //更新轉過的圈數
Motor_Send();//發送速度
}

❼ 8位單片機PID控制PWM的演算法如何實現,C語言計算

PID控制在8位單片機中仍然有廣泛的應用,比如溫度控制,利用比例、積分、微分補償來做恆溫補償控制,當然由於有這些數學處理,用C語言相對方便一些,以下是一個具體的實例。

#include<reg51.h>

#include<intrins.h>

#include<math.h>

#include<string.h>

struct PID {

unsigned int SetPoint; // 設定目標 Desired Value

unsigned int Proportion; // 比例常數 Proportional Const

unsigned int Integral; // 積分常數 Integral Const

unsigned int Derivative; // 微分常數 Derivative Const

unsigned int LastError; // Error[-1]

unsigned int PrevError; // Error[-2]

unsigned int SumError; // Sums of Errors

};

struct PID spid; // PID Control Structure

unsigned int rout; // PID Response (Output)

unsigned int rin; // PID Feedback (Input)

sbit data1=P1^0;

sbit clk=P1^1;

sbit plus=P2^0;

sbit subs=P2^1;

sbit stop=P2^2;

sbit output=P3^4;

sbit DQ=P3^3;

unsigned char flag,flag_1=0;

unsigned char high_time,low_time,count=0;//占空比調節參數

unsigned char set_temper=35;

unsigned char temper;

unsigned char i;

unsigned char j=0;

unsigned int s;

/***********************************************************

延時子程序,延時時間以12M晶振為准,延時時間為30us×time

***********************************************************/

void delay(unsigned char time)

{

unsigned char m,n;

for(n=0;n<time;n++)

for(m=0;m<2;m++){}

}

/***********************************************************

寫一位數據子程序

***********************************************************/

void write_bit(unsigned char bitval)

{

EA=0;

DQ=0; /*拉低DQ以開始一個寫時序*/

if(bitval==1)

{

_nop_();

DQ=1; /*如要寫1,則將匯流排置高*/

}

delay(5); /*延時90us供DA18B20采樣*/

DQ=1; /*釋放DQ匯流排*/

_nop_();

_nop_();

EA=1;

}

/***********************************************************

寫一位元組數據子程序

***********************************************************/

void write_byte(unsigned char val)

{

unsigned char i;

unsigned char temp;

EA=0;

TR0=0;

for(i=0;i<8;i++) /*寫一位元組數據,一次寫一位*/

{

temp=val>>i; /*移位操作,將本次要寫的位移到最低位*/

temp=temp&1;

write_bit(temp); /*向匯流排寫該位*/

}

delay(7); /*延時120us後*/

// TR0=1;

EA=1;

}

/***********************************************************

讀一位數據子程序

***********************************************************/

unsigned char read_bit()

{

unsigned char i,value_bit;

EA=0;

DQ=0; /*拉低DQ,開始讀時序*/

_nop_();

_nop_();

DQ=1; /*釋放匯流排*/

for(i=0;i<2;i++){}

value_bit=DQ;

EA=1;

return(value_bit);

}

/***********************************************************

讀一位元組數據子程序

***********************************************************/

unsigned char read_byte()

{

unsigned char i,value=0;

EA=0;

for(i=0;i<8;i++)

{

if(read_bit()) /*讀一位元組數據,一個時序中讀一次,並作移位處理*/

value|=0x01<<i;

delay(4); /*延時80us以完成此次都時序,之後再讀下一數據*/

}

EA=1;

return(value);

}

/***********************************************************

復位子程序

***********************************************************/

unsigned char reset()

{

unsigned char presence;

EA=0;

DQ=0; /*拉低DQ匯流排開始復位*/

delay(30); /*保持低電平480us*/

DQ=1; /*釋放匯流排*/

delay(3);

presence=DQ; /*獲取應答信號*/

delay(28); /*延時以完成整個時序*/

EA=1;

return(presence); /*返回應答信號,有晶元應答返回0,無晶元則返回1*/

}

/***********************************************************

獲取溫度子程序

***********************************************************/

void get_temper()

{

unsigned char i,j;

do

{

i=reset(); /*復位*/

} while(i!=0); /*1為無反饋信號*/

i=0xcc; /*發送設備定位命令*/

write_byte(i);

i=0x44; /*發送開始轉換命令*/

write_byte(i);

delay(180); /*延時*/

do

{

i=reset(); /*復位*/

} while(i!=0);

i=0xcc; /*設備定位*/

write_byte(i);

i=0xbe; /*讀出緩沖區內容*/

write_byte(i);

j=read_byte();

i=read_byte();

i=(i<<4)&0x7f;

s=(unsigned int)(j&0x0f); //得到小數部分

s=(s*100)/16;

j=j>>4;

temper=i|j; /*獲取的溫度放在temper中*/

}

/*====================================================================================================

Initialize PID Structure

=====================================================================================================*/

void PIDInit (struct PID *pp)

{

memset ( pp,0,sizeof(struct PID)); //全部初始化為0

}

/*====================================================================================================

PID計算部分

=====================================================================================================*/

unsigned int PIDCalc( struct PID *pp, unsigned int NextPoint )

{

unsigned int dError,Error;

Error = pp->SetPoint - NextPoint; // 偏差

pp->SumError += Error; // 積分

dError = pp->LastError - pp->PrevError; // 當前微分

pp->PrevError = pp->LastError;

pp->LastError = Error;

return (pp->Proportion * Error // 比例項

+ pp->Integral * pp->SumError // 積分項

+ pp->Derivative * dError); // 微分項

}

/***********************************************************

溫度比較處理子程序

***********************************************************/

void compare_temper()

{

unsigned char i;

if(set_temper>temper) //是否設置的溫度大於實際溫度

{

if(set_temper-temper>1) //設置的溫度比實際的溫度是否是大於1度

{

high_time=100; //如果是,則全速加熱

low_time=0;

}

else //如果是在1度范圍內,則運行PID計算

{

for(i=0;i<10;i++)

{

get_temper(); //獲取溫度

rin = s; // Read Input

rout = PIDCalc ( &spid,rin ); // Perform PID Interation

}

if (high_time<=100)

high_time=(unsigned char)(rout/800);

else

high_time=100;

low_time= (100-high_time);

}

}

else if(set_temper<=temper)

{

if(temper-set_temper>0)

{

high_time=0;

low_time=100;

}

else

{

for(i=0;i<10;i++)

{

get_temper();

rin = s; // Read Input

rout = PIDCalc ( &spid,rin ); // Perform PID Interation

}

if (high_time<100)

high_time=(unsigned char)(rout/10000);

else

high_time=0;

low_time= (100-high_time);

}

}

// else

// {}

}

/*****************************************************

T0中斷服務子程序,用於控制電平的翻轉 ,40us*100=4ms周期

******************************************************/

void serve_T0() interrupt 1 using 1

{

if(++count<=(high_time))

output=1;

else if(count<=100)

{

output=0;

}

else

count=0;

TH0=0x2f;

TL0=0xe0;

}

/*****************************************************

串列口中斷服務程序,用於上位機通訊

******************************************************/

void serve_sio() interrupt 4 using 2

{

/* EA=0;

RI=0;

i=SBUF;

if(i==2)

{

while(RI==0){}

RI=0;

set_temper=SBUF;

SBUF=0x02;

while(TI==0){}

TI=0;

}

else if(i==3)

{

TI=0;

SBUF=temper;

while(TI==0){}

TI=0;

}

EA=1; */

}

void disp_1(unsigned char disp_num1[6])

{

unsigned char n,a,m;

for(n=0;n<6;n++)

{

// k=disp_num1[n];

for(a=0;a<8;a++)

{

clk=0;

m=(disp_num1[n]&1);

disp_num1[n]=disp_num1[n]>>1;

if(m==1)

data1=1;

else

data1=0;

_nop_();

clk=1;

_nop_();

}

}

}

/*****************************************************

顯示子程序

功能:將占空比溫度轉化為單個字元,顯示占空比和測得到的溫度

******************************************************/

void display()

{

unsigned char code number[]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6};

unsigned char disp_num[6];

unsigned int k,k1;


k=high_time;

k=k%1000;

k1=k/100;

if(k1==0)

disp_num[0]=0;

else

disp_num[0]=0x60;

k=k%100;

disp_num[1]=number[k/10];

disp_num[2]=number[k%10];

k=temper;

k=k%100;

disp_num[3]=number[k/10];

disp_num[4]=number[k%10]+1;

disp_num[5]=number[s/10];

disp_1(disp_num);

}

/***********************************************************

主程序

***********************************************************/

void main()

{

unsigned char z;

unsigned char a,b,flag_2=1,count1=0;

unsigned char phil[]={2,0xce,0x6e,0x60,0x1c,2};

TMOD=0x21;

TH0=0x2f;

TL0=0x40;

SCON=0x50;

PCON=0x00;

TH1=0xfd;

TL1=0xfd;

PS=1;

EA=1;

EX1=0;

ET0=1;

ES=1;

TR0=1;

TR1=1;

high_time=50;

low_time=50;

PIDInit ( &spid ); // Initialize Structure

spid.Proportion = 10; // Set PID Coefficients 比例常數 Proportional Const

spid.Integral = 8; //積分常數 Integral Const

spid.Derivative =6; //微分常數 Derivative Const

spid.SetPoint = 100; // Set PID Setpoint 設定目標 Desired Value

while(1)

{

if(plus==0)

{

EA=0;

for(a=0;a<5;a++)

for(b=0;b<102;b++){}

if(plus==0)

{

set_temper++;

flag=0;

}

}

else if(subs==0)

{

for(a=0;a<5;a++)

for(b=0;a<102;b++){}

if(subs==0)

{

set_temper--;

flag=0;

}

}

else if(stop==0)

{

for(a=0;a<5;a++)

for(b=0;b<102;b++){}

if(stop==0)

{

flag=0;

break;

}

EA=1;

}

get_temper();

b=temper;

if(flag_2==1)

a=b;

if((abs(a-b))>5)

temper=a;

else

temper=b;

a=temper;

flag_2=0;

if(++count1>30)

{

display();

count1=0;

}

compare_temper();

}

TR0=0;

z=1;

while(1)

{

EA=0;

if(stop==0)

{

for(a=0;a<5;a++)

for(b=0;b<102;b++){}

if(stop==0)

disp_1(phil);

// break;

}

EA=1;

}

}

熱點內容
php獲取瀏覽器 發布:2025-03-11 09:03:31 瀏覽:876
安卓常駐後台需要什麼許可權 發布:2025-03-11 08:58:26 瀏覽:180
綠源電動車威牛是什麼配置 發布:2025-03-11 08:47:34 瀏覽:9
wps加密文件密碼忘記 發布:2025-03-11 08:36:49 瀏覽:46
可編程渲染管線 發布:2025-03-11 08:35:23 瀏覽:454
一般人手機設置密碼會是什麼 發布:2025-03-11 08:27:19 瀏覽:415
緩存電視劇軟體 發布:2025-03-11 08:26:26 瀏覽:134
安卓怎麼下載ios14 發布:2025-03-11 08:25:50 瀏覽:566
軟體調試源碼 發布:2025-03-11 08:24:59 瀏覽:487
剪輯視頻怎麼配置解說 發布:2025-03-11 08:24:23 瀏覽:264