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);//控制加热
}
}
|