无水警报,自动加水,防溢出,利用电子称检测水位, DS18B20检测温度。
制作出来的实物图如下:
电路原理图如下:
原理图
单片机源程序如下:
- #include <reg52.h>
- #include <intrins.h>
- #include <string.h>
- bit bdata flag_key;
- #include "main.h"
- #include "LCD1602.h"
- #include "HX711.h"
- #include "keyboard.h"
- sfr AUXR = 0x8e;
- #define uchar unsigned char
- #define uint unsigned int
- unsigned char code digit[10]={"0123456789"}; //定义字符数组显示数字
- unsigned char code Temp[]={"Temp:"}; //说明显示的是温度
- unsigned char code Cent[]={"C"}; //温度单位
- unsigned long HX711_Buffer = 0;
- unsigned long Weight_Maopi = 0;
- unsigned long Weight_Maopi_0 = 0;
- unsigned int qupi=0;
- long Weight_Shiwu = 100;
- //键盘处理变量
- unsigned char keycode;
- //unsigned char DotPos; //小数点标志及位置
- uint GapValue,GapValue1;
- unsigned int idata price=50; //温度设定值,长整型值
- //定义标识
- volatile bit FlagTest = 0; //定时测试标志,每0.5秒置位,测完清0
- volatile bit FlagKeyPress = 0; //有键按下标志,处理完毕清0
- //校准参数
- //因为不同的传感器特性曲线不是很一致,因此,每一个传感器需要矫正这里这个参数才能使测量值很准确。
- //当发现测试出来的重量偏大时,增加该数值。
- //如果测试出来的重量偏小时,减小改数值。
- //该值可以为小数
- //#define GapValue 349
- sbit LED=P1^1;
- sbit motor = P2^1; //水泵加水
- sbit jiare = P2^0; //启动热水壶的继电器控制位
- volatile bit ClearWeighFlag = 0; //传感器调零标志位,清除0漂
-
- //显示温度设置
- void Display_Price()
- {
- unsigned char a,b,c,d;
- a = price /1000%10;
- b = price /100%10;
- c = price /10%10;
- d = price %10;
- WriteAddress(0x86);
- WriteData(digit[a] );
- WriteData(digit[b] );
- WriteData(digit[c] );
- // WriteData(digit[d] );
- }
-
- //显示温度,第二行
- /************************************************************************
- 以下是DS18B20的操作程序
- ************************************************************************/
- sbit DQ=P2^2;
- unsigned char time; //设置全局变量,专门用于严格延时
- /*****************************************************
- 函数功能:将DS18B20传感器初始化,读取应答信号
- 出口参数:flag
- ***************************************************/
- bit Init_DS18B20(void)
- {
- bit flag; //储存DS18B20是否存在的标志,flag=0,表示存在;flag=1,表示不存在
- DQ = 1; //先将数据线拉高
- for(time=0;time<2;time++) //略微延时约6微秒
- ;
- DQ = 0; //再将数据线从高拉低,要求保持480~960us
- for(time=0;time<200;time++) //略微延时约600微秒
- ; //以向DS18B20发出一持续480~960us的低电平复位脉冲
- DQ = 1; //释放数据线(将数据线拉高)
- for(time=0;time<10;time++)
- ; //延时约30us(释放总线后需等待15~60us让DS18B20输出存在脉冲)
- flag=DQ; //让单片机检测是否输出了存在脉冲(DQ=0表示存在)
- for(time=0;time<200;time++) //延时足够长时间,等待存在脉冲输出完毕
- ;
- return (flag); //返回检测成功标志
- }
- /*****************************************************
- 函数功能:从DS18B20读取一个字节数据
- 出口参数:dat
- ***************************************************/
- unsigned char ReadOneChar(void)
- {
- unsigned char i=0;
- unsigned char dat; //储存读出的一个字节数据
- for (i=0;i<8;i++)
- {
-
- DQ =1; // 先将数据线拉高
- _nop_(); //等待一个机器周期
- DQ = 0; //单片机从DS18B20读书据时,将数据线从高拉低即启动读时序
- dat>>=1;
- _nop_(); //等待一个机器周期
- DQ = 1; //将数据线"人为"拉高,为单片机检测DS18B20的输出电平作准备
- for(time=0;time<2;time++)
- ; //延时约6us,使主机在15us内采样
- if(DQ==1)
- dat|=0x80; //如果读到的数据是1,则将1存入dat
- else
- dat|=0x00;//如果读到的数据是0,则将0存入dat
- //将单片机检测到的电平信号DQ存入r[i]
- for(time=0;time<8;time++)
- ; //延时3us,两个读时序之间必须有大于1us的恢复期
- }
- return(dat); //返回读出的十进制数据
- }
- /*****************************************************
- 函数功能:向DS18B20写入一个字节数据
- 入口参数:dat
- ***************************************************/
- WriteOneChar(unsigned char dat)
- {
- unsigned char i=0;
- for (i=0; i<8; i++)
- {
- DQ =1; // 先将数据线拉高
- _nop_(); //等待一个机器周期
- DQ=0; //将数据线从高拉低时即启动写时序
- DQ=dat&0x01; //利用与运算取出要写的某位二进制数据,
- //并将其送到数据线上等待DS18B20采样
- for(time=0;time<10;time++)
- ;//延时约30us,DS18B20在拉低后的约15~60us期间从数据线上采样
- DQ=1; //释放数据线
- for(time=0;time<1;time++)
- ;//延时3us,两个写时序间至少需要1us的恢复期
- dat>>=1; //将dat中的各二进制位数据右移1位
- }
- for(time=0;time<4;time++)
- ; //稍作延时,给硬件一点反应时间
- }
- /*****************************************************
- 函数功能:延时1ms
- (3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒
- ***************************************************/
- void delay1ms()
- {
- unsigned char i,j;
- for(i=0;i<4;i++)
- for(j=0;j<33;j++)
- ;
- }
- /*****************************************************
- 函数功能:延时若干毫秒
- 入口参数:n
- ***************************************************/
- void delaynms(unsigned char n)
- {
- unsigned char i;
- for(i=0;i<n;i++)
- delay1ms();
- }
- /***********************************************************
- //温度显示相关程序
- ***********************************************************/
- void display_symbol(void)
- {
- unsigned char i;
- WriteAddress(0x40); //写显示地址,将在第2行第1列开始显示
- i = 0; //从第一个字符开始显示
- while(Temp[i] != '\0') //只要没有写到结束标志,就继续写
- {
- WriteData(Temp[i]); //将字符常量写入LCD
- i++; //指向下一个字符
- delaynms(50); //延时1ms给硬件一点反应时间
- }
- }
- /*****************************************************
- 函数功能:显示温度的小数点
- ***************************************************/
- void display_dot(void)
- {
- WriteAddress(0x49); //写显示地址,将在第2行第10列开始显示
- WriteData('.'); //将小数点的字符常量写入LCD
- delaynms(50); //延时1ms给硬件一点反应时间
- }
- /*****************************************************
- 函数功能:显示温度的单位(C)
- ***************************************************/
- void display_cent(void)
- {
- unsigned char i;
- WriteAddress(0x4c); //写显示地址,将在第2行第13列开始显示
- i = 0; //从第一个字符开始显示
- while(Cent[i] != '\0') //只要没有写到结束标志,就继续写
- {
- WriteData(Cent[i]); //将字符常量写入LCD
- i++; //指向下一个字符
- delaynms(50); //延时1ms给硬件一点反应时间
- }
- }
- /*****************************************************
- 函数功能:显示温度的整数部分
- 入口参数:x
- ***************************************************/
- void display_temp1(unsigned char x)
- {
- unsigned char j,k,l; //j,k,l分别储存温度的百位、十位和个位
- j=x/100; //取百位
- k=(x%100)/10; //取十位
- l=x%10; //取个位
- WriteAddress(0x46); //写显示地址,将在第2行第7列开始显示
- WriteData(digit[j]); //将百位数字的字符常量写入LCD
- WriteData(digit[k]); //将十位数字的字符常量写入LCD
- WriteData(digit[l]); //将个位数字的字符常量写入LCD
- delaynms(50); //延时1ms给硬件一点反应时间
- }
- /*****************************************************
- 函数功能:显示温度的小数数部分
- 入口参数:x
- ***************************************************/
- void display_temP3(unsigned char x)
- {
- WriteAddress(0x4a); //写显示地址,将在第2行第11列开始显示
- WriteData(digit[x]); //将小数部分的第一位数字字符常量写入LCD
- delaynms(50); //延时1ms给硬件一点反应时间
- }
- void ReadyReadTemp(void)
- {
- Init_DS18B20(); //将DS18B20初始化
- WriteOneChar(0xCC); // 跳过读序号列号的操作
- WriteOneChar(0x44); // 启动温度转换
- for(time=0;time<100;time++)
- ; //温度转换需要一点时间
- Init_DS18B20(); //将DS18B20初始化
- WriteOneChar(0xCC); //跳过读序号列号的操作
- WriteOneChar(0xBE); //读取温度寄存器,前两个分别是温度的低位和高位
- }
- /***********************************************************/
- //数据初始化
- void Data_Init()
- {
- price = 0;
- // DotPos = 0;
- }
- //定时器0初始化
- void Timer0_Init()
- {
- ET0 = 1; //允许定时器0中断
- TMOD = 1; //定时器工作方式选择
- TL0 = 0xb0;
- TH0 = 0x3c; //定时器赋予初值
- TR0 = 1; //启动定时器
- // AUXR &= 0x7F; //定时器时钟12T模式
- // TMOD &= 0xF0; //设置定时器模式
- // TMOD |= 0x01; //设置定时器模式
- // TL0 = 0xCE; //设置定时初值
- // TH0 = 0xFF; //设置定时初值
- // TF0 = 0; //清除TF0标志
- // TR0 = 1; //定时器0开始计时
- // ET0 = 1; //允许定时器0中断
- // EA = 1;
- }
- //定时器0中断
- void Timer0_ISR (void) interrupt 1 //using 0
- {
- uchar Counter;
- TL0 = 0xb0;
- TH0 = 0x3c; //定时器赋予初值
- // TL0 = 0xCE; //设置定时初值
- // TH0 = 0xFF; //设置定时初值
- //每0.5秒钟刷新重量
- Counter ++;
- if (Counter >= 10)
- {
- FlagTest = 1;
- Counter = 0;
- }
- }
- //按键响应程序,参数是键值
- //返回键值:
- // 14 0 15 13 //11:清除设置
- // 7 8 9 12 //12:开启motor控制继电器
- // 4 5 6 11 //13:开启jiare控制继电器
- // 1 2 3 10 //15:关闭两个继电器
- void KeyPress(uchar keycode)
- {
- switch (keycode)
- {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 9: //目前在设置整数位,要注意price是整型,存储单位为分
- // if (DotPos == 0)
- // { //最多只能设置到千位
- if (price<10000)
- {
- price=price*10+keycode*10;
- }
- // }//目前在设置小数位
- // else if (DotPos==1) //小数点后第一位
- // {
- // price=price+keycode;
- // DotPos=2;
- // }
- Display_Price();
- break;
- case 10: //去皮键
- Display_Price();
- break;
- case 11: //删除键
- price=0;
- // DotPos=0;
- Display_Price();
- break;
- case 12: //
- motor = 1;
- break;
- case 13: //
- jiare = 1;
-
- break;
- case 15: // 停止加热,停止加水
- motor = 0;
- jiare = 0;
- break;
- }
- }
- //****************************************************
- //主函数
- //****************************************************
- void main()
- {
- unsigned char TL; //储存暂存器的温度低位
- unsigned char TH; //储存暂存器的温度高位
- unsigned char TN; //储存温度的整数部分
- unsigned char TD; //储存温度的小数部分
- unsigned int h;
- GapValue = 2200;
- Init_LCD1602(); //初始化LCD1602
- EA = 0;
- Data_Init();
- Timer0_Init();
- //初中始化完成,开断
- EA = 1;
- motor = 0;
- jiare = 0;
-
- if(Init_DS18B20()==1)
-
- display_symbol();
- display_dot(); //显示温度的小数点
- display_cent(); //显示温度的单位
- LCD1602_write_com(0x80); //指针设置
- LCD1602_write_word(" Welcome To Use "); //
- LCD1602_write_com(0x80+0x40); //指针设置
- LCD1602_write_word("Temp:");
- Get_Maopi();
- LCD1602_write_com(0x80); //指针设置
- LCD1602_write_word("Set: C ");
- Display_Price();
- while(1)
- {
- //每0.5秒称重一次
- if (FlagTest==1)
- {
- Get_Weight();
- FlagTest = 0;
- }
- if ( h == 1)
- {
- if (TN >= (price/10) )
- {
- jiare =0;
- Buzzer = 0;
- }
- if( (TN < (price/10))&&(Weight_Shiwu > 700))
- {
- jiare = 1;
- Buzzer = 1;
- }
- }
- ReadyReadTemp(); //读温度准备
- TL=ReadOneChar(); //先读的是温度值低位
- TH=ReadOneChar(); //接着读的是温度值高位
- TN=TH*16+TL/16; //实际温度值=(TH*256+TL)/16,即:TH*16+TL/16
- //这样得出的是温度的整数部分,小数部分被丢弃了
- TD=(TL%16)*10/16; //计算温度的小数部分,将余数乘以10再除以16取整,
- //这样得到的是温度小数部分的第一位数字(保留1位小数)
- display_temp1(TN); //显示温度的整数部分
- display_temP3(TD); //显示温度的小数部分
- delaynms(10);
-
-
- keycode = Getkeyboard();
- //有效键值0-15
- if (keycode<16)
- {
- KeyPress(keycode);
- Buzzer=0;
- Delay_ms(100);
- Buzzer=1;
- while(keycode<16)
- {
- if(keycode==12||keycode==13||keycode==15)
- {
- Buzzer=0;
- Delay_ms(10);
- Buzzer=1;
- KeyPress(keycode);
- Get_Weight();
- flag_key=1;
- h = 1;
- }
- keycode = Getkeyboard();
- }
- }
- }
- }
- //****************************************************
- //称重
- //****************************************************
- void Get_Weight()
- {
- Weight_Shiwu = HX711_Read();
- Weight_Shiwu = Weight_Shiwu - Weight_Maopi; //获取净重
-
- Weight_Shiwu = (unsigned int)((float)Weight_Shiwu*6/GapValue)-qupi ; //计算实物的实际重量
-
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
智能饮水系统.rar
(90.4 KB, 下载次数: 185)
|