一、系統概述
自動澆水灌溉系統設計方案,以AT89C51單片機為控制核心,采用模塊化的設計方法。
組成部分為:5V供電模塊、土壤濕度傳感器模塊、ADC0832模數轉換模塊、水泵控制模塊、按鍵輸入模塊、LCD顯示模塊和聲光報警模塊,結構如下。
工作原理為:土壤濕度傳感器測出土壤濕度模擬信號,經AD轉換器將模擬信號轉換成數字信號后傳輸到51單片機,單片機將土壤濕度數據與設定的上下限值進行比較。
當土壤濕度低于下限時,驅動水泵工作進行灌溉澆水,并提供聲光報警。設計獲取,蔣宇智QQ(2327603104)。
當土壤濕度增加至超過下限時,聲光報警關閉,但水泵會繼續工作,直到土壤濕度繼續增加并超過設定的上限值為止。
用戶可通過按鍵設定濕度上下限值,土壤濕度數據和上下限值數據均通過LCD顯示屏實時顯示。
二、土壤濕度傳感器
Proteus仿真電路
三、原理圖
仿真結果分析
打開Proteus仿真文件,其后綴名為.DSN。雙擊單片機,加載AutoWater.hex文件(位于Keil C程序文件夾內),運行仿真,結果如下。
由圖可知,LCD顯示當前測量的土壤濕度(Humidity)為53%,系統預設的濕度上限(H:High的縮寫)為60%,下限(L:Low的縮寫)為30%,土壤濕度正常,在上下限范圍之內。資源獲取,蔣宇智QQ(2327603104)。
此時,濕度低報警燈和蜂鳴器處于關閉狀態,繼電器RL1開關打至下方,水泵處于斷電狀態。
通過調節滑動變阻器RV2(鼠標點擊上下兩個紅色箭頭),改變輸入到ADC0832采樣通道0的電壓大小來模擬土壤濕度的變化。
點擊RV2向下的紅色箭頭,模擬土壤濕度的降低。例如,當土壤濕度從53%降低至23%,低于下限值30%時,紅色LED報警燈點亮,蜂鳴器發聲,繼電器RL1開關打至上方,水泵通電,開始自動澆水,綠色的水泵工作指示燈也被點亮。
點擊RV2向上的紅色箭頭,模擬土壤濕度的增加。
當土壤濕度從23%增加至37%,超過下限時,聲光報警停止工作,但水泵會繼續工作,直到土壤濕度繼續增加到高于上限值為止,過程如下所示。
需要說明的是,水泵停止工作(即:土壤濕度超過上限)后,調節RV2模擬土壤濕度的下降,在下降到上下限范圍內時,水泵不會啟動,只有土壤濕度繼續下降至低于下限時才會啟動。
通過按鍵可以預設濕度的上下限值。
點擊“設定”鍵,進入上下限設置模式,首先是H上限值光標閃爍,此時可以點擊加/減鍵,改變上限值大小。
上限值設置完成后,點擊“設定”鍵,L下限值光標閃爍,同理,點擊加/減鍵,改變下限值大小。
上下限值都設置完成后,再次點擊“設定”鍵,退出上下限設置模式。例如,我們設置濕度上限值H為75%,下限值L為25%,結果如下圖所示。
綜上所述,仿真運行效果滿足設計要求。
四、C代碼
void main()//主函數
{Init1602();//初始化液晶函數init(); //初始化定時器init_eeprom(); //開始初始化保存的數據while(1)//進入循環{for(m=0;m<50;m++)//讀50次AD值sum = adc0832(0)+sum; //讀到的AD值,將讀到的數據累加到sumtemp=sum/50;//跳出上面的for循環后,將累加的總數除以50得到平均值tempsum=0; //平均值計算完成后,將總數清零temp = temp*0.390625; //ADC0832存儲數據為1個字節,濕度顯示范圍為0~100,因此1單位濕度=100/256=0.390625
// if(temp<=full_range)
// temp=(temp*100)/full_range;
// else
// temp=100;if(set==0)//set為0,說明現在不是設置狀態Display_1602(temp,MH,ML);//顯示AD數值和報警值if(temp<ML&&set==0)//濕度值小于報警值{//資源獲取,蔣宇智QQ(2327603104)flag=1;//打開報警Relay=0;//繼電器觸點閉合,水泵工作LED_R=0; //紅燈點亮}else if(temp>MH&&set==0) //濕度值大于報警值{flag=0;//關閉報警Relay=1;//繼電器觸點打開,水泵停止LED_R=1; //紅燈熄滅}else{flag=0;LED_R=1; //紅燈熄滅}Key(); //調用按鍵函數}
}
#include <reg51.H>#include "intrins.h"#define uint unsigned int#define uchar unsigned char#define ulong unsigned long#define LCDIO P0 //液晶屏數據口//ADC0832的引腳sbit ADCLK =P1^1; //ADC0832 clock signalsbit ADDIO =P1^3; //ADC0832 k insbit ADCS =P1^4; //ADC0832 chip seclectsbit rs=P1^0; //定義1602 RSsbit lcden=P1^2; //定義1602 ENsbit key1=P3^0; //設定sbit key2=P3^1; //加sbit key3=P3^2; //減sbit motor=P3^7; //繼電器接口sbit speak=P1^5; //蜂鳴器接口uchar key; //設定指針uint RH=400,RL=200;//水位上下限float temp_f;ulong temp;uchar v;uchar count,s1num;uchar code table[]= " moisture: ";uchar code table1[]="RH: % ";uchar getdata; //獲取ADC轉換回來的值/*********************************************/void delay(uint z) //延時{uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}/**********************************************/void write_com(uchar com){rs=0;// rd=0;lcden=0;P0=com;delay(5);lcden=1;delay(5);lcden=0; }/*********************************************/void write_date(uchar date){rs=1;// rd=0;lcden=0;P0=date;delay(5);lcden=1;delay(5);lcden=0; }void lcdinit(){lcden=0;write_com(0x38);write_com(0x0c);write_com(0x06);write_com(0x01);}/***********************************************/void init(){uchar num;for(num=0;num<15;num++){write_date(table[num]);delay(5);}write_com(0x80+0x40);for(num=0;num<15;num++){write_date(table1[num]);delay(5);}}//****************************************************************************//************讀ADC0832函數************///采集并返回/****************************************************************************函數功能:AD轉換子程序入口參數:CH(如果讀取CH0,channel的值為0x01,如果讀取CH1則channel的值為0x03)出口參數:adval****************************************************************************/uchar Adc0832() //AD轉換,返回結果{uchar i;uchar dat=0;ADCLK=0;ADDIO=1;ADCS=0; //拉低CS端ADCLK=1; ADCLK=0; //拉低CLK端,形成下降沿1ADDIO=1;//指定轉換通道是CH1還是CH2,指定值位與0x1,取最后一位的值ADCLK=1; ADCLK=0; //拉低CLK端,形成下降沿2ADDIO=0;//指定值右移一位,再取最后一位的值ADCLK=1;ADCLK=0; //拉低CLK端,形成下降沿3ADDIO=1; for(i=0;i<8;i++){ADCLK=1;ADCLK=0; //形成一次時鐘脈沖if(ADDIO)dat|= 0x80>>i; //收數據}ADCS=1; //拉低CS端ADCLK=1;ADDIO=1; //拉高數據端,回到初始狀態return(dat); //return dat}/***************************************************************************//********************************************************/void displayRH() //下限顯示{write_com(0xc0+3);write_date(RH/100%10+0x30);//上限百位write_date(RH/10%10+0x30);//上限十位//write_date('.');//write_date(RH%10+0x30);}void displayRL() //下限顯示{write_com(0xca);write_date('R');write_date('L');write_date(':');write_date(RL/100%10+0x30);//下限百位write_date(RL/10%10+0x30);//下限十位write_date('%');}/**************************************************//********************************************************/void keyscan() //按鍵處理{bit kk1=0,kk2=0;if(key1==0){delay(30);while(key1==0);if(key>=2){key=0;}else{key++;}switch(key){speak=1;kk2=motor;motor=1;case 1:{write_com(0x0f);write_com(0xce); //光標閃爍while(key1!=0) //等待按鍵松開{if(key2==0) //key2按鍵下{delay(30); //按鍵延時消抖if(key2==0) //確定key2按下{while(key2==0); //等待松開if(RL>=998){RL=999; //RL下限最大設置為99}else{RL+=10; //RL加1} }displayRL(); //調用RL下限顯示函數write_com(0xce);} if(key3==0) //key3按下{delay(30); //按鍵延時消抖if(key3==0) //確定key3按下{while(key3==0); //等待key3按鍵松開if(RL<=1) //RL最小設置為1{RL=0;}else{RL-=10; //RL下限減1}}displayRL(); //調用RL下限顯示函數write_com(0xce);}}while(key1==0); }case 2:{write_com(0x0f);write_com(0xc4); //RH設置數據,光標閃爍while(key1==1){if(key2==0) //key2按下{delay(30); //按鍵延時消抖if(key2==0) //確定key2按下{while(key2==0); //等待松開if(RH>=998) //RH最大設置為99{RH=999;}else{RH+=10; //RH加1}}displayRH(); //RH上限顯示函數write_com(0xc4);}if(key3==0) //key3按下{delay(30); //按鍵延時消抖if(key3==0) //確定按下{while(key3==0);//等待松開if(RH<=1) //RH最小設置為1{RH=0;}else{RH-=10; //RH減1}}displayRH(); //調用RH顯示函數write_com(0xc4);}}while(key1==0);}case 0:{write_com(0x0c);motor=kk2;break;}}}}/**************************************************/void Conut(void) //土壤檢測數據轉換{ v=Adc0832();temp=v;temp_f=temp*9.90/2.55;temp=temp_f;temp=1000-temp; write_com(0x80+10);write_date(temp/100%10+0x30);//千位write_date(temp/10%10+0x30);//百位write_date('.');write_date(temp%10+0x30);write_date('%');//顯示符號位}/********************************************************/void main(void){lcdinit();init();displayRH(); //顯示上限displayRL(); //顯示下限delay(50); //啟動等待,等LCD講入工作狀態delay(50); //延時片刻(可不要)delay(50); //延時delay(50);Conut(); //顯示函數delay(150); while(1){ Conut(); //顯示當前濕度keyscan();if(temp>RH) //如果濕度大于上限停止澆水{motor=1; //關閉繼電器}else if(temp<RL) //如果濕度小于RL下限啟動澆水{motor=0; //啟動繼電器}if(temp<RL) //小于下限啟動報警并澆水{speak=0; //啟動報警delay(150); //延時speak=1;}keyscan(); //按鍵檢測delay(150); //延時50MS}}