PID恒溫控制出現可以加熱,但是不能關閉加熱,大佬們幫忙看下是啥問題?設置溫度為40度。
**********************************************************************************************************************/
/*********************************************************************************************************************/
#define INT_TIME 1000 //定時時間,單位為us
#define TH_VAL (unsigned char)((0x10000 - (INT_TIME*(FOSC/1000))/12000)>>8)
#define TL_VAL (unsigned char)((0x10000 - (INT_TIME*(FOSC/1000))/12000))
void TIMER0_ISR (void) interrupt 1 //每1ms產生中斷
{
TH0 = TH_VAL;
TL0 = TL_VAL;
count++;
if(count>=10) //10ms
{
cnt++; //計數
count=0;
}
// P03 = ~P03;
}
void Timer0_Init(void)
{
TMOD = (TMOD&0xFC)|0x01; //模式選擇: 定時器0,模式1。
TH0 = TH_VAL; //高8位裝初值
TL0 = TL_VAL; //低8位裝初值
TR0 = 1; //定時器0使能
ET0 = 1; //定時器0中斷使能
EA = 1;
// PT0 = 1; //設置定時器0中斷優先級為高優先級
}
/***********************************************************************************
函數名稱: ADC_Init
功能描述: 初始化ADC寄存器(設置ADC時鐘、設置采樣時間、選擇ADC參考電壓)
輸入參數: 無
返 回 值: 無
***********************************************************************************/
void ADC_Init(void)
{
// ADCON = AST(0) | ADIE(0) | HTME(7) | ADCALE(1) | VSEL(ADC_REF_INNER); //設置ADC參考電壓為內部1.5V
ADCON = AST(0) | ADIE(0) | HTME(7) | ADCALE(0) | VSEL(ADC_REF_VDD); //設置ADC參考電壓為VDD
ADCFGL = ACKD(7);
P06F = P06_ADC8_SETTING; //設置P0.6為ADC引腳功能
}
/***********************************************************************************
函數名稱: Get_AdcValue
功能描述: 獲取ADC轉換數值
輸入參數: channel ADC通道號
返 回 值: ADC值
***********************************************************************************/
unsigned int Get_AdcValue(unsigned char channel)
{
unsigned int AD_Value;
ADCFGL = (ADCFGL&0xE0) | ADCHS(channel); //選擇ADC通道
ADCON |= AST(1); //啟動ADC轉換
while(!(ADCON & ADIF)); //等待ADC轉換完成
ADCON |= ADIF; //清除ADC中斷標志
AD_Value = ADCDH*256 + ADCDL; //讀取AD值
AD_Value >>= 4;
return AD_Value;
}
/*********************************************************************************************************************/
struct _pid{
float Set_WD; //設定值
float Actual_WD; //實際值
float err; //偏差
float err_last; //上一次偏差
float err_next;
float Kp,Ki,Kd;
float voltage; //電壓值
float integral; //積分值
}pid;
void PID_INIT()
{
pid.Set_WD=0.0;
pid.Actual_WD=0.0;
pid.err=0.0;
pid.err_last=0.0;
pid.err_next=0.0;
pid.voltage=0.0;
pid.integral=0.0;
pid.Kp=0.4;
pid.Ki=0.5;
pid.Kd=0.4;
}
unsigned int temp=40; //設置溫度值
void PID_Realize(){ //PID控制
unsigned int index;
if(temp==40){temp_adc=1419;} //100K熱敏電阻40度溫度值時對應的ADC值
pid.Set_WD=temp_adc;
pid.err=pid.Set_WD-AD_Value;
if(pid.err>200 || pid.err<-200)
{
index=0;
}
else if(pid.err<100 || pid.err>-100)
{
index=1;
pid.integral+=pid.err;
}
else
{
if(pid.err>0)
{
index=(200-pid.err)/100;
pid.integral+=pid.err;
}
else
{
index=(200+pid.err)/100;
pid.integral+=pid.err;
}
}
pid.voltage=pid.Kp*pid.err + pid.Ki*pid.integral + pid.Kd*(pid.err-pid.err_last);
pid.err_last=pid.err;
PWM_OUT=pid.voltage*1.0; //賦值給PWM_OUT
if(PWM_OUT>100){PWM_OUT=100;}
}
void hot(unsigned int PWM) //加熱函數
{
if(cnt<PWM){P07=1;} //加熱,
if(cnt>PWM){P07=0;} //關閉加熱
if(cnt>100){cnt=0;}
}
/*********************************************************************************************************************/
void System_Init(void)
{
LVDCON = 0xE0; //開啟LVD,設置為低電壓復位模式,檢測電壓為2.7V
#ifdef SYSCLK_8MHZ
CKDIV = 0; //系統時鐘上電默認為IRCH的二分頻(4MHz),運行8MHz,則CKDIV設置為0
#endif
#ifdef UART1_EN
Uart1_Initial(UART1_BAUTRATE);
#endif
}
void main(void)
{
P06F = INPUT | PU_EN; //ADC腳
P07F = OUTPUT | PU_EN; //加熱腳
P06=1;
P07=0;
System_Init();
EA = 1; //開全局中斷
Timer0_Init(); //定時器初始化
ADC_Init(); //初始化ADC
PID_INIT(); //PID初始化
while(1)
{
AD_Value = Get_AdcValue(ADC_CH8); //獲取溫度值
PID_Realize(); //PID運算
hot(PWM_OUT);//控制加熱
}
}
|