您当前的位置:首页 > 今日分享头条 > 正文

如何制作一个基于单片机的自动浇花系统图(如何制作一个基于单片机的自动浇花系统)

如何制作一个基于单片机的自动浇花系统图(如何制作一个基于单片机的自动浇花系统)

生活中,人工给花木浇水要花很多时间,土壤湿度也没有控制好。有时候因为主人长期外出,家里的花草树木会因为没人浇水而枯死。为了解决上述问题,本文利用单片机设计了一种自动和手动的浇水系统(如图1所示)。

图1自动浇水系统

一、功能描述

系统有自动和手动两种工作模式。两种工作模式通过手动自动切换按钮进行切换。系统开机自检,如果系统有故障会报警。如果系统工作正常,将进入自动状态,初始设定值为25%。当土壤湿度小于设定值时,水泵工作浇水,当高于设定值加偏移量(偏移量可根据实际情况确定,本文设为2)时,系统停止加水。在自动工作模式下,如果水可以因缺水而停止,或测量信号异常,系统会报警,水泵停止加水。在手动工作模式下,可以通过按加水键和停止键来手动加水和停止加水。该键控制LCD背光的开关。完成的电路如图2所示。

图2自动供水系统的电路板

二、硬件系统设计

(1)硬件系统的组成

系统选用的元器件目前市场上比较常见,系统的核心控制器件是STC公司的STC89C52RC单片机,应用广泛。除单片机外,还包括土壤水分传感器、AD转换器、LCD1602液晶显示器、按键、指示灯、蜂鸣器、继电器和水泵等。

(2)电路的工作原理

电路原理图如图3所示,包括电源电路、晶振及复位电路、检测电路、按键及显示电路、报警电路和输出控制电路。

1.电源电路

系统所需的5V电源直接由外部提供,可以由各种常见的手机充电器提供。USB电源端子和圆形端子用于连接外部电源。使用时,连接其中一个,另一个可以对外提供5V电源,方便系统电源的连接。

2.晶体振荡器和复位电路

电容C6、C7和晶振Y1组成振荡电路,为单片机提供所需的时钟。C8、R13和RST1键组成单片机复位电路,可以实现上电复位和手动复位。

3.探测电路

检测电路由土壤湿度传感器和AD转换器组成。选用了廉价易用的土壤湿度传感器模块和AD转换器PCF8591模块(见图4)。该模块具有四路输入和一路输出,可以满足系统扩展的需要。该电路将土壤水分转换成模拟量,经过AD转换后,转换成相应的单片机可以识别的数字量。

图4土壤湿度传感器和AD转换模块

4.按键和显示电路

按键显示电路由四个独立按键、LED指示灯和LCD1602组成,用于人机操作和系统各种工作状态的信息显示。

5.告警电路

报警电路由蜂鸣器和LED指示灯组成,实现了声光报警。15次后声音停止,LED指示灯一直闪烁。

6.输出控制电路

单片机的输出信号通过驱动电路驱动继电器,控制继电器的通断,用于驱动执行机构(本文中为5V DC水泵)的通断。LED指示灯显示输出状态。

三、软件系统设计

(1)系统流程图(见图5)

(2)系统软件设计

系统采用项目多文件和模块化编程,便于编程和程序移植。它由main.c、I2C.c、键盘组成。c,Lcd1602.c文件,对应的头文件和配置文件config.h Lcd1602.c主要负责液晶的底层显示驱动。I2C.c主要负责AD转换器的底层功能驱动。键盘。c负责关键处理,main.c负责系统初始化、自检、土壤水分检测、中值滤波和信号li

整个项目的软件按流程图编写即可,程序代码如下(注意报纸因为版面原因,无法全部刊登,这里可以看到完整的代码)。

参考程序

/***************************************

配置文件

**************************************/

#ifndef _CONFIG_H

#定义配置H

#包括《reg52.h》

#包括《intrins.h》

#在0上定义

#定义关闭一

#定义偏移2 //上下限偏差

typedef无符号字符uchar//8位无符号数

typedef无符号整数单元;//8位无符号数

sbit ak_key=p1^0;//背光控制

sbit up_key=p1^1;//增加_启动

sbit dn_key=p1^2;//减小_停止

sbit ma_key=p1^3;//手动_自动

sbit alarm_led=p1^4;//故障指示

sbit pump_led=p1^5;//抽水指示

sbit manual_led=p1^6;//手动指示

sbit auto_led=p1^7;//自动指示

sbit pump=p2^2;//水泵控制

sbit buzzer=p2^3;//蜂鸣器报警

#定义LCD1602_DB P0 //1602液晶数据口

sbit lcd1602_rs=p2^7;//1602液晶数据_指令选择

sbit lcd1602_rw=p2^6;//1602液晶读写选择

sbit lcd1602_e=p2^5;//1602液晶使能信号

sbit lcd1602_ak=p2^4;//1602液晶背光信号

sbit i2c_scl=p2^1;//AD转换器

sbit i2c_sda=p2^0;

#endif

/***************************************

主要的H。

***************************************/

#ifndef _MAIN_H

#定义_主要_H

enum eStaSystem //系统运行状态枚举

{

电子自动,电子手动,电子报警

};//设置,自动,手动,故障报警

#ifndef _MAIN_C

外部枚举系统;

#endif

无效延迟ms(无符号整数t);//延时函数

void SysInit();//系统初始化

void自检();//系统自检

void AutoWork();//系统自动运行

void显示LCD 1602();//测量、状态显示

空隙湿度();//土壤湿度检测

无符号字符GetADCValue(无符号字符CHN);//AD转换

void ConfigTimer0(无符号整数毫秒);//T0配置函数

#endif

/***************************************

主网站

***************************************/

#定义_主要_C

#包含"config.h &quot

#包含" main.h "

#包含"键盘. h "

#包含" I2C.h "

#包含"液晶显示器1602.h "

#定义N 3 //AD采样次数

#定义偏移2//上限偏移量

enum esta system sta system=E _ AUTO;//初始为自动状态

无符号字符T0RH=0;//定时器T0载值

无符号字符T0RL=0;

无符号字符TestVal//测量值

无符号字符计数;//蜂鸣器报警15次

//-

void main()

{

SysInit();

自检();

while(1)

{

关键动作();

AutoWork();

}

}

/****************************************

函数功能:系统初始化

入口参数:无

*****************************************/

void SysInit()

{

AK _ KEY=OFF//按键超正析象管(图片Orthicon)口初始化

UP _ KEY=OFF//

DN _ KEY=OFF

MA _ KEY=关;

ALARM _ LED=OFF//指示灯熄灭

泵浦LED=关;

手动_ LED=关闭

AUTO _ LED=关;

蜂鸣器=关;//关蜂鸣器

泵=关闭;//关水泵

LcdInit();//初始化液晶

LcdShowStr(0,0,-自动浇水-);//显示系统自检

LcdShowStr(1,1,"系统测试");//

配置定时器0(10);//配置T0定时10ms

EA=0;//关中断

}

/****************************************

函数功能:系统自动运行,故障报警

入口参数:无

*****************************************/

无效自动工作()

{

if(staSystem==E_AUTO)

{

湿度();

AUTO _ LED=开;

手动_ LED=关闭

if(TestVal》96||TestVal《5》

{

staSystem=E _ ALARM

cnt=30

EA=1;

}//故障

elseif(TestVal《SetVal

{

泵=开;

泵浦LED=开;

}

else if(TestVal)(设置值偏移))

{

泵=关闭;泵浦LED=关;

}

}

显示LCD 1602();//更新显示

}

/****************************************

函数功能:系统自检,故障报警

入口参数:无

*****************************************/

无效自检()

{

unsignedchar i,k,n;

无符号字符温度;

for(I=0;我《3;我)

{

报警指示灯=开;

泵浦LED=开;//抽水指示

手动_ LED=开;//手动指示

AUTO _ LED=开;//自动指示

戴莱姆斯(500);

ALARM _ LED=关闭

泵浦LED=关;//抽水指示

MANUAL _ LED=OFF//手动指示

AUTO _ LED=关;//自动指示

戴莱姆斯(500);

}

蜂鸣器=开;

戴莱姆斯(500);

蜂鸣器=关;

LcdClearScreen();

LcdShowStr(0,0,测试结果:);

for(I=0;我《4;i )//读取3次测量结果,过高故障报警

{

temp=getadc值(3);//直接读取0通道

if(temp)240 | | temp《10》k;

}

如果(k 2)//自检故障

{

EA=0;//关中断

while(1)

{

报警指示灯=开;

LcdShowStr(1,10,错误!");

戴莱姆斯(550);

LcdShowStr(1,10,");

ALARM _ LED=关闭

戴莱姆斯(250);

如果(n 《3》蜂鸣器=!蜂鸣器;

elseBUZZER=OFF

}

}

LcdClearScreen();

}

/****************************************

函数功能:测量、状态显示

入口参数:无

*****************************************/

空的显示1602()

{

LcdShowStr(0,0,PV:);

ShowNum(0,3,测试值);//显示实测值

LcdShowStr(0,6,“% RH”);

LcdShowStr(0,10,状态:);

LcdShowStr(1,0,SV:);

ShowNum(1,3,set val);//显示设定值

LcdShowStr(1,6,“% RH”);

if(sta system==E _ AUTO)LcdShowStr(1,10,自动);

else if(sta system==E _ MANUAL)LcdShowStr(1,10,“MANUAL”);

}

/**********************************************

函数功能:读取当前的物理输出核心转换值

入口参数:中国,公元通道号0-3

**********************************************/

无符号字符GetADCValue(无符号字符)

{

乌恰瓦尔;

I2C start();

如果(!I2C写的(0x 48《1》//寻址PCF8591 PCF8591如未应答,则停止操作并返回,00

{

I2C站();

返回0

}

I2C写(0x 40 |中国);//写入控制字节,选择转换通道

I2C start();

I2C写((0x 48《1)|0x 01);//寻址PCF8591 PCF8591指定后续为读操作

I2CReadACK();//先空读一个字节,提供采样转换时间

val=I2CReadNAK();//读取刚刚转换完的值

I2C站();

returnval

}

/****************************************

函数功能:按升序排列数组元素

入口参数:数组及数组长度

*****************************************/

void SortArray(unsigned char a[],unsignedchar a_len)

{

未签名字符I,临时

for(I=1;我《艾伦》我)

{

if(a[i-1]》a[i])

{

temp=a[I-1];

a[I-1]=a[I];

a[I]=temp;

I=0;

}

}

}

/****************************************

函数功能:中值滤波,线性转换后,获得土

壤湿度0-100%

入口参数:无

*****************************************/

空隙湿度()

{

无符号char i,tmp

无符号字符adBuf[N];

for(I=0;我《N;I)adBuf[I]=getadc值(1);//读取湿度

SortArray(adBuf,sizeof(adBuf));

tmp=adBuf[N/2];

tmp=getadc值(3);

TestVal=100-100 .* tmp/255;

}

/****************************************

函数功能:配置定时器0,定时时间

壤湿度0-100

入口参数:毫秒,定时时间(毫秒)

****************************************/

void ConfigTimer0(无符号整数毫秒)

{

无符号长终端监督程式(Terminal Monitor Program的缩写)

tmp=11059200/12;//定时器计数频率

tmp=(tmp * ms)/1000;//计算所需的计数值

tmp=65536-tmp;//计算定时器重载值

tmp=tmp 12//修正中断响应延时造成的误差

T0RH=(unsigned char)(tmp《8》);//定时器重载值拆分为高低字节

T0RL=(无符号字符)tmp

TMOD=0xf 0;//清零T0的控制位

TMOD |=0x 01;//配置T0为模式11

TH0=T0RH//加载T0重载值

TL0=T0RL

ET0=1;//使能T0中断

TR0=1;//启动T0

}

/****************************************

函数功能:延时函数

入口参数:t,延时约t毫秒

****************************************/

//- 延时-

无效延迟(单位t)

{

乌恰里

while(t -)

for(I=0;我《123;I);

}

/****************************************

函数功能:T0中断服务函数

入口参数:无

****************************************/

无效中断定时器0()中断一

{

静态无符号字符tmrms=0;

静态无符号字符TMR=0;

TH0=T0RH//定时器重新加载重载值

TL0=T0RL

tmrms

TMR=(TMR 1)0;

if(staSystem==E_ALARM) //故障液晶报警显示

{

if(TMR《50》LcdShowStr(1,11,)报警");

elseLcdShowStr(1,11 ");

if(tmrms =50)//定时0.5s

{

tmrms=0;

ALARM_LED=!警报_ LED

如果(CNT 0){ CNT-;蜂鸣器=!蜂鸣器;}

否则{蜂鸣器=关}

}

}

其他

{

ALARM _ LED=关闭

蜂鸣器=关;

}

}

/***************************************

液晶显示器1602.h

***************************************/

#ifndef _LCD1602_H

#define _LCD1602_H

#ifndef _LCD1602_C

#endif

void LcdWaitReady();//读取"忙"表示,等待液晶准备好

void LcdWriteCmd(无符号字符cmd);//给液晶发送命令煤矿管理局

void LcdWriteDat(无符号char dat);//写入数据函数

void LcdClearScreen();//液晶清屏

void LcdInit();//液晶初始化函数

void CursorPos(无符号字符行,无符号字符列);//光标定位

void ShowNum(无符号字符行,无符号字符列,无符号字符数);//显示3位数

void LcdShowStr(unsigned char row,unsignedchar col,unsigned char code * str);//显示字符串

#endif

/***************************************

液晶显示器1602.c

***************************************/

#define _LCD1602_C

#包含"config.h &quot

#包含"液晶显示器1602.h "

/********************************************

函数功能:判断液晶模块忙碌状态。忙,等待。

入口参数:无。

********************************************/

void LcdWaitReady() //读取"忙"表示,等待液晶准备好

{

无符号字符无线电台临时使用许可证

LCD1602 _ DB=0xFF

LCD 1602 _ RS=0;

LCD 1602 _ RW=1;

做//做。在…期间循环语句

{

LCD 1602 _ E=1;

sta=LCD1602 _ DB//读取状态字

LCD 1602 _ E=0;//读完了要关闭使能,防止液晶输出数据干扰总线

} while(sta0x 80);//位七等于一表示液晶正忙,重复检测直到其等于0 为止

}

/************************************************

函数功能:给液晶发送命令

入口参数:cmd

**************************************************/

void LcdWriteCmd(无符号字符命令)

{

LcdWaitReady();

LCD 1602 _ RS=0;

LCD 1602 _ RW=0;

LCD1602 _ DB=cmd

LCD 1602 _ E=1;

LCD 1602 _ E=0;

}

/************************************************

函数功能:给液晶发送数据

入口参数:dat

**************************************************/

void LcdWriteDat(无符号字符数据)//写入数据函数

{

LcdWaitReady();

LCD 1602 _ RS=1;

LCD 1602 _ RW=0;

LCD1602 _ DB=dat

LCD 1602 _ E=1;

LCD 1602 _ E=0;

}

/************************************************

函数功能:清屏

入口参数:无

**************************************************/

void LcdClearScreen()

{

LcdWriteCmd(0x 01);

}

/************************************************

函数功能:液晶初始化

入口参数:无

**************************************************/

void LcdInit() //液晶初始化函数

{

LcdWriteCmd(0x 38);//16*2 显示,5*7 点阵,8 位数据接口

LcdWriteCmd(0x0C);//显示器开,光标关闭

LcdWriteCmd(0x 06);//文字不动,地址自动加一

LcdWriteCmd(0x 01);//清屏

}

/************************************************

函数功能:定位光标

入口参数:行行位置,栏列位置

**************************************************/

无效光标(无符号字符行,无符号字符列)

{

row %=2;col %=40//防止越界

if(row)LcdWriteCmd(0xc 0 col);//第2行

elseLcdWriteCmd(0x 80列);//第一行

}

/************************************************

函数功能:显示3位数

入口参数:行行位置,栏列位置,编号显示数据

**************************************************/

void ShowNum(无符号字符行,无符号字符列,无符号字符数)

{

row %=2;col %=40//防止越界

LcdWriteCmd(0x80行*0x40列);//光标定位

如果(数字《10》

{

LcdWriteDat(" ");//百位

LcdWriteDat(" ");//十位

lcdwritedat(num"0”);//个位

}

埃尔塞夫(编号《100》)

{

LcdWriteDat(" ");//百位

lcdwritedat(num/10“0”);//十位数

lcdwritedat(num“0”);//有点

}

其他

{

LcdWriteDat(数字/100 ' 0 ');//数百

lcdwritedat(num/10“0”);//十位数

lcdwritedat(num“0”);//有点

}

}

/************************************************

函数:在给定位置显示一个字符串。

参数:行位置、列位置、字符串

**************************************************/

Void LcdShowStr(unsigned char row,unsignedchar col,unsigned char code *str) //显示字符

{

uchari=0;

row %=2;col %=40//阻止越境

LcdWriteCmd(0x80行*0x40列);//光标定位

for(;col《40str[i]!=0;I,col){ LcdWriteDat(str[I]);}

}

/***************************************

I2C.h

***************************************/

# I2C国际机场

#定义I2C_H

# I2C国际机场

#endif

void I2C start();//产生总线启动信号

void I2C stop();//生成一个总线停止信号

位I2CWrite(无符号字符dat);//I2C总线写操作,要写的字节dat dat,返回值是响应状态。

位I2CWrite(无符号字符dat);//I2C总线写操作,要写的字节dat dat,返回值是响应状态。

无符号字符I2CReadACK();//I2C总线读取并发送响应信号,返回值为读取的字节。

无符号字符I2CReadNAK();

#endif

/***************************************

I2C.c

***************************************/

#定义I2C_C

#包含" config.h "

#包含“I2C.h”

# define I2C delay(){ _ nop _();_ nop _();_ nop _();_ nop _();}

/********************************************

功能:产生总线启动信号。

入口参数:无。

********************************************/

void I2CStart()

{

I2C _ SDA=1;//首先确定SDA和SCL都高。

I2C _ SCL=1;

I2C delay();

I2C _ SDA=0;//首先拉低SDA

I2C delay();

I2C _ SCL=0;//再拉下SCL

}

/********************************************

功能:产生公交停车信号。

入口参数:无。

********************************************/

voidI2CStop()

{

I2C _ SCL=0;//首先,确保SDA和SCL都为低电平。

I2C _ SDA=0;

I2C delay();

I2C _ SCL=1;//先把SCL拉高

I2C delay();

I2C _ SDA=1;//再次拉高SDA

I2C delay();

}

/********************************************

函数:I2C总线写操作,返回值为响应状态。

入口参数:要写入的字节dat。

********************************************/

I2CWrite位(无符号字符数据)

{

位ack//用于临时存储响应位的值

无符号字符掩码;//用于检测字节中的位值的掩码变量

for(mask=0x 80;面膜!=0;面具=1)//从高到低进行。

{

If ((maskdat)==0) //该位的值输出到SDA

I2C _ SDA=0;

其他

I2C _ SDA=1;

I2C delay();

I2C _ SCL=1;//拉高SCL

I2C delay();

I2C _ SCL=0;//再次拉低SCL以完成一个位周期。

}

I2C _ SDA=1;//8位数据发送后,主机释放SDA检测从机的回应。

I2C delay();

I2C _ SCL=1;//拉高SCL

ack=I2C _ SDA;//此时读取SDA值,即从机的响应值。

I2C delay();

I2C _ SCL=0;//再次拉低SCL完成响应位,保持总线。

return(~ ack);//将响应值反转以符合通常的逻辑:0=不存在或忙或写失败,1=存在且空闲或写成功。

}

/********************************************

功能:I2C总线读取并发送不应答信号,

返回值是读取的字节。

入口参数:无。

********************************************/

无符号字符I2CReadNAK()

{

无符号字符掩码;

无符号char dat

I2C _ SDA=1;//确保主机首先释放SDA

for(mask=0x 80;面膜!=0;面具=1)//从高到低进行。

{

I2C delay();

I2C _ SCL=1;//拉高SCL

If(I2C_SDA==0) //读取SDA的值

dat=~ mask当//为0时,dat中的相应位被清0。

其他

dat |=mask当//为1时,dat中相应的位置为1。

I2C delay();

I2C _ SCL=0;//再次拉低SCL,以便从机发送下一位。

}

I2C _ SDA=1;//8位数据发送后,拉高SDA,发送不应答信号。

I2C延迟();

I2C _ SCL=1;//拉高SCL

I2C延迟();

I2C _ SCL=0;//再拉低SCL完成非应答位,并保持住总线

返回数字式录音带(digital audio tape)DOS文件名数据文件

}

/********************************************

函数功能:I2C总线读操作,并发送应答信号,

返回值为读到的字节。

入口参数:无。

********************************************/

无符号字符I2CReadACK()

{

无符号字符掩码;

无符号字符数据

I2C _ SDA=1;//首先确保主机释放国家药品监督管理局

for(掩码=0x 80面膜!=0;面具》=1)//从高位到低位依次进行

{

I2C延迟();

I2C _ SCL=1;//拉高SCL

if(I2C_SDA==0) //读取国家药品监督管理局的值

dat=~ mask//为0 时,dat中对应位清零

其他

dat |=mask//为一时,dat中对应位置一

I2C延迟();

I2C _ SCL=0;//再拉低SCL,以使从机发送出下一位

}

I2C _ SDA=0;//8 位数据发送完后,拉低SDA,发送应答信号

I2C延迟();

I2C _ SCL=1;//拉高SCL

I2C延迟();

I2C _ SCL=0;//再拉低SCL完成应答位,并保持住总线

返回数字式录音带(digital audio tape)DOS文件名数据文件

}/***************************************

键盘。h

***************************************/

#ifndef _KEY_BOARD_H

#define _KEY_BOARD_H

#ifndef _KEY_BOARD_C

走读生无符号char SetVal

#endif

void键操作();//按键处理,手动运行

#endif

/***************************************

键盘C

***************************************/

#define _KEY_BOARD_C

#包含"config.h &quot

#包含"键盘. h "

#包含"液晶显示器1602.h "

#包含" main.h "

无符号字符SetVal=25//设定初始值

/****************************************

函数功能:按键处理,手动运行

入口参数:无

*****************************************/

void KeyAction()

{

if(AK_KEY==0)//LCD1602背光控制

{

戴莱姆斯(10);

if(AK_KEY==0)

{

LCD1602_AK=!液晶显示器1602 _ AK

而(!AK _ KEY);

}

}

如果(MA_KEY==0)

{

戴莱姆斯(10);

如果(MA_KEY==0)

{

if(staSystem==E_AUTO)

{

staSystem=E _ MANUAL

AUTO _ LED=关;

手动_ LED=开;

}

elseif(staSystem==E_MANUAL)

{

staSystem=E _ AUTO

AUTO _ LED=开;

手动_ LED=关闭

}

而(!MA _ KEY);

}

}

if(staSystem==E_MANUAL)//手动工作状态

{

if(UP _ KEY==0){ PUMP=ON;泵浦LED=开;}//手动开

else if(DN _ KEY==0){ PUMP=OFF;泵浦LED=关;}//手动关}

}

elseif(staSystem==E_AUTO)//自动状态

{

if(UP_KEY==0)

{

戴莱姆斯(10);

if(UP_KEY==0)

{

if(设置val《100》设置val;//设置

而(!UP _ KEY);

}

}

if(DN_KEY==0)

{

戴莱姆斯(10);

if(DN_KEY==0)

{

if(设置值0)设置val-;//设置-

而(!DN _ KEY);

}

}

}

}责任编辑人:CC


声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,谢谢。

上一篇: 最耐用的移动硬盘(哪个牌子的移动硬盘更耐用)

下一篇: fm2012埃弗顿(这个赛季结束我一定去复习)



推荐阅读