本项目是以AT89C51最小系统为核心,外接DS18B20温度传感器、OVEN加热棒、LCD1604显示屏、ADC0832模数转换器模拟浊度传感器、L298和MOTOR当电机模块。电机模块用于模拟洗碗机的进水、洗碗、出水状态,蜂鸣器模块用于提醒用户其洗碗机结束工作。
文章目录
- 1、仿真图
- 2、软件设计流程图
- 3、keil4编写代码
- 3.1 LCD1604模块
- 3.2 DS18B20模块
- 3.3 ADC0832模块
- 3.4 STATUS模块
- 3.5 KEY模块
- 3.6 main模块
1、仿真图
2、软件设计流程图
先把软件流程图画出来,有个思路也方便后面编写代码
3、keil4编写代码
我这里是写了一个主文件调用五个子文件,分别是:
main.c:主函数
ADC.c:ADC032模数转换器,获取电压大小,在主函数在将其转换为百分比
DS18B20.c: 获取温度传感器数据
KEY.c:按键模块
LCD1602.c: 对LCD1604显示屏进行初始化、写命令、写数据
STATUS.C:按钮功能、进水、出水、洗涤方式、定时器初始化函数以及一些公共定义
3.1 LCD1604模块
我是先写lcd显示屏,它是被调用,不需要调别的数据。LCD1604与LCD1602原理差不多,只是容量比LCD1602多一倍,我需要显示的数据比较多,所以本项目这里采用的LCD1604显示模块,主要显示当前选择模式、温度数据、浊度数据、定时时间、剩余时间、进度显示。RS引脚接单片机P2.0引脚,RW引脚接单片机P2.1引脚,E引脚接单片机P2.2,D0-D7引脚接单片机P0-P7引脚。这里我写了两种显示方式,一种是可根据我们的需要写进去,一种是获取数据再显示出来。
初始化状态
运行状态
#include "LCD1602.h"#include <intrins.h>
#define uchar unsigned char
#define DataPort P0sbit RS=P2^0;
sbit RW=P2^1;
sbit E=P2^2;void delay(unsigned int n)//延时函数
{unsigned int i=0,j=0;for(i=0;i<n;i++){for(j=0;j<120;j++);}
}
// lcd 写入命令函数
void lcd_writer_com(uchar com)
{RS=0; // RS:数据/命令选择端 RW=0; // R/W :读/写选择端 E=0; //使能端:下降沿有效 P0=com;delay(5);E=1;E=0; }
//写数据函数,
void lcd_write_data(uchar Data)
{RS=1; // RS:数据/命令选择端RW=0; // R/W :读/写选择端 E=0; // 使能端:下降沿有效 P0=Data;delay(5);E=1;E=0;
}
//xy位置
void GotoXY(unsigned char x, unsigned char y)
{if(x==0)lcd_writer_com(0x80+y); //0x80是第一行的起始地址if(x==1)lcd_writer_com(0xc0+y); //0xc0是第二行的起始地址if(x==2)lcd_writer_com(0x90+y); //0x90是第三行的起始地址if(x==3)lcd_writer_com(0xd0+y); //0xd0是第四行的起始地址
}
void Print(unsigned char *str) //在LCD上显示数据,内部调用
{while(*str!='\0'){lcd_write_data(*str);str++;}
}
void LCD_Print(unsigned char x, unsigned char y, unsigned char *str) //指定的位置打印指定数据
{GotoXY(x,y);Print(str);
}
void LCD_Print_num(unsigned char x, unsigned char y,long int temp_num) //指定的位置显示数值
{uchar temp_tab[7]=0;long int num=0;uchar i=0;num=temp_num;GotoXY(x,y);if(num<0){num=0-num;lcd_write_data('-');}temp_tab[0]=num/1000000%10+0x30;temp_tab[1]=num/100000%10+0x30;temp_tab[2]=num/10000%10+0x30;temp_tab[3]=num/1000%10+0x30;temp_tab[4]=num/100%10+0x30; temp_tab[5]=num/10%10+0x30;temp_tab[6]=num%10+0x30;for(i=0;i<7;i++){if(temp_tab[i]!=0x30)break;}if(i==7){lcd_write_data(0x30);}else{while(i<7){lcd_write_data(temp_tab[i]);i++;}}
}
//lcd初始化
void lcd_init(void)
{
// RS =0 RW =0 写命令
// RS=1 RW=0 写数据
// RS =0 RW=1 读状态lcd_writer_com(0x38); //0011 1000lcd_writer_com(0x38);lcd_writer_com(0x08); //0000 1000lcd_writer_com(0x0c); //0000 0001 0x0C:设置开显示,不显示光标lcd_writer_com(0x06); //0000 0110 0x06:写一个字符后地址指针加1lcd_writer_com(0x01); //0000 1111 显示清0,数据指针清0LCD_Print(0,0,"MODE:"); //显示屏显示当前模式LCD_Print(1,0,"TIME:"); //显示屏显示剩余时间LCD_Print(2,0,"DSHI:"); //显示屏显示定时LCD_Print(2,8,"ZD:"); //显示屏显示浊度 LCD_Print(1,8,"WD:"); //显示屏显示温度 LCD_Print(3,0,"ZhunBei"); //显示屏显示准备LCD_Print(2,14,"%" );
}
3.2 DS18B20模块
本项目这里采用的是DS18B20温度传感器模块,其VCC引脚接5V,GND引脚接地,DQ引脚接51单片机P3.3引脚,通过温度检测当前的水温来判断是否启动加热棒模块。
//测量温度
#include "DS18B20.h"
#include "lcd1602.h"
int readtemp =0; // 定义读出温度储存寄存器
unsigned char str[] ={"0123456789"}; //温度显示调用数组
sbit RS=P2^0;
sbit RW=P2^1;
sbit E=P2^2;
sbit DQ =P3^3; //DS18B20 温度传感器信号端口
void delay_18B20(unsigned int i)//延时函数
{for(;i>0;i--);
}
void Init_DS18B20(void) // DS18B20 温度传感器初始化子程序
{unsigned char x=0;DQ=1; //DQ拉高delay_18B20(8);DQ=0; //DQ拉低delay_18B20(80); //延时大于480usDQ=1; //拉高总线delay_18B20(14);x =DQ; //x =0 初始化成功,反之不成功delay_18B20(20);}
unsigned char ReadOneChar(void) //DS18B20温度传感器 读时序 子程序
{unsigned char i=0;unsigned char dat =0;for(i=8;i>0;i--){DQ=0; //拉低总线dat>>=1; //每读取移位向右移位DQ =1; //拉高总线if(DQ)dat |= 0x80;delay_18B20(4);}return(dat);
}
void WriteOneChar(unsigned char dat) //DS18B20温度传感器 写时序 子程序
{unsigned char i =0;for(i=8;i>0;i--){DQ =0;DQ =dat & 0x01;if(DQ){delay_18B20(1);DQ =1;}else{delay_18B20(5);DQ =1;}dat>>=1;}
}
unsigned char ReadTemperature(void) //DS18B20 温度传感器读出子程序
{unsigned char a =0,b=0;unsigned int temp =0;Init_DS18B20(); // 初始化温度WriteOneChar(0xcc); //跳过读序列号操作WriteOneChar(0x44); //启动温度转换delay_18B20(100);Init_DS18B20();WriteOneChar(0xCC); //跳过读序列号操作WriteOneChar(0xBE); //读取温度寄存器delay_18B20(100);a =ReadOneChar(); //读取温度低位b =ReadOneChar(); //读取温度高位temp=((b*256+a)>>4); // 当前采集温度除16得到实际温度return(temp); //显示屏显示温度
}void display() //显示函数
{unsigned int temp1=0,temp2=0,i=0;temp1=(readtemp%100)/10;temp2=readtemp%10;lcd_writer_com(0xc0+12); //0x80+0x40:LCD第2行的起始地址lcd_write_data(str[temp1]); lcd_write_data(str[temp2]);lcd_write_data(0xDF); lcd_write_data('C');
}
3.3 ADC0832模块
本项目这里采用的是ADC0832模数转换模块,通过电压大小来模拟浑浊程度,从而在选择智能洗的时候根据浑浊程度来进行相对应的洗涤时间。其VCC引脚接5V,GND引脚接地,CLK引脚接51单片机P1.1引脚,DI引脚接51单片机P1.2引脚,DO引脚接51单片机P1.3引脚,CS引脚接51单片机P1.4引脚,CH0引脚接滑动变阻器,
//浑浊度
#include "ADC.h"sbit ADC_CS =P1^4; //片选端
sbit ADC_CLK= P1^1;
sbit ADC_DATI= P1^2;
sbit ADC_DATO =P1^3;
//adc转换
uchar adc0832(uchar temp_CH)
{uchar temp_data =0x00; //ad值uchar i,temp_ad_val1,temp_ad_val2;temp_ad_val2 =0x00; temp_ad_val1 =0x00;ADC_CLK =0;//初始化ADC_DATI =1;_nop_();ADC_CS =0;_nop_();ADC_CLK =1;_nop_(); if (temp_CH ==0x00){ADC_CLK =0;ADC_DATI =1; //通道0的第一位_nop_();ADC_CLK =1;_nop_();ADC_CLK=0;ADC_DATI =0; //通道0的第二位_nop_();ADC_CLK =1;_nop_();}else{ADC_CLK =0;ADC_DATI =1; //通道0的第一位_nop_();ADC_CLK =1;_nop_();ADC_CLK=0;ADC_DATI =1; //通道0的第二位_nop_();ADC_CLK =1;_nop_();}ADC_CLK =0;ADC_DATI =1;for(i =0;i<8;i++) //读取前八位{_nop_();temp_ad_val2 <<=1;ADC_CLK =1;_nop_();ADC_CLK=0;if(ADC_DATO)temp_ad_val2 |=0x01;elsetemp_ad_val2 |=0x00;}for(i =0;i<8;i++) //后读取8位的值{temp_ad_val1 >>= 1;if (ADC_DATO)temp_ad_val1 |= 0x80;elsetemp_ad_val1 |= 0x00;_nop_();ADC_CLK = 1;_nop_();ADC_CLK = 0;}if (temp_ad_val2 == temp_ad_val1) //比较前8位与后8位的值,如果不相同舍去。若一直出现显示为零,请将该行去掉temp_data = temp_ad_val1;_nop_();ADC_CS = 1; //释放ADC0832ADC_DATO = 1;ADC_CLK = 1;return temp_data;
}
3.4 STATUS模块
定时器初始化
void timer0_init(void)
{TMOD =0X10; //定时器TH1=(65536 -50000)/256;TL1 =(65536-50000)%256;TR1=1;EA=1;ET1=1;TR0=0; //启动定时器为1
}
智能洗模块
uchar zhineng =0; // 智能洗的判断标志位 0 为不启动,1为启动
uchar zhuodu_ok =0; //智能洗时,根据浊度,确定洗涤时间
uchar zhineng_num =5; //智能洗时,循环检测5次,确保浊度稳定,之后根据浊度决定洗涤时间
void zhinengxi()
{ LCD_Print(0,5,"zhinengxi");jinshui();while(zhineng) //智能洗时{while(zhineng_num-- && !zhuodu_ok){if(p_zhoudu <25) //浊度小于25%,定时10s{t_ding =10; }else if (p_zhoudu<60) //浊度小于60%,定时20s{t_ding =20;}else //浊度大于等于60,定时30s{t_ding =30;}if (zhineng_num ==0){TR0 =1; //开启定时器,开始倒计时} }zhuodu_ok =1;motor(); //电机转动adc0832(0); //ADC处理函数LCD_Print_num(1,5,t_ding); //显示定时时间if (t_ding ==0){chushui();}}
}
电机模块
本项目这里采用的L298和MOTOR模块,其引脚IN1接单片机P1.5引脚,引脚IN2接单片机P1.6引脚,MOTOR步电机设置是5V。用于模拟进水状态、出水状态、洗涤状态。当处于进水状态、工作状态时,电机正转。出水状态时,电机反转。
void motor() //电机函数
{LCD_Print(3,0,"xiwanzhong");if(t_ding !=0){m1=1;m2=0;}if(t_ding ==0){m1=0;m2=0;}
}
进水模块
出水模块电机与之相反即可。
void jinshui() //进水时m1 =1,m2=0;出水时 m1=0,m2=1 ,进水出水电机运行相反
{LCD_Print(3,0,"jinshui");if (zhineng){m1 =1;m2=0;delay(10000); //进水10s}else if (jieneng){m1 =1;m2=0;delay(8000); //进水8s}else if (chaokuai){m1 =1;m2=0;delay(5000); //进水5s}else {m1 =1;m2=0;delay(3000);}m1=0;m2=0;c_num=0;delay(2000); //进水结束,电机停止2s
}
3.5 KEY模块
这里我用switch语句来进行分别。按下按钮进行相对应的功能
void key_choose(void)
{ int button;button =key_scan();switch(button){case 1:zhinengxi();zhineng =1;break;case 2:jienengxi();jieneng=1;break;case 3:chaokuaixi();chaokuai =1;break;case 4:dingshixi();dingshi =1;break;case 5:jia();break;case 6:jian();break;case 7:lcd_init();c_num=0;break;}
}
3.6 main模块
在主函数这里,我给按钮模块加了一个if判断语句,当按下一个按键时,只能等那个按键实现完功能,才能继续按其他按钮。如果要强制中断其运行,可点击复位按钮,本人能力有限。
#include "ADC.h"
#include "LCD1602.h"
#include "DS18B20.h"
#include "STATUS.h"
#include "KEY.h"
int num =0;
void zhongduan() interrupt 3 //中断程序,每经过一次中断为50ms,20次就是一秒
{TH1=(65536 -50000)/256;TL1 =(65536-50000)%256;num++;if(num>=20){t_ding--;num=0;if(t_ding<=0){TR0 =0;}}
}
void main()
{lcd_init(); //屏幕初始化timer0_init(); //定时器初始化m1 =0; //电机引脚m1,m2电平相同且为低,保证此时电机不转,因为两个引脚电压相同 m2 =0;OVEN=1; //加热棒是低电平触发,因此给高电平,此时不加热buzzer =1; //蜂鸣器是高电平触发,因此给低电平,此时不响while(1){v_zhoudu =adc0832(0); // 测浊度p_zhoudu =v_zhoudu *100/255; //计算浊度百分比 因为是5v电压,放大20倍,方便转换LCD_Print_num(2,12,p_zhoudu); //显示浊度readtemp=ReadTemperature(); //获取温度display(); //显示温度if(c_num==0) //!c_num 用于来记录按键按下的次数。未按时为0,这个while循环成立,反之不成立{key_choose(); //模式按键函数 ,用以决定是何种洗涤模式}if(readtemp<30) //温度低于30时,启动加热{OVEN=0; }else{OVEN=1;}while(zhineng) //智能洗时{zhinengxi();}while(jieneng) //节能洗时{jienengxi();}while(chaokuai) //超快洗{chaokuaixi();}while(dingshi) //定时洗{dingshixi();}}}
写的不够好,但是我会继续努力的!!!