新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 單片機(jī)的模擬智能灌溉系統(tǒng)

單片機(jī)的模擬智能灌溉系統(tǒng)

作者: 時(shí)間:2016-11-20 來源:網(wǎng)絡(luò) 收藏
模擬智能灌溉系統(tǒng)

先上原理圖

本文引用地址:http://m.butianyuan.cn/article/201611/318654.htm


這是用proteus畫的模擬圖,當(dāng)然還有實(shí)物圖,不過都被我放在自己的工作室了(話說明明是實(shí)驗(yàn)室好不好)目前是在外面進(jìn)一步學(xué)習(xí),我就不把實(shí)物曬出來了。


程序的好壞在于它的流程圖是否好,于是我就把我當(dāng)時(shí)畫的流程圖拿了出來!

那么該項(xiàng)目到底是什么呢?

就是當(dāng)年比賽的一個(gè)預(yù)習(xí)題,不過平臺(tái)不一樣搞得我當(dāng)時(shí)比較狼狽就拿了個(gè)三等獎(jiǎng)回來,哎,希望我嵌入式小組的學(xué)弟學(xué)妹們能夠加油,幫我拿個(gè)一等獎(jiǎng)回來!了了我心中的遺憾吧!

功能簡述:

要求“模擬智能灌溉系統(tǒng)”能夠?qū)崿F(xiàn)土壤濕度測(cè)量、土壤濕度和時(shí)間顯示、濕度閾值設(shè)定及存儲(chǔ)等基本功能。通過電位器Rb2輸出電壓信號(hào),模擬濕度傳感器輸出信號(hào),再通過AD采集完成濕度測(cè)量功能;通過DS1302芯片提供時(shí)間信息;通過按鍵完成灌溉系統(tǒng)控制和濕度閾值調(diào)整功能,通過LED完成系統(tǒng)工作狀態(tài)指示功能。系統(tǒng)硬件電路主要由單片機(jī)控制電路、顯示單元、ADC采集單元、RTC單元、EEPROM存儲(chǔ)單元、繼電器控制電路及報(bào)警輸出電路組成,系統(tǒng)框圖如圖1所示:


1. 系統(tǒng)工作及初始化狀態(tài)說明:

1.1、自動(dòng)工作狀態(tài),根據(jù)濕度數(shù)據(jù)自動(dòng)控制打開或關(guān)閉灌溉設(shè)備,以L1點(diǎn)亮指示;

1.2、手動(dòng)工作狀態(tài),通過按鍵控制打開或關(guān)閉灌溉設(shè)備,以L2點(diǎn)亮指示;

1.3、系統(tǒng)上電后處于自動(dòng)工作狀態(tài),系統(tǒng)初始濕度閾值為50%,此時(shí)若濕度低于50%,灌溉設(shè)備自動(dòng)打開,達(dá)到50%后,灌溉設(shè)備自動(dòng)關(guān)閉;

1.4、灌溉設(shè)備打開或關(guān)閉通過繼電器工作狀態(tài)模擬。

2. 數(shù)碼管單元:


“模擬智能灌溉系統(tǒng)”通過讀取DS1302時(shí)鐘芯片相關(guān)寄存器獲得時(shí)間,DS1302芯片時(shí)、分、秒寄存器在程序中設(shè)定為系統(tǒng)進(jìn)行初始化設(shè)定,時(shí)間為08時(shí)30分。

3. 報(bào)警輸出單元:

系統(tǒng)工作于手動(dòng)工作狀態(tài)下時(shí),若當(dāng)前濕度低于濕度閾值,蜂鳴器發(fā)出提示音,并可通過按鍵S6關(guān)閉提醒功能。

4. 功能按鍵:

4.1、按鍵S7設(shè)定為系統(tǒng)工作狀態(tài)切換按鍵;

4.2、手動(dòng)工作狀態(tài)下按鍵S6、S5、S4功能設(shè)定如下:

按下S6關(guān)閉蜂鳴器提醒功能,再次按下S6打開蜂鳴器提醒功能,如此循環(huán);

S5功能設(shè)定為打開灌溉系統(tǒng);S4功能設(shè)定為關(guān)閉灌溉系統(tǒng)。

4.3、自動(dòng)工作狀態(tài)下按鍵S6、S5、S4功能設(shè)定如下:

S6功能設(shè)定為濕度閾值調(diào)整按鍵,按下S6后,進(jìn)入濕度閾值調(diào)整界面(如圖3所示),此時(shí)按下S5為濕度閾值加1,按下S4濕度閾值減1,再次按下S6后,系統(tǒng)將新的濕度閾值保存到EEPROM中,并退出濕度閾值設(shè)定界面。


5. 實(shí)時(shí)時(shí)鐘:

“模擬智能灌溉系統(tǒng)”通過讀取DS1302時(shí)鐘芯片相關(guān)寄存器獲得時(shí)間,DS1302芯片時(shí)、分、秒寄存器在程序中設(shè)定為系統(tǒng)進(jìn)行初始化設(shè)定,時(shí)間為08時(shí)30分。

6. 濕度檢測(cè)單元:

以電位器Rb2輸出電壓信號(hào)模擬濕度傳感器輸出信號(hào),且假定電壓信號(hào)與濕度成正比例關(guān)系H濕度= KVRb2(K為常數(shù)),Rb2電壓輸出為5V時(shí)對(duì)應(yīng)濕度為99%。

7. EEPROM存儲(chǔ)單元:

系統(tǒng)通過EEPROM存儲(chǔ)濕度閾值,自動(dòng)工作狀態(tài)下,可通過按鍵S6、S5、S4設(shè)置和保存閾值信息。

下面將是我寫的一些代碼了,大三上寫的代碼,可能不是那么好吧!勿見怪啊,當(dāng)時(shí)都沒有代碼規(guī)范的思想,寫得比較凌亂,我也因?yàn)閷?duì)它不再想修改了,就不改格式了,因而對(duì)看本博客的同學(xué)們表示歉意了!

(1)主函數(shù)main.c#include#include #include#define  PCF8591 0x90    //PCF8591 地址#include<ds1302.h>//else IOunsigned char AD_CHANNEL;unsigned long xdata  LedOut[8];unsigned int  D[32];sbit LS138A=P2^2;  sbit LS138B=P2^3;sbit LS138C=P2^4;sbit L1=P2^5;sbit L2=P2^6;sbit beed=P1^0;sbit RELAY=P1^1;sbit k4=P1^2;sbit k5=P1^3;sbit k6=P1^4;sbit k7=P1^5; //此表為 LED 的字模, 共陰數(shù)碼管 0-9  - unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40}; unsigned char delay1[8]={10,10,0,0,0,0,0,0};unsigned char HUO,flag;unsigned char key,mode,th;/**延遲函數(shù)**/         void delay(){unsigned char a=100;while(a--); }/************at24c02功能模塊***/void At24c02Write(unsigned char addr,unsigned char dat){I2C_Start();I2C_SendByte(0xa0, 1);//發(fā)送寫器件地址I2C_SendByte(addr, 1);//發(fā)送要寫入內(nèi)存地址I2C_SendByte(dat, 0);    //發(fā)送數(shù)據(jù)I2C_Stop();}unsigned char At24c02Read(unsigned char addr){unsigned char num;I2C_Start();I2C_SendByte(0xa0, 1); //發(fā)送寫器件地址I2C_SendByte(addr, 1); //發(fā)送要讀取的地址I2C_Start();I2C_SendByte(0xa1, 1); //發(fā)送讀器件地址num=I2C_ReadByte(); //讀取數(shù)據(jù)I2C_Stop();return num;    }/*******************************************************************ADC發(fā)送字節(jié)[命令]數(shù)據(jù)函數(shù)               *******************************************************************/bit ISendByte(unsigned char sla,unsigned char c){Start_I2c();              //啟動(dòng)總線SendByte(sla);            //發(fā)送器件地址if(ack==0)return(0);SendByte(c);              //發(fā)送數(shù)據(jù)if(ack==0)return(0);Stop_I2c();               //結(jié)束總線return(1);}/*******************************************************************ADC讀字節(jié)數(shù)據(jù)函數(shù)               *******************************************************************/unsigned char IRcvByte(unsigned char sla){  unsigned char c;Start_I2c();          //啟動(dòng)總線SendByte(sla+1);      //發(fā)送器件地址if(ack==0)return(0);c=RcvByte();          //讀取數(shù)據(jù)0Ack_I2c(1);           //發(fā)送非就答位Stop_I2c();           //結(jié)束總線return(c);}unsigned char keysan(void){   if(!k7){while(!k7);return 7;}if(!k6){while(!k6);return 6;}if(!k5){while(!k5);return 5;}    if(!k4){while(!k4);return 4;}return 0;}/**初始設(shè)置函數(shù)**/void seting(){ unsigned char isFirstRun=0;beed=1;L1=0;L2=1;RELAY=1;mode=1;isFirstRun=!At24c02Read(2);//通過EEPROM的2地址出是否有值來判斷是否為第一次運(yùn)行if(isFirstRun)//若第一次運(yùn)行{At24c02Write(2,1);//往2地址寫入信息供以后開機(jī)時(shí)判斷At24c02Write(1,50);//寫入默認(rèn)閾值50}else{HUO=At24c02Read(1);//從EEPROM的1地址處讀出閾值}delay1[6]=HUO/10;delay1[7]=HUO%10;InitTIMER0();          //初始化定時(shí)器0Set_RTC(); }/****判斷函數(shù)***/void chouse(unsigned char key){  switch(key)                      {     case 4:if(mode==1){    if(j==1){  HUO--;delay1[6]=HUO/10;delay1[7]=HUO%10;delay();}   }else { RELAY=1;}break;                 case 5:if(mode==1){if(j==1){   HUO++; if(HUO>99)HUO=99;delay1[6]=HUO/10;delay1[7]=HUO%10;delay();}}else  {RELAY=0;}break;case 6:if(mode==1){  if(flag==1)//在設(shè)置模式,保存閾值并退出設(shè)置模式{At24c02Write(1,HUO);//在EEPROM的1地址處寫入閾值flag=0;}else//不在設(shè)置模式,將進(jìn)入設(shè)置模式{flag=1;}}else {beed=(beed==1)?0:1;} break;case 7:if(mode==1){mode=0;L1=0;L2=1;}else {mode=1;L1=1;L2=0;} break;default:break;}if(th99) th=99;l_tmpdisplay[6]=th/10;l_tmpdisplay[7]=th%10; }/**主函數(shù)***/void main(){  seting();while(1){    key=keysan();chouse(key);} }void InitTIMER0(void){TMOD=0x01;//定時(shí)器設(shè)置 16位TH0=0xef;//初始化值TL0=0xf0;ET0=1;TR0=1;EA=1;}/******************************************************************//*                   定時(shí)器中斷函數(shù)                               *//******************************************************************/void tim(void) interrupt 1 using 1//中斷,用于數(shù)碼管掃描{static unsigned char i,num;TH0=0xf5;TL0=0xe0;if(flag==1){//在設(shè)置模式P0=table[delay1[i]];}else{//P0=table[l_tmpdisplay[i]];    //查表法得到要顯示數(shù)字的數(shù)碼段}switch(i)                      {        case 0:LS138A=0; LS138B=0; LS138C=0; break;         case 1:LS138A=1; LS138B=0; LS138C=0; break;                 case 2:LS138A=0; LS138B=1; LS138C=0; break; case 3:LS138A=1; LS138B=1; LS138C=0; break; case 4:LS138A=0; LS138B=0; LS138C=1; break;case 5:LS138A=1; LS138B=0; LS138C=1; break;case 6:LS138A=0; LS138B=1; LS138C=1; break;case 7:LS138A=1; LS138B=1; LS138C=1; break;}i++;if(i==8){i=0;num++;if(10==num)       //隔段時(shí)間讀取1302的數(shù)據(jù)。時(shí)間間隔可以調(diào)整{ReadRTC_Flag=1; //使用標(biāo)志位判斷num=0;}}}(2)I2C總線函數(shù)#include#include #include #define  NOP()   _nop_()   /* 定義空指令 */#define  _Nop()  _nop_()   /*定義空指令*/sbit     SCL=P2^1;       //I2C  時(shí)鐘 sbit     SDA=P2^0;       //I2C  數(shù)據(jù) bit ack;                 /*應(yīng)答標(biāo)志位*//*******************************************************************起動(dòng)總線函數(shù)               函數(shù)原型: void  Start_I2c();  功能:     啟動(dòng)I2C總線,即發(fā)送I2C起始條件.  ********************************************************************/void Start_I2c(){SDA=1;         /*發(fā)送起始條件的數(shù)據(jù)信號(hào)*/_Nop();SCL=1;_Nop();        /*起始條件建立時(shí)間大于4.7us,延時(shí)*/_Nop();_Nop();_Nop();_Nop();    SDA=0;         /*發(fā)送起始信號(hào)*/_Nop();        /* 起始條件鎖定時(shí)間大于4μs*/_Nop();_Nop();_Nop();_Nop();       SCL=0;       /*鉗住I2C總線,準(zhǔn)備發(fā)送或接收數(shù)據(jù) */_Nop();_Nop();}/*******************************************************************結(jié)束總線函數(shù)               函數(shù)原型: void  Stop_I2c();  功能:     結(jié)束I2C總線,即發(fā)送I2C結(jié)束條件.  ********************************************************************/void Stop_I2c(){SDA=0;      /*發(fā)送結(jié)束條件的數(shù)據(jù)信號(hào)*/_Nop();       /*發(fā)送結(jié)束條件的時(shí)鐘信號(hào)*/SCL=1;      /*結(jié)束條件建立時(shí)間大于4μs*/_Nop();_Nop();_Nop();_Nop();_Nop();SDA=1;      /*發(fā)送I2C總線結(jié)束信號(hào)*/_Nop();_Nop();_Nop();_Nop();}/*******************************************************************字節(jié)數(shù)據(jù)發(fā)送函數(shù)               函數(shù)原型: void  SendByte(UCHAR c);功能:     將數(shù)據(jù)c發(fā)送出去,可以是地址,也可以是數(shù)據(jù),發(fā)完后等待應(yīng)答,并對(duì)此狀態(tài)位進(jìn)行操作.(不應(yīng)答或非應(yīng)答都使ack=0)     發(fā)送數(shù)據(jù)正常,ack=1; ack=0表示被控器無應(yīng)答或損壞。********************************************************************/void  SendByte(unsigned char  c){unsigned char  BitCnt;for(BitCnt=0;BitCnt<8;BitCnt++)  /*要傳送的數(shù)據(jù)長度為8位*/{if((c<0; b--){for(a=2; a>0; a--);}}/******************************************************************************** 函 數(shù) 名         : I2C_Start()* 函數(shù)功能           : 起始信號(hào):在I2C_SCL時(shí)鐘信號(hào)在高電平期間I2C_SDA信號(hào)產(chǎn)生一個(gè)下降沿* 輸    入         : 無* 輸    出         : 無* 備    注         : 起始之后I2C_SDA和I2C_SCL都為0****************************************************************************/void I2C_Start(){SDA = 1;I2C_Delay10us();SCL = 1;I2C_Delay10us();//建立時(shí)間是I2C_SDA保持時(shí)間>4.7usSDA = 0;I2C_Delay10us();//保持時(shí)間是>4usSCL = 0;            I2C_Delay10us();        }/******************************************************************************* 函 數(shù) 名           : I2C_Stop()* 函數(shù)功能             : 終止信號(hào):在I2C_SCL時(shí)鐘信號(hào)高電平期間I2C_SDA信號(hào)產(chǎn)生一個(gè)上升沿* 輸    入           : 無* 輸    出              : 無* 備    注           : 結(jié)束之后保持I2C_SDA和I2C_SCL都為1;表示總線空閑******************************************************************************/void I2C_Stop(){SDA = 0;I2C_Delay10us();SCL = 1;I2C_Delay10us();//建立時(shí)間大于4.7usSDA = 1;I2C_Delay10us();        }/******************************************************************************** 函 數(shù) 名           : I2cSendByte(uchar num)* 函數(shù)功能              : 通過I2C發(fā)送一個(gè)字節(jié)。在I2C_SCL時(shí)鐘信號(hào)高電平期間,*                    * 保持發(fā)送信號(hào)I2C_SDA保持穩(wěn)定* 輸    入           : num ,ack* 輸    出              : 0或1。發(fā)送成功返回1,發(fā)送失敗返回0* 備    注           : 發(fā)送完一個(gè)字節(jié)I2C_SCL=0, 需要應(yīng)答則應(yīng)答設(shè)置為1,否則為0******************************************************************************/unsigned char I2C_SendByte(unsigned char dat, unsigned char ack){unsigned char a = 0,b = 0;//最大255,一個(gè)機(jī)器周期為1us,最大延時(shí)255us。for(a=0; a<8; a++)//要發(fā)送8位,從最高位開始{SDA = dat >> 7;     //起始信號(hào)之后I2C_SCL=0,所以可以直接改變I2C_SDA信號(hào)dat = dat << 1;I2C_Delay10us();SCL = 1;I2C_Delay10us();//建立時(shí)間>4.7usSCL = 0;I2C_Delay10us();//時(shí)間大于4us        }SDA = 1;I2C_Delay10us();SCL = 1;while(SDA && (ack == 1))//等待應(yīng)答,也就是等待從設(shè)備把I2C_SDA拉低{b++;if(b > 200)     //如果超過200us沒有應(yīng)答發(fā)送失敗,或者為非應(yīng)答,表示接收結(jié)束{SCL = 0;I2C_Delay10us();return 0;}}SCL = 0;I2C_Delay10us();return 1;        }/******************************************************************************** 函 數(shù) 名           : I2cReadByte()* 函數(shù)功能             : 使用I2c讀取一個(gè)字節(jié)* 輸    入           : 無* 輸    出              : dat* 備    注           : 接收完一個(gè)字節(jié)I2C_SCL=0*****************************************************************************/unsigned char I2C_ReadByte(){unsigned char     a = 0,dat = 0;SDA = 1;            //起始和發(fā)送一個(gè)字節(jié)之后I2C_SCL都是0I2C_Delay10us();for(a=0; a<8; a++)//接收8個(gè)字節(jié){SCL = 1;I2C_Delay10us();dat <<= 1;dat = SDA;I2C_Delay10us();SCL = 0;I2C_Delay10us();}return dat;        }其H文件:extern bit ack;//起動(dòng)總線函數(shù)extern void Start_I2c();//結(jié)束總線函數(shù)  extern void Stop_I2c();//應(yīng)答子函數(shù)extern void Ack_I2c(bit a);//字節(jié)數(shù)據(jù)發(fā)送函數(shù)extern void  SendByte(unsigned char  c);//有子地址發(fā)送多字節(jié)數(shù)據(jù)函數(shù)               extern bit ISendStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no) ;//無子地址發(fā)送多字節(jié)數(shù)據(jù)函數(shù)   extern bit ISendStrExt(unsigned char sla,unsigned char *s,unsigned char no);//無子地址讀字節(jié)數(shù)據(jù)函數(shù)               extern unsigned char RcvByte();extern void I2C_Start();extern      void I2C_Stop();extern         unsigned char I2C_SendByte(unsigned char dat, unsigned char ack);extern         unsigned char I2C_ReadByte();(3)DS1302時(shí)鐘函數(shù):#include //包含頭文件,一般情況不需要改動(dòng),頭文件包含特殊功能寄存器的定義#include sbit SCK=P3^6;    //時(shí)鐘    sbit SDA=P3^4;    //數(shù)據(jù)    sbit RST = P3^5;// DS1302復(fù)位bit ReadRTC_Flag;//定義讀DS1302標(biāo)志unsigned char l_tmpdate[7]={0,30,8,15,5,3,8};//秒分時(shí)日月周年08-05-15 12:00:00unsigned char l_tmpdisplay[8];code unsigned char write_rtc_address[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //秒分時(shí)日月周年 最低位讀寫位code unsigned char read_rtc_address[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};  //code unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40}; //共陰數(shù)碼管 0-9  - 熄滅‘表/******************************************************************//*                   寫一個(gè)字節(jié)                                   *//******************************************************************/void Write_Ds1302_Byte(unsigned  char temp) {unsigned char i;for (i=0;i<8;i++)         //循環(huán)8次 寫入數(shù)據(jù){ SCK=0;SDA=temp&0x01;     //每次傳輸?shù)妥止?jié) temp>>=1;          //右移一位SCK=1;}}   /******************************************************************//*                  寫入DS1302                                    *//******************************************************************/void Write_Ds1302( unsigned char address,unsigned char dat )     {RST=0;_nop_();SCK=0;_nop_();RST=1;    _nop_();                    //啟動(dòng)Write_Ds1302_Byte(address);    //發(fā)送地址Write_Ds1302_Byte(dat);        //發(fā)送數(shù)據(jù)RST=0;                      //恢復(fù)}/******************************************************************//*                   讀出DS1302數(shù)據(jù)                               *//******************************************************************/unsigned char Read_Ds1302 ( unsigned char address ){unsigned char i,temp=0x00;RST=0;_nop_();_nop_();SCK=0;_nop_();_nop_();RST=1;_nop_();_nop_();Write_Ds1302_Byte(address);for (i=0;i<8;i++)         //循環(huán)8次 讀取數(shù)據(jù){        if(SDA)temp=0x80;            //每次傳輸?shù)妥止?jié)SCK=0;temp>>=1;            //右移一位_nop_();_nop_();_nop_();SCK=1;} RST=0;_nop_();                  //以下為DS1302復(fù)位的穩(wěn)定時(shí)間_nop_();RST=0;SCK=0;_nop_();_nop_();_nop_();_nop_();SCK=1;_nop_();_nop_();SDA=0;_nop_();_nop_();SDA=1;_nop_();_nop_();return (temp);            //返回}/******************************************************************//*                   讀時(shí)鐘數(shù)據(jù)                                   *//******************************************************************/void Read_RTC(void)            //讀取 日歷{unsigned char i,*p;p=read_rtc_address;         //地址傳遞for(i=0;i<7;i++)            //分7次讀取 秒分時(shí)日月周年{l_tmpdate[i]=Read_Ds1302(*p);p++;}}/******************************************************************//*                  設(shè)定時(shí)鐘數(shù)據(jù)                                  *//******************************************************************/void Set_RTC(void)            //設(shè)定 日歷{unsigned char i,*p,tmp;for(i=0;i<7;i++){       //BCD處理tmp=l_tmpdate[i]/10;l_tmpdate[i]=l_tmpdate[i]%10;l_tmpdate[i]=l_tmpdate[i]+tmp*16;}  Write_Ds1302(0x8E,0X00);p=write_rtc_address;    //傳地址    for(i=0;i<7;i++)        //7次寫入 秒分時(shí)日月周年{Write_Ds1302(*p,l_tmpdate[i]);p++;  }Write_Ds1302(0x8E,0x80);}其H文件:extern void Write_Ds1302_byte(unsigned char temp); extern void Write_Ds1302( unsigned char address,unsigned char dat );extern unsigned char Read_Ds1302 ( unsigned char address );extern void Read_RTC(void);//read RTC extern void Set_RTC(void); //set RTC extern void InitTIMER0(void);//inital timer0extern bit ReadRTC_Flag;//定義讀DS1302標(biāo)志extern  unsigned char l_tmpdisplay[8];extern unsigned char l_tmpdate[7];extern     bit ReadRTC_Flag;//定義讀DS1302標(biāo)志



評(píng)論


技術(shù)專區(qū)

關(guān)閉