PID控制溫度目前是可以加熱,但是到達設定溫度沒法關閉加熱,示波器里顯示時有關閉加熱的部分,不過一下又恢復成加熱了。大部分時間都是加熱。大佬們幫忙分析下是哪里的問題?
#include "include/ca51m020_config.h"
#include "include/ca51m020sfr.h"
#include "include/ca51m020xsfr.h"
#include "include/gpiodef_m020.h"
#include "include/system_clock.h"
#include "include/uart.h"
#include "include/adc.h"
#include "include/delay.h"
unsigned int count=0;
unsigned int temp_adc=0,cnt=0;
unsigned int PWM_OUT=0;
unsigned int get_ntc=0;
unsigned int AD_Value;
void Timer0_Init(void);
void ADC_Init(void);
unsigned int Get_AdcValue(unsigned char channel);
/*********************************************************************************************************************/
/*********************************************************************************************************************
ADC控制例程
**********************************************************************************************************************/
/*********************************************************************************************************************/
#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.3;
pid.Ki=0.05;
pid.Kd=0.3;
}
unsigned int temp=40;
void PID_Realize(){
unsigned int index;
if(temp==40){temp_adc=1419;} //設定溫度,對應100K熱敏電阻40攝氏度下的ADC值
pid.Actual_WD=AD_Value; //獲取ADC值
pid.Set_WD=temp_adc; //設定溫度
pid.err=pid.Set_WD-pid.Actual_WD;
if(pid.err>200 || pid.err<-200)
{
index=0;
}
else if((pid.err<100 && pid.err>0)|| (pid.err<0 && 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;
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; //加熱
P17F = OUTPUT | PU_EN;
P17=1;
P06=1;
P07=0;
System_Init();
EA = 1; //開全局中斷
Timer0_Init();
ADC_Init(); //初始化ADC
PID_INIT();
while(1)
{
AD_Value = Get_AdcValue(ADC_CH8); //獲取溫度值
PID_Realize(); //PID控制
hot(PWM_OUT); //加熱控制
// Uart1_PutChar(AD_Value>>8);
// Uart1_PutChar(AD_Value);
}
}
|