生活中,人工澆灌花木要耗費(fèi)大量時(shí)間,而且土壤濕度不好控制,有時(shí)候由于主人長(zhǎng)時(shí)間外出,家里的花木會(huì)因無(wú)人澆水而枯死。為了解決上述問(wèn)題,本文利用單片機(jī),設(shè)計(jì)了自動(dòng)和手動(dòng)澆花系統(tǒng)(如圖1所示)。
圖1 自動(dòng)澆花系統(tǒng)
一、功能描述
系統(tǒng)有自動(dòng)和手動(dòng)兩種工作模式,兩種工作模式由手自動(dòng)切換按鍵切換。系統(tǒng)開(kāi)機(jī)進(jìn)行自檢,如果系統(tǒng)有故障則報(bào)警,若系統(tǒng)工作正常則進(jìn)入自動(dòng)狀態(tài),初始設(shè)定值為25%。當(dāng)土壤濕度小于設(shè)定值時(shí)水泵工作澆水,當(dāng)高于設(shè)定值加上偏移量(偏移量可根據(jù)實(shí)際確定,本文設(shè)為2)時(shí)系統(tǒng)停止加水。在自動(dòng)工作模式下,如果由于缺水、加水不能停止或是測(cè)量信號(hào)不正常,則系統(tǒng)報(bào)警,水泵停止加水。在手動(dòng)工作模式下,可按加水鍵和停止鍵實(shí)現(xiàn)手動(dòng)加水和停止。背光按鍵控制液晶背光的開(kāi)關(guān)。電路成品如圖2所示。
圖2 自動(dòng)澆花系統(tǒng)電路板
二、硬件系統(tǒng)設(shè)計(jì)
(一)硬件系統(tǒng)構(gòu)成
系統(tǒng)選擇的各種元器件都是目前市面上常見(jiàn)的,系統(tǒng)核心控制器件采用應(yīng)用廣泛的STC公司的STC89C52RC單片機(jī)。除了單片機(jī)外,還包括土壤濕度傳感器、AD轉(zhuǎn)化器、LCD1602液晶顯示器、按鍵、指示燈、蜂鳴器、繼電器及水泵等。
(二)電路工作原理
電路原理圖見(jiàn)圖3,包括電源電路、晶振和復(fù)位電路、檢測(cè)電路、按鍵和顯示電路、報(bào)警電路、輸出控制電路。
1.電源電路
系統(tǒng)所需5V電源由外部直接提供,可由常見(jiàn)的各種手機(jī)充電器提供,留有USB電源端子和圓形端子跟外部電源連接,使用時(shí)連接其中之一,另外一個(gè)可以向外提供5V電源,方便系統(tǒng)電源連接。
2.晶振和復(fù)位電路
電容器C6、C7和晶振Y1構(gòu)成振蕩電路,給單片機(jī)提供所需的時(shí)鐘。C8、R13和按鍵RST1構(gòu)成單片機(jī)復(fù)位電路,實(shí)現(xiàn)上電復(fù)位和手動(dòng)復(fù)位。
3.檢測(cè)電路
檢測(cè)電路由土壤濕度傳感器和AD轉(zhuǎn)換器組成,選擇價(jià)格便宜且使用方便的土壤濕度傳感器模塊和AD轉(zhuǎn)換器PCF8591模塊(見(jiàn)圖4)。該模塊有4路輸入、1路輸出,可滿(mǎn)足系統(tǒng)擴(kuò)展需要。此電路把土壤濕度轉(zhuǎn)換成模擬量,經(jīng)AD轉(zhuǎn)換后轉(zhuǎn)換成單片機(jī)可以識(shí)別的對(duì)應(yīng)數(shù)字量。
圖4 土壤濕度傳感器和AD轉(zhuǎn)換模塊
4.按鍵和顯示電路
按鍵和顯示電路由四個(gè)獨(dú)立按鍵、LED指示燈和LCD1602構(gòu)成,用于人機(jī)操作和系統(tǒng)各種工作狀態(tài)的信息顯示。
5.報(bào)警電路
報(bào)警電路由蜂鳴器和LED指示燈構(gòu)成,實(shí)現(xiàn)聲光報(bào)警。聲音報(bào)警15次后停止,LED指示燈一直閃爍報(bào)警。
6.輸出控制電路
單片機(jī)引腳輸出信號(hào)通過(guò)驅(qū)動(dòng)電路驅(qū)動(dòng)繼電器,控制繼電器的通斷,用以驅(qū)動(dòng)執(zhí)行元件(文中為5V直流水泵)的通斷,LED指示燈顯示輸出狀態(tài)。
三、軟件系統(tǒng)設(shè)計(jì)
(一)系統(tǒng)流程圖(見(jiàn)圖5)
(二)系統(tǒng)軟件設(shè)計(jì)
系統(tǒng)采用項(xiàng)目化多文件,模塊化編程,便于程序編寫(xiě)和程序移植。由main.c,I2C.c,KEYBOARD.C,Lcd1602.c文件和對(duì)應(yīng)頭文件以及配置文件config.h組成。Lcd1602.c主要負(fù)責(zé)液晶的底層顯示驅(qū)動(dòng)。I2C.c主要負(fù)責(zé)AD轉(zhuǎn)化器的底層功能驅(qū)動(dòng)。KEYBOARD.C責(zé)按鍵處理,main.c負(fù)責(zé)系統(tǒng)初始化,自檢,土壤濕度檢測(cè),中值濾波和信號(hào)線(xiàn)性化處理,手動(dòng)自動(dòng)程序運(yùn)行。中斷程序負(fù)責(zé),系統(tǒng)運(yùn)行時(shí)的故障處理和報(bào)警,程序較短,也放在main.c中。整個(gè)項(xiàng)目,軟件按流程圖編寫(xiě),結(jié)構(gòu)清晰,流程也比較清楚。為方便讀者學(xué)習(xí)和參考,把所有文件和程序都列了出來(lái),并做了詳細(xì)的注釋。
整個(gè)項(xiàng)目的軟件按流程圖編寫(xiě)即可,程序代碼如下(注意報(bào)紙因?yàn)榘婷嬖颍瑹o(wú)法全部刊登,這里可以看到完整的代碼)。
參考程序
/***************************************
config.h
**************************************/
#ifndef _CONFIG_H
#define _CONFIG_H
/*通用頭文件*/
#include《reg52.h》
#include《intrins.h》
#define ON 0
#define OFF 1
#define OFFSET 2 //上下限偏差
/*數(shù)據(jù)類(lèi)型定義*/
typedef unsigned char uchar ;//8位無(wú)符號(hào)數(shù)
typedef unsigned int uint ;//8位無(wú)符號(hào)數(shù)
/*IO引腳分配定義*/
sbit AK_KEY=P1^0;//背光控制
sbit UP_KEY=P1^1; //增加_啟動(dòng)
sbit DN_KEY=P1^2;//減小_停止
sbit MA_KEY=P1^3;//手動(dòng)_自動(dòng)
sbit ALARM_LED=P1^4;//故障指示
sbit PUMP_LED=P1^5;//抽水指示
sbit MANUAL_LED=P1^6;//手動(dòng)指示
sbit AUTO_LED=P1^7;//自動(dòng)指示
sbit PUMP=P2^2;//水泵控制
sbit BUZZER=P2^3;//蜂鳴器報(bào)警
#define LCD1602_DB P0 //1602液晶數(shù)據(jù)口
sbit LCD1602_RS=P2^7; //1602液晶數(shù)據(jù)_指令選擇
sbit LCD1602_RW=P2^6; //1602液晶讀寫(xiě)選擇
sbit LCD1602_E=P2^5; //1602液晶使能信號(hào)
sbit LCD1602_AK=P2^4; //1602液晶背光信號(hào)
sbit I2C_SCL=P2^1;//AD轉(zhuǎn)換器
sbit I2C_SDA=P2^0;
#endif
/***************************************
MAIN.H
***************************************/
#ifndef _MAIN_H
#define _MAIN_H
enum eStaSystem //系統(tǒng)運(yùn)行狀態(tài)枚舉
{
E_AUTO,E_MANUAL,E_ALARM
}; //設(shè)置,自動(dòng),手動(dòng),故障報(bào)警
#ifndef _MAIN_C
extern enum eStaSystem staSystem;
#endif
void delayms(unsigned int t);//延時(shí)函數(shù)
void SysInit();//系統(tǒng)初始化
void SelfCheck();//系統(tǒng)自檢
void AutoWork();//系統(tǒng)自動(dòng)運(yùn)行
void ShowLcd1602();//測(cè)量、狀態(tài)顯示
void Humidity();//土壤濕度檢測(cè)
unsigned char GetADCValue(unsigned char chn); //AD轉(zhuǎn)換
void ConfigTimer0(unsigned int ms); //T0 配置函數(shù)
#endif
/***************************************
main.c
***************************************/
#define _MAIN_C
#include“config.h”
#include “main.h”
#include “Keyboard.h”
#include “I2C.h”
#include “Lcd1602.h”
#define N 3 //AD采樣次數(shù)
#define OFFSET 2//上限偏移量
enum eStaSystem staSystem=E_AUTO;//初始為自動(dòng)狀態(tài)
unsigned char T0RH=0; //定時(shí)器T0載值
unsigned char T0RL=0;
unsigned char TestVal;//測(cè)量值
unsigned char cnt; //蜂鳴器報(bào)警15次
//----------------------------------------------------------------------------------
void main ()
{
SysInit();
SelfCheck();
while(1)
{
KeyAction();
AutoWork();
}
}
/****************************************
函數(shù)功能:系統(tǒng)初始化
入口參數(shù):無(wú)
*****************************************/
void SysInit()
{
AK_KEY=OFF;//按鍵IO口初始化
UP_KEY=OFF;//
DN_KEY=OFF;
MA_KEY=OFF;
ALARM_LED=OFF;//指示燈熄滅
PUMP_LED=OFF;
MANUAL_LED=OFF;
AUTO_LED=OFF;
BUZZER=OFF;//關(guān)蜂鳴器
PUMP=OFF;//關(guān)水泵
LcdInit(); // 初始化液晶
LcdShowStr(0,0, “-Auto watering- ”); // 顯示系統(tǒng)自檢
LcdShowStr(1,1, “system testing”); //
ConfigTimer0(10); // 配置T0 定時(shí)10ms
EA=0;// 關(guān)中斷
}
/****************************************
函數(shù)功能:系統(tǒng)自動(dòng)運(yùn)行,故障報(bào)警
入口參數(shù):無(wú)
*****************************************/
void AutoWork()
{
if(staSystem==E_AUTO)
{
Humidity();
AUTO_LED=ON;
MANUAL_LED=OFF;
if(TestVal》96||TestVal《5)
{
staSystem=E_ALARM;
cnt=30;
EA=1;
}//故障
elseif(TestVal《SetVal)
{
PUMP=ON;
PUMP_LED=ON;
}
elseif(TestVal》(SetVal+OFFSET))
{
PUMP=OFF;PUMP_LED=OFF;
}
}
ShowLcd1602();//更新顯示
}
/****************************************
函數(shù)功能:系統(tǒng)自檢,故障報(bào)警
入口參數(shù):無(wú)
*****************************************/
void SelfCheck()
{
unsignedchar i,k,n;
unsignedchar temp;
for(i=0;i《3;i++)
{
ALARM_LED=ON;
PUMP_LED=ON;//抽水指示
MANUAL_LED=ON;//手動(dòng)指示
AUTO_LED=ON;//自動(dòng)指示
delayms(500);
ALARM_LED=OFF;
PUMP_LED=OFF;//抽水指示
MANUAL_LED=OFF;//手動(dòng)指示
AUTO_LED=OFF;//自動(dòng)指示
delayms(500);
}
BUZZER=ON;
delayms(500);
BUZZER=OFF;
LcdClearScreen();
LcdShowStr(0,0,“Test Results:”);
for(i=0;i《4;i++)//讀取3次測(cè)量結(jié)果,過(guò)高故障報(bào)警
{
temp=GetADCValue(3);//直接讀取0通道
if(temp》240||temp《10)k++;
}
if(k》2)//自檢故障
{
EA=0;//關(guān)中斷
while(1)
{
ALARM_LED=ON;
LcdShowStr(1,10,“ERROR!”);
delayms(550);
LcdShowStr(1,10,“ ”);
ALARM_LED=OFF;
delayms(250);
if(n++《3)BUZZER=!BUZZER;
elseBUZZER=OFF;
}
}
LcdClearScreen();
}
/****************************************
函數(shù)功能:測(cè)量、狀態(tài)顯示
入口參數(shù):無(wú)
*****************************************/
void ShowLcd1602()
{
LcdShowStr(0,0,“PV:”);
ShowNum(0,3,TestVal);//顯示實(shí)測(cè)值
LcdShowStr(0,6,“%RH”);
LcdShowStr(0,10,“State:”);
LcdShowStr(1,0,“SV:”);
ShowNum(1,3,SetVal);//顯示設(shè)定值
LcdShowStr(1,6,“%RH”);
if(staSystem==E_AUTO)LcdShowStr(1,10,“ Auto ”);
elseif(staSystem==E_MANUAL) LcdShowStr(1,10,“Manual”);
}
/**********************************************
函數(shù)功能:讀取當(dāng)前的ADC 轉(zhuǎn)換值
入口參數(shù):chn,AD通道號(hào)0-3
**********************************************/
unsigned char GetADCValue(unsigned charchn)
{
ucharval;
I2CStart();
if(!I2CWrite(0x48《《1)) // 尋址PCF8591 PCF8591,如未應(yīng)答,則停止操作并返回,00
{
I2CStop();
return0;
}
I2CWrite(0x40|chn);// 寫(xiě)入控制字節(jié),選擇轉(zhuǎn)換通道
I2CStart();
I2CWrite((0x48《《1)|0x01);// 尋址PCF8591 PCF8591,指定后續(xù)為讀操作
I2CReadACK();// 先空讀一個(gè)字節(jié),提供采樣轉(zhuǎn)換時(shí)間
val= I2CReadNAK(); // 讀取剛剛轉(zhuǎn)換完的值
I2CStop();
returnval;
}
/****************************************
函數(shù)功能:按升序排列數(shù)組元素
入口參數(shù):數(shù)組及數(shù)組長(zhǎng)度
*****************************************/
void SortArray(unsigned char a[],unsignedchar a_len)
{
unsignedchar i,temp;
for(i=1;i《a_len;i++)
{
if(a[i-1]》a[i])
{
temp=a[i-1];
a[i-1]=a[i];
a[i]=temp;
i=0;
}
}
}
/****************************************
函數(shù)功能:中值濾波,線(xiàn)性轉(zhuǎn)換后,獲得土
壤濕度0-100%
入口參數(shù):無(wú)
*****************************************/
void Humidity()
{
unsigned char i, tmp;
unsigned char adBuf[N];
for(i=0;i《N;i++)adBuf[i]=GetADCValue(1);//讀取濕度
SortArray(adBuf,sizeof(adBuf));
tmp=adBuf[N/2];
tmp=GetADCValue(3);
TestVal=100-100.*tmp/255;
}
/****************************************
函數(shù)功能:配置定時(shí)器0,定時(shí)時(shí)間
壤濕度0-100
入口參數(shù):ms,定時(shí)時(shí)間(毫秒)
****************************************/
void ConfigTimer0(unsigned int ms)
{
unsigned long tmp;
tmp = 11059200 /12; // 定時(shí)器計(jì)數(shù)頻率
tmp = (tmp * ms) /1000; // 計(jì)算所需的計(jì)數(shù)值
tmp = 65536 - tmp; // 計(jì)算定時(shí)器重載值
tmp = tmp + 12; // 修正中斷響應(yīng)延時(shí)造成的誤差
T0RH = (unsigned char)(tmp 》》 8); // 定時(shí)器重載值拆分為高低字節(jié)
T0RL = (unsigned char)tmp;
TMOD &= 0xF0; // 清零T0 的控制位
TMOD |= 0x01; // 配置T0 為模式11
TH0 = T0RH; // 加載T0 重載值
TL0 = T0RL;
ET0 = 1; // 使能T0 中斷
TR0 = 1; // 啟動(dòng)T0
}
/****************************************
函數(shù)功能:延時(shí)函數(shù)
入口參數(shù):t,延時(shí)約t毫秒
****************************************/
//---------延時(shí)----------------
void delayms(uint t)
{
uchari;
while(t--)
for(i=0;i《123;i++);
}
/****************************************
函數(shù)功能:T0 中斷服務(wù)函數(shù)
入口參數(shù):無(wú)
****************************************/
void InterruptTimer0() interrupt 1
{
static unsigned char tmrms=0;
static unsigned char tmr=0;
TH0 = T0RH; // 定時(shí)器重新加載重載值
TL0 = T0RL;
tmrms++;
tmr=(tmr+1)%100;
if(staSystem==E_ALARM) //故障液晶報(bào)警顯示
{
if(tmr《50)LcdShowStr(1,11, “ALARM ”);
elseLcdShowStr(1,11, “ ”);
if(tmrms》=50) // 定時(shí)0.5s
{
tmrms=0;
ALARM_LED=!ALARM_LED;
if(cnt》0){cnt--;BUZZER=!BUZZER;}
else{BUZZER=OFF;}
}
}
else
{
ALARM_LED=OFF;
BUZZER=OFF;
}
}
/***************************************
Lcd1602.h
***************************************/
#ifndef _LCD1602_H
#define _LCD1602_H
#ifndef _LCD1602_C
#endif
void LcdWaitReady(); //讀取“忙”表示,等待液晶準(zhǔn)備好
void LcdWriteCmd(unsigned char cmd);//給液晶發(fā)送命令cmd
void LcdWriteDat(unsigned char dat); //寫(xiě)入數(shù)據(jù)函數(shù)
void LcdClearScreen();//液晶清屏
void LcdInit(); //液晶初始化函數(shù)
void CursorPos(unsigned char row,unsignedchar col);//光標(biāo)定位
void ShowNum(unsigned char row,unsignedchar col,unsigned char Num);//顯示3位數(shù)
void LcdShowStr(unsigned char row, unsignedchar col,unsigned char code *str); //顯示字符串
#endif
/***************************************
Lcd1602.c
***************************************/
#define _LCD1602_C
#include“config.h”
#include“Lcd1602.h”
/********************************************
函數(shù)功能:判斷液晶模塊忙碌狀態(tài)。忙,等待。
入口參數(shù):無(wú)。
********************************************/
void LcdWaitReady() //讀取“忙”表示,等待液晶準(zhǔn)備好
{
unsigned char sta;
LCD1602_DB = 0xFF;
LCD1602_RS = 0;
LCD1602_RW = 1;
do// do.。.while 循環(huán)語(yǔ)句
{
LCD1602_E= 1;
sta= LCD1602_DB; //讀取狀態(tài)字
LCD1602_E= 0; //讀完了要關(guān)閉使能,防止液晶輸出數(shù)據(jù)干擾總線(xiàn)
}while (sta & 0x80); //bit7 等于1 表示液晶正忙,重復(fù)檢測(cè)直到其等于0 為止
}
/************************************************
函數(shù)功能:給液晶發(fā)送命令
入口參數(shù):cmd
**************************************************/
void LcdWriteCmd(unsigned char cmd)
{
LcdWaitReady();
LCD1602_RS = 0;
LCD1602_RW = 0;
LCD1602_DB = cmd;
LCD1602_E = 1;
LCD1602_E = 0;
}
/************************************************
函數(shù)功能:給液晶發(fā)送數(shù)據(jù)
入口參數(shù):dat
**************************************************/
void LcdWriteDat(unsigned char dat) //寫(xiě)入數(shù)據(jù)函數(shù)
{
LcdWaitReady();
LCD1602_RS = 1;
LCD1602_RW = 0;
LCD1602_DB = dat;
LCD1602_E = 1;
LCD1602_E = 0;
}
/************************************************
函數(shù)功能:清屏
入口參數(shù):無(wú)
**************************************************/
void LcdClearScreen()
{
LcdWriteCmd(0x01);
}
/************************************************
函數(shù)功能:液晶初始化
入口參數(shù):無(wú)
**************************************************/
void LcdInit() //液晶初始化函數(shù)
{
LcdWriteCmd(0x38); //16*2 顯示,5*7 點(diǎn)陣,8 位數(shù)據(jù)接口
LcdWriteCmd(0x0C); //顯示器開(kāi),光標(biāo)關(guān)閉
LcdWriteCmd(0x06); //文字不動(dòng),地址自動(dòng)加1
LcdWriteCmd(0x01); //清屏
}
/************************************************
函數(shù)功能:定位光標(biāo)
入口參數(shù):row行位置,col列位置
**************************************************/
void CursorPos(unsigned char row,unsignedchar col)
{
row%=2; col%=40; //防止越界
if(row)LcdWriteCmd(0xC0+col); //第2行
elseLcdWriteCmd(0x80+col); //第1行
}
/************************************************
函數(shù)功能:顯示3位數(shù)
入口參數(shù):row行位置,col列位置,Num顯示數(shù)據(jù)
**************************************************/
void ShowNum(unsigned char row,unsignedchar col,unsigned char Num)
{
row%=2; col%=40; //防止越界
LcdWriteCmd(0x80+row*0x40+col);//光標(biāo)定位
if(Num《10)
{
LcdWriteDat(‘’); //百位
LcdWriteDat(‘’);//十位
LcdWriteDat(Num%10+‘0’);//個(gè)位
}
elseif(Num《100)
{
LcdWriteDat(‘’); //百位
LcdWriteDat(Num/10%10+‘0’); //十位
LcdWriteDat(Num%10+‘0’); //個(gè)位
}
else
{
LcdWriteDat(Num/100+‘0’); //百位
LcdWriteDat(Num/10%10+‘0’); //十位
LcdWriteDat(Num%10+‘0’); //個(gè)位
}
}
/************************************************
函數(shù)功能:在給定位置顯示字符串
入口參數(shù):row行位置,col列位置,str字符串
**************************************************/
void LcdShowStr(unsigned char row, unsignedchar col, unsigned char code *str) //顯示字符
{
uchari=0;
row%=2;col%=40; //防止越界
LcdWriteCmd(0x80+row*0x40+col);//光標(biāo)定位
for(;col《40&&str[i]!=0;i++,col++){LcdWriteDat(str[i]);}
}
/***************************************
I2C.h
***************************************/
#ifndef _I2C_H
#define _I2C_H
#ifndef _I2C_C
#endif
void I2CStart(); // 產(chǎn)生總線(xiàn)起始信號(hào)
void I2CStop(); // 產(chǎn)生總線(xiàn)停止信號(hào)
bit I2CWrite(unsigned char dat); //I2C 總線(xiàn)寫(xiě)操作,待寫(xiě)入字節(jié)dat dat,返回值為應(yīng)答狀態(tài)
bit I2CWrite(unsigned char dat); //I2C 總線(xiàn)寫(xiě)操作,待寫(xiě)入字節(jié)dat dat,返回值為應(yīng)答狀態(tài)
unsigned char I2CReadACK(); //I2C 總線(xiàn)讀操作,并發(fā)送應(yīng)答信號(hào),返回值為讀到的字節(jié)
unsigned char I2CReadNAK();
#endif
/***************************************
I2C.c
***************************************/
#define _I2C_C
#include “config.h”
#include “I2C.h”
#define I2CDelay(){_nop_();_nop_();_nop_();_nop_();}
/********************************************
函數(shù)功能:產(chǎn)生總線(xiàn)起始信號(hào)。
入口參數(shù):無(wú)。
********************************************/
void I2CStart()
{
I2C_SDA = 1; //首先確保SDA、SCL 都是高電平
I2C_SCL = 1;
I2CDelay();
I2C_SDA = 0; //先拉低SDA
I2CDelay();
I2C_SCL = 0; //再拉低SCL
}
/********************************************
函數(shù)功能:產(chǎn)生總線(xiàn)停止信號(hào)。
入口參數(shù):無(wú)。
********************************************/
voidI2CStop()
{
I2C_SCL = 0; //首先確保SDA、SCL 都是低電平
I2C_SDA = 0;
I2CDelay();
I2C_SCL = 1; //先拉高SCL
I2CDelay();
I2C_SDA = 1; //再拉高SDA
I2CDelay();
}
/********************************************
函數(shù)功能:I2C 總線(xiàn)寫(xiě)操作,返回值為應(yīng)答狀態(tài)。
入口參數(shù):待寫(xiě)入字節(jié)dat。
********************************************/
bit I2CWrite(unsigned char dat)
{
bit ack; //用于暫存應(yīng)答位的值
unsigned char mask; //用于探測(cè)字節(jié)內(nèi)某一位值的掩碼變量
for (mask=0x80; mask!=0; mask》》=1) //從高位到低位依次進(jìn)行
{
if ((mask&dat) == 0) //該位的值輸出到SDA 上
I2C_SDA = 0;
else
I2C_SDA = 1;
I2CDelay();
I2C_SCL = 1; //拉高SCL
I2CDelay();
I2C_SCL = 0; //再拉低SCL,完成一個(gè)位周期
}
I2C_SDA = 1; //8 位數(shù)據(jù)發(fā)送完后,主機(jī)釋放SDA,以檢測(cè)從機(jī)應(yīng)答
I2CDelay();
I2C_SCL = 1; //拉高SCL
ack = I2C_SDA; //讀取此時(shí)的SDA 值,即為從機(jī)的應(yīng)答值
I2CDelay();
I2C_SCL = 0; //再拉低SCL 完成應(yīng)答位,并保持住總線(xiàn)
return (~ack); //應(yīng)答值取反以符合通常的邏輯:0=不存在或忙或?qū)懭胧。?=存在且空閑或?qū)懭氤晒?/p>
}
/********************************************
函數(shù)功能:I2C 總線(xiàn)讀操作,并發(fā)送非應(yīng)答信號(hào),
返回值為讀到的字節(jié)。
入口參數(shù):無(wú)。
********************************************/
unsigned char I2CReadNAK()
{
unsigned char mask;
unsigned char dat;
I2C_SDA = 1; //首先確保主機(jī)釋放SDA
for (mask=0x80; mask!=0; mask》》=1) //從高位到低位依次進(jìn)行
{
I2CDelay();
I2C_SCL = 1; //拉高SCL
if(I2C_SDA == 0) //讀取SDA 的值
dat &= ~mask; //為0 時(shí),dat 中對(duì)應(yīng)位清零
else
dat |= mask; //為1 時(shí),dat 中對(duì)應(yīng)位置1
I2CDelay();
I2C_SCL = 0; //再拉低SCL,以使從機(jī)發(fā)送出下一位
}
I2C_SDA = 1; //8 位數(shù)據(jù)發(fā)送完后,拉高SDA,發(fā)送非應(yīng)答信號(hào)
I2CDelay();
I2C_SCL = 1; //拉高SCL
I2CDelay();
I2C_SCL = 0; //再拉低SCL 完成非應(yīng)答位,并保持住總線(xiàn)
return dat;
}
/********************************************
函數(shù)功能:I2C 總線(xiàn)讀操作,并發(fā)送應(yīng)答信號(hào),
返回值為讀到的字節(jié)。
入口參數(shù):無(wú)。
********************************************/
unsigned char I2CReadACK()
{
unsigned char mask;
unsigned char dat;
I2C_SDA = 1; //首先確保主機(jī)釋放SDA
for (mask=0x80; mask!=0; mask》》=1) //從高位到低位依次進(jìn)行
{
I2CDelay();
I2C_SCL = 1; //拉高SCL
if(I2C_SDA == 0) //讀取SDA 的值
dat &= ~mask; //為0 時(shí),dat 中對(duì)應(yīng)位清零
else
dat |= mask; //為1 時(shí),dat 中對(duì)應(yīng)位置1
I2CDelay();
I2C_SCL = 0; //再拉低SCL,以使從機(jī)發(fā)送出下一位
}
I2C_SDA = 0; //8 位數(shù)據(jù)發(fā)送完后,拉低SDA,發(fā)送應(yīng)答信號(hào)
I2CDelay();
I2C_SCL = 1; //拉高SCL
I2CDelay();
I2C_SCL = 0; //再拉低SCL 完成應(yīng)答位,并保持住總線(xiàn)
return dat;
}/***************************************
Keyboard.h
***************************************/
#ifndef _KEY_BOARD_H
#define _KEY_BOARD_H
#ifndef _KEY_BOARD_C
extern unsigned char SetVal;
#endif
void KeyAction();//按鍵處理,手動(dòng)運(yùn)行
#endif
/***************************************
KEYBOARD.C
***************************************/
#define _KEY_BOARD_C
#include “config.h”
#include “keyboard.h”
#include “Lcd1602.h”
#include “main.h”
unsigned char SetVal=25;//設(shè)定初始值
/****************************************
函數(shù)功能:按鍵處理,手動(dòng)運(yùn)行
入口參數(shù):無(wú)
*****************************************/
void KeyAction()
{
if(AK_KEY==0)//LCD1602背光控制
{
delayms(10);
if(AK_KEY==0)
{
LCD1602_AK=!LCD1602_AK;
while(!AK_KEY);
}
}
if(MA_KEY==0)
{
delayms(10);
if(MA_KEY==0)
{
if(staSystem==E_AUTO)
{
staSystem=E_MANUAL;
AUTO_LED=OFF;
MANUAL_LED=ON;
}
elseif(staSystem==E_MANUAL)
{
staSystem=E_AUTO;
AUTO_LED=ON;
MANUAL_LED=OFF;
}
while(!MA_KEY);
}
}
if(staSystem==E_MANUAL)//手動(dòng)工作狀態(tài)
{
if(UP_KEY==0){PUMP=ON;PUMP_LED=ON;}//手動(dòng)開(kāi)
elseif(DN_KEY==0){PUMP=OFF;PUMP_LED=OFF;}//手動(dòng)關(guān)}
}
elseif(staSystem==E_AUTO)//自動(dòng)狀態(tài)
{
if(UP_KEY==0)
{
delayms(10);
if(UP_KEY==0)
{
if(SetVal《100) SetVal++; //設(shè)置+
while(!UP_KEY);
}
}
if(DN_KEY==0)
{
delayms(10);
if(DN_KEY==0)
{
if(SetVal》0) SetVal--; //設(shè)置-
while(!DN_KEY);
}
}
}
}
責(zé)任編輯人:CC
-
單片機(jī)
+關(guān)注
關(guān)注
6056文章
44799瀏覽量
643616
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
怎樣去設(shè)計(jì)一種基于單片機(jī)的士壤濕度檢測(cè)自動(dòng)澆花系統(tǒng)?
怎么實(shí)現(xiàn)基于51單片機(jī)的智能大棚澆花系統(tǒng)的設(shè)計(jì)?
基于51單片機(jī)的自動(dòng)澆花系統(tǒng)設(shè)計(jì)
如何去實(shí)現(xiàn)基于單片機(jī)的智能澆花系統(tǒng)設(shè)計(jì)
如何去實(shí)現(xiàn)基于單片機(jī)的自動(dòng)澆花灌溉系統(tǒng)設(shè)計(jì)
如何去實(shí)現(xiàn)基于單片機(jī)的自動(dòng)澆花灌溉系統(tǒng)設(shè)計(jì)
如何使用單片機(jī)進(jìn)行智能澆花系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)的資料說(shuō)明

使用單片機(jī)設(shè)計(jì)士壤濕度檢測(cè)自動(dòng)澆花系統(tǒng)的資料說(shuō)明

使用51單片機(jī)控制自動(dòng)澆花器的源程序和PCB及電路圖合集免費(fèi)下載

使用51單片機(jī)實(shí)現(xiàn)智能澆花水系統(tǒng)灌溉土壤濕度檢測(cè)設(shè)計(jì)的源代碼

設(shè)計(jì)并制作一個(gè)單片機(jī)最小系統(tǒng)

51單片機(jī)自動(dòng)澆水系統(tǒng)/51單片機(jī)自動(dòng)澆花系統(tǒng)/智能澆水系統(tǒng)

基于單片機(jī)的智能澆花(灌溉)系統(tǒng)設(shè)計(jì)

685【畢設(shè)課設(shè)】基于單片機(jī)士壤濕度檢測(cè)及自動(dòng)澆花系統(tǒng)

基于單片機(jī)的盆栽自動(dòng)澆花系統(tǒng)-畢設(shè)課設(shè)protues仿真全套資料

評(píng)論