⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pid.txt

📁 电阻炉的温度PID控制 经过实际实验验证可用
💻 TXT
字号:
// qq 609051974
//
#include<avr\io.h>
#include<avr\interrupt.h>
#include<math.h>
#include<avr\PGMSPACE.h>

#define SYS_CLK    16000000
#define NOP()  asm volatile("nop")
//ADC片选信号
#define ADC_CS_L    DDRB |= (1<<DDB0);PORTB |= (1<<PB0);    
#define ADC_CS_H    DDRB |= (1<<DDB0);PORTB |= (1<<PB0);

//端口初始化函数
void PORT_Init(void);
//SPI初始化 
void SPI_Init(void);
void ADC_Init(void);
unsigned char ADC_WRITE_TO_REG(unsigned char byte_word);
unsigned char READ_DRDY(void);
void ADC_READ(void);
void Delay_1ms(unsigned int ms);
//定时器初始化
void Timer0_Init(void);
void Timer1_Init(void);
unsigned char volatile T0_cnt=0;
unsigned char ADC_DATA_BUFFER[2]; 
//十进制转换成ASC码
void Dec2Asc(int Dec_val);
unsigned char T_buf[4];
//分度表计算部分
unsigned char PROGMEM RTD_TABLE[2002]={
                                 
                                       };

unsigned int RTD_TAB_WORKOUT(float i);
unsigned int volatile temp,j_search;
unsigned char tmp_H, tmp_L;
//串口函数
#define BAUDRATE 9600
#define MYUBRR   SYS_CLK/16/BAUDRATE - 1
unsigned char uart_data,sign_bit;
unsigned char U_RX_FLG = 0;
void UART_Init(unsigned int ubrr);
void UART_Transmit(unsigned char data);
//电压,阻值计算
float Vout_workout(unsigned int Tadc);
float Rtd_workout(float to);
//温度搜索,获取
unsigned int temp_search(unsigned int s_d);
void temp_get(void);
void compute_temp(long tt);
float volatile rr,temperature;
unsigned char volatile temp_flag;
int volatile t_val=0,temp_mid;
long volatile temp_val=0;
//控制部分
#define fan_off     DDRD |= (1<<DDD6); PORTD |= (1<<PD6);
#define fan_on      DDRD |= (1<<DDD6); PORTD &= ~(1<<PD6);
#define cool_off    DDRD |= (1<<DDD7); PORTD |= (1<<PD7);
#define cool_on     DDRD |= (1<<DDD7); PORTD &= ~(1<<PD7);

void temp_control(void);
void bang_con(void);
float PID(void);
unsigned char com_cnt=0,con_flag=0,cnt=0,set_flag=1,bang_flag=0;
float pid_out=0.0,temp_set=50.0,Ki=0.2,Kd=25.0;
float K_p=20.0,err=0,err_1=0,err_2=0,temp_neg=0.0,temp_pos=0.0;
int con_cnt=0,con_plus=0;

int main(void)
{
  PORT_Init();
  Timer0_Init();
  Timer1_Init();
  UART_Init(MYUBRR);
  ADC_Init();
  //总中断打开
  sei();

  do
  {
    unsigned char j;
  	if(temp_flag) 
  	{ 
  		cli();
  		temp_flag=0;
  		compute_temp(temp_mid);
  		TCCR0 |=(1<<CS02)|(1<<CS00);
  		sei();
  	}
  	if(set_flag)
  	{
  		set_flag=0;
  		if(temp_set<32.0)
  		{
  			cool_on;
  			K_p=40.0;
  			Ki=2.0;
  			Kd=36.0;
  			con_plus=((int)(temp_set/2));
  			temp_neg=-(temp_set/10.0);
  			temp_pos=4.5+temp_neg;
  		}
  		else
  		{
  			cool_off;
  			K_p=25.0;
  			Ki=0.5;
  			Kd=16.0;
  			con_plus=0;
  			temp_neg=-(temp_set/100.0);
  			temp_pos=6.0-(temp_set/12.0);
  		}   		
  	}
  	if (con_flag) 
  	{
  		cli();
  		fan_on;
  		cool_off;
  		con_flag=0;
  		temp_control(); 
  		Dec2Asc(temperature*10);
  		UART_Transmit('t');
  		UART_Transmit(32);
      for(j=0;j<4;j++) UART_Transmit(T_buf[j]);
      UART_Transmit('\n'); 
      UART_Transmit('\r');		
  		Dec2Asc(con_cnt*10);
  		UART_Transmit('c');
  		UART_Transmit(32);
      for(j=0;j<4;j++) UART_Transmit(T_buf[j]);
      UART_Transmit('\n');
      UART_Transmit('\r');	
      UART_Transmit('e');
      UART_Transmit(32);
      Dec2Asc(10*err);
      for(j=0;j<4;j++) UART_Transmit(T_buf[j]);
      UART_Transmit('\n');
      UART_Transmit('\r');	
  		sei();
    }
  }
  while(1);
}

//端口初始化函数
void PORT_Init(void)
{
  DDRA    |= 0xFF;
  PORTA   |= 0xFF;

  DDRB    |= 0xFF;
  PORTB   |= 0xFF;

  DDRC    |= 0xFF;
  PORTC   |= 0xFF;  

  DDRD    |= 0xFF;
  PORTD   |= 0xFF;
}

void SPI_Init(void)
{ 
  PORTA |= (1<<PA7);
  DDRB  |= (1<<DDB4);
  PORTB |= (1<<PB4);
  DDRB  |= (1<<DDB5);
  PORTB |= (1<<PB5); 
  PORTB |= (1<<PB6);
  DDRB &= ~(1<<DDB6);
  DDRB  |= (1<<DDB7);
  PORTB |= (1<<PB7);
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<CPOL)|(1<<CPHA); 
}

//ADC操作
unsigned char ADC_WRITE_TO_REG(unsigned char byte_word)
{ 
  unsigned char q;
  cli();
  SPI_Init();
  ADC_CS_L;
  Delay_1ms(10);
  q = SPSR;
  q = SPDR;//清数据发送结束标志SPIF
  SPDR = byte_word;
  while(!(SPSR&0x80));
  q = SPSR;
  q = SPDR;
  ADC_CS_H;
  Delay_1ms(10);
  sei();
  return q;
}

//读忙标志位
unsigned char READ_DRDY(void)  //读取DRDY bit
{
  ADC_WRITE_TO_REG(0x08);     //读0号寄存器
  return ADC_WRITE_TO_REG(0);
}

void ADC_Init(void)
{
  //寄存器初始化
  ADC_WRITE_TO_REG(0x20); //选择时钟寄存器,写入
  ADC_WRITE_TO_REG(0x0C); //时钟2.4576M,系统更新速率50Hz
  ADC_WRITE_TO_REG(0x10); //选择设定寄存器,写入
  ADC_WRITE_TO_REG(0x52); //增益为四,执行自校准模式
}
舍我其谁 20:51:23
void ADC_READ(void)
{
  unsigned char *p_f;
  p_f = ADC_DATA_BUFFER;
  while(1)
   {
    if((READ_DRDY() & 0x80))    //DRDY为1,说明系统忙,不能读取数据
	  {NOP();}
	 else                        //为0,说明数据准备好,可以读取
	  break;
    }  
  ADC_WRITE_TO_REG(0x38);
  *(p_f++) = ADC_WRITE_TO_REG(0);
  *(p_f++) = ADC_WRITE_TO_REG(0);
}


void Delay_1ms(unsigned int ms)
{
   unsigned int i;
   while(ms)
     {
	   for(i = SYS_CLK/4000;i>0;i--)
	     asm volatile("NOP");
	   ms--;
	  }
}

//正温度数据计算
/*unsigned int RTD_TAB_WORKOUT(float i)
{
  unsigned int  rtd;
  float RTD, t;
  t=i;
  RTD = 10000.0*(1.0+3.90802*(1.0E-3f)*t-0.580195*(1.0E-6f)*t*t);
  rtd = (unsigned int) RTD;
  return rtd;
}*/

void UART_Init(unsigned int ubrr)
{
  UBRR0H = (unsigned char)(ubrr>>8);
  UBRR0L = (unsigned char)ubrr;
  UCSR0B  |= (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);
}

void UART_Transmit(unsigned char data)
{
  while(!(UCSR0A & 0x20))
       ;
  UDR0 = data;
}

ISR(USART0_RX_vect)
{
    UCSR0B &= ~0x80;             //关闭接收中断
    uart_data = UDR0;          //为真 接收数据
    U_RX_FLG  = 1;             //置收到数据标志
    UCSR0B |= 0x80;              //打开接收中断
}
舍我其谁 20:51:33
//输出电压计算
float Vout_workout(unsigned int Tadc)
{
   float t1;
   t1 = (float)(((float)Tadc * 2.5011)/32768.0/4.0/2.5011);    //2的 5 次幂为 32.0
   return t1;  
}

float Rtd_workout(float to)
{
  float t2;
  t2 = ((float)(((0.1+2.1*to)*2.0)/(2.0-(2.1*to))))*1000.0; //千欧转换为欧姆
  return t2;
}

void temp_get(void)
{
	unsigned int trr=0;	
  ADC_READ();
  temp = (unsigned int)(ADC_DATA_BUFFER[0]<<8)+(unsigned int)ADC_DATA_BUFFER[1];
  if(temp>=0x8000)
  {
  	sign_bit=0;
    temp -=0x8000;
  }
  else 
  {
  	sign_bit=1;
  	temp=0x8000-temp;
  }
  rr = Rtd_workout(Vout_workout(temp));
  trr = (100*rr);
  t_val=temp_search(trr);//电阻值rr乘以100,然后查表求出温度数据值
  t_val=(t_val>>1);
  if(sign_bit) t_val=-t_val;
  //通过串口上传测得的数据
//  ADC_READ();
}
舍我其谁 20:51:47
unsigned int temp_search(unsigned int s_d)
{
  //unsigned char 
  const unsigned char *p_i,*pp_i;
//  unsigned int j_search;
//  unsigned char tmp_H, tmp_L;
  // search_save[8];
  p_i = RTD_TABLE;
//  p_i =(unsigned int)p_i;
  pp_i=p_i;  
  do
  {
    j_search = 0;
	  tmp_H = pgm_read_byte_near(p_i);
	  tmp_L = pgm_read_byte_near(p_i+1);
    j_search = (((unsigned int)tmp_H)<<8) +(unsigned int) tmp_L;
	  if(j_search>s_d)
	  {
	    break;
	  }
	  p_i +=500;
  }
  while(1);
  //返回的i值,为100度区间
  if(p_i==RTD_TABLE)
  return (*p_i);
	else
	p_i=p_i-500;
   
  do{
     j_search=0;
     tmp_H = pgm_read_byte_near(p_i);
	   tmp_L = pgm_read_byte_near(p_i+1);

     j_search = (((unsigned int)tmp_H)<<8) +(unsigned int) tmp_L;
     if(j_search>s_d)
	   {
	    break;
	   }
	   p_i +=100;
    }
    while(1);
    p_i = p_i-100;
  do{
      j_search=0;
      tmp_H = pgm_read_byte_near(p_i);
	    tmp_L = pgm_read_byte_near(p_i+1);

      j_search = (((unsigned int)tmp_H)<<8) +(unsigned int) tmp_L;
      if(j_search>s_d)
	    {
	     break;
	    }
	    p_i +=10;
    }
  while(1);
  p_i = p_i-10;
  do
   {
     j_search = 0;
	   tmp_H = pgm_read_byte_near(p_i);
	   tmp_L = pgm_read_byte_near(p_i+1);
     j_search = (((unsigned int)tmp_H)<<8) +(unsigned int) tmp_L;
//	   search_save[0] = tmp_H;
//	   search_save[1] = tmp_L;
	   if(j_search>s_d)
	   {
	     break;
	   }
	   p_i +=2;
   }
  while(1);
  if(p_i!=0)
  {
    / arch_save[2] = RTD_TABLE[i-2];
	//  search_save[3] = RTD_TABLE[i-2+1];
	}
 //数组search_save[0],[1]存储上限电阻值;[2],[3]存储下限电阻值
  return (p_i-pp_i);        //返回区间上限
}

void compute_temp(long tt)
{
	com_cnt++;
	if(com_cnt>=12)         //12*0.5 = 6s执行一次控制算法
	{
	  con_flag=1;
	  com_cnt=0;
	}
//	temp_mid=(int)(tt/20);
	temperature=(float)(tt/200.0);
}

void Timer0_Init(void)
{
  TCCR0 &= 0x00;
  TCNT0  = 0x3D;                //预分频1024,定时25毫秒
  TIMSK |= (1<<TOIE0);
  TCCR0 |=(1<<CS02)|(1<<CS00);
}

void Timer1_Init(void)
{
  TCCR1A |= (1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);
  TCCR1B |= (1<<WGM13);
  ICR1  = 20000;               //PWM脉冲载波频率50 Hz
  OCR1A = 0x0000;            
  OCR1B = 0x0000;
  TIMSK |= (1<<TOIE1);
  TCCR1B |= (1<<CS11); 
}

ISR(TIMER0_OVF_vect)
{
  cli();
  TCCR0 &= 0x00;
  TCNT0  = 0x3D;              //预分频1024,定时25毫秒
  temp_get();                 //获取温度
  temp_val+=t_val;            //温度累加,累加没有起作用
  T0_cnt++;
  if(T0_cnt>=20)              //计数20*25=500ms,采集一次温度
  {
  	temp_flag=1;
  	temp_mid=temp_val;        //应该采用滤波算法,取中间值
  	temp_val=0;
  	T0_cnt=0;
  }
  else
  {
    TCCR0 |=(1<<CS02)|(1<<CS00);     
  }
  sei();
}

ISR(TIMER1_OVF_vect)
{
	 cli();
   cnt++;     
   if(cnt<=con_cnt) OCR1A=0;
   else OCR1A=10000;
   if(cnt>=100) cnt=0; 
   sei();
}
void temp_control(void)
{			   
	if(bang_flag) bang_con();
	else
	{		
	  err_2=err_1;
	  err_1=err;
	  err=temp_set-temperature;	   
	  if(err>=temp_pos) {pid_out=0;con_cnt=100;bang_flag=1;}
	  else if(err<=temp_neg) {pid_out=0;con_cnt=0;bang_flag=1;}
	  else 
	  {
	   	pid_out+=PID();
	   	if(((int)pid_out+con_plus)>100) {pid_out=100.0-(float)con_plus;}
	    else if(((int)pid_out+con_plus)<1) {pid_out=0.0-(float)con_plus;}
	    else pid_out+=0;	
	   	con_cnt=(int)(pid_out)+con_plus;
	  }  	
	  if(con_cnt>100) con_cnt=100;
	  else if(con_cnt<1) con_cnt=0;
	  else con_cnt+=0;
	}
}

void bang_con(void)
{
	err=temp_set-temperature;
	if(err<temp_pos&&err>temp_neg) 
	{
		if(con_cnt==100)
		{
		  if(temp_set>=32) pid_out=100.0-K_p*err;
		  else            pid_out=K_p*err;
		}
		else pid_out=0;		
		if(((int)pid_out+con_plus)>100) {pid_out=100.0-(float)con_plus;}
	  else if(((int)pid_out+con_plus)<1) {pid_out=0.0-(float)con_plus;}
	  else pid_out+=0;
	  con_cnt=(int)(pid_out)+con_plus;
		bang_flag=0;
		err_1=err;
	}
	else
	{
	  if(err>=temp_pos) con_cnt=100;
	  else         con_cnt=0;	  
	}		
}

float PID(void)
{
	float y;
	y=K_p*(err-err_1)+Ki*err+Kd*(err-2*err_1+err_2);
	return y;
}

void Dec2Asc(int Dec_val)
{
	if(Dec_val<0)
  {
  	T_buf[0]=45;
  	T_buf[1]=(-Dec_val)/10+48;
  	T_buf[2]=46;
  	T_buf[3]=(-Dec_val)%10+48;
  }
  else if(Dec_val<10)
  {
  	T_buf[0]=32;
  	T_buf[1]=48;
  	T_buf[2]=46;
  	T_buf[3]=Dec_val+48;
  }
  else if(Dec_val<100)
  {
    T_buf[0]=32;
  	T_buf[1]=Dec_val/10+48;
  	T_buf[2]=46;
  	T_buf[3]=Dec_val%10+48;
  	
  }
  else
  {
  	T_buf[0]=Dec_val/100+48;
  	T_buf[1]=(Dec_val%100)/10+48;
  	T_buf[2]=46;
  	T_buf[3]=Dec_val%10+48;
  }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -