//-----------定义模糊系统参数-----------------------------------------------------------
//------------------------------------------------------------------------------------
// 定义差距输入常量
#define GAP_ZERO 0x00
#define GAP_VSMALL 0x01
#define GAP_SMALL 0x02
#define GAP_MEDIUM 0x03
#define GAP_BIG 0x04
// 定义控制输出常量
#define TURN_ZERO 0x80
#define TURN_VSMALL 0x81
#define TURN_SMALL 0x82
#define TURN_MEDIUM 0x83
#define TURN_BIG 0x84
#define uchar unsigned char
#define uint unsigned int
//-----------定义模糊系统参数-----------------------------------------------------------
//------------------------------------------------------------------------------------
unsigned char Temp_H,Temp_L;
uint sum; //10次AD值的综合变量
uchar RH,RH_H=12,RH_L=8,state,ms,cs; //当前水位, 水位上限,下限, 设置项变量,50ms变量 ,cs 为计次数变量 ,
bit beep1,zt,s1; //报警标志位, 工作模式标志位, 闪烁标志位
int Temperature;
//-----------定义模糊系统参数-----------------------------------------------------------
//------------------------------------------------------------------------------------
//-------------定义常量----------------------------------------------------------------
#define MU_MAX 0XFF //模糊度的最大值为0XFF代表面1
#define RULE_TOT 10 //规则数个数
#define MF_TOT 5 //成员函数的个数
#define IO_NUM 0x07
#define LABEL_NUM 0x70
#define DEFAULT_VALUE 0x00
//----------------定义数据库-----------------------------------------------------------
unsigned char code output_memf[MF_TOT]={0, 15, 35, 60, 102};// OUTPUT TURNING NUMBER:
// ZERO, VSMALL, SMALL, MEDIUM, BIG
// 输入功能函数以点斜式方式存储. 第一维成员函数标号第二维是点斜式数据
unsigned char code input_memf[MF_TOT][4]={ //距离功能函数
{ 0x00, 0x00, 0x00, 0x0d }, // VSLOW
{ 0x00, 0x0d, 0x14, 0x0d }, // SLOW
{ 0x1e, 0x0d, 0x32, 0x0d }, // MEDIUM
{ 0x3C, 0x0d, 0x50, 0x0d }, // FAST
{ 0x50, 0x09, 0x6e, 0x00 } // VFAST
};
//-----------定义模糊系统参数-----------------------------------------------------------
//------------------------------------------------------------------------------------
//-----------定义模糊系统规则-----------------------------------------------------------
unsigned char code rules[RULE_TOT]={
// if... then... 规则
GAP_ZERO,TURN_ZERO,
GAP_VSMALL,TURN_VSMALL,
GAP_SMALL,TURN_SMALL,
GAP_MEDIUM,TURN_MEDIUM,
GAP_BIG,TURN_BIG
};
//-----------定义模糊系统参数-----------------------------------------------------------
//------------------------------------------------------------------------------------
//-----------定义各变量-----------------------------------------------------------------
unsigned char outputs[MF_TOT],fuzzy_out; //模糊输出mu值
//-----------子程序函数头申明-----------------------------------------------------------
void fuzzy_engine(uchar);
uchar compute_memval(uchar,uchar);
void defuzzify(void);
/***************************************************************************************************************/
uchar compute_memval(uchar input,uchar label)
{
int data temp;
if (input < input_memf[label][0])
{ // 如果输入不在曲线下u值为0
return 0;
}
else
{
if (input < input_memf[label][2])
{
temp=input; // 用点斜式计算mu
temp-=input_memf[label][0];
if (!input_memf[label][1])
{
temp=MU_MAX;
}
else
{
temp*=input_memf[label][1];
}
if (temp < 0x100)
{ // 如果结果不超过1
return temp; // 返回计算结果
}
else
{
return MU_MAX; // 确保mu值在范围内
}
}
else
{ // 输入落在第二条斜线上
temp=input; // 用点斜式方法计算 mu
temp-=input_memf[label][2];
temp*=input_memf[label][3];
temp=MU_MAX-temp;
if (temp < 0)
{ // 确保结果不小于0
return 0;
}
else
{
return temp; // mu为正 – 返回结果
}
}
}
return 0;
}
/*******************************************************************************
Function: defuzzify 解模糊
Description: 计算模糊输出的重心并调用函数把它
转换成可被系统使用的输出量
Parameters: 无.
Returns: 无.
Side Effects: outputs[][] 数组被清零.
*******************************************************************************/
void defuzzify(void)
{
unsigned long numerator, denominator;
unsigned char j;
numerator=0; // 恢复总数值
denominator=0;
for (j=0; j<MF_TOT; j++)
{ // 计算总和值
numerator+=(outputs[j]*output_memf[j]);
denominator+=outputs[j];
outputs[j]=0; // 清零输出作为参考使用
if (denominator)
{ // 确保分母是0的情况不发生
fuzzy_out=numerator/denominator; // 确定 COG
}
else
{
fuzzy_out=DEFAULT_VALUE; // 没有规则被触发
}
}
}
/*******************************************************************************
Function: fuzzy_engine
Description: 实施规则基中的规则
Parameters: 无
Returns: 无.
Side Effects: 无
********************************************************************************/
unsigned char bdata clause_val; // 保存当前的分支进行快速访问
sbit clause_type = clause_val^7; // 表示分支是否是条件分支或者是结果分支
void fuzzy_engine(uchar input)
{
bit then; // 当正在分析结果时置位
unsigned char if_val, // 保存当前规则中条件分支中的值
clause, // 规则基中当前的分支
mu, // 保存当前分支中的值
label=0; // 被条件使用的成员函数
then=0; // 设第一个分支是条件分支
if_val=MU_MAX; // max out mu for the first rule
for (clause=0; clause<RULE_TOT; clause++)
{ // 遍历每条规则
clause_val=rules[clause]; // 读入当前的分支
if (!clause_type)
{ // 当前的分支是不是条件分支
if (then)
{ // 是否正在分析结果...
then=0;
if_val=MU_MAX; // 复位mu
}
mu=compute_memval(input, label); // 得到条件分支的值
if_val=mu;
label++;
}
else
{ // 当前分支是结果
then=1; // 置位标志位,如果当前规则的mu比参考的值要大,保存这个值作为新的模糊输出
if (outputs[clause_val&0x07] < if_val)
{
outputs[clause_val&0x07]=if_val;
}
}
}
defuzzify(); // 用COG方法计算模糊输出和反模糊输出
}
#include<reg52.h>
#include<intrins.h>
#include<math.h>
#include<string.h>
#include"fuzzy.h"
struct PID
{
unsigned int SetPoint; // 设定目标 Desired Value
unsigned int Proportion; // 比例常数 Proportional Const
unsigned int Integral; // 积分常数 Integral Const
unsigned int Derivative; // 微分常数 Derivative Const
unsigned int LastError; // Error[-1] 当前偏差
unsigned int PrevError; // Error[-2] 上一次偏差
unsigned int SumError; // Sums of Errors 累计偏差
};
struct PID spid; // PID Control Structure
unsigned int rout; // PID Response (Output) 响应输出
unsigned int rin; // PID Feedback (Input)//反馈输入
unsigned char high_time,low_time,count=0;//占空比调节参数
#define uchar unsigned char
#define uint unsigned int
char Usart_Data[3];
bit FinishFlag =0;
char UsartCount=0;
uchar buzzer_flag = 0;
sbit buzzer = P1^2;
sbit output=P1^0;
sbit ds=P3^2;
sbit DQ=P3^2;//ds18b20与单片机连接口
sbit lcden=P2^7;//LCE使能引脚
sbit lcdrs=P2^5;
sbit lcdrw=P2^6;
sbit ledred=P1^6; //加热指示灯
sbit ledgreen=P1^7; //加热指示灯
sbit key0=P2^0;//按键引脚
sbit key1=P2^1;
bit busy;
uchar set[2]={0};
uchar code str1[]="now temp: C";
uchar code str2[]="set temp: C";
uchar code table[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};
uchar n,num;
int set_temper=30,temper,temp; //温度变量定义
unsigned int s;
float f_temp;//转换后的温度
uint tvalue;
uchar tflag;//温度正负标志
void SendData(unsigned char dat);
void SetSendData(unsigned char SetNum);
void delay(i)//延时函数
{
uint j;
for(i;i>0;i--)
for(j=110;j>0;j--);
}
void Delay_Ms(i){
delay(i);
}
void Timer2_init()
{
RCAP2H = (0XFFFF - 50000)/256;
RCAP2L = (0XFFFF - 50000)%256;
T2CON =0;
//T2MOD = 0;
IE |=0xA0;
TR2 = 1;
}
void wr_com(uchar ml)//写命令
{
lcdrs=0;
P0=ml;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
void wr_data(uchar shuju)//写数据
{
lcdrs=1;
//lcden=1;
P0=shuju;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
void init() //按照时序操作的初始化
{
lcdrw=0;
wr_com(0x38);//显示模式设置,设置为16*2显示,5*7点阵,八位数据口
wr_com(0x0c);//开显示,但不开光标,光标不闪
wr_com(0x06);//显示光标移动设置
wr_com(0x01);// 清屏
wr_com(0x80); // 数据指针初始化
for(num=0;num<16;num++)
{
wr_data(str1[num]);//now temp
}
wr_com(0x80+0x40); //地址初始化
for(num=0;num<16;num++)
{
wr_data(str2[num]);//set temp
}
}
/*************************DS1820程序****************************/
void delay_18B20(unsigned int i)//延时1微秒
{
while(i--);
}
void ds1820rst(void)/*ds1820复位*/
{
unsigned char x=0;
DQ = 1; //DQ复位
delay_18B20(4); //延时
DQ = 0; //DQ拉低
TR0=0;
delay_18B20(100); //精确延时大于
TR0=1;
DQ = 1; //拉高
delay_18B20(40);
}
uchar ds1820rd(void)/*读数据*/
{
unsigned char i=0;
unsigned char dat = 0;
TR0=0;
for (i=8;i>0;i--)
{
DQ = 0; //给脉冲信号
dat>>=1;
DQ = 1; //给脉冲信号
if(DQ)
dat|=0x80;
delay_18B20(10);
}
return(dat);
}
void ds1820wr(uchar wdata)/*写数据*/
{
unsigned char i=0;
TR0=0;
for (i=8; i>0; i--)
{
DQ = 0;
DQ = wdata&0x01;
delay_18B20(10);
DQ = 1;
wdata>>=1;
}
}
uint get_temper()//获取温度
{
uchar a,b;
ds1820rst();
ds1820wr(0xcc);//*跳过读序列号*/
ds1820wr(0x44);//*启动温度转换*/
ds1820rst();
ds1820wr(0xcc);//*跳过读序列号*/
ds1820wr(0xbe);//*读取温度*/
a=ds1820rd();
b=ds1820rd();
tvalue=b;
tvalue<<=8;
tvalue=tvalue|a;
TR0=1;
if(tvalue<0x0fff) tflag=0;
else {tvalue=~tvalue+1;tflag=1;}
tvalue=tvalue*(0.625);//温度值扩大10倍,精确到1位小数
temp=tvalue;
return temp;
}
void dis_temp(int t)//显示温度
{
uchar d0,d1,d2,d3;
//t=26;
if(tflag==0)
{
d0=t/1000+0x30;
d1=t%1000/100+0x30;
d2=t%100/10+0x30;
d3=t%10+0x30;
if(d0==0x30)
{
wr_com(0x80+9);
wr_data(d1);
wr_com(0x80+10);
wr_data(d2);
wr_com(0x80+11);
wr_data(0x2e);
wr_com(0x80+12);
wr_data(d3);
SendData('N');
SendData(d1);
SendData(d2);
SendData('.');
SendData(d3);
SendData('E');
SendData('\r');
SendData('\n');
}
else
{
wr_com(0x80+9);
wr_data(d0);
wr_com(0x80+10);
wr_data(d1);
wr_com(0x80+11);
wr_data(d2);
wr_com(0x80+12);
wr_data(' ');
SendData('N');
SendData(d0);
SendData(d1);
SendData(d2);
SendData('E');
SendData('\r');
SendData('\n');
}
}
else
{
wr_com(0x80+9);
wr_data('-');
wr_com(0x80+10);
wr_data(d1);
wr_com(0x80+11);
wr_data(d2);
wr_com(0x80+12);
wr_data(' ');
//wr_com(0x80+12);
//wr_data(d3);
// SendData('N');
// SendData(d1);
// SendData(d2);
// SendData('E');
// SendData('\r');
// SendData('\n');
}
wr_com(0x80+14);
wr_data(0xdf);
temper=t/10;
}
void keyscan()//键盘扫描
{
if(key0==0)
{
delay(1);
if(key0==0)
{
while(!key0);
delay(1);
while(!key0);
set_temper++;
}
set[0]=set_temper/10; //获得设置温度显示值
set[1]=set_temper%10;
wr_com(0x80+0x40+9);
wr_data(table[set[0]]);
delay(1);
wr_com(0x80+0x40+10);
wr_data(table[set[1]]);
delay(1);
//wr_com(0x80+0x40+11);
//wr_data(0x2e);
//wr_com(0x80+0x40+14);
//wr_data(0xdf);
delay(1);
}
if(key1==0)
{
delay(3);//延时去抖
if(key1==0)
{
while(!key1);
delay(3);
while(!key1);
set_temper--;//温度减
if(set_temper==0)
{set_temper=0;}
}
set[0]=set_temper/10; //获得设置温度显示值
set[1]=set_temper%10;
wr_com(0x80+0x40+9); //显示设置温度值
wr_data(table[set[0]]);
delay(1);
wr_com(0x80+0x40+10);
wr_data(table[set[1]]);
delay(1);
//wr_com(0x80+0x40+11);
//wr_data(0x2e);
wr_com(0x80+0x40+14);
wr_data(0xdf);
delay(1);
}
}
void PIDInit (struct PID *pp)
{
memset ( pp,0,sizeof(struct PID)); //用参数0初始化pp
}
unsigned int PIDCalc( struct PID *pp, unsigned int NextPoint ) //PID计算
{
unsigned int dError,Error;
Error = pp->SetPoint - NextPoint; // 偏差
pp->SumError += Error; // 积分
dError = pp->LastError - pp->PrevError; // 当前微分
pp->PrevError = pp->LastError;
pp->LastError = Error;
return (pp->Proportion * Error//比例
+ pp->Integral * pp->SumError //积分项
+ pp->Derivative * dError); // 微分项
}
/***********************************************************
温度比较处理子程序
***********************************************************/
void compare_temper(void)
{
unsigned char i;
if(set_temper>temper) //设置温度大于当前温度
{
buzzer_flag = 0;
ledred=0;
ledgreen=1;
if(set_temper-temper>1) //温度相差1度以上
{
high_time=100;
low_time=0;
}
else //设置温度不大于当前温度
{
//模糊计算
fuzzy_engine((set_temper-temper)*10);
high_time=(unsigned char)(fuzzy_out*4);
if(high_time>100)
high_time = 100;
low_time= (100-high_time);
}
}
else if(set_temper<=temper) //设置温度不大于当前温度
{
buzzer_flag = 1;
ledred=1;
ledgreen=0;
if(temper-set_temper>0) //温度相差0度以上
{
high_time=0;
low_time=100;
}
else
{
high_time=0;
low_time=100;
}
}
}
/*****************************************************
T0中断服务子程序,用于控制电平的翻转 ,40us*100=4ms周期
******************************************************/
void serve_T0() interrupt 1 using 1
{
if(++count<=(high_time)) output=0;
else if(count<=50)
{
output=1;
}
else count=0;
TH0=0x2f;
TL0=0x40;
}
void UsarrtInit(){
SCON = 0x50; //8-bit variable UART
TMOD |= 0x20; //Set Timer1 as 8-bit auto reload mode
TH1 = TL1 = 0XFD; //Set auto-reload vaule
TR1 = 1; //Timer1 start run
ES = 1; //Enable UART interrupt
EA = 1; //Open master interrupt switch
}
void SendData(unsigned char dat)
{
while (busy); //Wait for the completion of the previous data is sent
ACC = dat; //Calculate the even parity bit P (PSW.0)
busy = 1;
SBUF = ACC; //Send data to UART buffer
}
/*----------------------------
UART interrupt service routine
----------------------------*/
void Uart_Isr() interrupt 4
{
unsigned char a;
if (RI)
{
RI = 0; //Clear receive interrupt flag
a=SBUF;
if(!FinishFlag){
Usart_Data[UsartCount]=a;
if(++UsartCount>2){
UsartCount=0;
FinishFlag=1;
}
}else{
}
}
if (TI)
{
TI = 0; //Clear transmit interrupt flag
busy = 0; //Clear transmit busy flag
}
}
void TemSendData(unsigned char SetNum){
uchar d0,d1,d2,d3;
if(tflag==0){
d0=SetNum/1000+0x30;
d1=SetNum%1000/100+0x30;
d2=SetNum%100/10+0x30;
d3=SetNum%10+0x30;
if(d0==0x30){
SendData('N');
SendData(d1);
SendData(d2);
SendData('.');
SendData(d3);
SendData('E');
SendData('\r');
SendData('\n');
}else{
SendData('N');
SendData(d0);
SendData(d1);
SendData(d2);
SendData('E');
SendData('\r');
SendData('\n');
}
}else{
SendData('N');
SendData(d1);
SendData(d2);
SendData('E');
SendData('\r');
SendData('\n');
}
}
void SetSendData(unsigned char SetNum){
SendData('S');
SendData(SetNum/10+48);
SendData(SetNum%10+48);
SendData('E');
SendData('\r');
SendData('\n');
}
void LedA_StateData(){
SendData('L');
SendData('A');
if(ledred){
SendData('1');
}else{
SendData('0');
}
SendData('E');
SendData('\r');
SendData('\n');
}
void LedB_StateData(){
SendData('L');
SendData('B');
if(ledgreen){
SendData('1');
}else{
SendData('0');
}
SendData('E');
SendData('\r');
SendData('\n');
}
void USart_Handle(){
if(FinishFlag){
if(Usart_Data[0]=='S'){;
set_temper=((Usart_Data[1]-48)*10)+(Usart_Data[2]-48);
}
set[0]=set_temper/10; //获得设置温度显示值
set[1]=set_temper%10;
wr_com(0x80+0x40+9); //显示设置温度值
wr_data(table[set[0]]);
delay(1);
wr_com(0x80+0x40+10);
wr_data(table[set[1]]);
delay(1);
FinishFlag=0;
}
}
|
|