[经验] MSP430 PID温度控制(转帖)

xiongpb   2015-7-29 22:41 楼主
程序框架:

本设计使用高速晶体振荡器,程序如下:
BCSCTL1 &= ~XT2OFF;//打开XT2高频晶体振荡
do
{
   IFG1 &= ~OFIFG;//清除晶振失败标志
   for (i = 0xFF; i > 0; i--);//等待8MHz晶体起振
}
   while ((IFG1 & OFIFG));//晶振失效标志仍然存在?
   BCSCTL2 |= SELM_2 + SELS;//MCLK和SMCLK选择高频晶振
PID算法程序:
void PIDCalc(void)
{
float Rate;//误差变化率                              
Current_Error =   Set_Temp  - Pre_Temp ;// 当前误差计算
Sum_Error    +=   Current_Error;// 误差积分
Prev_Error    =   Last_Error;// 存储误差更新
Last_Error    =   Current_Error;// 存储误差更新
Rate          =   ( Current_Error - Last_Error )*1000/ Ctrl_Period;  
// 当前误差微分
if(Rate>5)//对误差变化率进行限制,锅炉温度不可能变化太大
Rate=5;
if(Rate<-5)
Rate=-5;
    P_OUT = P * Gain * Current_Error  ; /*比例项*/
I_OUT = I * Gain * Sum_Error  ;/*积分项*/
//积分限幅处理
if( I_OUT>PID_I_MAX )  I_OUT = PID_I_MAX;
if( I_OUT
if( ( Current_Error <= 2.5 ) && ( Prev_Error <=2.8))
{
I_OUT=I_OUT * 0.5;
}
if( (Current_Error <= 0.45 ) && ( Last_Error <=55))
{
I_OUT=I_OUT * 0.08;
}
//因为锅炉只能加温不能降温所以一旦超过设定值令积分值为零      
if( ( Current_Error <= 0 ) && ( Last_Error <=0 ))
{
  I_OUT=0;
  }      
  //微分延迟输出处理
  D_OUT= ( D_OUT * Sdde_Para + D * Rate * (1-Sdde_Para) )*Gain  ;
  PID_OUT =  P_OUT  +  I_OUT  +  D_OUT ;
  if ( PID_OUT >= PWM_DATA_MAX )  PID_OUT = PWM_DATA_MAX;
  if ( PID_OUT <= PWM_DATA_MIN )  PID_OUT = PWM_DATA_MIN;
  if( Set_Temp - Pre_Temp >=10)  
  PID_OUT=16383;
  }
void main()
{
Device_Init( );
while(1)
{
LED8_Rollback;//系统运行指示灯
Parameter_Show( );
}
}
ADC模数转换程序
char ADC12Init(char n,char channels[],char rep)
{
if(n>15)
return 0;
ADC12CTL0 = ADC12ON + MSC + SHT0_0 + REFON + REF2_5V;
// 开启ad,参考电压2.5v
ADC12CTL1 = SHP + ADC12SSEL_3;  //Use sampling timer, SMCLK
for(int i = 0;i < n;i++)
{
if(channels >= 0x80)
return 0;
*(char*)(ADC12MCTL0_ + i) = channels;//每个MCTL设置
}
*(char*)(ADC12MCTL0_ + n - 1) |= EOS;//序列结束      
if(rep != 0)//多次转换
{
ADC12CTL1 |= CONSEQ_3;
}
else
{
ADC12CTL1 |= CONSEQ_1;
}
ADC12IE = 1<<(n-1);// Enable ADC12IFG.n-1
return 1;
}
定时器设置程序
void TA_Init(void)
{
  TACTL=TASSEL0+TACLR;//设定定时器A控制寄存器
  CCTL0=CCIE;//使能中断
  CCR0=3276;//设置CCR0初值,及100毫秒中断一次
  TACTL|=MC0;//计数器加模式
}
void TimerB_Init(void)
{
    TBCTL=TBSSEL_1+TBCLR+MC0+ID_3;
    TBCCTL1=OUTMOD_3;
    TBCCR0=16384;//PWM中断周期
    TBCCR1=4000;//PWM低电平时间
    P4DIR|=BIT1;//设置PWMIO口
    P4SEL|=BIT1;
}
void TimerB_Duty(u16 duty)
{
    TBCCR1=duty;//PWM低电平时间
}
异步通讯程序
void UART0_Init(void)
{   
    WDTCTL = WDTPW + WDTHOLD;// Stop WDT
    P3SEL |= 0x30;// P3.4,5 = USART0 TXD/RXD
    ME1 |= UTXE0+URXE0;// Enable USART0 TXD/RXD
    UCTL0 |= CHAR;// 8-bit character
    UTCTL0 |= SSEL0;// UCLK = ACLK
    UBR00 = 0x03;// 32k/9600 - 3.41
    UBR10 = 0x00;                             
    UMCTL0 = 0x4A;// Modulation
    UCTL0 &= ~SWRST;// Initialize USART state machine
    IE1 |= URXIE0;// 使能USART0的接收中断
}
void PutChar(uchar data)
{
    while (!(IFG1 & UTXIFG0));// TX缓存空闲?
     TXBUF0 = data;// 发送数据
}
void Blank(void)   
{   
  PutChar(0x20);
}
void Newline()   
{
   PutChar(0x0d);//发送一个回车
   PutChar(0x0a);//发送一个换行
}
void PutString(uchar *ptr)
{
   while(*ptr != '\0')
{
     PutChar(*ptr++);
  }
  }
温度拟合程序
float Scale_Conv( u16 Value)
{
float  Temp1=0,Temp2=0;
//温度拟合(二次函数)
Temp1=Value*A_para;
Temp1=Value*Temp1;
Temp2=Value*B_para;
//当前温度=A*X*X+B*X+C-零漂
return (Temp1+Temp2+C_para+Null_shift);        
}

回复评论 (5)

谢谢楼主,学习一下
点赞  2015-7-29 22:49
多谢楼主分享,来学习下下,…
玩板看这里: https://bbs.eeworld.com.cn/elecplay.html EEWorld测评频道众多好板等你来玩,还可以来频道许愿树许愿说说你想要玩的板子,我们都在努力为大家实现!
点赞  2015-7-29 23:31
感谢分享,顶一下
点赞  2015-7-29 23:37
可以的,最缺的就是PID的示例程序,光看PID没例子快看吐了
点赞  2015-8-7 15:43
不错
点赞  2015-8-9 20:51
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复