用智能控制的算法实现的,三角形隶属函数,输入为污泥度和油脂度,输出为电动机的转动时间,程序都有详细标注
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- /**********
- 论域e ec u 规则r
- e[e_length] e_length 5+1 //第一个输入变量表的长度
- ec[ec_length] ec_length 5+1 //第二个输入变量表的长度
- u[]
- r[r_Line_width][r_Column_width] r_Line_width 5 //规则表的行
- r_Column_width 5//规则表的列
- //等级表自动生成的
- unsigned char e_level[e_length-1]={0};
- unsigned char ec_level[ec_length]={0};
- unsigned char u_level[u_level_length]={0};
- unsigned char x;//第一个电压的等级
- unsigned char y;//第二个电压的等级
- unsigned char z;//输出等级
- *************/
- #include <REG52.H>//头文件
- #include "TLC2543.h"
- #define uchar unsigned char//宏定义
- #define uint unsigned int
- /*******************************数码表****************************/
- unsigned char code Tab[11]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //数码管显示0~9的段码表
- /************修改长度区****************************/
- //论域的长度
- #define e_length 5+1 //e的长度
- #define ec_length 5+1 //第二个输入变量表的长度
- #define u_length 5
- //规则表的行列
- #define r_Line_width 5 //规则表的行
- #define r_Column_width 5//规则表的列
- /*************论域表****************************/
- // 0 1 2 3 4
- double code e[e_length] ={0, 0.7, 2.0, 3.0, 4.2, 5};//5个范围6个数代表实际输入电压
- double code ec[ec_length]={0, 0.7, 2.0, 3.0, 4.2, 5};//5个范围6个数
- unsigned char code u[u_length]={28,34,40,46,52};
- /*************论域等级表****************************/
- unsigned char e_level[e_length-1]={0};//等级表自动生成的
- unsigned char ec_level[ec_length-1]={0};
- unsigned char u_level[u_length]={0};
- /*****************规则表**************************/
- unsigned char r[r_Line_width][r_Column_width]= //规则表(里面的数据代表的输出等级)
- {
- 1,1,2,3,4,
- 1,2,3,4,5,
- 2,3,3,4,5,
- 3,4,4,5,5,
- 4,5,5,5,5
- };
- //两个输入和一个输出得等级
- unsigned char x;//第一个电压的等级
- unsigned char y;//第二个电压的等级
- unsigned char z;//输出等级
- //两个真实的电压
- double e_u;
- double ec_u;
- unsigned char u_t;//电动机转动时间
- //tlc2543读取的两个电压
- uint ad_value1=0;
- uint ad_value2=0;
- unsigned char int_time; //记录中断次数
- unsigned char second; //储存秒
- unsigned char second1; //储存秒
- uint t=0,tt=0;
- uint t1=0,tt1=0;
- //按键定义
- sbit k_start=P0^7;
- sbit k_stop=P0^6;
- sbit k3=P0^2;
- sbit sg=P0^3;
- sbit Upper_leve=P0^4;//上液位
- sbit Lower_level=P0^5;//下液位
- sbit ledon=P0^7;
- sbit washing_led=P2^0;//洗涤灯
- sbit drying_led=P2^1;//甩干灯
- sbit in_led=P2^5;//进水灯
- sbit out_led=P2^6;//排水灯
- sbit p30=P3^0;
- sbit p31=P3^1;
- sbit beepon=P2^7;//蜂鸣器
- sbit sm1=P3^6;//进水阀门
- sbit sm2=P3^7;//出水阀门
- void DisplaySecond(unsigned char k);
- unsigned char rule_process(double e_local[e_length] ,double ec_local[ec_length],unsigned char r_local[r_Line_width][r_Column_width])
- {
- //将两个输入的论域分为等级存在两个表中分别为01234....
- uchar i=0;
- uchar j=0;
- uchar t;
- //等级i分为01234
- for(i=0;i<e_length-1;i++)//循环01234
- {
- e_level[i]=i; //存进去表01234
- if ( (e_local[i]<e_u) && (e_u<=e_local[i+1]) ) //e电压大于第0个数小于第一个数
- x=i; // x等级为0
- }
-
- //等级j分为01234
- for(j=0;j<ec_length-1;j++)
- {
- ec_level[j]=j;
- if ( (ec_local[j]<ec_u) && (ec_u<=ec_local[j+1]) ) //ec电压大于第0个数小于第一个数
- y=j; // y等级为0
- }
- z=r_local[x][y];//确定输出z的等级(查找规则)等级输出为12345
- t=u[z-1];//输出电动机转动的时间//等级输出01234所对应的时间
- return t;
- }
- //延时函数
- void delay2(void)
- {
- unsigned char m;
- for(m=0;m<200;m++);
- }
- void delay1(int s)
- {
- int i;
- for(;s>0;s--)
- for(i=0;i<65;i++);
- }
-
- void delay(uint i)
- {
- uchar j;
- for(i;i>0;i--)
- for(j=255;j>0;j--);
- }
- //显示函数
- void DisplaySecond(unsigned char k)
- {
-
- sm1=0; //P2.6引脚输出低电平, DS6点亮
- P1=Tab[k/10]; //显示十位
- delay2();
- delay2();
- sm1=1;
- sm2=0; //P2.7引脚输出低电平, DS7点亮
- P1=Tab[k%10]; //显示个位
- delay2();
- delay2();
- P3=0xff; //关闭所有数码管
- P1=1; //显示个位
- delay2();
- delay2();
- }
- //响蜂鸣器程序
- void beep()
- {
- p30=0;
- p31=0;
- t=0;
- while(1)
- {
- beepon^=1;
- delay(300);
- if(t>=80) break;
- }
- beepon=0;
- }
-
- void Washing(uint Washing_time_sec)
- {
- t=0;
- tt=0;
- int_time=0;
- second=Washing_time_sec;
- //洗涤的时间
- while(1)
- {
- //每20代表真实的一秒
- if(tt>=Washing_time_sec*20) break; //洗涤时间总共是Washing_time_sec秒 时间到了退出循环
- t=0;
- //正转2s
- while(t<40&&tt<=Washing_time_sec*20)
- {
- p31=0;
- p30=1; //正转 2s
- DisplaySecond(second);
- }
- t=0;
- //反转 2s
- while(t<40&&tt<=400)
- {
- p30=0;
- p31=1;
- DisplaySecond(second);
- }
- }
- //停止转动
- p30=0;
- p31=0;
- }
- void out_water()
- {
- p30=0;
- p31=0;
- out_led=1; //排水阀灯亮 等待霍尔开关2
- while(Lower_level);
- if(Lower_level==0) //如果闭合
- out_led=0; //排水灯灭
- }
- void in_water()
- {
- p30=0;
- p31=0;
- in_led=1;//进水灯亮起
- while(Upper_leve);//等待
- if(Upper_leve==0)//进水完毕
- in_led=0;//进水灯关闭
- }
- void drying(uint Drying_time)
- {
- t=0;
- int_time=0;
- DisplaySecond(0);
- second=Drying_time;
- while(t<=Drying_time*20)
- {
- p31=0;
- p30=1;
- if(second>=0)
- DisplaySecond(second);
- }
- }
- void work()
- {
- //甩干占4s 两次占8s 两次进出水共计6s 所以两次洗涤 (u_t-14)/2
- in_water(); //等待进水完毕才往下走
- Washing((u_t-14)/2); //洗涤10S
- out_water(); //洗涤结束开始排水//等待排水排干再继续往下走
- drying(4); //甩干4s
- in_water(); //进水开始等待进水结束
- Washing((u_t-14)/2); //漂洗10S
- out_water(); //漂洗结束开始排水//等待排水排干再继续往下走
- drying(4);
- beep();
- }
- void Read_voltage()
- {
- // e_u=3; //输入电压
- // ec_u=4; //输入电压
- // u_t=rule_process(e,ec,r);//输入参数为e ec 和r
- //真实得到电压小数 第一个电压
- //小数两位b=(uint)(e_u*1000)%1000/10
- //整数一位a=(uint)(e_u*1000)/1000
- ad_value1=(read2543(0)*5000.0)/4095;//第一通道//输出电压是一个4位整数
- e_u=ad_value1/1000.0;
- ad_value2=(read2543(1)*5000.0)/4095;//第二通道//输出电压是一个4位整数
- ec_u=ad_value2/1000.0; //第二个电压
- }
- int main(void)
- {
- TMOD=0x01; //方式1 16位计数器
- TH0=-50000/256; //设定初值
- TL0=-50000%256;
- EA=1; //开总中断
- ET0=1; //开定时器0中断
- TR0=1; //启动定时器0
- P2=0;
- int_time=0; //中断次数初始化
- second=00; //秒初始化
- while(1)
- {
- if(k_start==0)
- {
- while(1)
- {
- Read_voltage(); //将两个的电压读入到e_u ec_u
- u_t=rule_process(e,ec,r); //输入参数为e ec 和r
- work();
- }
-
- }
-
-
- // DisplaySecond(u_t); //显示出应该输出的电机转动的时间
- }
- return 0;
- }
- void time0() interrupt 1 using 1
- {
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
程序加仿真洗衣机版本五.rar
(161.4 KB, 下载次数: 150)
|