引言
溫度是工、農業生產的主要環境因素,它對工農業的生產有著重要的影響,所以對其進行準確快速的測量并進行處理是具有很特殊的重要意義。測量溫度模塊是否正確、快速、及時決定著工農業生產的產品的質量是否符合預期設計的要求,而在當今是世界中,質量是企業生存的基本,所以許多對溫度要求很高的工、農業生產企業把溫度測量控制系統看成是企業生存的基本。
在市場競爭日益激烈的壓力面前,企業已經意識到要想提升自己企業的競爭能力,就必須采用新技術對企業產品進行質量等各方面的管理。而對溫度要求嚴格的產品,測量產品生產環境的溫度的技術決定著系統能否生存并繼續發展,所以很多工業生產企業都非常重視溫度控制系統。
對溫度進行采集,并送到PC機實時處理,以前往往采用的是計算機的串行接口,但這一老式計算機接口存在著不少缺陷。比如接口規格不統一、非共享式接口、占用資源大等等這樣那樣的缺點。隨著計算機的發展,USB(通用串行總線)接口是一種計算機應用領域的新型接口,USB接口的出現是計算機端接口的技術重大變革,其最早是由Compaq、Digital Equipment、IBM、Intel、Microsoft 、NEC和Northern Telecom 7家公司于1994年提出的,在2000年做出了改進,提出了USB2.0版本,隨著這一版本的提出,USB越來越流行,目前它已經成為了一種標準接口,現在市場上的所有PC機都百分之百支持USB接口,本文將采用這一USB接口來對采集到的溫度實時傳輸。
基于USB接口的溫度控制系統就是通過溫度傳感器對現場溫度進行測量,并利用微型處理器(單片機),通過USB接口實時的傳給計算機,計算機利用軟件根據已經設計好的要求對其進行報警等相應的處理。它是計算機技術、單片機技術、溫度傳感器技術的科技產物。適合于工業等需要對溫度進行實時大范圍的精確的處理。
1 背景知識
在USB產生之前,外設與PC機的通信主要是通過PC機主板上所提供的各種接口來
實現,如ISA接口、PCI接口、串行接口等,這些老式的接口存在著很多缺點:非共享式接口、體積大、接口規格不統一、采用傳統的I/O模式等等。為了克服老式接口這些缺點,PC機制造商和用戶迫切需要一種新型的外設連接方式。這時USB應運而生,它是一種快速、快速、雙向、同步、廉價、并支持熱插撥功能的串行接口。
早在1995年,就已經有PC機帶有USB接口了,但由于缺乏軟件及硬件設備的支持,這些PC機的USB接口都閑置未用。1998年后,隨著微軟在Windows 98中內置了對USB接口的支持模塊,加上USB設備的日漸增多,USB接口才逐步走進了實用階段。
這幾年,隨著大量支持USB的個人電腦的普及,USB逐步成為PC機的標準接口已經是大勢所趨。在主機(host)端,最新推出的PC機幾乎100%支持USB;而在外設(device)端,使用USB接口的設備也與日俱增,例如數碼相機、掃描儀、游戲桿、磁帶和軟驅、圖像設備、打印機、鍵盤、鼠標等等。正是USB具有熱插拔、共享式接口、攜帶方便、標準統一、可以連接多個設備等這樣的優點,才使USB得于快速的發展。
本文將利用這一新型計算機接口來設計溫度控制系統。
2 系統概述
本章將對基于USB接口的溫度控制系統在工業上的應用進行分析,并介紹系統的特點、功能以及使用到的開發工具。
2.1 系統的特性
由于該系統利用USB接口,所以具有USB的實時傳送數據,與上位機進行信息交流,而上位機又可以連接在互聯網上,所以遠程的PC機也可以利用互聯網對溫度檢測系統進行查看等各種操作。該系統利用先進的溫度傳感器,可以對溫度快速的進行反應,把溫度數據傳到下位機進行初步處理數據,進而與上位機通信。總的來說,該系統有以下幾點特點:
·工作人員可以遠離生產環境通過計算機對其進行查看處理;
·多點溫度測量;
·全天候檢測溫度,并可以在沒有工作人員的參與下對生產環境進行簡單處理;
·對生產環境的溫度進行設計極限溫度,一旦超過極限溫度,系統將對起進行報警,并停止生產環境的工作;
·測量溫度誤差比較精確,在0.5℃內;
2.2 系統的功能
該系統主要有以下功能:
(1)對溫度進行檢測。利用該系統可以遠離惡劣生產環境的情況下,對其進行溫度測量;
(2)對現場溫度進行實時采集;并在PC機上顯示出來;
(3)在PC機上實時做出溫度圖像;工作人員在電腦上便可以直觀的得到系統溫度圖像;
(4)簡單的系統控制;通過計算機上的應用軟件可以對溫度設置,一旦超過極限溫度,發出報警,進而通知工作人員快速的對生產現場進行各種相應操作,這樣可以防止溫度超出極限溫度;
(5)在上位機端的應用軟件上提供系統使用幫助。用戶可以利用該功能幫助對系統進行操作。
2.3 系統開發平臺
本次系統需要用到的開發工具為:keil C、 C++ builder、Protel、計算機、燒寫器。
Keil C是目前世界上最好的MC-51單片機的匯編和C語言的開發工具。支持匯編、c語言以及混合編程。同時具備功能強大的軟件仿真和硬件仿真。C++ builder 是計算機高級語言C++比較好用的編程工具,它是屬于一種可視化的計算機語言。 Protel是世界上最好的硬件電路圖制作的工具。
3 系統總體設計
3.1 系統整體方框圖
根據前面的分析,知道系統要實現以上功能,必須由以下幾部分組成:溫度采集單元、下位機溫度初步處理單元、USB設備接口、上位機應用程序。
系統的結構原理圖如圖3.1:

圖3.1系統整體實現的結構原理圖
溫度傳感器單元對生產溫度環境進行測量,將測量溫度傳給下位機(單片機),單片機對采集到的溫度進行初步處理后,將處理了的數據通過USB接口上傳給PC機上位機,而上位機將實時的顯示采集到的溫度,如果要對現場環境進行處理,則上位機可以發送命令,經過USB接口傳送到下位機,下位機根據接受到的數據并對其進行分析,進而做出處理,如報警等各種操作。
3.2 系統方案比較
對于本系統,方案的選擇是根據溫度傳感器來選擇。
目前市場上有兩種傳感器:模擬傳感器和數字集成傳感器,對于選擇不同的傳感器將會有不同的方案。下面給出兩種不同的方案,并對其進行分析,最終選擇其中一種方案。
3.2.1系統兩種可行方案
方案1:選擇模擬傳感器
所謂模擬傳感器,簡單的說就是傳感器對被測量的物質感應,并隨著檢測的不同做出不同的反應,但這一反應是有規律的,而且有規律的輸出模擬信號。由于單片機是數字信號系統,只能識別數字信號,所以這種方案要想利用單片機對溫度信號進行處理,必須將對模擬輸出量數字化,也就是說要對其輸出的模擬電壓或電流轉換成數字信號,這么一來就系統要加入模擬信號轉換成數字信號的處理單元,通常,實現這一功能的是A/D轉換器,市場對于這一A/D轉換器有不少類型。所以選擇這一方案也是可以有效而快速的設計出本系統。
圖3.2給出使用模擬傳感器這一方案的設計原理圖。

圖3.2 方案1的結構原理圖
方案2:選擇數字傳感器
今天隨著計算機的飛速發展以及單片機的日益普及,世界進入了數字時代,人們在處理被測信號時首先想到的是信息處理器(單片機或計算機)。具有輸出數字信號便于電腦處理的傳感器就是所謂的數字傳感器。
數字傳感器是近幾年才出現的并得到廣泛的應在在實踐當中,所謂數字傳感器,進一步的講,就是將模擬傳感器產生的信號經過放大、A/D轉換、線性化及量綱處理后變成純粹的數字信號,是在模擬傳感器上加入數字處理單元,并將數字單元集成在一塊芯片上,所以輸出的是數字信號,便于數字處理機對其直接進行處理。
圖3.3給出利用數字傳感器設計的方案圖:

圖3.3 方案2的結構原理圖
3.2.2方案最終選擇
以上已經提出了兩種方案,下面對這兩重方案進行分析,并做最后方案選擇:
分析近幾年來傳感器的發展,我們知道傳感器在未來的發展中將會向以下的方向發展:(1)向高精度發展。隨著自動化生產程度的不斷提高,對傳感器的要求也在不斷提高,必須研制出具有靈敏度高、精確度高、響應速度快、互換性好的新型傳感器以確保生產自動化的可靠性。目前能生產精度在萬分之一以上的傳感器的廠家為數很少,其產量也遠遠不能滿足要求。(2)向高可靠性、寬溫度范圍發展。傳感器的可靠性直接影響到電子設備的抗干擾等性能,研制高可靠性、寬溫度范圍的傳感器將是永久性的方向。提高溫度范圍歷來是大課題,大部分傳感器其工作范圍都在-20℃~70℃,在軍用系統中要求工作溫度在-40℃~85℃范圍,而汽車鍋爐等場合要求傳感器工作在-20℃~120℃,在冶煉、焦化等方面對傳感器的溫度要求更高,因此發展新興材料(如陶瓷)的傳感器將很有前途。(3)向微型化發展。各種控制儀器設備的功能越來越大,要求各個部件體積能占位置越小越好,因而傳感器本身體積也是越小越好,這就要求發展新的材料及加工技術,目前利用硅材料制作的傳感器體積已經很小。如傳統的加速度傳感器是由重力塊和彈簧等制成的,體積較大、穩定性差、壽命也短,而利用激光等各種微細加工技術制成的硅加速度傳感器體積非常小、互換性可靠性都較好。(4)向微功耗及無源化發展。傳感器一般都是非電量向電量的轉化,工作時離不開電源,在野外現場或遠離電網的地方,往往是用電池供電或用太陽能等供電,開發微功耗的傳感器及無源傳感器是必然的發展方向,這樣既可以節省能源又可以提高系統壽命。目前,低功耗損的芯片發展很快,如TI2702運算放大器,靜態功耗只有1.5mA,而工作電壓只需2~5V。(5)向智能化數字化發展。傳感器一般都是非電量向電量的轉化,工作時離不開電源,在野外現場或遠離電網的地方,往往是用電池供電或用太陽能等供電,開發微功耗的傳感器及無源傳感器是必然的發展方向,這樣既可以節省能源又可以提高系統壽命。目前,低功耗損的芯片發展很快,如TI2702運算放大器,靜態功耗只有1.5mA,而工作電壓只需2~5V。
由于模擬傳感器,沒有把模擬轉化為數字處理單元集成在一塊芯片上,這樣必帶來傳感檢測單元的體積大等各個方面的影響,再者,模擬轉化成數字單元也需要單片機對其進行處理,這樣會浪費時間、資源。所以這樣一來我們知道數字傳感器在未來必將取代模擬傳感器。而且隨著數字傳感器的發展,現在市場上數字傳感也不是那么貴,本次系統對溫度精度的要求不是很高,所以選擇方案二。
4 系統硬件設計
4.1 中央處理器----AT89C51
AT89C51由美國Atmel 公司生產的,是一種帶4K字節閃爍可編程可擦除只讀存儲器(FPEROM—Falsh Programmable and Erasable Read Only Memory)的低電壓,高性能CMOS8位單片機,該器件采用ATMEL高密度非易失存儲器制造技術制造,與工業標準的MCS-51指令集和輸出管腳相兼容。下文將對AT89C51單片機做簡單介紹。
(1) AT89C51的特點
AT89C51具有以下幾個特點:
①中央處理器CPU;
②AT89C51與MCS-51系列的單片機在指令系統和引腳上完全兼容;
③片內有4k字節在線可重復編程快擦寫程序存儲器;
④全靜態工作,工作范圍:0Hz~24MHz;
⑤三級程序存儲器加密;
⑥128×8位內部RAM;
⑦32位雙向輸入輸出線;
⑧兩個十六位定時器/計數器
⑨五個中斷源,兩級中斷優先級;
⑩一個全雙工的異步串行口;
(2)AT89C51的結構圖如圖4.1
圖4.1 89C51的結構圖
由上圖,知:AT89C51主要由CPU、存儲器、I/O端口等幾部分組成。
(3)AT89C51的功能描述
AT89C51是一種低損耗、高性能、CMOS八位微處理器,片內有4k字節的在線可重復編程、快速擦除快速寫入程序的存儲器,能重復寫入/擦除1000次,數據保存時間為十年。它與MCA-51系列單片機在指令系統和引腳上完全兼容,不僅可完全代替MCS-51系列單片機,而且能使系統具有許多MCS-51系列產品沒有的功能。
AT89C51可構成真正的單片機最小應用系統,縮小系統體積,增加系統的可靠性,降低系統的成本。只要程序長度小于4K,四個I/O口全部提供給用戶。可用5V電壓編程,而且擦寫時間僅需10毫秒,僅為8751/87C51的擦除時間的百分之一,與8751/87C51的12V電壓擦寫相比,不易損壞器件,沒有兩種電源的要求,改寫時不拔下芯片,適合許多嵌入式控制領域。工作電壓范圍寬(2.7V~6V),全靜態工作,工作頻率寬在0Hz~24MHz之間,比8751/87C51等51系列的6MHz~12MHz更具有靈活性,系統能快也能慢。
AT89C51芯片提供三級程序存儲器加密,提供了方便靈活而可靠的硬加密手段,能完全保證程序或系統不被仿制。P0口是三態雙向口,通稱數據總線口,因為只有該口能直接用于對外部存儲器的讀/寫操作。
(4)AT89C51引腳功能及說明
圖4.2是AT89C51的引腳

圖4.2
①口線:P0、P1、P2、P3口。
P0口是三態雙向口,通稱數據總線口,為一個8位漏級開路雙向I/O口,每腳可吸收8TTL門電流。當P1口的管腳第一次寫1時,被定義為高阻輸入。P0能夠用于外部程序數據存儲器,它可以被定義為數據/地址的第八位。在FIASH編程時,P0 口作為原碼輸入口,當FIASH進行校驗時,P0輸出原碼,此時P0外部必須被拉高。因為只有該口能直接用于對外部存儲器的讀/寫操作。P0口也用以輸出外部存儲器的低8位地址。由于是分時輸出,故應在外部加鎖存器將此地址數據鎖存,地址鎖存信號用ALE。
P1口是專門供用戶使用的I/O口,是準雙向口。P1口是一個內部提供上拉電阻的8位雙向I/O口,P1口緩沖器能接收輸出4TTL門電流。
P2口是從系統擴展時作高8位地址線用。不擴展外部存儲器時,P2口也可以作為用戶I/O口線使用,P2口也是準雙向口。
P3口是雙功能口,該口的每一位均可獨立地定義為第一I/O功能或第二功能。作為第一功能使用時操作同P1口。P3口的第二功能如表4.1所示。
②控制口線:PSEN(片外選取控制)、ALE(地址鎖存控制)、EA(片外存儲器選擇)、RESET(復位控制);
③電源及時鐘:VCC、VSS、XTAL1、XTAL2 操作方法。
表4.1 P3口的第二功能

④操作方法
程序存儲器加密。AT89C51芯片程序存儲器有三級硬件加密,能夠有效地保證系統不被仿制和軟件不被復制,加密等級設置見附錄2。
工作模式。AT89C51有間歇和掉電兩種工作模式。間歇模式是由軟件來設置的,當外圍器件仍然處于工作狀態時,CPU可根據工作情況適時地進入睡眠狀態,內部RAM和所有特殊的寄存器值將保持不變。這種狀態可被任何一個中斷所終止或通過硬件復位。
掉電模式是VCC電壓低于電源下限,振蕩器停止振動,CPU停止執行指令。該芯片內RAM和特殊功能寄存器值保持不變,直到掉電模式被終止。只有VCC電壓恢復到正常工作范圍而且在振蕩器穩定振蕩后,通過硬件復位掉電模式可被終止。
4.2 溫度傳感器DS18B20
溫度傳感器是該系統的測量器件,溫度傳感器的好壞直接影響到測量結果,所以本文將對溫度傳感器的選擇詳細介紹。根據本次設計論文的要求,包括精度要求等,經過分析,本文決定選擇數字溫度傳感器DSB8B20。下面將給予介紹。
(1) DS18B20的概述
DS18B20是DALLAS公司生產的一線式數字溫度傳感器,具有3引腳TO-92小體積封裝形式;溫度測量范圍為-55℃~+125℃,可編程為9位~12位A/D轉換精度,測溫分辨率可達0.0625℃,被測環境的溫度用符號擴展的16位數字量方式串行輸出;其工作電源既可在遠端引入,也可采用寄生電源方式產生;多個DS18B20可以并聯到3根或2根線上,CPU只需一根端口線就能與諸多DS18B20通信,占用微處理器的端口較少,可節省大量的引線和邏輯電路。以上特點使DS18B20非常適用于遠距離多點溫度檢測系統。
(2)DS18B20的內部結構
圖4.3是DS18B20的內部結構圖

圖4.3 DS18B20的內部結構
由圖可知,DS18B20主要由4部分組成:64位ROM、溫度傳感器、非揮發的溫
警觸發器TH和TL、配置寄存器。DS18B20的管腳排列如圖4.4所示,

圖4.4 DS18B20的管腳排列
DS18B20的3個管腳說明如下:
DQ為數字信號輸入/輸出端。是漏極開路一線接口。也在寄生電源接線方式時,給設備提供電源。
GND為電源地。
VDD為外接供電電源輸入端(在寄生電源接線方式時接地)。
DS18B20的64位ROM保存了設備的唯一序列碼,是DS18B20的地址序列碼,每一個DS18B20的地址序列碼是不同的,這樣就可以實現一根總線上掛接多個DS18B20。高速閃存(scratchpad)包括2個字節的溫度寄存器。保存了溫度傳感器的數字輸出。該閃存還提供了對上限(TH)和下限(TL)的超標報警寄存器、配置寄存器(一個字節)的訪問。TH、TL和配置寄存器是EEPROM,所以系統掉電時可以保存數據。
DS18B20利用DALLAS的單總線控制協議,實現了利用單線控制信號在總線上進行通信。由于所有的設備通過漏極開路端(DQ腳)連在總線上,控制線需要一個大約5K上拉電阻。在這一總線控制系統中,微控制器通過唯一的64位地址序列碼識別和訪問總線上的器件。由于地址序列碼不同,所以連接在總線上的DS18B20可以說是無限的 。
(3)DS18B20的寄存器
DS18B20存儲器組織結構如表4.2所示:
表4.2 存儲器的組織圖
高速閃存(上電狀態)
字節0 | 溫度底字節 |
字節1 | 溫度高字節 |
字節2 | 高溫報警用戶字節“1” |
字節3 | 低溫報警用戶字節“2” |
字節4 | 配置寄存器 |
字節5 | 保留(FFH) |
字節6 | 保留(0CH) |
字節7 | 保留(10H) |
字節8 | CRC校驗 |
字節0和字節1分別包含溫度寄存器的LSB和MSB,這些字節是只讀的,字節2和字節3提供對TH(上限報警觸發寄存器)和TL(下限報警觸發寄存器)的訪問,字節4包配置寄存數據,字節5、6和7保留做器件內部使用,不能被改寫,當讀時,這些字節返回全1值,字節8是只讀的,含有字節0到字節的CRC校驗。
高速閃存的第四個字節包含配置寄存器,其組織結構如下表4.3所示:
表4.3 配置寄存器
Bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
表4.4 測溫分辨率配置
R1 | R1 | 分辨率 | 最大轉換時間 |
0 | 0 | 9bit | 93.75ms |
0 | 1 | 10bit | 187.5ms |
1 | 0 | 11bit | 375ms |
1 | 1 | 12bit | 750ms |
(4)DS18B20的讀寫時序
訪問DS18B20的順序如下:
----初始化;
----ROM命令(接著是任何需要的數據交換);
----DS18B20的函數命令(接著是任何需要的數據交換);
每一次訪問DS18B20時必須要按照這一順序,如果其中的任何一個步驟缺少或打亂,DS18B20將不會響應。
①初始化時序
初始化時序如圖4.5:

圖4.5 DS18B20初始化時序
所有與DS18B20的通信都要首先初始化,從而才能進行下一部的工作:控制器發出復位脈沖,DS18B20以存在脈沖響應。圖4.5給出了描述。當DS18B20發出存在脈沖對復位響應時,它指示控制器該DS18B20已經在總線上并準備好操作。
②讀/寫時序
控制器在寫時序到數據到DS18B20,在讀時序從DS18B20中讀數據,每一個總線時序傳送一個數據位。
讀/寫時序見下圖4.6

(a)寫時序

(b)讀時序
圖4.6 DS18B20的工作時序圖
③寫時序
有兩種類型的寫時序:寫1時序和寫0時序。控制器用寫“1”時序寫邏輯“1” 到DS18B20,用寫“0”時序寫邏輯“0”到DS18B20。所有寫時序必須持續60μs,每一個寫時序之間必須要至少有1μs的恢復時間。兩種類型的寫時序都從控制器把總線拉低開始。
為產生寫“1”的時序,在將總線拉低之后,總線控制器必須在15μs內釋放總線。總線釋放后,5K的上拉電阻將總線電平抬高。為產生寫“0”時序,在總線拉低后,控制器在整個時序內必須持續控制總線為低電平(至少60μs)。
DS18B20在控制器發出寫時序后的15-60μs的時間內采樣總線。如果在采樣窗口期間總線為高,“1”就被寫到DS18B20;如果在采樣窗口期間為低電平,則“0”就被寫入DS18B20。
④讀時序
當總線發出讀時序時,DS18B20可以發送數據到控制器。所有讀時序必須持續最少60μs,每一個讀時序之間必須有至少1μs的恢復時間。讀時序從控制設備將總線拉低至少1μs后釋放總線開始。控制器啟動讀時序后,DS18B20開始在總線上傳送“1”或者“ 0”。DS18B20通過保持總線為高發送“1”,將總線拉低發送“0”。發送“0”時,DS18B20在60μs時釋放總線; 發送“1” 時,總線被上拉電阻高電平空閑狀態。從DS18B20輸出的數據在啟動時序的下降沿后15μs有效。因此,控制器必須在時序開始的15μs內釋放總線,然后采樣總線狀態。
通過讀/寫時序,控制器可以發出控制命令,對DS18B20進行讀寫操作。
(5)DS18B20的常用命令
①SKIP ROM [CCH]
控制器可以用這一命令同時訪問總線上的所有設備而不需要發送ROM序列碼信息。控制器可以使總線上的所有DS18B20同時進行溫度轉換。
②SEARCH ROM [F0]
當系統開始上電時,控制器必須識別總線上所有從機的ROM序列碼,以確定從機的數目和它們的類型。控制器需要執行 search ROM循環足夠多次才能識別所有的從設備。如果只有一個從屬設備在總線上,可使用簡單的Read ROM命令期待Search ROM。每一個Search ROM命令之后必須返回到事務序列的步驟(初始化)。
③READ ROM[33]
這一命令只有在總線上只有一個設備的時候使用,它使得控制器可以不用Search ROM命令就可以讀出從機的64位ROM序列碼。當多于一個從機設備在總線上時,如果還使用該命令,由于所有的設備企圖響應該設備,這樣將產生數據沖突。
④CONVRTT [44]
這一命令開始一次溫度轉換。變換之后,數據保存在暫存器的2個字節溫度寄存器中,DS18B20回到低功耗空閑狀態。如果設備工作在寄存電壓模式,則這一命令發送后10μs之內,整個變換期間控制器必須在總線上能夠有較強的上拉。如果DS18B20由外部電源供電,那么Convert T命令后控制器可以發出讀時序。如果溫度變換正在進行,那么返回“0”;如果已經完畢,則返回“1”。
⑤WRITE SCTATCHPAD [4EH]
這一命令使得控制器可以寫3個字節數據到DS18B20的寄存器中。第一字節數據
到TH寄存器中,第二字節寫到TL中,第3字節寫到配置寄存器中。數據以最低有效位先發送。所有3字節必須在控制器發出復位或者數據丟失之前寫完。
⑥READ SCRTCHPAD[BEH]
這一命令使得控制器可以讀寄存器的內容。數據傳送開始于字節0的最低位,直到寄存器的第9字節被讀出,任何時候,如果只需部分寄存器數據,控制器可以結束讀操作。
上面已經介紹了數字溫度傳感器的原理,下面將利用DS18B20設計溫度采集模塊電路。
4.3 溫度采集模塊電路設計
以上已經介紹了AT89C51和數字溫度傳感器DS18B20基本知識,下面將利用它們來設計本系統的溫度采集電路。DS18B20連接到單片機的方法很簡單,它有兩種方法連接到電路上,既外接電源方式和寄生電源方式,這里使用的是系統提供的外接電源方式,而不采用寄生電源,只要VCC、DQ、GND連接到單片機的電源正極、一個I/O端口、電源地就可以了。但是要注意的是在DQ數據線中要加一個4.7K的上拉電阻,這一個是必須要加的,無論它是接在P1口還是P0口,這點特別注意,特別提醒。之外在電源兩端之間加個0.01U的電容,這樣的作用主要是濾波。

圖4.7 單片機和DS18B20接口圖
由圖4.7,知DS18B20工作在外部電源供電方式。單片機采用采用P1.1口與DS18B20通信。下面根據單片機的初始化時序和讀寫時序,寫出DS18B20和單片機之間的讀寫操作,這里只給了溫度的讀取,下位機部分程序在附錄中給出。
這里特別提醒的是DS18B20對時序要求很高,精度要求很高,所以程序的延時對是否能讀起數據起到非常關鍵的作用。
DS18B20讀寫數據程序如下:
void delaym(int time) //延時為(time*2+2)us
{ int s;
for(s=0;s<time; s++)
}
void write_bite(unit8 bite) //寫一位數據位
{ DQ=0;
if(bite==1)
DQ=1; //如果寫"1",DQ=1;
delaym(29);//延時60us提供DS18B20采樣
DQ=1; //釋放DQ
}
unit8 read_bite(void) //讀一位數據位
{ DQ=0; //將總線DQ拉低開始讀時序
delaym(0); //延時2us
DQ=1; //釋放DQ;
delaym(1); //延時4us后再讀數據
return(DQ);
}
void write_byte(unit8 dat) //寫一字節數據
{ unit8 i;
unit8 temp;
for(i=0;i<8;i++)
{ temp=dat>>1; //右移一位
temp&=0x01;
write_bite(temp);
}
}
unit8 read_byte(void)
{ unit8 i,value=0;
for(i=0;i<8;i++)
{ if(read_bite())
value|=0x01<<i;//讀一字節數據,一個讀時序讀一位,并做移位
delaym(29) ; //延時60us有以完成讀一位,之后再讀下一位
}
return(value);
}
unit8 DS18B20_RESET(void)
{ unit8 data;
DQ=0;
delaym(239); //保持DQ低480us
DQ=1;
delaym(35);
da=DQ;
delaym(211);
return (data);//有芯片應答data=0,無則data=1
}
4.4 系統接口模塊電路設計
本系統的采集模塊采集到數據后,必須要經過CH372傳到上位機應用軟件才能實現控制下位機的各種操作。而CH372是USB接口芯片,下位機和上位機通信的要通過CH372接口芯片來完成,其和計算機的連接很簡單,所以這一部分主要的硬件實現是CH372和單片機AT89C51的連接問題。
4.4.1 USB簡介
USB(Universal Serial Bus)是外圍設備與計算機進行連接的新型接口,既一種新型的通用串型總線接口,USB具有即插即用、熱插撥、接口體積小、節省系統資源、傳輸可靠、提供電源、良好的兼容性、共享試通信等優點。
在USB產生之前,外部設備和計算機的通信主要是通過計算機主板所提供的各種接口,比如ISA接口、PCI接口、PS/2接口、串行接口,并行接口等,這些接口,存在這樣那樣的缺陷,比如接口規格不統一、不共享等為了克服上述外圍設備的缺陷,P制造商和用戶迫切需要一種新型的外設接口,USB正是在這樣的環境下產生的,它是一種快速、雙向、同步、廉價、并支持熱插撥功能的串行接口。
USB是一種新型的接口,那么它必定有它的通信標準,也就是我們所說的協議,下面簡單介紹USB的通信協議。
一般的,對終端用戶來看,USB系統是USB設備連接到主機的簡單連接,但對開放人員來說,這中連接可分為三個層次:功能層、USB設備層、USB總線接口層,且每一層都由主機和USB設備的不同功能模塊組成。可以用下面的圖型來形容。下圖4.8是這種分層通信機制的簡化。

圖4.8 USB通信層次模型
由圖,一個USB設備由三個功能模塊組成:USB總線接口、USB邏輯設備、功能單元。USB總線接口是USB設備中的串行引擎(SIE);USB邏輯單元被看作是一個端點的集合;功能單元客戶軟件被看作接口的集合。
USB傳輸類型包括批量傳輸、同步傳輸、中斷傳輸和控制傳輸,每種傳輸類型的傳輸速度、可靠性以及應用范圍都不同。控制傳輸可靠性是最高的,但速度最慢;同步傳輸速度快,滿足實時性,但可靠性低。在具體應用中,端點傳輸類型可根據傳輸速度和可靠性選擇。
在USB通信協議中,主機取得絕對主動權利,設備只能是“聽命令行事”,通過一定的命令格式(設備請求)完成通信。USB設備請求包括標準請求、廠商請求和設備類請求。設備的枚舉是標準請求命令完成的;廠商請求是用戶定義的請求;設備類請求是特定的USB設備類發出的請求,例如海量儲存類、打印機類和HID(人機接口)類。固件編程中設備請求必須遵循一定的格式,包括請求類型、設備請求、值、索引和長度。
4.4.2 USB芯片選擇
USB的傳輸速度可分為低速(1.5Mbps)、全速(12Mbps)和高速(480Mb/s),按傳輸速度來分,供選擇的USB芯片類型主要有:低速(1.5Mbps)和全速(12Mbps),可選擇Philips公司的PDIUSBD12和Cypress公司的EZ-USB2100系列以及國產的CH372芯片; 高速(480Mbps)可選Philips公司的ISP1581和Cypress公司的USB接口芯片CY7C68013。
本次系統要傳輸的速率比較少,可以所以選擇全速的USB接口芯片,由于國產的芯片已經有所好轉,再加上資料比較齊全,這次系統設計所選擇的USB接口芯片是國產芯片CH372。
芯片介紹:
CH372是南京沁恒電子有限公司生產的新型USB接口芯片,具有8位數據總線和讀、寫、片選控制線以及中斷輸出,可以方便地掛接到單片機/DSP/MCU/MPU等控制器的系統總線上;它屏蔽了USB通信協議,用戶如果沒有涉及到底層開放,那么只要了解芯片的普通用法就可以快速的設計USB設備。利用CH372進行USB設備的通信設計可以如下的方框圖4.9
圖4.9 CH372和單片機框架連接
下面給出CH372的引腳圖(圖4.10)及部分命令:
圖4.10 CH372的管腳
CH372芯片占用兩個地址位,當A0 引腳為高電平時選擇命令端口,可以寫入命令;當A0引腳為低電平時選擇數據端口,可以讀寫數據。單片機通過8 位并行口對CH372 芯片進行讀寫,所有操作都是由一個命令碼、若干個輸入數據和若干個輸出數據組成,部分命令不需要輸入數據,部分命令沒有輸出數據。命令操作步驟如下:
①在A0=1 時向命令端口寫入命令代碼;
②如果該命令具有輸入數據,則在A0=0 時依次寫入輸入數據,每次一個字節;
③如果該命令具有輸出數據,則在A0=0 時依次讀取輸出數據,每次一個字節;
④命令完成,可以暫停或者轉到①繼續執行下一個命令。
CH372的命令如表4.5:
表 4.5 CH372命令
代碼 | 命令名稱 | 輸入數據 | 輸出數據 | 命令用途 |
05H | RESET_ALL | | (等40mS) | 執行硬件復位 |
06H | CHECK_EXIST | 任意數據 | 按位取反 | 測試工作狀態 |
12H | SET_USB_ID | VID 字節 PID 字節 | | 設置USB的廠商VID和PID |
15H | SET_USB_MODE | 模式代碼 | (等20uS) 操作狀態 | 設置USB工作模式 |
22H | GET_STATUS | | 中斷狀態 | 獲取中斷狀態并取消請求 |
28H | RD_USB_DATA | | | 從當前USB中斷的端點緩沖區讀取數據塊并釋放當前緩沖區 |
2AH | WR_USB_DATA5 | | | 向USB端點1的上傳緩沖區寫入數據塊 |
2BH | WR_USB_DATA7 | | | 向USB端點2的上傳緩沖區寫入數據塊 |
4.4.3 USB設備端的接口設計
CH372芯片在本地端提供了通用的被動并行接口,包括:8位雙向數據總線D7~D0、讀選通輸入引腳RD#、寫選通輸入引腳WR#、片選輸入引腳CS#、中斷輸出引腳INT#以及地址輸入引腳A0。通過被動并行接口,CH372 芯片可以很方便地掛接到各種8位單片機、DSP、MCU 的系統總線上,并且可以與多個外圍器件共存。CH372芯片的RD#和WR#可以分別連接到單片機的讀選通輸出引腳和寫選通輸出引腳。CS#由地址譯碼電路驅動,用于當單片機具有多個外圍器件時進行設備選擇。INT#輸出的中斷請求是低電平有效,可以連接到單片機的中斷輸入引腳或者普通I/O 引腳,單片機可以使用中斷方式或者查詢方式獲知中斷請求。當WR#為高電平并且CS#和RD#及A0 都為低電平時,CH372 中的數據通過D7~D0輸出;當RD#為高電平并且CS#和WR#及A0 都為低電平時,D7~D0上的數據被寫入CH372 芯片中;當RD#為高電平并且CS#和WR#都為低電平而A1 為高電平時,D7~D0 上的數據被作為命令碼寫入CH372芯片中。CH372 芯片的VD+和VD-引腳應該直接連接到USB 總線上。如果為了芯片安全而串接保險電阻或者電感,那么交直流等效串聯電阻應該在5Ω之內。
USB定義了四種傳輸類型:控制傳輸、快傳輸、中斷傳輸和同步傳輸。南京沁恒公司的USB接口芯片CH372支持控制傳輸、批量傳輸、中斷傳輸。CH372主要有兩種數據流傳輸方式:單向數據流方式和請求應答方式。其中請求應答方式步驟如下:
① 計算機應用層按事先約定的格式將數據請求發送給CH372芯片;
② CH372 芯片以中斷方式通知單片機;
③ 單片機進入中斷服務程序,獲取CH372的中斷狀態并分析;
④ 如果是上傳,則釋放當前USB 緩沖區,然后退出中斷程序;
⑤ 如果是下傳,則從數據下傳緩沖區中讀取數據塊;
⑥ 分析接收到的數據塊,準備應答數據,也可以先退出中斷程序再處理;
⑦ 單片機將應答數據寫入批量端點的上傳緩沖區中,然后退出中斷程序;
⑧ CH372 芯片將應答數據返回給計算機;
⑨ 計算機應用層接收到應答數據。
這種傳輸方式是必需要有計算機斷發出響應才可以進行的。在本次系統設計中,可以通過向計算機發出命令,下位機根據命令來進行各種操作,包括設計報警溫度,采集溫度等。
由于系統不需要那么多I/O口,所以本次系統設計的單片機端不需要擴展,直接用端片機的I/O端口,值得注意的是MCU不擴展,那么P0只能口只能作為I/O口使用,而不能作為數據/地址端口復用。這一點必須注意,而P0口做普通I/O使用必需要加上拉電阻1K到10K左右。否則系統將無法運行,這點特別提醒要注意的地方。
最終CH372與單片機AT89C51之間的連接圖,如下圖4.11

4.11 CH372和89C51的連接圖
圖中P2作為CH372芯片8位雙向數據總線通信端口來使用。P1和P0端口作為普通的I/O口,USB 總線包括一對5V 電源線和一對(D+、D-)數據信號線。通常,+5V 電源線是紅色,接地線是黑色,D+信號線是綠色,D-信號線是白色。USB 總線提供的電源電流最大可以達到500mA,一般情況下,低功耗的USB 產品可以直接使用USB 總線提供的5V 電源。如果USB 產品通過其它供電方式提供常備電源,那么CH372 應該與單片機一起使用該常備電源并且斷開USB總線的電源;如果需要同時使用USB 總線的電源,那么可以通過阻值約為1Ω的電阻R1 連接USB 總線的5V 電源線與USB 產品的5V 常備電源,并且兩者的接地線直接相連接。
CH372 的CS#固定為低電平,一直處于片選狀態,在單片機程序中,可以控制各個I/O引腳模擬并口時序與CH372 進行數據交換。比如控制P05、P06、P07來讀、寫命令。
圖4.11中,可選電阻R2 用于在電源斷電后將電解電容C5 中的電能及時釋放掉,使VCC 及時下降到0V,確保在下次通電時CH372 能夠可靠地上電復位。電容C3 用于CH372 內部電源節點退耦,C3 是容量為0.01μF 的獨石或高頻瓷片電容,如果對EMI 沒有要求那么可以省掉C3。電容C4和C5用于外部電源退耦,C4 是容量為0.1μF的獨石或高頻瓷片電容。晶體X1、電容C1 和C2 用于CH372的時鐘振蕩電路。X1的頻率是12MHz,C1和C2是容量為15pF-30pF 的獨石或高頻瓷片電容。
本次系統設計的USB接口硬件設計已經完成。而且應用部分的硬件設計也已經完成,下節將給出整體硬件設計的電路圖。
4.5 系統硬件整體實現
下位機的應用部分是DS18B20,DS18B20采集到溫度信號,并轉換成數字信號然后輸出到單片機AT89C51,單片機對數字信號進行處理,然后將處理的數據通過USB接口芯片傳到上位機的USB設備驅動程序,上位機的主USB控制驅動程序接受來自USB設備驅動程序的數據,在計算機端的應用軟件進行各種操作。反之,計算機的控制命令通過USB總線接口,把控制命令通過USB芯片傳到單片機,由于本系統已經對計算機程序的命令編碼過,所以單片機接受來自上位機命令,對其進行判斷,從而做出不同的響應。
硬件電路整體實現電路圖在附件中給出。
5 系統軟件設計
本系統進行軟件設計包括下位機軟件設計和上位機軟件設計,下位機軟件設計可以使用匯編語言和單片機C語言,上位機設計可以采用的很多計算機高級語言,比如VC++、Delphi、C++ builder等,在這里選擇C++ builder來編寫上位機程序。至于下位機程序,主要有匯編語言、PL/M語言和C語言。匯編語言有執行效率高、速度快、與硬件結合緊密等特點,尤其在I/O端口管理時,使用匯編語言有快捷、直觀的優點。但是使用匯編語言相對于高級語言,比如單片機C語言來講,難度要大很多,而且匯編語言的呈現可讀性低、開放性差。所以下位機的程序設計選擇單片機C語言。下面簡單介紹本次軟件設計的編程工具。
5.1 軟件設計開發工具
Keil C51是單片機的編寫軟件,是美國Keil Software公司出品的51系列兼容單片機C語言軟件開發系統,與匯編相比,C語言在功能上、結構性、可讀性、可維護性上有明顯的優勢,因而易學易用。用過匯編語言后再使用C來開發,體會更加深刻。 Keil C51軟件提供豐富的庫函數和功能強大的集成開發調試工具,全Windows界面。另外重要的一點,只要看一下編譯后生成的匯編代碼,就能體會到Keil C51生成的目標代碼效率非常之高,多數語句生成的匯編代碼很緊湊,容易理解。在開發大型軟件時更能體現高級語言的優勢。
C++ builder是Inprise公司1998 年推出的,面向對象的32位Windows程序設計開放工具,C++ builder不僅繼承了Delphi使用簡便、功能強大、效率高等特點,而且它還結合了C++語言的所有優點。 C++ builder可以說是至今為止功能最強、最簡單易學的Windows開發工具之一。C++ builder 6具有非常友好的集成開發環境,提供一百多個VCL組件,使開發人員不需要太多的時間編碼,就能實現很多復雜的功能。它的編譯器 能夠自動列出VCL組件的屬性和方法供程序員選擇,而不必手工輸入復雜的代碼。正式因為這些優點,所以本次系統設計選擇 C++ builder作為上位機軟件設計的開發工具。
5.2 系統軟件設計
系統要對溫度進行采集,首先必須利用上位機對下位機(單片機)發出命令,單片機根據接收到的命令,根據預先的規則對不同的命令做出不同的處理。然后把處理結果發回上位機,上位機接收到溫度數據后,根據溫度數據畫出數據采集圖像。這就是系統要實現功能,根據這一要求,設計出系統的軟件。
系統整體模塊流程圖如圖5.1
圖5.1 系統整體模塊圖
下面分別設計下位機和上位機的程序流程圖。
5.2.1下位機的軟件設計
單片機端的應用程序主要實現的功能就是對DS18B20進行采集溫度,把采集到的溫度通過USB接口芯片上傳到計算機端的應用程序。
下位機的程序設計流程圖5.2


圖5.2 下位機的程序設計流程圖
下位機的程序流程圖中包括單片機和DS18B20和單片機的通信流程圖,以及單片機和USB設備接口芯片的通信流程圖。
其中DS18B20和單片機的通信流程圖如下圖5.3
這里是單片機如何根據DS18B20的特性來控制它,進行溫度轉換,并讀取溫度。把溫度數據保存在單片機端。

圖5.3 DS18B20的程序流程圖
單片機先初始化DS18B20溫度傳感器,對其復位,然后按DS18B20的時序來讀寫命令,DS18B20根據命令進行操作,單片機和DS18B20的通信過程主要為:單片機對DS18B20復位,跳過讀寫系列號操作(送0xCC命令到DS18B20),啟動溫度轉換,再次復位,送讀溫度命令0xBE,讀出溫度。這就是單片機和DS18B20的通信過程,將得到的溫度單片機在進行處理,把溫度數據傳到上位機。上位機實時顯示溫度值。為了便于說明DS18B20和單片機間的通信過程,下面給出讀出DS18B20溫度的程序:
unsigned int readtemperature(void) //讀溫度
{ unit8 a=0,b=0;
unit8 c,d;
unsigned int t=0;
float tt=0;
c=DS18B20_RESET();
write_byte(0xCC); // 跳過讀序號列號的操作
write_byte(0x44); // 啟動溫度轉換
d=DS18B20_RESET();
write_byte(0xCC); //跳過讀序號列號的操作
write_byte(0xBE); //讀取溫度寄存器等前兩個就是溫度
a=read_byte();
b=read_byte();
t=b;
t<<=8;
t=t|a;
return(t); }
單片機讀出溫度后,接下來的工作就是單片機和CH372芯片的通信。CH372已經屏蔽了USB通訊協議,所以只要知道CH372單片機之間的通信過程,就很方便的寫出它們的通信流程圖。圖5.4是CH372和89C51的程序流程圖。
(1)單片機向CH372上傳數據 (2) 下載數據到單片機
圖5.4 單片機和CH372的通信流程圖
上傳數據是通過查詢DS18B2是否轉換完,轉換完,則上傳,否則等待;上位機的應用軟件向下位機發送數據,CH372的端點接受器接受來著來自計算機的數據,通過中斷來通知單片機,單片機開始接受收據,并進行處理。
5.2.2 上位機軟件設計
上位機接受來自下位機的數據,根據數據進行操作,實現各種功能。有一點必須要注意的是,要利用動態連接庫的知識,才能打開USB設備,從而進行通信,所以在編寫應用軟件前,一定要了解C++ builder 動態連接庫的使用。由于CH372驅動程序提供的動態連接庫是用VC編寫的,C++ builder要建立起PC機和CH372的通信,必須要使用VC編寫的動態連接庫,但C++ builder不能直接使用VC編寫的動態連接庫。關于這點,在調試部分將做更多說明,這里只介紹上位機軟件整體設計方面的內容。
下面給出上位機的程序流程圖5.5:

圖5.5 上位機流程圖
這就是上位機軟件的設計思想,具體實現在程序中有將進一步說明。
6 系統調試
前面幾章節,已經對整個系統進行了設計,可是對于硬件來說,這只是完成一部分的工作 ,硬件系統真正的挑戰在于調試,很多情況下,電路圖是在理論是正確的,可以實現的,可是真正的到了實際中,會出現很多情況,但不管怎么樣,重要的一點是結合設計理論知識來分析系統,逐步調試系統。
6.1 硬件調試
系統硬件電路并不是很復雜,但調試中必需要注意以下幾點,否則將會出現系統工作不穩定情況,嚴重的話,將CH372芯片燒壞,這是電路特別需要的地方。下面給出硬件調式中碰到的問題,并提出如何解決。
(1)CH372的WR、RD、A0信號線是由單片機89C51的P0口提供的,P0口作為I/O口使用,必須要加上拉電阻,很多資料寫著加1K-10K的上拉電阻,但這對于本系統是不正確的。
實際上在本系統中P0口的上拉F范圍是30K-125K,最好選擇100K的上拉電阻。因為如果只是10K,那么流入CH372的芯片的電流為500uA,遠遠超過了芯片規定的最高電流160uA,這樣肯定會燒壞芯片。所以這個上拉電阻的范圍是一定要根據芯片的參數來設計,而不能從其他資料上說的選擇1K-10K。這點要特別注意。
(2)在CH372的濾波電容0.1uF中,并聯一個5K-10K的電阻。這樣的作用是系統在斷電時,把電容中的電能及時的釋放掉,使VCC及時的下降到0V,確保電路下使用通電時CH372能夠可上電復位。
如果不加這個電阻,不少情況下,一旦下位機通電,芯片很久才顯示出來,上位機需要較久時間來確認接口芯片,所以應該加5K-10K的電阻,這是系統的一個改進。
(3)共用晶振問題。USB接口芯片CH372和單片機都要需要晶振才能工作,但CH372的晶振必須是12M。單片機可以和CH372共用同一個晶振,但必需是12M。這樣的優點是可以節約材料,但是不便于PCB排版,還有如果有芯片壞了,也不容易覺察出是不是CH372壞,還是單片機壞了,所以這里考慮單片機和CH372不能共用晶振。方便硬件調試。
(4)DS18B20的接法。DS18B20連接到單片機的接法很簡單,這里提出需要注意的一點是,DS18B20用在P11做通信端口,但必須接4.7K的上拉電阻。P1口是I/O口用驅動外部電路時,一般都不用接上拉電阻的,但這里需要上拉電阻。這一點也就要注意。否則DS18B20工作不穩定,有可能有干擾。
本次系統調試硬件主要出現的問題就是上面所提到的,只要根據理論來分析,綜合實際應用,便可以做出正確的硬件,這樣為后期軟件調試減少很多麻煩,否則,后期軟件調試的時候,出現問題有可能是軟件問題,或者是硬件問題,混合起來處理會很不方便,需花很多時間。
6.2 軟件調試
本系統的軟件調試主要有下位機端的軟件調試和上位機端的軟件調試。
6.2.1 下位機的軟件調試
下位機的軟件調試主要分兩部分:單片機和CH372Z時間的通信、單片機與溫度傳感器DS18B20的通信。
(1)單片機和CH372之間的通信
這一部分是必須首先要調試出來的, 因為要依靠這一部分通過計算機才能顯示出單片機和溫度傳感器之間的通信。
硬件部分利用具有上拉電阻的P0口作為CH372的WR、RD、A0線,所以通過軟件控制P0口信號來達到控制CH372的讀寫命令和讀寫數據。只要注意CH372的讀寫時間要求就可以很快實現。單片機的P2口是作為CH372的數據口,利用它來發送和接受CH372的數據。
這里特別強調的一點是CH372的初始化程序,如果初始化不成功,電腦無法識別硬件,后期將無法進行。所以初始化程序必須注意的一點。下面給出CH372的初始化程序。
#define VID 0x8888 //廠商ID
#difine PID 0x9999 //產品ID
CH372_Init() //初始化CH372
{ int i;
CH372_WR_CMD_PORT(CMD_SET_USB_ID); //設置USB設備VID和PID
CH372_WR_DATA_PORT(VID&0xff); //寫入廠商ID的低字節
CH372_WR_DATA_PORT(VID>>8); //寫入廠商ID的高字節
CH372_WR_DATA_PORT(PID&0xff); //寫入產品ID的低字節
CH372_WR_DATA_PORT(PID>>8); //寫入產品ID的高字節
CH372_WR_CMD_PORT(CMD_SET_USB_MODE); //設置CH372工作模式
CH372_WR_DATA_PORT(2);//工作模式2
for( i=200;i>0;i--) //20us時間復位
if (CH372_RD_DATA_PORT==CMD_RET_SUCCESS) //復位成功
break;
}
另外,CH372最大可以傳送64個字節,每一個讀寫函數每一次操作的只能一個字節,要讀寫多個字節,這里使用的是循環的方法。
CH372初始化成功后,下位機連接到PC機上,安裝了CH372驅動程序的PC機就可以識別硬件。完成這部分工作之后先進入上為機和下位機聯合的調試,然后再調試DS18B20和DS18B20之間的通信。
(2)單片機和DS18B20之間的通信
單片機要根據DS18B20的時序要求和讀寫要求來讀取溫度數據。由于DS18B20是一線式數字溫度傳感器,對時序要求比較高,延時程序誤差大,則不能讀出數據。還有要按照訪問DS18B20的順序來操作。這里再次說明訪問DS18B20的順序如下:①初始化;②ROM命令;③DS18B20的函數命令。
總之,這部分編程主要注意的就是延時程序的準確性。并按照DS18B20的操作順序便可以把溫度數字傳到單片機。
6.2.2 上位機的軟件調試
上位機的編程工具是C++ builder,主要是VCL控件的使用。主要有兩個模塊組成:通信模塊和圖像處理模塊。其中通信模塊負責處理上位機和下位機之間的通信,圖像處理模塊負責溫度采集圖像。
對于通信模塊,主要是調用CH372的動態連接庫,但由于廠家的CH372動態連接庫是使用Visual C++制作的,C++ builder 不能直接運用,否則將會有出錯信息。所以要經過一定的處理。
處理這一問題主要有兩種方法:顯式連接法和使用C++Builder中提供的導入庫生成工具。由于顯示連接對于在系統中多次調用動態連接庫的多個函數很不方便,這里選擇使用C++Builder中提供的導入庫生成工具。步驟如下:
(1)用C++Builder提供的implib.exe工具重新生成該動態庫(xxx.dll)的導入庫(xxx.lib)。命令如下:
implib ch372.lib ch372.dll。
ch372.dll為已有動態庫,ch372.lib為要生成的導入庫。由此生成的導入庫ch372.lib格式與C++Builder開發平臺是相容的;
(2)在動態庫的頭文件ch372.h中,對其輸出函數重新說明,語句如下:
extern _stdcall HANDLE WINAPI CH375OpenDevice(
ULON GiIndex );// 指定CH372
設備序號,0對應第一個設備
(3)然后采用隱式鏈接法,將重新生成的導入庫(ch372.lib)和重新說明的頭文件(ch372.h)加入到C++Builder應用程序的工程項目中,進行編譯和連接。
對于圖像處理模塊,應用軟件根據接受到的溫度,利用C++ builder在窗體上畫出動態連接圖,主要采用窗體Canvas屬性來實現。
6.2.3 上位機和下位機聯機調試
下位機(單片機)對CH372初始化成功之后,上位機就能夠識別下位機設備(USB設備),上位機調試部分也初步完成,那就進入系統整體調試。
整體調試主要分三步:
(1)測試單片機和PC機能否正常通信;
這里利用的方法如下:在下位機的程序部分設計一個往上位機發送的字符數組,比如“1214”,然后在PC機上進行操作,看是否能成功接受數組,如果能,則說明單片機可以往上位機發生數據,不行則修改上位機和下位機相關部分的程序。接下來PC往下位機發送數據,如果下位機能夠成功返回相同的數據到PC機上,則說明上為機和下位之間的通信已經成功。
(2)測試單片機能否對DS18B20正常的讀取溫度;
完成上面一步才能進行這一步調試,前面已經提到,DS18B20的對時序要求很高,一定要準確,并且按DS18B20的順序來進行操作,在硬件電路原理沒有錯的情況下,如果溫度讀起不正確,或者無法讀取溫度,只能是出現兩種錯誤,一是時序問題,沒有按照DS18B20的時序精度來對其進行操作,二是單片機訪問DS18B20的順序問題,單片機沒有嚴格按照訪問DS18B20的順序對起發送命令,單片機訪問DS18B20的順序這里再次聲明:初始化、ROM命令、DS18B20的函數命令。
這一部分出現的兩個問題,大部分情況下出現的是時序問題,所以特別注意單片機對于DS18B20的精確延時。
(3)采集溫度;
各部分通信正常后,便可以采集數據并處理。因為系統采集過程是上位機每發送一條采集命令,下位機就上傳一次溫度數據,所以這一步主要調試的是上位機要間隔多長時間定時向下位機發送采集命令,使系統能快速采集溫度并上傳,并防止發生讀寫等沖突。
6.3 系統性能指標
系統性能指標主要是:
(1)測量溫度誤差小于或者等于0.5℃;
(2)溫度顯示分辨率為0.0625℃;
(3)測量溫度范圍在0℃~70℃;
(4)具有控制報警功能。
7 系統的簡單操作說明
若用戶使用本系統,將可以對其進行以下的簡單操作:
(1)首先打開USB設備;在上位機軟件上打開USB設備,建立起上位機和下位機的通信機制。使用本系統都首先要打開USB設備。
(2)對計算機端的應用軟件進行溫度讀取操作,將立即得到該環境溫度的實時溫度;
(3)可以在上位機上輸入報警極限溫度,上位機把極限溫度發送到下位機,并且保留在上位機,一旦超過,則報警;
(4)上位機應用軟件提供實時使用幫助功能。如果用戶不知道怎么樣使用軟件,則可以通過幫助,便能快速使用本系統軟件。
8 總結
在此次畢業設計的開發過程中,感覺C 語言(單片機C語言和C++)的熟練程度是項目開發的關鍵。許多問題其實原理上都是非常成熟的東西,從一些資料上都可以找到。在自己的題目中,要做的也就是將原理表述的溫度采集后傳到單片機。因此,開發工作本身沒有多少創造性,沒有多少高深的知識,要具備的僅是對C 語言的熟練,以及學會解決遇到的問題。
做完這次畢業設計的另一個體會就是對于硬件的設計不能硬搬書上或者是相關材料上的。往往由于系統硬件體系不同,所以需要一定的變通,書和材料只能起到提示參考的作用。比如本系統單片機的上拉電阻,書上都說一般用的是1K-10K,可是實際在這個系統中是不適用的,如果用1K-10K,由于進入CH372的電流段過大,這個沖擊電流會燒壞芯片。而關于芯片的參數很多情況下,設計人員并不在乎,所以往往只憑書上的知識來設計電路,忽略了細節,這就是本次系統設計中存在的問題。
本系統設計采用的傳感器DS18B20對延時要求很高,往往在調試的過程中,溫度無法顯示,檢查硬件電路和軟件問題都沒有發現出問題,當時首先要考慮的是溫度傳感器DS18B20芯片已經壞了,經過多次分析,覺得芯片才第一次使用,壞的可能性很小,而一線溫度傳感器對時序要求很高,所以溫度無法讀起,首先考慮到單片機無法正確按照DS18B20的時序讀取溫度。最后確實讀到了溫度數據。單片機的延時程序一般對系統來說,要求不是很精確,可是本次設計卻要求非常嚴格,這點必須注意。
之外,上位機應用軟件的編寫工具是C++ builder , 國內很多資料都是介紹的都是基本控件的使用,涉及到畫圖的資料比較少,特別是畫動態圖象,本系統只能是另做窗體來畫出系統的溫度采集圖像。而且C ++的動態連接問題并不是書上介紹的那樣,真正操作起來碰到了不少問題,連接錯誤等等。
謝 辭
首先,我要感謝我的導師龍老師,在這次畢業設計的整個過程中,她給與我極大的幫助。
經過這次畢業設計,使我真正的運用了大學里學到的很多理論知識,應用到實際系統的設計中,這次畢業設計可以說是一個實戰,一個理論與實踐的有機結合,這次畢業設計歷程3個月,通過3個月的時間了,我不斷的學習新知識,掌握新東西,并且即學即用,龍老師在這里畢業設計過程中就我碰到的問題給以正確有效的引導,使我能夠順利的做完畢業時間,她治學嚴謹、知識淵博、態度熱情認真,給我留下了深刻的印象,所以我在這里非常的感謝我的導師老老師,也感謝學校給以我這樣的一次鍛煉的機會,感謝本次畢業設計中給以我幫助的所有的老師、同學!
參考文獻
[1] 張培仁.基于C語言編程--MS-51單片機用力和應用[M] .清華大學出版社 .2003.1
[2] 席衛文.C++ builder 6程序設計與實例[M] .冶金工業出版社.2003.6
[3] 余明興.Borland C++ Builder 5 實例精講[M] . 清華大學出版社.2001.6
[4] 雷曉平.單片機及其應用[M].電子可見大學出版社. 2003.3
[5] 陳啟美. 計算機USB接口技術[M] 南京大學出版社. 2003.1
[6] 徐科 楊朝霖.C++ builder實用技術與經典案例[M].清華大學出版社. 2002.11
[7] 王成儒 李英偉.USB2.0原理與工程開發[M].國防工業出版社.2002.3
[8] 沙占友 葛家怡.集成化智能傳感器原理與應用[M].電子工業出版社.2004.1
[9] 劉明業.集成電路/計算機硬件描述語言VHDL高等教程[M].清華大學出版社.2003.6
[10] Universal Serial Bus Specification Revision 1.1. Compaq Computer Corporation,Intel
Corporation,Microsoft Corporation,NEC Corporation: September 23, 1998.
附 錄
1.protel原理圖

1PCB圖

2本系統部分程序
(1)下位機部分程序圖
#include <reg51.h>
#include <string.h>
#include "ch372.h"
#define uchar unsigned char
#define uint unsigned int
#define VID 0x8888
#define PID 0x9999
#define USBCMD_WR 100 //上傳數據
#define USBCMD_RD 101 //設置報警溫度
#define DS18B20 102 //檢測是否有溫度傳感器
#define CH375PORT P2
sbit CH375_WR=P0^5; //控制CH372的寫數據信號
sbit CH375_RD=P0^6; //控制CH372的讀數據信號
sbit CH375_A0=P0^7; //控制CH372的寫命令信號
data uchar buffer[64];
data uchar USBCMD;
bit UsbRecvOk;
sbit LED0=P1^1;
sbit LED1=P1^2;
sbit DQ=P1^0;
static float bwendu;
//DS18B20的程序
void delaym(uchar time) //延時為(time*2+3)us
{
for(;time>0;time--);
}
uchar read_byte(void)
{uchar i,value=0;
for(i=0;i<8;i++)
{value>>=1;
DQ=0; //將總線DQ拉低開始讀時序
DQ=1; //釋放DQ;
delaym(1);
if(DQ) value|=0x80;
delaym(6); //讀取時間間隙,要大于1us
}
return (value);
}
void write_byte(uchar value)
{ uchar i;
for(i=0;i<8;i++)
{DQ=0;
DQ=value&0x01; //每次寫1位,通過val右移得到
delaym(5); //延時34us(15~60us采樣時間)
DQ=1;
value>>=1;
}
delaym(5); //2次寫的時間間隙要大于1us
}
uchar DS18B20_RESET(void)
{uchar da;
DQ=0;
delaym(29); //保持DQ低480us
DQ=1;
delaym(3); //等待15~60us
da=DQ;
delaym(25);
return (da);//有芯片應答da=0,無則da=1
}
unsigned int readtemperature(void) //讀溫度
{ uchar a=0,b=0; // c為溫度的小數部分?
unsigned int t=0;
DS18B20_RESET();
write_byte(0xCC); // 跳過讀序號列號的操作
write_byte(0x44); // 啟動溫度轉換
DS18B20_RESET();
write_byte(0xCC); //跳過讀序號列號的操作
write_byte(0xBE); //讀取溫度寄存器等(共可讀9個寄存器) 前兩個就是溫度
a=read_byte();
b=read_byte();
t=b;
t<<=8;
t=t|a;
return(t);
}
void Delayms(uint m)
{
uint i;
while(m-->0)
for (i=0; i<500; i++);
}
void CH375_CMD(uchar x) //向CH372寫命令
{
CH375_A0=1;
CH375PORT=x;
CH375_WR=0;
CH375_WR=1;
}
void CH375_DAT_WR(uchar x) //向CH372寫數據
{
CH375_A0=0;
CH375PORT=x;
CH375_WR=0;
CH375_WR=1;
}
uchar CH375_DAT_RD() //從CH372讀數據
{
uchar x;
CH375_A0=0;
CH375PORT=0xff;
CH375_RD=0;
x=CH375PORT;
CH375_RD=1;
return x;
}
void CH375_Init( ) //CH372初始化
{
CH375_CMD(CMD_SET_USB_ID); //寫 VID和PID
CH375_DAT_WR(VID&0xff);
CH375_DAT_WR(VID>>8);
CH375_DAT_WR(PID&0xff);
CH375_DAT_WR(PID>>8);
CH375_CMD(CMD_SET_USB_MODE);
CH375_DAT_WR(2);
}
void LoadUpData( uchar data *Buf, uchar Len ) //上傳數據
{
uchar i;
CH375_CMD(CMD_WR_USB_DATA7);
CH375_DAT_WR(Len);
for ( i=0; i<Len; i++ )
CH375_DAT_WR(Buf[i]); /* 加載數據 */
}
void CH375Interrupt( ) interrupt 0 using 1
{
unsigned char Status;
unsigned char length, i;
EX0 = 0;
CH375_CMD(CMD_GET_STATUS);
Status = CH375_DAT_RD();
switch(Status)
{
case USB_INT_EP2_OUT: /* 批量端點下傳成功 */
CH375_CMD(CMD_RD_USB_DATA);
length = CH375_DAT_RD();
if(length>64) length=64;
for(i=0; i<length; i++)
buffer[i] = CH375_DAT_RD();
LED1=0;
UsbRecvOk=1;
USBCMD=buffer[0];
break;
case USB_INT_EP2_IN:
LED1=0;
CH375_CMD(CMD_UNLOCK_USB);
break;
case USB_INT_EP1_IN:
CH375_CMD(CMD_UNLOCK_USB);
break;
}
EX0 = 1;
}
void main( )
{ uint wendu;
float tt;
uchar a,b;
uchar reset; //DS18B20復位成功
uint k;
EA=1; EX0 = 1;
CH375_CMD(CMD_RESET_ALL);
Delayms(50);
CH375_Init();
UsbRecvOk=0;
LED0=1;
LED1=0;
while(1)
{ k++;
if(UsbRecvOk)
{
UsbRecvOk=0;
switch(USBCMD)
{
case USBCMD_RD:
wendu=readtemperature(); //讀溫度
b=wendu&0x0f;
a=(wendu>>4)&0xff;
buffer[0]=a; //溫度整數部分
buffer[1]=b; //溫度小數部分
LoadUpData(buffer,3); //上傳溫度
tt=a+b*0.0625;
break;
case USBCMD_WR: //設置報警溫度
bwendu=buffer[1]+buffer[2]*0.1;
break;
case DS18B20 : //檢測有無溫度傳感器
reset=DS18B20_RESET();
buffer[0]=reset;
LoadUpData(buffer,3);
}
}
if(tt>=bwendu)
LED0=0;
else
LED0=1;
}
}
(2)上位機部分程序:
//----------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//----------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
//----------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *Button1;
TButton *Button2;
TButton *Button3;
TEdit *Edit1;
TEdit *Edit2;
TButton *Button4;
TLabel *Label1;
TLabel *Label2;
TShape *Shape1;
TShape *Shape2;
TShape *Shape3;
TButton *Button5;
TTimer *Timer1;
TTimer *Timer2;
TShape *Shape4;
TLabel *Label3;
TLabel *Label4;
TLabel *Label5;
TLabel *Label6;
TLabel *Label7;
TLabel *Label8;
TLabel *Label9;
TLabel *Label10;
void __fastcall Button4Click(TObject *Sender);
void __fastcall Button1Click(TObject *Sender);
void __fastcall Button3Click(TObject *Sender);
void __fastcall Button2Click(TObject *Sender);
void __fastcall Button5Click(TObject *Sender);
void __fastcall Timer1Timer(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);
ULONG index ;
float baojing; //存放設置的報警溫度
unsigned char sent[64],jieshou[64];
unsigned long length;
unsigned int image[64];
unsigned int x1,y1; //坐標
};
//----------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//----------------------------------------------------------------------
#endif
//----------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#include "CH375DLL.H"
//----------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//----------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{ Form1->Timer1->Enabled=false; //關定時器
Form1->Timer2->Enabled=false;
baojing=50;
}
//----------------------------------------------------------------------
void __fastcall TForm1::Button4Click(TObject *Sender)
{
Form1->Close(); //關閉窗口
CH375CloseDevice(0);//關閉CH372
}
//----------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{ length=64;
if(LoadLibrary("CH375DLL.DLL")==NULL)
ShowMessage("無法加載DLL文件");
if ( CH375OpenDevice(0) == INVALID_HANDLE_VALUE )
ShowMessage("無法打開CH372") ;
else
ShowMessage("成功打開CH372");
sent[0]=102;
CH375WriteData(0,&sent,&length); //發送檢測溫度傳感器的命令
CH375ReadData(0,&jieshou,&length); //接受收據
if(jieshou[0])
ShowMessage("無法檢測到溫度傳感器");
Form1->Timer1->Enabled=false;
Form1->Label9->Canvas->Pen->Width=6; //畫系統坐標軸
Form1->Label9->Canvas->MoveTo(0,0); Form1->Label9->Canvas->LineTo(0,270);
Form1->Label9->Canvas->MoveTo(0,270); Form1->Label9->Canvas->LineTo(350,270);
Form1->Label9->Canvas->Pen->Width=1;
Form1->Label9->Canvas->Pen->Style=psDashDotDot;
Form1->Label9->Canvas->MoveTo(0,220); Form1->Label9->Canvas->LineTo(350,220);
Form1->Label9->Canvas->MoveTo(0,170); Form1->Label9->Canvas->LineTo(350,170);
Form1->Label9->Canvas->MoveTo(0,120); Form1->Label9->Canvas->LineTo(350,120);
Form1->Label9->Canvas->MoveTo(0,70);
Form1->Label9->Canvas->LineTo(350,70);
Form1->Label9->Canvas->MoveTo(0,20); Form1->Label9->Canvas->LineTo(350,20);
x1=0;
y1=30;
}
//----------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
Form1->Timer1->Enabled=true;
}
//----------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{ float j;
unsigned int t1,t2;
unsigned long length=64;
unsigned char value,i;
unsigned char n,m;
i=StrToInt(Edit1->GetTextLen());
if(i==0)
ShowMessage("請輸入數據");
else
j=StrToFloat(Edit1->Text);
if(j>50)
value=Application->MessageBox(" 你設置的報警溫度已經超過上限溫度:50", "information", 5);
switch(value)
{ case 4: Edit1->Text=InputBox("溫度","請輸入報警溫度","");
break;
case 2: break;
}
j=StrToFloat(Edit1->Text);
baojing=j;
t1=(int)(j);
t2=(int)(j*10);
m=(char) t1; //整數部分
n=(char)(t2%10); //小數部分
sent[0]=101;
sent[1]=m;
sent[2]=n;
if(CH375WriteData(0,&sent,&length))
Form1->Shape1->Brush->Color=clTeal; //下傳成功
else ShowMessage("無法設置報警溫度");
}
//----------------------------------------------------------------------
void __fastcall TForm1::Button5Click(TObject *Sender)
{
Form1->Timer1->Enabled=false; //打開定時器
}
//----------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
unsigned char a,b,c,i;// a為溫度整數部分,b為溫度小數部分
unsigned long len=64;
float wendu;
sent[0]=101;
CH375WriteData(0,&sent,&len) ;
if(CH375ReadData(0,&jieshou,&len))
{ a=jieshou[0]; //a溫度的整數部分
b=jieshou[1]; //b為小數部分
wendu=(float)(a+b*0.0625);
Edit2->Text=FloatToStr(wendu);
Form1->Shape2->Brush->Color=clRed;
if(wendu>=baojing)
Form1->Shape4->Brush->Color=clRed;
else
Form1->Shape4->Brush->Color=clWhite;
if(c>0.5)
a=a+1; //四舍五入;
Form1->Label9->Canvas->Pen->Width=2; //畫動態圖象
Form1->Label9->Canvas->Pen->Color=clRed;
Form1->Label9->Canvas->MoveTo(x1,270-y1*5);
Form1->Label9->Canvas->LineTo(x1+10,270-a*5);
y1=a;
x1=x1+10;
if(x1>350)
{ Form1->Label9->Refresh();
x1=0,y1=30;
Form1->Label9->Canvas->Pen->Color=clBlack; //重新畫坐標
Form1->Label9->Canvas->Pen->Width=6;
Form1->Label9->Canvas->MoveTo(0,0); Form1->Label9->Canvas->LineTo(0,270);
Form1->Label9->Canvas->MoveTo(0,270); Form1->Label9->Canvas->LineTo(350,270);
Form1->Label9->Canvas->Pen->Width=1;
Form1->Label9->Canvas->Pen->Style=psDashDotDot;
Form1->Label9->Canvas->MoveTo(0,220); Form1->Label9->Canvas->LineTo(350,220);
Form1->Label9->Canvas->MoveTo(0,170); Form1->Label9->Canvas->LineTo(350,170);
Form1->Label9->Canvas->MoveTo(0,120); Form1->Label9->Canvas->LineTo(350,120);
Form1->Label9->Canvas->MoveTo(0,70); Form1->Label9->Canvas->LineTo(350,70);
Form1->Label9->Canvas->MoveTo(0,20); Form1->Label9->Canvas->LineTo(350,20);}
}
else
{Form1->Timer1->Enabled=false;
ShowMessage("接收不成功"); }
}
//----------------------------------------------------------------------
3上位機應用軟件
