标题:
非原创 单片机热风器控制 自整定PID程序+PCB文件原理图
[打印本页]
作者:
171821203
时间:
2020-2-29 02:04
标题:
非原创 单片机热风器控制 自整定PID程序+PCB文件原理图
很早以前淘来的 热风器 自整定 PID 参考程序,现发布出来给大伙分享,内容仅供学习参考,包含PCB图;
Altium Designer画的原理图和PCB图如下:(51hei附件中可下载工程文件)
51hei.png
(17.97 KB, 下载次数: 68)
下载附件
2020-2-29 02:13 上传
51hei.png
(47.16 KB, 下载次数: 83)
下载附件
2020-2-29 02:13 上传
单片机源程序如下:
#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, 下载次数: 289)
2024-1-22 02:54 上传
点击文件名下载附件
51
下载积分: 黑币 -5
作者:
上善若水001
时间:
2020-2-29 09:54
好资料,感谢!!!
作者:
jovew
时间:
2020-2-29 10:03
好东西,值得分享。。。。。。
作者:
到处走看
时间:
2020-2-29 10:41
慢慢学习 谢谢楼主分享!
作者:
YYZZ052
时间:
2020-2-29 13:08
这个自整定PID,有详细解说过程就好了,,,,
作者:
wangniuliu
时间:
2020-5-30 09:28
可惜自己不懂没有学过单片机
作者:
sjpdiy
时间:
2020-6-19 21:20
新手学习中
作者:
cooleaf
时间:
2021-3-29 22:59
自整定PID,还是有点难度的,谢谢楼主分享!!!
作者:
felix_tao
时间:
2021-7-10 12:25
正需要研究自整定,不错的资料,谢谢楼主分享
作者:
yanfeng082
时间:
2021-8-31 22:08
感谢楼主正在搞自整定pid可以借鉴
作者:
常永峰51单片机
时间:
2021-12-19 12:21
分析了一下感觉程序不会引起震荡首先zero_across_counter每次都会在主循环里复位如果温度在很短的时间不会震荡的话zero_across_counter会不断的清零,所以就采集不到最高和最低温度,如果把zero_across_counter清零语句屏蔽掉zero_across_counter会瞬间加到5然后在清零,这样程序会直接跳到自整定结束。有没有人看明白讨论一下
作者:
lhtlhtl
时间:
2024-1-25 08:56
慢慢学习 谢谢楼主分享!
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1