PID恒温控制出现可以加热,但是不能关闭加热,大佬们帮忙看下是啥问题?是数据符号类型不一致吗?**********************************************************************************************************************//*********************************************************************************************************************/#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);//控制加热 }}
|