📄 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 + -