基于51单片机的多功能洗碗机(Protues仿真)

本项目是以AT89C51最小系统为核心,外接DS18B20温度传感器、OVEN加热棒、LCD1604显示屏、ADC0832模数转换器模拟浊度传感器、L298和MOTOR当电机模块。电机模块用于模拟洗碗机的进水、洗碗、出水状态,蜂鸣器模块用于提醒用户其洗碗机结束工作。

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  P0

sbit 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 1000
	lcd_writer_com(0x38);

	lcd_writer_com(0x08);	//0000 1000
	lcd_writer_com(0x0c);	//0000 0001	   0x0C:设置开显示,不显示光标
	lcd_writer_com(0x06);	//0000 0110	   0x06:写一个字符后地址指针加1
	lcd_writer_com(0x01);	 //0000 1111   显示清0,数据指针清0
	LCD_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); //延时大于480us
   DQ=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;
	  else
	  	temp_ad_val2 |=0x00;

    }
    for(i =0;i<8;i++)		   //后读取8位的值
    {
    temp_ad_val1 >>= 1;
    if (ADC_DATO)
      temp_ad_val1 |= 0x80;
    else
      temp_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;        //释放ADC0832
    ADC_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();
		}
	}

}


写的不够好,但是我会继续努力的!!!
在这里插入图片描述

  • 13
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帕法西尔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值