標題:
非原創(chuàng) 單片機熱風(fēng)器控制 自整定PID程序+PCB文件原理圖
[打印本頁]
作者:
171821203
時間:
2020-2-29 02:04
標題:
非原創(chuàng) 單片機熱風(fēng)器控制 自整定PID程序+PCB文件原理圖
很早以前淘來的 熱風(fēng)器 自整定 PID 參考程序,現(xiàn)發(fā)布出來給大伙分享,內(nèi)容僅供學(xué)習(xí)參考,包含PCB圖;
Altium Designer畫的原理圖和PCB圖如下:(51hei附件中可下載工程文件)
51hei.png
(17.97 KB, 下載次數(shù): 68)
下載附件
2020-2-29 02:13 上傳
51hei.png
(47.16 KB, 下載次數(shù): 83)
下載附件
2020-2-29 02:13 上傳
單片機源程序如下:
#include<intrins.h>
#include<stdlib.h>//包含 rand() 這樣的隨機函數(shù)
#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);//定義一個函數(shù)指針的數(shù)據(jù)類型
//之后用該數(shù)據(jù)類型定義一個數(shù)組
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];//必須設(shè)計成全局變量才不會顯示錯亂
uchar temp_buffer_8_16_comm[16];//必須設(shè)計成全局變量才不會顯示錯亂
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;//用于溫度控制的當(dāng)前溫度
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; //設(shè)定溫度值
float PV_value = 0.0; //用于參與計算的當(dāng)前溫度值
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; // 比例常數(shù) Proportional Const
float Integral = 0.0; // 積分常數(shù) Integral Const
float Derivative = 0.0; // 微分常數(shù) 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; //臨界比例系數(shù) 初始默認的值
int TC = 40; //振蕩周期 初始默認的值
int temp_pid = 0;//設(shè)定成全局變量
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 對應(yīng)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
////////////////////////////////////////////////////////
//函數(shù)定義
void SendByte(uchar Dbyte); //發(fā)送字節(jié)數(shù)據(jù)
void write_cmd(uchar Cbyte);//寫指令
void write_data(uchar Dbyte);//寫數(shù)據(jù)
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個字節(jié)表示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);//可以顯示數(shù)字及英文
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); //讀一個字節(jié)
void ds_18b20_write_date(uchar date);//寫一個字節(jié)
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
////////////////////////////////////////////////////////
//中斷函數(shù)ttttttttttttttttttttttttttttt
void tm0_isr(void) interrupt 1 using 1 //1ms
{
TL0 = 0x20; //設(shè)置定時初值
TH0 = 0xD1; //設(shè)置定時初值
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對應(yīng)1s 那么中間不能有關(guān)中斷的行為發(fā)生
{
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; //軟件清零
}
////////////////////////////////////////////////////////
//函數(shù)
void Timer0Init(void) //1毫秒@12.000MHz 定時器0
{
AUXR |= 0x80; //定時器時鐘1T模式
TMOD &= 0xF0; //設(shè)置定時器模式
TMOD |= 0x01; //設(shè)置定時器模式
TL0 = 0x20; //設(shè)置定時初值
TH0 = 0xD1; //設(shè)置定時初值
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驅(qū)動
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);
}
//引用一下基本的函數(shù) 否則老是出現(xiàn)警告錯誤
if( refer_fun_flag == 1 )//讓refer_fun_flag永遠為0 意思就是永遠不實際引用這些函數(shù)
{
// PUTchar8x8(1,1,5,zifu8x8);
// PUTchar24x24(1,1,2,zifu24x24);
// PUTBMP();//圖片
// PUTREVERSEBMP();//圖片反顯
// LcmClear();//清屏
// LcmSet();//顯示所有 即滿屏都是黑色的
// LcmInit();//初始化
// ohengxian();//O橫線程序
// jihengxian();//奇橫線程序
// oshuxian();//O豎線程序
// jishuxian();//奇豎線程序
// dianxian();//點顯示程序 滿屏都是點
// zifu8x16xian();//可以顯示數(shù)字及英文
// zifu16x16xian();//可以顯示特定的漢字
// lcd_dis_position_16_16(1,1,"鄭");
// lcd_dis_position_8_16(1,1,'8');
}
}
//s_12864 lllllllllllllllllllllllllllllll
void SendByte(uchar Dbyte) //發(fā)送字節(jié)數(shù)據(jù)
{
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 )//寫數(shù)據(jù)
{
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代表字符數(shù)組 16個字節(jié)代表一個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個字節(jié)表示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為具體的圖片數(shù)組
}
}
}
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 可以調(diào)節(jié)對比對 之有 0x23 0x24 這2個值可以選擇 0x24的對比度強 粗調(diào)
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: 通過改變這里的數(shù)值來改變電壓 //也可以調(diào)節(jié)對比度 從0x00 -- 0x3f 值越大對比度越大 細調(diào)
//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)//可以顯示數(shù)字及英文
{
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 == "當(dāng)" ){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 == "設(shè)" ){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)//將數(shù)字轉(zhuǎn)成字符串 最大顯示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;//關(guān)中斷
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)//說明復(fù)位成功
{
ds_18b20_reset_ok_flag = 0;
ds_18b20_DelayXus(200);
DQ=1;
}
EA = 1;//開中斷
}
uchar ds_18b20_read_date(void) //讀一個字節(jié)
{
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)//寫一個字節(jié)
{
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); //發(fā)出溫度轉(zhuǎn)換命令
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); //發(fā)出讀溫度命令
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)//測試用 顯示當(dāng)前溫度
{
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,"當(dāng)");
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 切換的開關(guān)
{
pid_tune_flag ^= 1;
LcmClear();//清屏
//清除最后一行的內(nèi)容
//dis_4_line_as_null();
if(pid_tune_flag == 1)//自整定階段
{
//記錄此刻的狀態(tài) 即設(shè)定溫度是否 高于或等于 當(dāng)前溫度
if( SV_value >= PV_value )//設(shè)定溫度 高于 或者 等于 當(dāng)前溫度 啟動加熱
{
pid_self_first_status_flag = 1;
once_add_1_flag = 0;
}
else//設(shè)定溫度 低于 當(dāng)前溫度
{
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)) //- 設(shè)定溫度
{
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行 當(dāng)前溫度
//第2行 設(shè)定溫度
//第3行 顯示pid 各參數(shù)的名字
//第4行 顯示pid 各參數(shù)的具體值
if (comm_dis_once_flag == 1)//基本信息只顯示一次
{
comm_dis_once_flag = 0;
lcd_dis_position_16_16(1,1,"當(dāng)");
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,"設(shè)");
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
//當(dāng)前溫度
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');
//設(shè)定溫度
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控制的時候顯示的內(nèi)容
{
//比例 積分 微分
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 為設(shè)定的溫度 now_temp 代表實際輸入的當(dāng)前溫度值 0 - 100的輸出值
{
Error = set_temp - now_temp; // 偏差
if(( Error < max_value_error ) && ( Error > (min_value_error) ))//只有在一定的溫差范圍內(nèi)才pid計算
{
SumError += Error;
dError = LastError - PrevError; // 當(dāng)前微分
PrevError = LastError;
LastError = Error;
temp_pid = (int)((Proportion * Error) + (Integral * SumError) + (Derivative * dError));
//temp_pid = (int)(temp_pid * 0.5) ;//輸出比例控制
}
else//只有開關(guān)作用
{
if( Error >= max_value_error )//遠大于當(dāng)前溫度,加熱
{
temp_pid = 100;
//temp_pid = 80;
}
else if( Error <= (min_value_error) )//遠小于當(dāng)前溫度,不加熱
{
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)//由計算結(jié)果控制輸出
{
//適用于 pwm
//每200ms根據(jù)結(jié)果改變一次輸出電壓的值
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 )//自整定階段 完畢之后轉(zhuǎn)成pid控制
{
//自整定ok后自動轉(zhuǎn)為pid階段
//自整定失敗的情況下 讓基本參數(shù)恢復(fù)默認值
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;//臨界比例系數(shù) 初始默認的值
TC = 40; //振蕩周期 初始默認的值
}
if(( pid_self_first_status_flag == 1) || ( pid_self_first_status_flag == 0))//0 設(shè)定溫度 低于 當(dāng)前溫度 //1設(shè)定溫度 高于 或者 等于 當(dāng)前溫度 啟動加熱
{
//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)//連續(xù)3次都是一樣的結(jié)果 說明確定 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;//此時的時間不是最低溫度對應(yīng)的時間
}
}
}
}
else//當(dāng)前溫度 大于 設(shè)定溫度 停止加熱
{
//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;//此時的時間不是最低溫度對應(yīng)的時間
}
}
}
}
//最低溫度 出現(xiàn)在 zero_across_counter = 3 的階段
//最高溫度 出現(xiàn)在 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 時 最低溫度出現(xiàn)在3階段
//pid_self_first_status_flag = 0 時 最低溫度出現(xiàn)在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 則說明出現(xiàn)了振蕩 整定成功
{
zero_across_counter = 0;
pid_tune_flag = 0;//進入pid階段
//pid_tune_flag = 1;//test
TIME_Hight = pid_self_time_sec - 3;//此時的時間不是最高溫度對應(yīng)的時間
LcmClear();//清屏
comm_dis_once_flag = 1;
special_dis_once_flag = 1;
//dis_4_line_as_null();//清除最后一行的內(nèi)容
//計算 T_Hight T_LOW TIME_Hight TIME_LOW 這4個值
//根據(jù)以上4個值 KC 與 TC 的值便會計算出來
KC = 12.7/(T_Hight - T_LOW);
KC = 5.0 * KC;//因為是0.2s一次 所以擴大5倍
TC = 1 * (TIME_Hight - TIME_LOW);//如果記錄了 最低溫度 與 最高溫度對應(yīng)的時間 那么沿用這個公式: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 * ( 高點溫度對應(yīng)時間 - 低點溫度對應(yīng)時間 )
// TC = 2 * (TIME_Hight - TIME_LOW)
//1 算出 具體的比例系數(shù) 積分秒數(shù) 微分秒數(shù)
//Proportion = 0.6*KC
//I_value = 0.5*TC
//D_value = 0.125*TC
//2 算出具體的 比例帶 積分系數(shù) 微分系數(shù)
//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黑下載附件…………
復(fù)制代碼
所有資料51hei提供下載:
熱風(fēng) 自整定 PID 51單片機程序 + 原理圖 PCB.7z
(162.76 KB, 下載次數(shù): 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
慢慢學(xué)習(xí) 謝謝樓主分享!
作者:
YYZZ052
時間:
2020-2-29 13:08
這個自整定PID,有詳細解說過程就好了,,,,
作者:
wangniuliu
時間:
2020-5-30 09:28
可惜自己不懂沒有學(xué)過單片機
作者:
sjpdiy
時間:
2020-6-19 21:20
新手學(xué)習(xí)中
作者:
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每次都會在主循環(huán)里復(fù)位如果溫度在很短的時間不會震蕩的話zero_across_counter會不斷的清零,所以就采集不到最高和最低溫度,如果把zero_across_counter清零語句屏蔽掉zero_across_counter會瞬間加到5然后在清零,這樣程序會直接跳到自整定結(jié)束。有沒有人看明白討論一下
作者:
lhtlhtl
時間:
2024-1-25 08:56
慢慢學(xué)習(xí) 謝謝樓主分享!
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1