很早以前淘来的 热风器 自整定 PID 参考程序,现发布出来给大伙分享,内容仅供学习参考,包含PCB图;
Altium Designer画的原理图和PCB图如下:(51hei附件中可下载工程文件)
单片机源程序如下:
- #include<intrins.h>
- #include<stdlib.h>//包含 rand() 这样的随机函数
- #include "STC12C5A60S2.h"
- #include "zcy.h"
- #include "s_12864.h"
- ////////////////////////////////////////////////////////
- //全局变量
- volatile long time0_temp1 = 0;
- volatile long time0_temp2 = 0;
- volatile long global_sec = 0;
- int key_counter = 0 ;
- int led_flash_mode_index = 2 ;//led闪灯模式 1--8 从1开始 最多8种模式 ssssssssss
- volatile int time0_10ms_flag = 0;
- int time0_10ms_counter = 0;
- int led_active_flag = 0;
- typedef void (*led_fun_str)(void);//定义一个函数指针的数据类型
- //之后用该数据类型定义一个数组
- led_fun_str led_fun_bufffer[29+29];
- void (*led_flash_fun_str)(void);
- int led_index = 1;
- int k_off = 0;
- int k_on = 0;
- uchar temp_random = 0;
- uchar now_temp_random = 0;
- uchar last_temp_random = 0;
- uchar temp_diff = 0;
- uchar temp_buffer_random[29];
- int k_extern = 0;
- int loop_temp = 0;
- uchar temp_buffer_16_16_comm[32];//必须设计成全局变量才不会显示错乱
- uchar temp_buffer_8_16_comm[16];//必须设计成全局变量才不会显示错乱
- int refer_fun_flag = 0;
- int key_perss_counter = 0;
- int key_once_active_flag = 0;//key动作一次
- int key_value = 0 ;
- float now_temp = 0.0;
- long dis_now_temp = 0;
- float wenkong_now_temp = 0.0;//用于温度控制的当前温度
- volatile int global_sec_flag = 0;
- int temp_zero_below_flag = 1 ;//1说明是0及正温度 0说明是负温度
- char temp_dis_num_buffer[10];//必须定义成全局变量 否则出错 原因不详
- char *temp_str;
- uint them = 0;
- int ds_18b20_reset_ok_flag = 0;
- //pid
- float SV_value = 50.0; //设定温度值
- float PV_value = 0.0; //用于参与计算的当前温度值
- volatile float P_value = 0.0; //比例带 比如56.3代表56.3% 0.0--200.0
- int I_value = 0; //积分时间 秒 0-3600
- int D_value = 0; //微分时间 秒 0-900
- int comm_dis_once_flag = 1; //初始为1
- volatile int special_dis_once_flag = 1; //初始为1
- int pid_tune_flag = 0;//初始为0 即pid阶段 采用默认的值 1 为自整定过程
- int three_dot_dis_flag = 0;
- float Proportion = 0.0; // 比例常数 Proportional Const
- float Integral = 0.0; // 积分常数 Integral Const
- float Derivative = 0.0; // 微分常数 Derivative Const
- float LastError = 0.0; // Error[-1]
- float PrevError = 0.0; // Error[-2]
- float SumError = 0.0; // Sums of Errors
- float dError = 0.0;
- float Error = 0.0;
- int pid_result = 0;
- float T_Hight = 0.0;
- float T_LOW = 100.0; //温度
- long TIME_Hight = 0;
- long TIME_LOW = 0; //具体的秒
- int pid_con_10ms_flag = 0;
- int pid_con_counter = 0;
- float KC = 1.0; //临界比例系数 初始默认的值
- int TC = 40; //振荡周期 初始默认的值
- int temp_pid = 0;//设定成全局变量
- volatile int get_now_temp_flag = 0;
- volatile int enable_pid_sec_flag = 0;
- volatile int pid_self_sec_flag = 0;
- //uint pid_self_calc_buffer[200] _at_ 0xF000; //0xffff 对应flash的最顶端
- int zero_across_counter = 0;
- int pid_self_first_status_flag = 0;
- long pid_self_time_sec = 0;
- float max_temp = 0.0 ; //初始温度等于0
- float min_temp = 100.0 ;//初始温度等于100
- float sum_temp = 0.0 ; //初始温度等于0
- float aver_temp = 0.0 ;
- int cool_ack_counter = 0;
- int hot_ack_counter = 0;
- int once_add_1_flag = 0;
- float pid_self_calc_buffer[4];
- int k_pid_self_counter = 0;
- int enable_calc_min_max_flag = 0;
- int k_max_min = 0;
- int dis_tune_once_flag = 1;
- int k_cut_off_flag = 0;//断k偶标志
- long k_reou_value = 0;
- int soft_dis_flag = 1;
- int soft_counter = 0;
- int soft_end_counter = 0;
- int pwm_con_time_flag = 0;
- //qqqqqqqqqqqqqq
- ////////////////////////////////////////////////////////
- //函数定义
- void SendByte(uchar Dbyte); //发送字节数据
- void write_cmd(uchar Cbyte);//写指令
- void write_data(uchar Dbyte);//写数据
- void PUTchar8x8(int row,int col,int count,uchar *put);
- void PUTchar8x16(int row,int col,int count,uchar *put);
- void PUTchar16x16(int row,int col,int count,uchar *put);//32个字节表示1个汉字
- void PUTchar24x24(int row,int col,int count,uchar *put);
- void PUTBMP(void);//图片
- void PUTREVERSEBMP(void);//图片反显
- void LcmClear(void);//清屏
- void LcmSet(void);//显示所有 即满屏都是黑色的
- void LcmInit(void);//初始化
- void ohengxian(void);//O横线程序
- void jihengxian(void);//奇横线程序
- void oshuxian(void);//O竖线程序
- void jishuxian(void);//奇竖线程序
- void dianxian(void);//点显示程序 满屏都是点
- void zifu8x16xian(void);//可以显示数字及英文
- void zifu16x16xian(void);//可以显示特定的汉字
- void lcd_dis_position_16_16(int line,int column,uchar zifu_16_16[2]);// 1行 1列 具体的字符
- void lcd_dis_position_8_16(int line,int column,uchar zifu_8_16);// 1行 1列 具体的字符
- void lcd_s_12864_dis_8_16_str(int dis_line,int start_position,char *dis_str);//显示一行的8*16的字符
- void ds_18b20_DelayXus(int n);
- void ds_18b20_init(void);//DS18B20的初始化
- uchar ds_18b20_read_date(void); //读一个字节
- void ds_18b20_write_date(uchar date);//写一个字节
- float read_18b20_temp(void);//读出18b20的温度值 实际温度值返回 同时改变temp_zero_below_flag的值 如果是0 说明是0度以下
- void key_pro(void);
- void display_pro(void);
- void pid_pro(void);
- void dis_4_line_as_null(void);
- void dis_pid_self_value(void);
- float read_max6675_temper(void);// 利用max6675读k探头的温度 返回最终温度的1倍
- void PWM_clock(uchar clock);
- void PWM_start(uchar module,uchar mode);
- void set_pwm_value(uchar value);//0--255之间 value越大,占空比越高 输出电压也越大 40-->0.8v 237-->4.6v
- //hhhhhhhhhhhhhhhhhhhhhhhhhhh
- ////////////////////////////////////////////////////////
- //中断函数ttttttttttttttttttttttttttttt
- void tm0_isr(void) interrupt 1 using 1 //1ms
- {
- TL0 = 0x20; //设置定时初值
- TH0 = 0xD1; //设置定时初值
-
- time0_temp1++;
- if(time0_temp1 % 2 == 0 )//2ms
- {
-
- pid_con_10ms_flag = 1;
-
- }
- if(time0_temp1 >= 10 )//10ms
- {
- time0_temp1 = 0;
- time0_10ms_flag = 1;
-
- }
- time0_temp2++;
- if(time0_temp2 % 200 == 0)//200ms
- {
- get_now_temp_flag = 1;
- }
- if(time0_temp2 % 200 == 0)//200ms
- {
- //get_now_temp_flag = 1;
-
- pid_self_sec_flag = 1;
-
- pwm_con_time_flag = 1;
- enable_pid_sec_flag = 1;
- special_dis_once_flag = 1;
-
- }
- if(time0_temp2 >= 1000 )//1s 如果要想1000对应1s 那么中间不能有关中断的行为发生
- {
- time0_temp2 = 0;
- global_sec++;
- global_sec_flag = 1;
-
- three_dot_dis_flag ^= 1;
-
- soft_dis_flag = 1;//软启动
-
- //ssr_con_1;delay_ms(10);ssr_con_0;//test
-
- }
- }
- void PCA_Intrrpt(void) interrupt 7 //pwm 的中断
- {
- if(CCF0) CCF0=0;
- if(CCF1) CCF1=0; //软件清零
- if(CF) CF=0; //软件清零
- }
- ////////////////////////////////////////////////////////
- //函数
- void Timer0Init(void) //1毫秒@12.000MHz 定时器0
- {
- AUXR |= 0x80; //定时器时钟1T模式
- TMOD &= 0xF0; //设置定时器模式
- TMOD |= 0x01; //设置定时器模式
- TL0 = 0x20; //设置定时初值
- TH0 = 0xD1; //设置定时初值
- TF0 = 0; //清除TF0标志
- TR0 = 1; //定时器0开始计时
- ET0 = 1; //enable timer0 interrupt
- }
- void io_init(void)
- {
- P3M0 = 0x00 ; // 0000 0000
- P2M0 = 0xf0 ; // 1111 0000 低四位为按键
- P1M0 = 0xff ; // 1111 1111 强推挽输出 lcd 及 ssr驱动
- P0M0 = 0x00 ; // 0000 0000 强推挽输出
- key_1_in;
- key_2_in;
- key_3_in;
- key_4_in;
- ssr_con_out;
- lcd_s_12864_cs_out;
- lcd_s_12864_reset_out;
- lcd_s_12864_rs_out;
- lcd_s_12864_sda_out;
- lcd_s_12864_sck_out;
- lcd_s_12864_light_out;
- lcd_s_12864_cs_0;
- lcd_s_12864_reset_0;
- lcd_s_12864_rs_0;
- lcd_s_12864_sda_0;
- lcd_s_12864_sck_0;
- lcd_s_12864_light_0;
- max6675_so_in;
- max6675_sck_out;
- max6675_cs1_out;
- cs1_1;
- pwm_con_out;
- pwm_con_0;
- }
- void power_on_event(void)//eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
- {
- int k;
- for( k = 0; k < 2; k++ )//闪灯2次
- {
- lcd_s_12864_light_0;
- delay_ms(200);
- lcd_s_12864_light_1;
- delay_ms(200);
- }
- //引用一下基本的函数 否则老是出现警告错误
- if( refer_fun_flag == 1 )//让refer_fun_flag永远为0 意思就是永远不实际引用这些函数
- {
- // PUTchar8x8(1,1,5,zifu8x8);
- // PUTchar24x24(1,1,2,zifu24x24);
- // PUTBMP();//图片
- // PUTREVERSEBMP();//图片反显
- // LcmClear();//清屏
- // LcmSet();//显示所有 即满屏都是黑色的
- // LcmInit();//初始化
- // ohengxian();//O横线程序
- // jihengxian();//奇横线程序
- // oshuxian();//O竖线程序
- // jishuxian();//奇竖线程序
- // dianxian();//点显示程序 满屏都是点
- // zifu8x16xian();//可以显示数字及英文
- // zifu16x16xian();//可以显示特定的汉字
- // lcd_dis_position_16_16(1,1,"郑");
- // lcd_dis_position_8_16(1,1,'8');
- }
- }
- //s_12864 lllllllllllllllllllllllllllllll
- void SendByte(uchar Dbyte) //发送字节数据
- {
- uchar i,TEMP;
- TEMP = Dbyte;
- for(i=0;i<8;i++)
- {
- lcd_s_12864_sck_0;
- _nop_();
- _nop_();
- if( TEMP & 0x80 )
- {
- lcd_s_12864_sda_1;
- }
- else
- {
- lcd_s_12864_sda_0;
- }
- lcd_s_12864_sck_1;
- _nop_();
- _nop_();
- TEMP = TEMP<<1;
- }
- }
- void write_cmd(uchar Cbyte )//写指令
- {
- lcd_s_12864_cs_0;
- lcd_s_12864_rs_0;
- SendByte(Cbyte);
- }
- void write_data(uchar Dbyte )//写数据
- {
- lcd_s_12864_cs_0;
- lcd_s_12864_rs_1;
- SendByte(Dbyte);
- }
- void PUTchar8x8(int row,int col,int count,uchar *put)
- {
- uint X=0;
- int j,i;
- write_cmd(0xb0+row);
- write_cmd(0x10+(8*col/16));
- write_cmd(0x00+(8*col%16));
- for(j=0;j<count;j++)
- {
- for(i=0;i<8;i++)
- {
- write_data(put[X++]);
- }
- }
- }
- void PUTchar8x16(int row,int col,int count,uchar *put)//row 0--3代表1--4行 col 0--15 代表1--16个起始位置 count 1--16 代表写入了几个字符 *put代表字符数组 16个字节代表一个8*16的字符
- {
- uint X=0;
- int j,i;
- write_cmd(0xb0+row);
- write_cmd(0x10+(8*col/16));
- write_cmd(0x00+(8*col%16));
- for(j=0;j<count;j++)
- {
- for(i=0;i<8;i++)
- {
- write_data(put[X++]);
- }
- write_cmd(0xb1+row);
- write_cmd(0x10+(8*col/16));
- write_cmd(0x00+(8*col%16));
- for(i=0;i<8;i++)
- {
- write_data(put[X++]);
- }
- write_cmd(0xb0+row);
- col=col+1;
- }
- }
- void PUTchar16x16(int row,int col,int count,uchar *put)//32个字节表示1个汉字
- {
- uint X=0;
- int j,i;
- write_cmd(0xb0+row);
- write_cmd(0x10+(8*col/16));
- write_cmd(0x00+(8*col%16));
- for(j=0;j<count;j++)
- {
- for(i=0;i<16;i++)
- {
- write_data(put[X++]);
- }
- write_cmd(0xb1+row);
- write_cmd(0x10+(8*col/16));
- write_cmd(0x00+(8*col%16));
- for(i=0;i<16;i++)
- {
- write_data(put[X++]);
- }
- write_cmd(0xb0+row);
- col=col+2;
- }
- }
- void PUTchar24x24(int row,int col,int count,uchar *put)
- {
- uint X=0;
- int j,i;
- write_cmd(0xb0+row); //纵坐标
- write_cmd(0x10+(8*col/16)); //横坐标
- write_cmd(0x00+(8*col%16));
- for(j=0;j<count;j++)
- {
- for(i=0;i<24;i++)
- {
- write_data(put[X++]);
- }
- write_cmd(0xb1+row);
- write_cmd(0x10+(8*col/16));
- write_cmd(0x00+(8*col%16));
- for(i=0;i<24;i++)
- {
- write_data(put[X++]);
- }
- write_cmd(0xb2+row);
- write_cmd(0x10+(8*col/16));
- write_cmd(0x00+(8*col%16));
- for(i=0;i<24;i++)
- {
- write_data(put[X++]);
- }
- write_cmd(0xb0+row);
- col=col+3;
- }
- }
- void PUTBMP(void)//图片
- {
- uint X=0;
- int j,i;
- for(j=0;j<8;j++)
- {
- write_cmd(0xb0+j);
- write_cmd(0x10);
- write_cmd(0x00);
- for(i=0;i<128;i++)
- {
- write_data(bmp1[X++]);//bmp1为具体的图片数组
- }
- }
- }
- void PUTREVERSEBMP(void)//图片反显
- {
- uint X=0;
- int j,i;
- for(j=0;j<8;j++)
- {
- write_cmd(0xb0+j);
- write_cmd(0x10);
- write_cmd(0x00);
- for(i=0;i<128;i++)
- {
- write_data(~bmp1[X++]);
- }
- }
- }
- void LcmClear(void)//清屏
- {
- int x,y;
- for(y=0;y<8;y++)
- {
- write_cmd(0xb0+y);
- write_cmd(0x10);
- write_cmd(0x00);
- for(x=0;x<132;x++)
- {
- write_data(0);
- }
- }
- }
- void LcmSet(void)//显示所有 即满屏都是黑色的
- {
- int x,y;
- for(y=0;y<8;y++)
- {
- write_cmd(0xb0+y);
- write_cmd(0x10);
- write_cmd(0x00);
- for(x=0;x<132;x++)
- {
- write_data(0xff);
- }
- }
- }
- void LcmInit(void)//初始化
- {
- lcd_s_12864_cs_0;
- lcd_s_12864_reset_0;
- delay_ms(100);
- lcd_s_12864_reset_1;
- delay_ms(100);
- write_cmd(0xe2);//system reset
- delay_ms(10);
- write_cmd(0x24);//SET VLCD RESISTOR RATIO 0x20--0x27 可以调节对比对 之有 0x23 0x24 这2个值可以选择 0x24的对比度强 粗调
- write_cmd(0xa2);//BR=1/9
- write_cmd(0xa0);//set seg direction
- write_cmd(0xc8);//set com direction
- write_cmd(0x2f);//set power control
- write_cmd(0x40);//set scroll line
- write_cmd(0x81);//SET ELECTRONIC VOLUME
- write_cmd(0x1c);//set pm: 通过改变这里的数值来改变电压 //也可以调节对比度 从0x00 -- 0x3f 值越大对比度越大 细调
- //write_cmd(0xa6);//set inverse display a6 off, a7 on 打开跟不打开没有任何影响
- //write_cmd(0xa4);//set all pixel on 打开跟不打开没有任何影响
- write_cmd(0xaf);//set display enable
- LcmClear(); //先清屏
- }
- void ohengxian(void)//O横线程序
- {
- int x,y;
- for(y=0;y<8;y++)
- {
- write_cmd(0xb0+y);
- write_cmd(0x10);
- write_cmd(0x00);
- for(x=0;x<128;x++)
- {
- write_data(0x55);
- }
- }
- }
- void jihengxian(void)//奇横线程序
- {
- int x,y;
- for(y=0;y<8;y++)
- {
- write_cmd(0xb0+y);
- write_cmd(0x10);
- write_cmd(0x00);
- for(x=0;x<128;x++)
- {
- write_data(0xAA);
- }
- }
- }
- void oshuxian(void)//O竖线程序
- {
- int x,y;
- for(y=0;y<8;y++)
- {
- write_cmd(0xb0+y);
- write_cmd(0x10);
- write_cmd(0x00);
- for(x=0;x<128;x++)
- {
- if(x%2==0)
- {
- write_data(0xFF);
- }
- else
- {
- write_data(0);
- }
- }
- }
- }
- void jishuxian(void)//奇竖线程序
- {
- int x,y;
- for(y=0;y<8;y++)
- {
- write_cmd(0xb0+y);
- write_cmd(0x10);
- write_cmd(0x00);
- for(x=0;x<128;x++)
- {
- if(x%2==0)
- {
- write_data(0);
- }
- else
- {
- write_data(0xFF);
- }
- }
- }
- }
- void dianxian(void)//点显示程序 满屏都是点
- {
- int x,y;
- for(y=0;y<8;y++)
- {
- write_cmd(0xb0+y);
- write_cmd(0x10);
- write_cmd(0x00);
- for(x=0;x<128;x++)
- {
- if(x%2==0)
- {
- write_data(0xAA);
- }
- else
- {
- write_data(0x55);
- }
- }
- }
- }
- void zifu8x16xian(void)//可以显示数字及英文
- {
- int k;
- for(k=0;k<4;k++)//代表显示4行
- {
- PUTchar8x16(2*k,0,16,zifu8x16);
- }
- }
- void zifu16x16xian(void)//可以显示特定的汉字
- {
- int k;
- for(k=0;k<4;k++)
- {
- PUTchar16x16(2*k,0,16,zifu16x16);
- }
- }
- //zzzzzzzzzzzzzzzzzzz
- void lcd_dis_position_16_16(int line,int column,uchar zifu_16_16[2])// 1行 1列 具体的字符
- {
- uint X=0;
- int i;
- /////////////////////////////////////
- if ( zifu_16_16 == "郑" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_001[i];}}
- else if( zifu_16_16 == "州" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_002[i];}}
- else if( zifu_16_16 == "迎" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_003[i];}}
- else if( zifu_16_16 == "之" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_004[i];}}
- else if( zifu_16_16 == "胜" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_005[i];}}
- else if( zifu_16_16 == "电" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_006[i];}}
- else if( zifu_16_16 == "子" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_007[i];}}
- else if( zifu_16_16 == "公" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_008[i];}}
- else if( zifu_16_16 == "司" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_009[i];}}
- else if( zifu_16_16 == "当" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_010[i];}}
- else if( zifu_16_16 == "前" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_011[i];}}
- else if( zifu_16_16 == "温" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_012[i];}}
- else if( zifu_16_16 == "度" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_013[i];}}
- else if( zifu_16_16 == "设" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_014[i];}}
- else if( zifu_16_16 == "定" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_015[i];}}
- else if( zifu_16_16 == "比" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_016[i];}}
- else if( zifu_16_16 == "例" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_017[i];}}
- else if( zifu_16_16 == "积" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_018[i];}}
- else if( zifu_16_16 == "分" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_019[i];}}
- else if( zifu_16_16 == "微" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_020[i];}}
- else if( zifu_16_16 == "自" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_021[i];}}
- else if( zifu_16_16 == "整" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_022[i];}}
- else if( zifu_16_16 == "定" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_023[i];}}
- else if( zifu_16_16 == "中" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_024[i];}}
- else if( zifu_16_16 == "软" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_025[i];}}
- else if( zifu_16_16 == "启" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_026[i];}}
- else if( zifu_16_16 == "动" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_027[i];}}
- /////////////////////////////////////
- write_cmd(0xb0+((line-1)*2));//第1行
- write_cmd(0x10+(8*(2*(column-1))/16));
- write_cmd(0x00+(8*(2*(column-1))%16));//起始位置
- for(i=0;i<16;i++)
- {
- write_data(temp_buffer_16_16_comm[X++]);
- }
- write_cmd(0xb1+((line-1)*2));
- write_cmd(0x10+(8*(2*(column-1))/16));
- write_cmd(0x00+(8*(2*(column-1))%16));
- for(i=0;i<16;i++)
- {
- write_data(temp_buffer_16_16_comm[X++]);
- }
- write_cmd(0xb0+((line-1)*2));
- }
- void lcd_dis_position_8_16(int line,int column,uchar zifu_8_16)// 1行 1列 具体的字符
- {
- uint X=0;
- int i;
- /////////////////////////////////////
- if ( zifu_8_16 == '0' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_001[i];}}
- else if( zifu_8_16 == '1' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_002[i];}}
- else if( zifu_8_16 == '2' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_003[i];}}
- else if( zifu_8_16 == '3' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_004[i];}}
- else if( zifu_8_16 == '4' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_005[i];}}
- else if( zifu_8_16 == '5' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_006[i];}}
- else if( zifu_8_16 == '6' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_007[i];}}
- else if( zifu_8_16 == '7' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_008[i];}}
- else if( zifu_8_16 == '8' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_009[i];}}
- else if( zifu_8_16 == '9' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_010[i];}}
- else if( zifu_8_16 == ':' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_011[i];}}
- else if( zifu_8_16 == '-' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_012[i];}}
- else if( zifu_8_16 == '.' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_013[i];}}
- else if( zifu_8_16 == '+' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_014[i];}}
- else if( zifu_8_16 == '%' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_015[i];}}
- else if( zifu_8_16 == 'S' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_016[i];}}
- else if( zifu_8_16 == 'C' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_017[i];}}
- else if( zifu_8_16 == 'P' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_018[i];}}
- else if( zifu_8_16 == 'I' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_019[i];}}
- else if( zifu_8_16 == 'D' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_020[i];}}
- else if( zifu_8_16 == ' ' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_021[i];}}
- /////////////////////////////////////
- write_cmd(0xb0+((line-1)*2));//第1行
- write_cmd(0x10+(8*(1*(column-1))/16));
- write_cmd(0x00+(8*(1*(column-1))%16));//起始位置
- for(i=0;i<8;i++)
- {
- write_data(temp_buffer_8_16_comm[X++]);
- }
- write_cmd(0xb1+((line-1)*2));
- write_cmd(0x10+(8*(1*(column-1))/16));
- write_cmd(0x00+(8*(1*(column-1))%16));
- for(i=0;i<8;i++)
- {
- write_data(temp_buffer_8_16_comm[X++]);
- }
- write_cmd(0xb0+((line-1)*2));
- }
- char *convert_num_to_str(long num)//将数字转成字符串 最大显示21亿 第1位为0的话,则显示0
- {
- temp_dis_num_buffer[0] = ((num/1000000000)%10) + '0';
- temp_dis_num_buffer[1] = ((num/100000000)%10) + '0';
- temp_dis_num_buffer[2] = ((num/10000000)%10) + '0';
- temp_dis_num_buffer[3] = ((num/1000000)%10) + '0';
- temp_dis_num_buffer[4] = ((num/100000)%10) + '0';
- temp_dis_num_buffer[5] = ((num/10000)%10) + '0';
- temp_dis_num_buffer[6] = ((num/1000)%10) + '0';
- temp_dis_num_buffer[7] = ((num/100)%10) + '0';
- temp_dis_num_buffer[8] = ((num/10)%10) + '0';
- temp_dis_num_buffer[9] = ((num/1)%10) + '0';
- temp_str = temp_dis_num_buffer;
- return temp_str;
- }
- void lcd_s_12864_dis_8_16_str(int dis_line,int start_position,char *dis_str)//显示一行的8*16的字符
- {
- int temp_1=0;
- int i;
- char *temp_str;
- temp_str = dis_str;
- while(1)//求出长度
- {
- temp_1++;
- if( *temp_str++ == '\0' )
- {
- break;
- }
- }
- for(i = 0; i < (temp_1 - 1) ; ++i)
- {
- lcd_dis_position_8_16(dis_line,start_position + i , *dis_str++);
- }
- }
- void dis_long_number(int dis_line,long dis_num)
- {
- lcd_dis_position_8_16(dis_line,0,((dis_num/1000000000)%10) + '0');
- lcd_dis_position_8_16(dis_line,1,((dis_num/100000000)%10) + '0');
- lcd_dis_position_8_16(dis_line,2,((dis_num/10000000)%10) + '0');
- lcd_dis_position_8_16(dis_line,3,((dis_num/1000000)%10) + '0');
- lcd_dis_position_8_16(dis_line,4,((dis_num/100000)%10) + '0');
- lcd_dis_position_8_16(dis_line,5,((dis_num/10000)%10) + '0');
- lcd_dis_position_8_16(dis_line,6,((dis_num/1000)%10) + '0');
- lcd_dis_position_8_16(dis_line,7,((dis_num/100)%10) + '0');
- lcd_dis_position_8_16(dis_line,8,((dis_num/10)%10) + '0');
- lcd_dis_position_8_16(dis_line,9,((dis_num/1)%10) + '0');
- }
- //key
- int key_scan(void)
- {
- int key_temp = 0;
- if(!(key_1_status))
- {
- delay_ms(10);
- if(!(key_1_status))
- {
- key_perss_counter++;
- if(( key_perss_counter > key_perss_long_max_num ) && ( key_perss_counter < key_perss_long_long_max_num ))
- {
- //lcd_s_12864_light_0;
- //delay_ms(20);
- //lcd_s_12864_light_1;//报警
- //delay_ms(20);
- key_temp = 11;//长按
- }
- else if( key_perss_counter >= key_perss_long_long_max_num )
- {
- lcd_s_12864_light_0;
- delay_ms(50);
- lcd_s_12864_light_1;//报警
- delay_ms(50);
- key_temp = 111;//超长按
- }
- else
- {
- if( key_once_active_flag == 1 )
- {
- key_once_active_flag = 0;
- //lcd_s_12864_light_0;
- //delay_ms(10);
- //lcd_s_12864_light_1;//报警
- key_temp = 1;//短按
- }
- }
- }
- }
- else if(!(key_2_status))
- {
- delay_ms(10);
- if(!(key_2_status))
- {
- key_perss_counter++;
- if(( key_perss_counter > key_perss_long_max_num ) && ( key_perss_counter < key_perss_long_long_max_num ))
- {
- //lcd_s_12864_light_0;
- //delay_ms(20);
- //lcd_s_12864_light_1;
- //delay_ms(20);
- key_temp = 22;//长按
- }
- else if( key_perss_counter >= key_perss_long_long_max_num )
- {
- lcd_s_12864_light_0;
- delay_ms(50);
- lcd_s_12864_light_1;
- delay_ms(50);
- key_temp = 222;//超长按
- }
- else
- {
- if( key_once_active_flag == 1 )
- {
- key_once_active_flag = 0;
- //lcd_s_12864_light_0;
- //delay_ms(10);
- //lcd_s_12864_light_1;
- key_temp = 2;//短按
- }
- }
- }
- }
- else if(!(key_3_status))
- {
- delay_ms(10);
- if(!(key_3_status))
- {
- key_perss_counter++;
- if(( key_perss_counter > key_perss_long_max_num ) && ( key_perss_counter < key_perss_long_long_max_num ))
- {
- //lcd_s_12864_light_0;
- //delay_ms(20);
- //lcd_s_12864_light_1;
- //delay_ms(20);
- //key_temp = 33;//长按
- key_temp = 3;
- }
- else if( key_perss_counter >= key_perss_long_long_max_num )
- {
- lcd_s_12864_light_0;
- delay_ms(50);
- lcd_s_12864_light_1;
- delay_ms(50);
- key_temp = 333;//超长按
- //key_temp = 3;
- }
- else
- {
- if( key_once_active_flag == 1 )
- {
- key_once_active_flag = 0;
- //lcd_s_12864_light_0;
- //delay_ms(10);
- //lcd_s_12864_light_1;
- key_temp = 3;//短按
- }
- }
- }
- }
- else if(!(key_4_status))
- {
- delay_ms(10);
- if(!(key_4_status))
- {
- key_perss_counter++;
- if(( key_perss_counter > key_perss_long_max_num ) && ( key_perss_counter < key_perss_long_long_max_num ))
- {
- //lcd_s_12864_light_0;
- //delay_ms(20);
- //lcd_s_12864_light_1;
- //delay_ms(20);
- //key_temp = 44;//长按
- key_temp = 4;
- }
- else if( key_perss_counter >= key_perss_long_long_max_num )
- {
- lcd_s_12864_light_0;
- delay_ms(50);
- lcd_s_12864_light_1;
- delay_ms(50);
- key_temp = 444;//超长按
- //key_temp = 4;
- }
- else
- {
- if( key_once_active_flag == 1 )
- {
- key_once_active_flag = 0;
- //lcd_s_12864_light_0;
- //delay_ms(10);
- //lcd_s_12864_light_1;
- key_temp = 4;//短按
- }
- }
- }
- }
- else//没有任何key按动的时候
- {
- key_once_active_flag = 1;//允许再按时1次动作
- key_perss_counter = 0;
- }
- return key_temp;
- }
- //DS18B20
- void ds_18b20_DelayXus(int n)
- {
- while (n--)
- {
- _nop_();
- //_nop_();
- }
- }
- void ds_18b20_init(void)//DS18B20的初始化
- {
- EA = 0;//关中断
- DQ=1;
- ds_18b20_DelayXus(1);//1US
- DQ=0;
- ds_18b20_DelayXus(600);//600US
- DQ=1;
- ds_18b20_DelayXus(100); //100US
- if(DQ==0)
- {
- ds_18b20_reset_ok_flag = 1;
- ds_18b20_DelayXus(200);
- DQ=1;
- }
- if(DQ==1)//说明复位成功
- {
- ds_18b20_reset_ok_flag = 0;
- ds_18b20_DelayXus(200);
- DQ=1;
- }
- EA = 1;//开中断
- }
- uchar ds_18b20_read_date(void) //读一个字节
- {
- uchar temp,i;
- EA = 0;
- for( i=0;i<8;i++)
- {
- DQ=1;
- ds_18b20_DelayXus(2);
- DQ=0;
- ds_18b20_DelayXus(3);
- DQ=1;
- ds_18b20_DelayXus(2);
- temp>>=1;
- if(DQ)
- {
- temp=temp|0x80;
- }
- ds_18b20_DelayXus(50);
- }
- EA = 1;
- return temp;
- }
- void ds_18b20_write_date(uchar date)//写一个字节
- {
- uchar i;
- //EA = 0;
- for( i=0 ;i<8;i++)
- {
- DQ=0;
- ds_18b20_DelayXus(2);
- DQ = date&0x01;
- ds_18b20_DelayXus(50);//50us
- DQ=1;
- date>>=1;
- }
- EA = 1;
- }
- float read_18b20_temp(void)//读出18b20的温度值 实际温度值返回 同时改变temp_zero_below_flag的值 如果是0 说明是0度以下
- {
- uchar themh=0;
- uchar theml=0;
- uint temp_0 = 0;
- float temp_1;
- ds_18b20_init();
- if(ds_18b20_reset_ok_flag == 0)//检测传感器是否存在
- {
- ds_18b20_write_date(0xcc); //跳过ROM匹配
- ds_18b20_write_date(0x44); //发出温度转换命令
- ds_18b20_DelayXus(1000);
- }
- ds_18b20_init();
- if(ds_18b20_reset_ok_flag == 0)
- {
- ds_18b20_write_date(0x0cc); //跳过ROM匹配
- ds_18b20_write_date(0x0be); //发出读温度命令
- theml=ds_18b20_read_date() ; //读出温度值并存放在 theml,themh
- themh=ds_18b20_read_date() ;
- }
- //temp_0 = themh*256 + theml;
- temp_0 = (themh<<8) | theml; //2句作用一样
- if( temp_0 & 0xf000 ) //说明是 负温度
- {
- temp_0 = (~temp_0)+ 1 ;//等于268 0000 0001 0000 1100 == 按位反 = 1111 1110 1111 0011 = fef3 = 65267 然后加1 = 65267+1 = 65268
- //temp_0 = (65536 - temp_0) ;//负温度求补码 65268 + 268 = 65536 跟用这个办法计算出的值一样
- temp_zero_below_flag = 0;
- }
- else//为0 ,说明是 正温度
- {
- temp_zero_below_flag = 1;
- }
- temp_1 = (float)(temp_0)*0.0625;
- return temp_1;
- }
- void dis_now_temp_test(void)//测试用 显示当前温度
- {
- if( global_sec_flag == 1 )//1秒1次
- {
- global_sec_flag = 0;
- ssr_con_1;delay_ms(10);ssr_con_0;//test
-
- now_temp = read_18b20_temp();
- wenkong_now_temp = now_temp;
- dis_now_temp = (long)(wenkong_now_temp*10);//*10是为了显示的需要
-
- //dis_now_temp = 396;//test
- lcd_dis_position_16_16(1,1,"当");
- lcd_dis_position_16_16(1,2,"前");
- lcd_dis_position_16_16(1,3,"温");
- lcd_dis_position_16_16(1,4,"度");
-
- if (temp_zero_below_flag == 1)//正温度
- {
- lcd_dis_position_8_16(2,1, '+');
- lcd_dis_position_8_16(2,2, (dis_now_temp/100%10) + '0');
- lcd_dis_position_8_16(2,3, (dis_now_temp/10%10) + '0');
- lcd_dis_position_8_16(2,4, '.');
- lcd_dis_position_8_16(2,5, (dis_now_temp/1%10) + '0');
- }
- else if (temp_zero_below_flag == 0)//负温度
- {
- lcd_dis_position_8_16(2,1, '-');
- lcd_dis_position_8_16(2,2, (dis_now_temp/100%10) + '0');
- lcd_dis_position_8_16(2,3, (dis_now_temp/10%10) + '0');
- lcd_dis_position_8_16(2,4, '.');
- lcd_dis_position_8_16(2,5, (dis_now_temp/1%10) + '0');
- }
- }
- }
- //kkkkkkkkkkkkkkkkkkkk
- void key_pro(void)
- {
- key_value = key_scan();
- if (key_value == 1)//A 作为 自整定 跟 pid 切换的开关
- {
- pid_tune_flag ^= 1;
- LcmClear();//清屏
- //清除最后一行的内容
- //dis_4_line_as_null();
- if(pid_tune_flag == 1)//自整定阶段
- {
-
- //记录此刻的状态 即设定温度是否 高于或等于 当前温度
- if( SV_value >= PV_value )//设定温度 高于 或者 等于 当前温度 启动加热
- {
- pid_self_first_status_flag = 1;
- once_add_1_flag = 0;
- }
- else//设定温度 低于 当前温度
- {
- pid_self_first_status_flag = 0;
- once_add_1_flag = 1;
- }
-
- dis_tune_once_flag = 1;
- zero_across_counter = 0;
- pid_self_time_sec = 0;
- pid_self_calc_buffer[0]=0.0;
- pid_self_calc_buffer[1]=0.0;
- pid_self_calc_buffer[2]=0.0;
- pid_self_calc_buffer[3]=0.0;
- k_pid_self_counter = 0;
- enable_calc_min_max_flag = 0;
- max_temp = 0.0 ; //初始温度等于0
- min_temp = 1024.0 ;//初始温度等于1024
- sum_temp = 0.0 ; //初始温度等于0
- aver_temp = 0.0 ;
- T_Hight = 0.0;
- T_LOW = 1024.0; //温度
- TIME_Hight = 0;
- TIME_LOW = 0; //具体的0.2s
-
- }
- else if(pid_tune_flag == 0)//pid阶段
- {
- comm_dis_once_flag = 1;
- special_dis_once_flag = 1;
- }
- }
- else if(key_value == 2)//B
- {
-
- }
- else if((key_value == 3) || (key_value == 333)) //- 设定温度
- {
- special_dis_once_flag = 1;
- if(key_value == 3)
- {
- SV_value-=1.0;
- }
- else
- {
- SV_value-=10.0;
- }
- if(SV_value < 0.0)
- {
- SV_value = 999.9;
- }
- }
- else if((key_value == 4) || (key_value == 444)) //+
- {
- special_dis_once_flag = 1;
- if(key_value == 4)
- {
- SV_value+=1.0;
- }
- else
- {
- SV_value+=10.0;
- }
- if(SV_value > 999.9)
- {
- SV_value = 0.0;
- }
- }
- }
- //dddddddddddddddddddddd
- void display_pro(void)
- {
- if( pid_tune_flag == 0 )//pid阶段
- {
- //第1行 当前温度
- //第2行 设定温度
- //第3行 显示pid 各参数的名字
- //第4行 显示pid 各参数的具体值
- if (comm_dis_once_flag == 1)//基本信息只显示一次
- {
- comm_dis_once_flag = 0;
-
- lcd_dis_position_16_16(1,1,"当");
- lcd_dis_position_16_16(1,2,"前");
- lcd_dis_position_16_16(1,3,"温");
- lcd_dis_position_16_16(1,4,"度");
-
- lcd_dis_position_16_16(2,1,"设");
- lcd_dis_position_16_16(2,2,"定");
- lcd_dis_position_16_16(2,3,"温");
- lcd_dis_position_16_16(2,4,"度");
-
- lcd_dis_position_8_16(1,15,'C');
- lcd_dis_position_8_16(2,15,'C');
-
- lcd_dis_position_16_16(3,1,"比");
- lcd_dis_position_16_16(3,2,"例");
- lcd_dis_position_16_16(3,4,"积");
- lcd_dis_position_16_16(3,5,"分");
- lcd_dis_position_16_16(3,7,"微");
- lcd_dis_position_16_16(3,8,"分");
-
- }
-
- if (special_dis_once_flag == 1)//独立信息 0.2秒1次
- {
- special_dis_once_flag = 0;
-
- //lcd_s_12864_light_1;delay_ms(10);lcd_s_12864_light_0;//test
- //当前温度
- lcd_dis_position_8_16(1,9, ((uint)(PV_value*10)/1000)%10 + '0');//百位
- lcd_dis_position_8_16(1,10,((uint)(PV_value*10)/100)%10 + '0');
- lcd_dis_position_8_16(1,11,((uint)(PV_value*10)/10)%10 + '0');
- lcd_dis_position_8_16(1,12,'.');
- lcd_dis_position_8_16(1,13,((uint)(PV_value*10)/1)%10 + '0');
-
- //设定温度
- lcd_dis_position_8_16(2,9, ((uint)(SV_value*10)/1000)%10 + '0');
- lcd_dis_position_8_16(2,10,((uint)(SV_value*10)/100)%10 + '0');
- lcd_dis_position_8_16(2,11,((uint)(SV_value*10)/10)%10 + '0');
- lcd_dis_position_8_16(2,12,'.');
- lcd_dis_position_8_16(2,13,((uint)(SV_value*10)/1)%10 + '0');
-
- lcd_dis_position_8_16(4,6,'%');
- lcd_dis_position_8_16(4,11,'S');
- lcd_dis_position_8_16(4,16,'S');
-
- if( pid_tune_flag == 1 )//如果启动了pid自整定 ,则显示 pid自整定中...
- {
- lcd_dis_position_8_16(4,1,'P');
- lcd_dis_position_8_16(4,2,'I');
- lcd_dis_position_8_16(4,3,'D');
-
- lcd_dis_position_16_16(4,3,"自");
- lcd_dis_position_16_16(4,4,"整");
- lcd_dis_position_16_16(4,5,"定");
- lcd_dis_position_16_16(4,6,"中");
-
- if ( three_dot_dis_flag == 1 )//显示不断闪烁的3个点 表示运算中
- {
- lcd_dis_position_8_16(4,14,'.');
- lcd_dis_position_8_16(4,15,'.');
- lcd_dis_position_8_16(4,16,'.');
- }
- else if( three_dot_dis_flag == 0 )
- {
- lcd_dis_position_8_16(4,14,' ');
- lcd_dis_position_8_16(4,15,' ');
- lcd_dis_position_8_16(4,16,' ');
- }
- }
- else if( pid_tune_flag == 0 )//整定ok后 显示计算获得的pid值 正常pid控制的时候显示的内容
- {
- //比例 积分 微分
- lcd_dis_position_8_16(4,1,((uint)(P_value*10)/1000)%10 + '0');
- lcd_dis_position_8_16(4,2,((uint)(P_value*10)/100)%10 + '0');
- lcd_dis_position_8_16(4,3,((uint)(P_value*10)/10)%10 + '0');
- lcd_dis_position_8_16(4,4,'.');
- lcd_dis_position_8_16(4,5,((uint)(P_value*10)/1)%10 + '0');
-
- lcd_dis_position_8_16(4,7,((I_value*1)/1000)%10 + '0');
- lcd_dis_position_8_16(4,8,((I_value*1)/100)%10 + '0');
- lcd_dis_position_8_16(4,9,((I_value*1)/10)%10 + '0');
- lcd_dis_position_8_16(4,10,((I_value*1)/1)%10 + '0');
-
- lcd_dis_position_8_16(4,13,((D_value*1)/100)%10 + '0');
- lcd_dis_position_8_16(4,14,((D_value*1)/10)%10 + '0');
- lcd_dis_position_8_16(4,15,((D_value*1)/1)%10 + '0');
- }
- }
- }
- else if( pid_tune_flag == 1 )//自整定阶段
- {
- if(dis_tune_once_flag == 1)//显示一次
- {
- dis_tune_once_flag = 0;
- dis_pid_self_value();
- }
- }
- }
- int pid_calc(float set_temp ,float now_temp )// pid计算 set_temp 为设定的温度 now_temp 代表实际输入的当前温度值 0 - 100的输出值
- {
- Error = set_temp - now_temp; // 偏差
- if(( Error < max_value_error ) && ( Error > (min_value_error) ))//只有在一定的温差范围内才pid计算
- {
- SumError += Error;
- dError = LastError - PrevError; // 当前微分
- PrevError = LastError;
- LastError = Error;
- temp_pid = (int)((Proportion * Error) + (Integral * SumError) + (Derivative * dError));
- //temp_pid = (int)(temp_pid * 0.5) ;//输出比例控制
- }
- else//只有开关作用
- {
- if( Error >= max_value_error )//远大于当前温度,加热
- {
- temp_pid = 100;
- //temp_pid = 80;
- }
- else if( Error <= (min_value_error) )//远小于当前温度,不加热
- {
- temp_pid = 0;
- }
- }
- if( temp_pid < 0 )
- {
- temp_pid = 0;
- }
- else if( temp_pid > 100 )
- {
- temp_pid = 100;
- }
- return temp_pid;
- }
- void pid_con(void)//由计算结果控制输出
- {
- //适用于 pwm
- //每200ms根据结果改变一次输出电压的值
- if( pwm_con_time_flag == 1)
- {
- pwm_con_time_flag = 0;
-
- //lcd_s_12864_light_1;delay_ms(10);lcd_s_12864_light_0;//test
- //set_pwm_value(40 + (uchar)(pid_result * (((float)(237-40))/100.0)) );
- set_pwm_value(40 + (uchar)(pid_result * 1.97) );//跟上面这句话等价
-
- }
- }
- void pid_pro(void)//pid 自整定及控制输出 ppppppppppppppppppppppppppppp
- {
- //每200ms获得一次温度
- if( get_now_temp_flag == 1)//200ms秒获得一次温度
- {
- get_now_temp_flag = 0;
-
- //lcd_s_12864_light_1;delay_ms(10);lcd_s_12864_light_0;//test
- PV_value = read_max6675_temper();
- }
- if ( pid_tune_flag == 1 )//自整定阶段 完毕之后转成pid控制
- {
- //自整定ok后自动转为pid阶段
- //自整定失败的情况下 让基本参数恢复默认值
- if( pid_self_sec_flag == 1 )//自整定过程 0.2秒1次
- {
- pid_self_sec_flag = 0;
- dis_tune_once_flag = 1;//0.2秒显示1次基本信息
- //lcd_s_12864_light_0;delay_ms(10);lcd_s_12864_light_1;//test
- pid_self_time_sec++;
- if(pid_self_time_sec > (3600*3)) // 如果总的自整定时间大于了3/5=0.6个小时,则说明整定失败
- {
- pid_self_time_sec = 0;
- //lcd_s_12864_light_0;delay_ms(10);lcd_s_12864_light_1;//test
- LcmClear();//清屏
- comm_dis_once_flag = 1;
- special_dis_once_flag = 1;
- pid_tune_flag = 0;//那么将自动退出自整定过程 同时采用默认值 进入pid阶段
- KC = 1.0;//临界比例系数 初始默认的值
- TC = 40; //振荡周期 初始默认的值
- }
- if(( pid_self_first_status_flag == 1) || ( pid_self_first_status_flag == 0))//0 设定温度 低于 当前温度 //1设定温度 高于 或者 等于 当前温度 启动加热
- {
- //lcd_s_12864_light_0;delay_ms(10);lcd_s_12864_light_1;//test
- //基本on/off控制
- if( SV_value >= PV_value )//启动加热
- {
- cool_ack_counter = 0;
- hot_ack_counter++;
- if(hot_ack_counter > 3)//连续3次都是一样的结果 说明确定 SV_value >= PV_value
- {
-
- ssr_con_1;
- //pwm_con_1;//一旦pwm参与将不能通过操作io的形式控制该口线
- set_pwm_value(237);//全速加热
- if(once_add_1_flag == 0)
- {
- once_add_1_flag = 1;
- zero_across_counter++;
-
- //lcd_s_12864_light_0;delay_ms(10);lcd_s_12864_light_1;//test
-
- if(zero_across_counter == 3 )
- {
- TIME_LOW = pid_self_time_sec - 3;//此时的时间不是最低温度对应的时间
- }
- }
- }
- }
- else//当前温度 大于 设定温度 停止加热
- {
-
- //lcd_s_12864_light_0;delay_ms(10);lcd_s_12864_light_1;//test
-
- hot_ack_counter = 0;
- cool_ack_counter++;
- if(cool_ack_counter > 3)
- {
- ssr_con_0;
- set_pwm_value(40);//不加热
- if(once_add_1_flag == 1)
- {
- once_add_1_flag = 0;
- zero_across_counter++;
- if(zero_across_counter == 3 )
- {
- TIME_LOW = pid_self_time_sec - 3;//此时的时间不是最低温度对应的时间
- }
- }
- }
- }
- //最低温度 出现在 zero_across_counter = 3 的阶段
- //最高温度 出现在 zero_across_counter = 4 的阶段
- if((zero_across_counter == 3 ) || (zero_across_counter == 4 ))
- {
- pid_self_calc_buffer[k_pid_self_counter] = PV_value;
- k_pid_self_counter++;
- if(k_pid_self_counter > 3)//0--3 共4个元素
- {
- k_pid_self_counter = 0;
- enable_calc_min_max_flag = 1;
- }
- if(enable_calc_min_max_flag == 1)//只要有4个值,就可以计算了 后面来的值覆盖了前面的值
- {
- //去掉最小值 最大值 取剩下2个值的平均值
- sum_temp = 0.0; //先清0
- min_temp = 1024.0;
- max_temp = 0.0;
-
- for(k_max_min = 0; k_max_min < 4; k_max_min++ )
- {
- if(pid_self_calc_buffer[k_max_min] <= min_temp)
- {
- min_temp = pid_self_calc_buffer[k_max_min];
- }
- if(pid_self_calc_buffer[k_max_min] >= max_temp)
- {
- max_temp = pid_self_calc_buffer[k_max_min];
- }
- sum_temp = (sum_temp + pid_self_calc_buffer[k_max_min]);
- }
- sum_temp = sum_temp - min_temp - max_temp ;
-
-
- //pid_self_first_status_flag = 1 时 最低温度出现在3阶段
- //pid_self_first_status_flag = 0 时 最低温度出现在4阶段
- if(pid_self_first_status_flag == 1)
- {
- if(zero_across_counter == 3 )//最低温度
- {
- aver_temp = (sum_temp/2.0);
- if( aver_temp <= T_LOW )
- {
- T_LOW = aver_temp;
- }
- }
- else if(zero_across_counter == 4 )//最高温度
- {
- aver_temp = (sum_temp/2.0);
- if( aver_temp >= T_Hight )
- {
- T_Hight = aver_temp;
- }
- }
- }
- else if(pid_self_first_status_flag == 0)
- {
- if(zero_across_counter == 4 )//最低温度
- {
- aver_temp = (sum_temp/2.0);
- if( aver_temp <= T_LOW )
- {
- T_LOW = aver_temp;
- }
- }
- else if(zero_across_counter == 3 )//最高温度
- {
- aver_temp = (sum_temp/2.0);
- if( aver_temp >= T_Hight )
- {
- T_Hight = aver_temp;
- }
- }
- }
- }
- }
- else if(zero_across_counter == 5 )//4次过0 则说明出现了振荡 整定成功
- {
- zero_across_counter = 0;
- pid_tune_flag = 0;//进入pid阶段
- //pid_tune_flag = 1;//test
- TIME_Hight = pid_self_time_sec - 3;//此时的时间不是最高温度对应的时间
- LcmClear();//清屏
- comm_dis_once_flag = 1;
- special_dis_once_flag = 1;
- //dis_4_line_as_null();//清除最后一行的内容
- //计算 T_Hight T_LOW TIME_Hight TIME_LOW 这4个值
- //根据以上4个值 KC 与 TC 的值便会计算出来
-
- KC = 12.7/(T_Hight - T_LOW);
- KC = 5.0 * KC;//因为是0.2s一次 所以扩大5倍
- TC = 1 * (TIME_Hight - TIME_LOW);//如果记录了 最低温度 与 最高温度对应的时间 那么沿用这个公式:TC = 2 * (TIME_Hight - TIME_LOW);
- }
- }
- //显示具体的值 测试用
- //dis_pid_self_value(); //test
- }
- }
- else if( pid_tune_flag == 0 )//pid 阶段 默认开机进入此阶段
- {
- //0 算出 临界增益 KC 及 振荡周期 TC
- // KC = (4*d)/(3.14*A) ---> d = 5(输出幅值) ; A = 记录的温度最高值与最低值的差值的0.5倍 即:(T_Hight - T_LOW)*0.5
- // KC = (4*5)/(3.14*((T_Hight - T_LOW)*0.5)) = 40/3.14/(T_Hight - T_LOW) = 12.7/(T_Hight - T_LOW)
- // KC = 12.7/(T_Hight - T_LOW)
- // TC = 2 * (TIME_Hight - TIME_LOW) ---> 2 * ( 高点温度对应时间 - 低点温度对应时间 )
- // TC = 2 * (TIME_Hight - TIME_LOW)
- //1 算出 具体的比例系数 积分秒数 微分秒数
- //Proportion = 0.6*KC
- //I_value = 0.5*TC
- //D_value = 0.125*TC
- //2 算出具体的 比例带 积分系数 微分系数
- //P_value = (1/Proportion)*100
- //Integral = Proportion/I_value = (0.6*KC)/(0.5*TC)
- //Derivative = Proportion*D_value = (0.6*KC)*(0.125*TC)
- //3显示用的3个变量的值
- //P_value = (1/Proportion)*100 百分比
- //I_value = 0.5*TC 秒
- //D_value = 0.125*TC 秒
- //4pid计算用的3个变量的值
- //Proportion = 0.6*KC
- //Integral = Proportion/I_value = (0.6*KC)/(0.5*TC)
- //Derivative = Proportion*D_value = (0.6*KC)*(0.125*TC)
-
- //KC = 21.4;//test
- //TC = 471;//test
-
- if(enable_pid_sec_flag == 1)//进入pid时,0.2秒计算1次
- {
-
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
热风 自整定 PID 51单片机程序 + 原理图 PCB.7z
(162.76 KB, 下载次数: 278)
|