在Proteus中通過模擬溫濕度,外接溫濕度值,將模擬到的數據進行采集與A/D轉換,顯示到LCD液晶并控制后級電路進行反饋,完成晾衣架的功能。
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
智能晾衣架 第三章:硬件單元電路經過上述分析明確了本次設計的主要目標,為了實現晾衣自身能夠完成對外界數據的采集與分析,集成控制環節我們采用了ATMEL公司生產的AT89C52單片機,與市面上的其他嵌入式控制單元相比較在體積與功耗方面都相當出色。此次設計主要突破在于設計合理的控制電路單元,同時結合采用的主控編寫高質量的源碼并使系統在實際與應用中能夠發揮出色的穩定性和參考價值。本次將圍繞主控單元設計合理的電路,結合SHT11溫濕度采集單元、感光原件單元、LCD顯示單元、模式控制單元使晾衣架能夠得到外界的實時數據并作出相應的調整。在設定合適的溫濕度及感光度的條件下能夠自動控制電機驅動滑桿實現自動量曬與回收衣物,結合光線角度進行上下左右調整。主要框架如下圖所示:
3.1主控單元設計 為了使智能晾衣架在使用時滿足嵌入式系統功耗、抗干擾、適用空間等要求,設計之初除了上述因素也考慮到成本因素。通過比較我們選擇了51系列中的AT89C52芯片作為主控制單元。無論是功耗還是處理速度上都有著不錯的表現,與CONTEX-M3系列單片機相比較處理上稍微慢點,但本次設計對分時處理的要求不是特別高,同時52系列具有簡單高效的指令集和,大大減少設計難度,結合SHT11與ADC0804精準的完成數采集與電機控制。 我們常見的主控封裝形式有40腳的DIP直插的也有PQFP類型的貼片封裝,在proteus中仿真的時候選擇DIP類型,方便自主設計與搭建外圍電路單元。從產品角度和制版工藝上面來講貼片能夠節省空間。這次采用的主控制芯片是8位CMOS工藝的單片機,內部有八位CPU和FlASH,在工控領域有著廣泛的用途,脫機運行性能穩定,相比較51有著更大的存儲和定時器資源,其主要內部參數與引腳分布見下圖:
表:3.1.1主要參數 圖:3.1.2雙列直插型 圖:3.1.3 PLCC貼片型 由上圖可以直接看到引腳標識與編號,左下角的GND與右上角的VCC需要外接合適的工作電壓,一般采用5V工作電壓。兩側的P0-P3 I/O口是可編程輸入輸出管腳,一組有四個,一共32個,可以看到I/O資源挺豐富且適合驅動多種外設。最小控制單元自工作的時候需要外部晶振提供合適的工作頻率同時為了防止程序跑飛或者陷入死循環還要提供合理的復位單元。通俗點好比人要正常工作的需要心臟提供合適的脈搏跳動,這里我們選的是11.529MHZ的外部無源晶振,在外圍接上兩個22PF的非極性濾波電容連接到18、19管腳,為最小系統提供合適的工作頻率。復位環節通過分壓電阻與按鍵開關為9管腳提供復位信號,10uf的極性電容較減少按動過程中的抖動信號,發送有效地高電平信號可以讓單片機重新加載程序,從頭開始跑。此次仿真過程中由于I/O分配的原因采用了兩片主控,另外需要注意的是P3口除了通用的管腳功能外,還有拓展的第二功能,配置其引腳功能能夠實現定時/計數功能以及外部中斷資源,在實際設計過程中有著非常多的用途。下面是最小控制單元的原理圖以及P3管腳工能分布圖:, 圖:3.1.3最小系統 圖:3.1.4 P3口復用 3.2LCD液晶顯示 主控單元在上電之后會對液晶屏幕進行初始化,直觀的顯示出各項參數,結合獨立按鍵顯示控制模式,給用戶提供良好的人機交互。常見的顯示屏幕有很多尺寸,市面上的電容、電阻屏也數不勝數,這里我們選用戶LCD1602作為液晶顯示,同樣的考慮到功耗與顯示區間等因素。1602有著八個數據端口,體積很小亮度飽和能夠直觀簡單的顯示ASCII碼與字符,與單片機的接口連接簡單,控制屏幕上的液晶分子顯示出字符,不同的電壓控制不同區域 上下兩行能夠分別顯示16個字符,不具備漢字現實的能力,這點上不如12864,但完成設計的時候能夠帶來更穩定的顯示,較強的抗干擾能力。實際硬件分為有無背光源,帶背光的厚度稍微大點,會有更好的顯示效果且調節背光源之間的滑變能夠顯示效果。常用的有16個管腳,分為電源區、指令控制區、數據區、背光區。實際外觀尺寸見下圖: 圖:3.2.1 LDC液晶尺寸圖 可以看到上圖中有兩行顯示區域,左上角有1-16個外圍引腳可以用,用來驅動屏幕顯示想要的數據與字符,先簡單說下管腳分布和功能:1管腳與2管腳用來接工作電源;3管腳通過VCC與分壓電阻控制屏幕的對比度且會隨著電壓的變化而增加減少,對比度過高會出現陰影不清晰等現象,因此需要條調節合適的對比度以滿足正常顯示,可以外接10K電阻進行調整;4管腳RS控制端用來告訴模塊當前是發送/讀寫數據還是指令,在實際現實過程中參與控制時序,高的電平信號控制數據控制寄存器、低電平信號控制指令寄存器;5管腳為W/R讀寫控制端,與4管腳結合起來可以實現數據/命令&讀/寫功能;6管腳作為EN使能控制端用來控制液晶的工作狀態;7管腳到14管腳為數據線,用來讀寫數據;15與16管腳控制背光,根據實際情況考慮是否需要接入電路中。 對控制端口有一定的了解后,還需要掌握讀寫時序圖從而根據時序去設計軟件驅動,這里以寫數據時序圖為例子說下原理過程: 圖3.2.2 寫數據時序 上圖中RS決定當前是要啟用命令寄存器還是數據寄存器,寫數據的過程中RS要保持高電平信號,寫命令的過程要保持低電平信號。當往液晶上寫字符的時候,首先要將RS拉低,R/W保持低電頻信號,隨后有個上升沿將RS拉成高電位,也就是上圖RS對應的第二條信號線。圖中tsp_x、tR、tHD_x等間距在設計過程中都可以采用延時實現時序同步。我們可以看到valid data是有效地數據段,只有當RS = 1、R/W = 0、DB0-DB7發送數據、EN使能等狀態都滿足的時候才能實現數據從I/O寫入到液晶。這種時序圖在液晶操作與與不同工控領域的傳感器數據采集中經常會用到,因此軟件設計過程中要嚴格遵守時序從而獲得準確有效地數據值。關于讀寫命令及讀寫數據的操作時序就不一一說明了,在下表中根據邏輯時序已經歸出控制區域I/O的工作狀態,方便開發使用。 讀狀態 | 輸入 | RS=L,R/W=H,E=H | 輸出 | D0—D7=狀態字 | 寫指令 | 輸入 | RS=L,R/W=L,D0—D7=指令碼,E=高脈沖 | 輸出 | 無 | 讀數據 | 輸入 | RS=H,R/W=H,E=H | 輸出 | D0—D7=數據 | 寫數據 | 輸入 | RS=H,R/W=L,D0—D7=數據,E=高脈沖 | 輸出 | 無 |
表:3.2.3 控制時序 上面也有提到16個顯示區域,它們也是有對應的基帶地址,要在固定的地址上顯示字符就需要發送對應的地址指令,第一行地址起始地址為0x00,第二行起始地址為0x40,后續的地址參考圖3.2.3。設計時如果沒有用到屏幕滾動的話可以不考慮虛擬地址。也就是說從0x10以后到0x27以及0x50到0x67需要開啟其滾動顯示才能顯示出該地址空間上的數據。 關于常見的操作指令可以參考手冊中的指令集部分, 圖3.2.3地址映射 3.3SHT11溫濕度 對于外界環境的一些非線性參數,需要使用傳感器將時變環境參數轉換成時變模擬信號,經過預處理后由單片機把模擬信號轉化成能夠識別的數字信號。對于外界環境的溫濕度參數獲常用到的測量原件有DHT_x系列與SHT_x系列等測量原件。DHT11在控制領域有著廣泛的應用,此外對于高精度的測量儀器儀表設備中SHT11也有著廣泛的應用。這兩款芯片本質上的區別在于內部采樣部分,DHT11的核心部件采用的是濕敏電阻原件,準確度與穩定性相對來講比較差;SHT11內部采用的濕敏電容元器件,抗擾能力強,準確度高,當然成本上會比DHT11高點,這里設計的時候我們選用SHT11電容性原件進行采樣與分析處理。另外一點SHT11的接口上與DHT11也有些許差異,同門內部通信需要遵守各自的協議。詳細的管腳圖及與控制元件的接線見圖3.3.1。 圖:3.3.1 SHT11使用原理圖 上述原件預留了四個I/O接口,實際上該芯片有8個管腳且NC全部都接空,除了電源接口提供0-5V的工作電壓之外還有串行數據通信接口SCK與DATA。我們采樣的數據就需要通過IIC協議傳送到8位單片機上,為了避免傳送過程中帶來的干擾需要在VDD與GND之間加上去耦濾波電容。 在采集數據周期內同樣要遵守采樣時序電路,前面已經以1602寫數據為例說明。此外需要知道在啟動傳感器后如何發送指令集選擇自己要得到數據,啟動傳輸時序緩釋通過SCK、DATA數據端口控制。SCK由高電頻到低電頻再到高電平的反轉過程中農DATA同時出現高變低再變高的過程,下圖為啟動時序圖:圖:3.3.2SHT11啟動時序 常用的獲取參數的指令有:溫度測量0x03、濕度測量0x50、讀狀態寄存器0x07、寫狀態寄存器0x06、軟復位0x1E等。當我們要完成溫濕度是測量的時候,需要發布測試命令0x05標識RH當前濕度值,0x03表示當前溫度值。當指令發送完成以后會有20ms~320ms的等待時間,分別對應不同位數的的采樣單元,常見的有8位12位和14位,位數越大精度越高同時處理時間也要變長,等待數據測量完成以后會有“數據妥備”信號,緊接著進行2個字節的測量數據和一個字節的CRC校驗確定數據沒有發生錯誤以后才能夠將這組數據打包發送;在收到CRC的校驗完成以后,表明通訊完成,如果不進行CRC-8校驗的能在測量到LSB之后保持高電位的ACK能夠終止通訊且SHT1x會自動進入到睡眠模式。詳細的查看完整的測量時序見圖3.3.3。圖:3.3.3 SHT11采樣時序 3.4感光采樣單元 晾衣架的設計要符合日常使用習慣,實現室外環境,溫濕度的監控與感光值得檢測,這部分的用到LDR光敏電阻,常見的樓房中樓道的聲控光控燈中就有光敏電阻,常見的光敏電阻會隨著光照的增強電阻值會變小。為了直觀的看到光敏值變化我們可以通過ADC0804模數轉換芯片將動態變化的電位差轉換成直觀的數字信號,需要了解到的是0804的采樣電壓是0-5V,8位的分辨率映射到256,根據0-5V的采樣電勢差映射到0-256區間,換算成百分比顯示出來。關于ADC0804的管腳說明這里不再贅述,詳細參考使用手冊。圖3.4.1是光敏電阻與三極管構成的光感度檢測電路,圖3.4.2是ADC0804引腳說明。 圖:3.4.1 感光度測試電路 圖:3.4.2 ADC0804引腳分布 3.5獨立按鍵單元設置了獨立按鍵用于控制顯示模式和增益控制方式,系統按鍵事件的觸發條件可以是外部觸發,也可以軟件去抖動檢測IO高低電平變化。這里為了節省資源開銷,采用按鍵去抖動,監測電平反轉情況確定按鍵是否被按下。按鍵部分的原理圖如下: 圖一 按鍵電路 圖二 按鍵抖動 硬件部分的結構通過外接3.3正電壓,流經10K上拉電阻后接開關接回GND。電路很簡單,上拉電阻正常情況下往IO口輸入的電平為高電平,默認拉高電位。按鍵按下的時候會有按鍵抖動隨后電位編程低電平,按鍵松開的過程亦如此,隨后回復高電平。機械按鍵的接觸點抖動會對IO口監測電頻帶來干擾,通過軟件延時去抖動可以合理的判斷案件的工作狀態。實際抖動過程狀態見下上面圖二。按鍵再按下的時候會有連續按下模式和單次按下模式,這里通過軟件按位取反設置連續模式還是單次模式,具體實現方法見附件代碼。 設計中要求具備初始值設定,對于溫濕度的上下限有合適的設置范圍,檢測當前的溫濕度實時變化與EEPROM中預存值進行比較,從而驅動電機進行角度與高低調整。按鍵一方面參與了模式控制另一方面人機交互提供了良好的體驗,結合EEPROM將數據保存下來,避免了掉電之后的數據丟失。由于單片機I/O帶負載能有限,所以要驅動電機轉動還用到了繼電器控制電路。下圖是電機驅動控制電路: 圖:3.5.1 電機驅動單元 第四章:系統軟件流程4.1設計流程軟件結構這塊主要采用STM32的內部資源,因其內置的ADC/DAC的功能很方便,不用再去單獨設計模數和數模轉換電路。DAC主要功能是驅動增益控制部分,結合按鍵模式可以設置出自動增益控制或者手動增益控制。同時將控制的結果反饋輸出到液晶屏幕上,可以很直觀的看到信號的各種數據,ADC的反饋可以實現系統的閉環增益控制,對輸出的信號有直觀的了解與認識。按鍵與液晶結合可以在顯示模式上有多種選擇,此外系統內部的一些定時器,中斷的等內部資源也發揮了很大的作用。在任務調度上起到了隔離保護的作用,整體采用低功耗、高效處理的工作模式,使系統更加穩定且自帶反饋功能。下面是軟件流程結構:
4.2系統原理 經過上述硬件單元以及軟件流程設計,整個流程中用到了單片機,SHT11溫濕度采集及ADC0804模數轉光感值,通過讀寫24C02記錄與裝載值,實時數據與設定值進行匹配,整個系統具有實時反饋,在proteus7中進行了仿真部分仿真原理圖如下: 圖中通過兩片52單片機的原因是由于1602、單機控制、SHT11、獨立按鍵等外設占用了太多I/O,由于需要給ADC0804提供正常的工作時序,所以這里直接選擇了兩片52單片機,實際上可以通過74HC573等鎖存芯片進行I/O分配與拓展,相比較而言效果會好點,這里采用兩片也能夠很好地滿足設計要求。 第五章:數據測量分析5.1實驗測試數據 本次測試過程用到了SHT11與LDR光敏電阻,由于仿真的緣故需要在仿真過程中設置外界環境因素,人為的模擬溫濕度與光感度。溫濕度根據SHT11自身的%RH進行溫濕度切換,增加按鍵模擬當前數值。光敏電阻為了直觀的看到數據變化通過電壓變觀察電阻兩端的電位差變化,比較SHT11本身設定值與電壓表示數值,與LCD1602顯示數據對比,觀測數據偏差分析出現誤差原因。詳細測試數據見表5.1.1 測試條件:提前設定溫濕度上下限并保存(溫度:30℃ 濕度:30%) 5.2結果誤差分析、 通過上表測量數據發現模擬過程中的溫濕度實測值與模擬設定值有0.2-0.3的實際誤差,經分查閱手冊發現SHT11在測量過程中會有±3%的測量誤差,出現上訴情況屬于正常現象,當然為更加直觀看到數據,可以在軟件里面增加誤差值,在顯示到液晶之前對數據提前進行預處理,減去相對誤差值從而讓結果顯示出來更加精確。解決方案辦法在軟件中進行了處理,見下圖: 
單片機源碼:
- #include<reg52.h>
- #include <intrins.h>
- #include <math.h>
- #include <stdio.h>
- #include <1602.h>
- #include <sht11.h>
- #include <24c02.h>
-
- #define uchar unsigned char
- #define uint unsigned int
- #define W_cmd 0xa0 //24c02寫指令
- #define R_cmd 0xa1
- uint temp,humi;
- value humi_val,temp_val; //定義兩個共同體,一個用于濕度,一個用于溫度
- uchar error; //用于檢驗是否出現錯誤
- uchar checksum; //CRC
- uchar TEMP_data[7]; //用于記錄實測的溫度
- uchar HUMI_data[6]; //用于記錄實測的濕度
- uchar LIGH_data[4]; //用于記錄實測光感度
- uchar show_temp[5]; //顯示設定的溫度
- uchar show_humi[4]; //顯示設定的濕度
- uchar data temp_humi_cache[4]; //溫濕度設置緩存
- uchar temp_set; //保存溫度變量
- uchar humi_set; //保存濕度變量
- uchar presskeynum; //按鍵次數變量
- uchar nn; //用于蜂鳴器
- uchar code word1[]={" a product of "};
- uchar code word2[]={"UNITED ELECTRONS"};
- uchar code word3[]={" Welcome........"};
- sbit k1=P2^0; //選擇按鍵
- sbit k2=P2^1; //增加按鍵
- sbit k3=P2^2; //減小按鍵
- sbit k4=P2^3;// 確認按鍵
- sbit led1=P1^4; //溫度過低指示燈
- sbit led2=P1^5; //溫度過高
- sbit led3=P1^6; //濕度低于下限值,報警,加濕。
- sbit led4=P1^7; //濕度過高,報警,不調濕
- sbit motor1=P3^4;
- sbit motor2=P3^5;
- sbit motor3=P3^6;
- sbit motor4=P3^7;
- sbit P2_6=P2^6;
- //********延時函數*********
- void delay(uint z) //z為毫秒數
- {
- int a,b;
- for(a=z;a>0;a--)
- for(b=120;b>0;b--);
- }
- void key()
- {
- uchar m;
- if (k1==0) //調整按鍵檢測
- {
- delay(5);
- if (k1==0)
- {
- presskeynum++;
- if(presskeynum==3)
- presskeynum=0;
- while(k1==0); //若一直按下,循環
- LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏
- }
- }
- if(presskeynum==1)//溫度設置
- {
- if(k2==0) // 加
- {
- delay(300);
- temp_set++;
- if (temp_set>30)
- temp_set=30;
- while(k2==0); //加上此句必須松按鍵才處理
- }
- if(k3==0)//減
- {
- delay(300);
- temp_set--;
- if (temp_set<18)
- temp_set=18;
- while(k3==0); //加上此句必須松按鍵才處理
- }
-
- }
-
- if(presskeynum==2)//濕度設置
- {
- if(k2==0)// 加
- {
- delay(300);
- humi_set++;
- if (humi_set>99)
- humi_set=99;
- while(k2==0);
- }
- if(k3==0)//減
- {
- delay(300);
- humi_set--;
- if (humi_set<1)
- humi_set=1;
- // while(k3==0); //這句是調試加入的
- }
-
- }
-
-
- if(k4==0)// 退出鍵 //設置完初始值以后通過IIC寫入24c02并清屏
- {
- delay(10);
- if(k4==0)
- {
- while(k4==0);
- presskeynum=0;
- temp_humi_cache[0]=temp_set/10;
- temp_humi_cache[1]=temp_set%10;
- temp_humi_cache[2]=humi_set/10;
- temp_humi_cache[3]=humi_set%10;
-
- for(m=0;m<4;m++)
- {
- WriteIIC(W_cmd,0x00+m,temp_humi_cache[m]); //設定值寫入24c02
- }
- LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏
- }
- }
- }
- //主函數
- void main()
- {
- uchar t;
- uchar temp_adc;
- k1=k2=k3=k4=1;
- motor1=motor2=motor3=motor4=0;
- P2_6=0;
- for (t=0;t<4;t++)
- temp_humi_cache[t]=ReadIIC(W_cmd,0x00+t,R_cmd); //讀入24c02設定的值
- temp_set=temp_humi_cache[0]*10+temp_humi_cache[1]; //設置溫度
- humi_set=temp_humi_cache[2]*10+temp_humi_cache[3]; //設置濕度
- LCD_Initial(); //液晶初始化
- GotoXY(0,0);
- Print_slow(word1);
- GotoXY(0,1);
- Print_slow(word2);
- LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏
- GotoXY(0,0);
- Print_slow(word3);
- LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏 //完成系統初始化
- while(1)
- {
- key();
- P1 = 0xff; //P1口初始化
- temp_adc = P1; //讀取光敏值,8位精度最大256
- if(presskeynum==0) //測量溫濕度
- {
- s_connectionreset(); //啟動連接復位
- error=0; //初始化error=0,即沒有錯誤
- error+=s_measure((unsigned char*)&temp_val.i,&checksum,TEMP); //溫度測量值返回到temp.val.i
- error+=s_measure((unsigned char*)&humi_val.i,&checksum,HUMI); //濕度測量值返回到humi_val.i
- if(error!=0)
- s_connectionreset(); //如果發生錯誤,系統復位
- else
- {
- humi_val.f=(float)humi_val.i; //轉換為浮點數
- temp_val.f=(float)temp_val.i; //轉換為浮點數
- calc_sth10(&humi_val.f,&temp_val.f); //修正相對濕度及溫度,誤差彌補
- temp=temp_val.f*10;
- humi=humi_val.f*10;
- GotoXY(0,0); //選擇溫度顯示位置
- Print("Temp: C --- "); //5格空格
- GotoXY(0,1); //選擇濕度顯示位置
- Print("Humi: % "); //5格空格
-
- GotoXY(5,0); //設置溫度顯示位置
- TEMP_data[0]=temp/1000+'0'; //溫度百位
- if (TEMP_data[0]==0x30) //ASCLL = 0
- TEMP_data[0]=0x20; //對應的ASCLL位空格
- TEMP_data[1]=temp%1000/100+'0'; //溫度十位
- if (TEMP_data[1]==0x30 && TEMP_data[0]!=0x30)
- TEMP_data[1]=0x20;
- TEMP_data[2]=temp%100/10+'0'; //溫度個位
- TEMP_data[3]=0x2e; //小數點
- TEMP_data[4]=temp%10+'0'; //溫度小數點后第一位
- TEMP_data[5]=0xdf; //顯示溫度符號℃書上是第248
- TEMP_data[6]='\0'; //實際上0xdf對應的是小圓圈
- Print(TEMP_data); //輸出溫度
-
- GotoXY(5,1);
- HUMI_data[0]=humi/1000+'0'; //濕度百位
- if (HUMI_data[0]==0x30)
- HUMI_data[0]=0x20;
- HUMI_data[1]=humi%1000/100+'0'; //濕度十位
- HUMI_data[2]=humi%100/10+'0'; //濕度個位
- HUMI_data[3]='.' ; //小數點
- HUMI_data[4]=humi%10+'0'; //濕度小數點后第一位
- HUMI_data[5]='\0';
- Print(HUMI_data); //輸出濕度
- GotoXY(13,1);
- LIGH_data[0] = temp_adc%1000/100+'0';
- // if(LIGH_data[0] == 0x30)
- // LIGH_data[0] = 0x20;
- LIGH_data[1] = temp_adc%100/10+'0';
- LIGH_data[2] = temp_adc%10+'0';
- LIGH_data[3] = '\0';
- Print(LIGH_data);
-
- if ((temp/10)<temp_set)
- {
- motor1=1;
- motor2=0;
- }else if ((temp/10)>=temp_set)
- {
- motor2=1;
- motor1=0;
-
- }
- if ((humi/10)<humi_set)
- {
- motor3=1;
- motor4=0;
- }
- else if ((humi/10)>=humi_set)
- {
- motor4=1;
- motor3=0;
- }
-
- } //else
- } //if
-
- if(presskeynum==1) //設定溫度時顯示的內容
- {
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
全部資料51hei下載地址(內含仿真與源碼等全套資料):
智能晾衣架.docx
(1.6 MB, 下載次數: 512)
2018-5-27 16:08 上傳
點擊文件名下載附件
設計文檔
光敏電阻.zip
(36.01 KB, 下載次數: 326)
2018-5-27 16:09 上傳
點擊文件名下載附件
光敏模擬
溫濕采集.zip
(158.77 KB, 下載次數: 318)
2018-5-27 16:09 上傳
點擊文件名下載附件
溫濕度模擬
原件詳解.zip
(4.75 MB, 下載次數: 400)
2018-5-27 16:10 上傳
點擊文件名下載附件
單元電路元件詳解
|