目錄
1. 理論學(xué)習(xí)
2.實操
2.1 頂層模塊
2.1.1 整體模塊框圖
2.1.2 頂層代碼
2.2?DHT11 控制模塊
2.2.1 模塊框圖
2.2.2 狀態(tài)轉(zhuǎn)換圖繪制
2.2.3?波形圖繪制
2.2.4?RTL代碼
2.3?上板驗證
3. 總結(jié)
1. 理論學(xué)習(xí)
DHT11簡介
? ? ? ?DHT11數(shù)字溫濕度傳感器是一款含有已校準數(shù)字信號輸出的溫濕度復(fù)合傳感器。它應(yīng)用專用的數(shù)字模塊采集技術(shù)和溫濕度傳感技術(shù),確保產(chǎn)品具有 具有成本低、抗干擾力強、長期穩(wěn)定等優(yōu)點。
?實物圖
? ? ?如上圖為DHT11的實物圖,有四個引腳,各引腳說明如下表格所示:
? ? ??DHT11的性能參數(shù):
? ? ? 濕度的量程為 5%RH—95%RH,誤差為±5%RH。溫度的量程為-20℃—60℃,誤差為±2℃。需要注意的是采樣周期要大于2S/次,也就是要大于 2S 才能讀取一次溫濕度。
? ?DHT11通信方式
1.單總線說明
? ? ? DHT11器件采用簡化的單總線通信。單總線即只有一根數(shù)據(jù)線,系統(tǒng)中的數(shù)據(jù)交換、控制均由單總線完成。設(shè)備(主機或從機)通過一個漏極開路或三態(tài)端口連至該數(shù)據(jù)線,以允許設(shè)備在不發(fā)送數(shù)據(jù)時能夠釋放總線。,F(xiàn)PGA與傳感器是主從結(jié)構(gòu)只有主機呼叫從機時,從機才能應(yīng)答,因此主機訪問器件都必須嚴格遵循單總線序列。
2.單總線傳送數(shù)據(jù)位定義
? ? ??主機與 DHT11 之間的通訊和同步采用單總線數(shù)據(jù)格式,一次傳送 40 位數(shù)據(jù),高位先出。
? ? ? ?數(shù)據(jù)格式為: 8bit 濕度整數(shù)數(shù)據(jù)+8bit 濕度小數(shù)數(shù)據(jù)+8bit 溫度整數(shù)數(shù)據(jù)+8bit 溫度小數(shù)數(shù)據(jù)+8bit 校驗位。(其中濕度小數(shù)部分為 0)
? ? ? ?校驗位數(shù)據(jù)定義: “8bit 濕度整數(shù)數(shù)據(jù)+8bit 濕度小數(shù)數(shù)據(jù)+8bit 溫度整數(shù)數(shù)據(jù)+8bit 溫度小數(shù)數(shù)據(jù)”8bit 校驗位等于所得結(jié)果的末 8 位。
? ? ? ? 如上圖所示為各個信號的定義圖。首先濕度的小數(shù)部分為 0,所以輸出的濕度為整數(shù)。而溫度數(shù)據(jù)是可以顯示小數(shù)部分的,如:接收到的 40位數(shù)據(jù)為: 00110101(濕度高八位) +00000000(濕度低八位) +00011000(溫度高八位)+00000100(溫度低八位) +010110001(校驗位)。通過計算: 00110101+00000000+00011000+00000100=01010001 與校驗位相同,結(jié)果正確。所以其濕度溫度分別為:
濕度=整數(shù)+小數(shù)=00110101+0=35H=53.0%RH
溫度=整數(shù)+小數(shù)=00011000+00000100=18H+04H=24℃+0.4℃=24.4℃。
? ? ? 需注意濕度是沒有負數(shù)的,但是溫度有。溫度的高八位與低八位的最高位都為符號位,不計入校驗和中。經(jīng)實際的測量發(fā)現(xiàn),目前 DHT11 溫度只能精確到0.1℃,我們應(yīng)用時用小數(shù)數(shù)據(jù)的低四位來表示溫度的小數(shù)值即可。
3. 數(shù)據(jù)時序圖
? ? ? ?主機發(fā)送一次開始信號后, DHT11 從低功耗模式轉(zhuǎn)換到高速模式,待主機發(fā)送的開始信號結(jié)束后, DHT11 發(fā)送響應(yīng)信號,送出 40bit 的數(shù)據(jù)。信號發(fā)送如下圖所示:
主機讀取 DHT11 溫濕度數(shù)據(jù)的步驟:
step1: DHT11準備狀態(tài)
? ? ?DHT11 上電后(DHT11 上電后要等待 1S 以越過不穩(wěn)定狀態(tài)在此期間不能發(fā)送任何指令),測試環(huán)境溫濕度數(shù)據(jù),并記錄數(shù)據(jù),同時 DHT11 的 DATA 數(shù)據(jù)線由上拉電阻拉高一直保持高電平;此時 DHT11 的單總線引腳處于輸入狀態(tài),時刻檢測外部信號。
step2: 主機發(fā)送開始信號,傳感器發(fā)出應(yīng)答信號
? ? ? 主機發(fā)送開始信號輸出低電平,持續(xù)時間不小于 18ms 且不超過 30ms。發(fā)送完之后釋放總線等待 DHT11 應(yīng)答。起始信號時序圖如下。
? ? ? DHT11 的 DATA 引腳檢測到外部信號有低電平時,等待外部信號低電平結(jié)束,延遲后DHT11 的 DATA 引腳輸出 83us 的低電平作為應(yīng)答信號,緊接著輸出 87us 的高電平通知外設(shè)準備接收數(shù)據(jù)。DHT11 響應(yīng)信號時序圖如下。
step3: 傳送數(shù)據(jù)位
40位數(shù)據(jù)位:
? ? ? ?由 DHT11 的 DATA 引腳輸出 40 位數(shù)據(jù), 主機根據(jù) I/O 電平的變化接收 40 位數(shù)據(jù),位數(shù)據(jù) “0” 的格式為: 54us 的低電平后 23~27us 的高電平,位數(shù)據(jù) “1” 的格式為: 54us 的低電平后68~74us 的高電平。位數(shù)據(jù)“0”、 “1”格式信號如下圖所示:
結(jié)束信號:
? ? ? ? DHT11 的 DATA 引腳輸出 40 位數(shù)據(jù)后,繼續(xù)輸出低電平 54us 后轉(zhuǎn)為輸入狀態(tài),由上拉電阻變?yōu)楦唠娖?,又開始再一次檢測,等待開始信號的到來。
2.實操
? ? ? ?實驗?zāi)繕耍嚎刂艱HT11,讀出濕度溫度數(shù)據(jù)并顯示在數(shù)碼管中,通過按鍵使?jié)穸群蜏囟仍跀?shù)碼管中切換顯示。
硬件資源:
? ? ??需使用到開發(fā)板上的按鍵、數(shù)碼管及 DHT11 接口,其中按鍵和數(shù)碼管硬件資源之前說過不再詳細說明。
?DHT11 接口圖
?DHT11 接口原理圖
? ? ? 其接線圖和原理圖如上圖所示,該接口是單總線接口,之前也接過DS18B20(溫度傳感器),兩者相似。
2.1 頂層模塊
2.1.1 整體模塊框圖
?DHT11 溫濕度顯示實驗整體框圖
? ? ? ?通過上圖可以看到,該工程共分四個模塊。各模塊簡介見下表。
? ? ? 其中按鍵消抖模塊和數(shù)碼管動態(tài)顯示模塊已經(jīng)有學(xué)習(xí)過,直接調(diào)用其模塊。重點是學(xué)習(xí)DHT11 控制模塊。
2.1.2 頂層代碼
`timescale 1ns/1ns
module dht11
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire key_in , //按鍵信號
inout wire dht11 , //數(shù)據(jù)總線
output wire [5:0] sel, //數(shù)碼管位選信號
output wire [7:0] seg //數(shù)碼管段選信號
);
wire [19:0] data_out; //需要顯示的數(shù)據(jù)
wire key_flag; //按鍵消抖后輸出信號
wire sign ; //輸出符號
dht11_ctrl dht11_ctrl_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.key_flag (key_flag ),
.dht11 (dht11 ),
.data_out (data_out ),
.sign (sign )
);
key_filter key_filter_inst
(
.sys_clk (sys_clk ) ,
.sys_rst_n (sys_rst_n) ,
.key_in (key_in ) ,
.key_flag (key_flag )
);
seg_dynamic seg_dynamic_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.data (data_out ), //數(shù)碼管要顯示的值
.point (6'b000010), //小數(shù)點顯示,高電平有效
.seg_en (1'b1 ), //數(shù)碼管使能信號,高電平有效
.sign (sign ), //符號位,高電平顯示負號
.sel (sel ), //數(shù)碼管位選信號
.seg (seg ) //數(shù)碼管段選信號
);
endmodule
2.2?DHT11 控制模塊
2.2.1 模塊框圖
? ? ? 模塊作用是將實時的環(huán)境濕度,溫度轉(zhuǎn)換出來,然后將轉(zhuǎn)換出來的溫濕度讀出來,通過按鍵切換顯示在數(shù)碼管上。
2.2.2 狀態(tài)轉(zhuǎn)換圖繪制
? ? ? ?根據(jù) DHT11 的數(shù)據(jù)時序圖可以畫出狀態(tài)跳轉(zhuǎn)圖來進一步了解如何控制 DHT11,以及讀出 DHT11 的濕度溫度值。
? ? ? ? ?各個狀態(tài)的時間以下表提供的范圍進行設(shè)計。
2.2.3?波形圖繪制
1. 產(chǎn)生單位時鐘為 1us 的時鐘
? ? ??在整個時序過程中無論是發(fā)送開始信號,還是“1”,“0”的時序組成我們都需要用到時間信號,而這些時間信號的最小單位為 us,所以我們先產(chǎn)生單位時鐘為 1us 的時鐘來作為 DHT11 的控制時鐘。如下波形圖所示,產(chǎn)生方法為分頻法。
2.? 提取dht11信號的上升沿和下降沿
? ? ? 直接對dht11信號延時兩拍。
3. 處理dht11信號
? ? ? ?dht11:單總線,其類型為輸入輸出型,定義為 wire 型變量,所以我們將借助dht11_out(總線輸入)和 dht11_en(總線使能信號)來給 dht11 賦值。由時序圖可知,只需要控制總線發(fā)送開始信號( 18ms 的低電平),其他狀態(tài)釋放即可。如圖中的dht11_out 與 dht11_en 信號所示,當 dht11_en 信號為 1 時 dht11 的值等于 dht11_out 的值(輸出),當 dht11_en 為 0 時釋放總線(輸入)。?
4. 各個狀態(tài)間的跳轉(zhuǎn)?
? ? ? ?state:狀態(tài)機的狀態(tài)。初始狀態(tài)為 S_WAIT_1S,上電后需要等待 1S 以越過不穩(wěn)定狀態(tài)。所以我們需要一個計數(shù)器(cnt_us)去進行產(chǎn)生 1S 的時間信號。當計數(shù)器計到 1S 時跳到下一個狀態(tài)。
? ? ? ?S_LOW_18MS:發(fā)送開始信號狀態(tài)。開始信號是由 18ms 的低電平組成,又需要用到計器,而且在發(fā)送時需要從 0 開始計數(shù)。當計數(shù)器計到 18ms 時(0-17999),狀態(tài)機跳轉(zhuǎn)計數(shù)器清零。
? ? ? ?S_DLY1:拉高等待狀態(tài)。等待 10us 后跳轉(zhuǎn)到下一狀態(tài),等待回應(yīng)信號的到來。
? ? ? ?S_REPLY: DHT11 回應(yīng)狀態(tài)(DHT11 響應(yīng)低電平 81~85us)。跳到這個狀態(tài)后計數(shù)器開始持續(xù)計數(shù),但是此無法判斷有沒有此時回應(yīng)信號開始發(fā)送。需要一個新的計數(shù)器( cnt_low)進行對響應(yīng)信號計數(shù),當檢測到 dht11 為低電平時,說明響應(yīng)信號開始發(fā)送了,我們就可以讓 cnt_low 計數(shù)器開始計數(shù)。同時 dht11 的上升沿到來時說明響應(yīng)信號發(fā)送完畢。響應(yīng)這個值協(xié)議 規(guī)定為81~85us是可以視情況而設(shè),將范圍改大如 70us 可使有些沒有嚴格按照協(xié)議發(fā)送的 DHT11 也可以兼容。
? ? ??若在這個狀態(tài)一直沒有檢測到響應(yīng)信號,則在 cnt_us 計到 1ms 時跳回S_LOW_18MS 狀態(tài),重新發(fā)送開始信號(這里應(yīng)該是要滿足最小測量時間2s左右的特點),波形圖如上圖所示。
? ? ? S_DLY2: DHT11 拉高等待輸出狀態(tài)。當下降沿到來時,若此時的值滿足其發(fā)送時間則跳轉(zhuǎn)到下一狀態(tài)。
5. 數(shù)據(jù)處理
? ? ? S_RD_DATA: DHT11 輸出數(shù)據(jù)狀態(tài)。從時序圖可以看到,數(shù)據(jù)“ 0”和數(shù)據(jù)“1”的時序都是由低電平開始的,而且持續(xù)時間相同,不同的地方在于高電平的持續(xù)時間。所以只需要判斷高電平的持續(xù)時間即可判斷其輸出的是 0 還是 1。當上升沿到來時計數(shù)器清零開始計數(shù),當下降沿到來時說明 1bit 的數(shù)據(jù)發(fā)送完畢,此時對計數(shù)器采樣。我們知道數(shù)據(jù)“0”是維持 23-27us 的高電平,數(shù)據(jù)“1”是維持 68-74us 的高電平。我們取一個中間值(50us)去判斷輸出的是“0”還是“1”,若下降沿到來 cnt_us 小于等于 50 則判斷為0,若大于 50 則判斷為 1。
? ? ? BIT_CNT:判斷傳輸了采了幾個數(shù)據(jù)。其初始值為 0,當下降沿到來時 bit_cnt 加 1,當其加到 39 時說明發(fā)送到了最后一個數(shù)據(jù)。所以當其為 40 的時候表示數(shù)據(jù)發(fā)送完畢,同時 dht11 會發(fā)送結(jié)束信號(拉低一段時間)。當 dht11 上升沿到來時表示整個時序結(jié)束。狀態(tài)跳回 S_LOW_18MS狀態(tài)發(fā)送開始信號開始新一輪的數(shù)據(jù)讀取,同時 bit_cnt 清零。
? ? ? ??上圖為數(shù)據(jù)采集波形圖。當在 S_RD_DATA 狀態(tài)時,每來一個下降沿,采集一次數(shù)據(jù)。因為數(shù)據(jù)是從高位開始發(fā)送的 ,所以第一個采集的數(shù)據(jù)放在數(shù)據(jù)寄存器(data_tmp)的最高位即 data_tmp[39],依次類推最后一位放在最低位即 data_tmp[0]??梢钥吹较陆笛貭顟B(tài)到來時 bit_cnt 的值應(yīng)為上一狀態(tài)的值,所以 bit_cnt 與寄存器賦值位數(shù)的關(guān)系為 data_tmp[39-bit_cnt]。當 40 位數(shù)據(jù)發(fā)送完之后發(fā)現(xiàn)檢驗位與“ 8bit 濕度整數(shù)數(shù)據(jù)+8bit 濕度小數(shù)數(shù)據(jù)+8bit 溫度整數(shù)數(shù)據(jù)+8bit 溫度小數(shù)數(shù)據(jù)”所得結(jié)果的末 8 位相等時,則將濕度溫度數(shù)據(jù)值賦給 data。
6.數(shù)據(jù)切換
? ? ? 當按鍵按下時, data_flag 取反為 1,此時顯示的是溫度值,溫度小數(shù)部分用低四位計算即可;按鍵沒有按下data_flag 為 0,此時顯示的是濕度值,無小數(shù)部分,顯示在第二第三個數(shù)碼管,而第二三個數(shù)碼管顯示的是十分位和百分位,所以讀出的整數(shù)值要乘以 10。
? ? ? 需要注意的是應(yīng)使用系統(tǒng)時鐘對 key_flag 進行采樣,而不能使用 clk_1us,因為我們產(chǎn)生 key_flag 用的是系統(tǒng)時鐘,而且 key_flag只維持了一個系統(tǒng)時鐘的高電平,所以如果用分頻的時鐘去采的話是幾乎采不到這個信號的。
2.2.4?RTL代碼
`timescale 1ns/1ns
module dht11_ctrl
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire key_flag , //按鍵消抖后標志信號
inout wire dht11 , //控制總線,采用wire型
output reg [19:0] data_out , //輸出顯示的數(shù)據(jù)
output reg sign //輸出符號位,高電平顯示負號
);
parameter S_WAIT_1S = 3'd1 , //上電等待1s狀態(tài)
S_LOW_18MS = 3'd2 , //主機拉低18ms,發(fā)送開始信號狀態(tài)
S_DLY1 = 3'd3 , //等待20-40us狀態(tài)
S_REPLY = 3'd4 , //DHT11響應(yīng)80us狀態(tài)
S_DLY2 = 3'd5 , //拉高等待80us狀態(tài)
S_RD_DATA = 3'd6 ; //接收數(shù)據(jù)狀態(tài)
parameter T_1S_DATA = 999999 ; //1s時間計數(shù)值
parameter T_18MS_DATA = 17999 ; //18ms時間計數(shù)值
reg clk_1us ; //1us時鐘,用于驅(qū)動整個模塊
reg [4:0] cnt ; //時鐘分頻計數(shù)器
reg [2:0] state ; //狀態(tài)機狀態(tài)
reg [20:0] cnt_us ; //us計數(shù)器
reg dht11_out ; //總線輸出數(shù)據(jù)
reg dht11_en ; //總線輸出使能信號
reg [5:0] bit_cnt ; //字節(jié)計數(shù)器
reg [39:0] data_tmp ; //讀出數(shù)據(jù)寄存器
reg data_flag ; //數(shù)據(jù)切換標志信號
reg dht11_d1 ; //總線信號打一拍
reg dht11_d2 ; //總線信號打兩拍
reg [31:0] data ; //校驗位數(shù)據(jù)
reg [6:0] cnt_low ; //低電平計數(shù)器
wire dht11_fall; //總線下降沿
wire dht11_rise; //總線上升沿
//cnt:分頻計數(shù)器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt <= 5'b0;
else if(cnt == 5'd24)
cnt <= 5'b0;
else
cnt <= cnt + 1'b1;
//clk_1us:產(chǎn)生單位時鐘為1us的控制時鐘
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
clk_1us <= 1'b0;
else if(cnt == 5'd24)
clk_1us <= ~clk_1us;
else
clk_1us <= clk_1us;
//檢測總線信號的上升沿下降沿
assign dht11_rise = (~dht11_d2) & (dht11_d1) ;
assign dht11_fall = (dht11_d2) & (~dht11_d1) ;
//對dht11信號打拍
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
dht11_d1 <= 1'b0 ;
dht11_d2 <= 1'b0 ;
end
else
begin
dht11_d1 <= dht11 ;
dht11_d2 <= dht11_d1 ;
end
//當使能信號為1是總線的值為dht11_out的值,為0時值為高阻態(tài)(釋放總線)
assign dht11 = (dht11_en == 1 ) ? dht11_out : 1'bz;
//狀態(tài)機狀態(tài)跳轉(zhuǎn)
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
state <= S_WAIT_1S ;
else
case(state)
S_WAIT_1S:
if(cnt_us == T_1S_DATA) //上電1s后跳入起始狀態(tài)
state <= S_LOW_18MS ;
else
state <= S_WAIT_1S ;
S_LOW_18MS:
if(cnt_us == T_18MS_DATA)
state <= S_DLY1 ;
else
state <= S_LOW_18MS ;
S_DLY1:
if(cnt_us == 10) //等待10us后進入下一狀態(tài)
state <= S_REPLY ;
else
state <= S_DLY1 ;
S_REPLY: //上升沿到來且低電平保持時間大于70us,則跳轉(zhuǎn)到下一狀態(tài)
if(dht11_rise == 1'b1 && cnt_low >= 70)
state <= S_DLY2 ;
//若1ms后,dht11還沒響應(yīng),則回去繼續(xù)發(fā)送起始信號
else if(cnt_us >= 1000)
state <= S_LOW_18MS ;
else
state <= S_REPLY ;
S_DLY2: //下降沿到來且計數(shù)器值大于70us,則跳轉(zhuǎn)到下一狀態(tài)
if(dht11_fall == 1'b1 && cnt_us >= 70)
state <= S_RD_DATA ;
else
state <= S_DLY2 ;
S_RD_DATA: //讀完數(shù)據(jù)后,回到起始狀態(tài)
if(bit_cnt == 40 && dht11_rise == 1'b1) //結(jié)束位
state <= S_LOW_18MS ;
else
state <= S_RD_DATA ;
default:
state <= S_WAIT_1S ;
endcase
//各狀態(tài)下的計數(shù)器賦值
//cnt_us:每到一個新的狀態(tài)就讓該計數(shù)器重新計數(shù)
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
cnt_low <= 7'd0 ;
cnt_us <= 21'd0 ;
end
else
case(state)
S_WAIT_1S:
if(cnt_us == T_1S_DATA)
cnt_us <= 21'd0 ;
else
cnt_us <= cnt_us + 1'b1;
S_LOW_18MS:
if(cnt_us == T_18MS_DATA)
cnt_us <= 21'd0 ;
else
cnt_us <= cnt_us + 1'b1;
S_DLY1:
if(cnt_us == 10)
cnt_us <= 21'd0 ;
else
cnt_us <= cnt_us + 1'b1;
S_REPLY:
if(dht11 == 1'b0) //當dht11發(fā)送低電平回應(yīng)時,計算其低電平的持續(xù)時間
begin
cnt_low <= cnt_low + 1'b1 ;
cnt_us <= cnt_us + 1'b1 ;
end
else if(dht11_rise == 1'b1 && cnt_low >= 70) //在規(guī)定范圍內(nèi)產(chǎn)生響應(yīng)
begin
cnt_low <= 7'd0 ;
cnt_us <= 21'd0 ;
end
else if(cnt_us <= 1000) //若1ms前,dht11沒響應(yīng)
begin
cnt_low <= cnt_low ;
cnt_us <= cnt_us + 1'b1 ;
end
else //若1ms后,dht11還沒響應(yīng),則回去繼續(xù)發(fā)送起始信號
begin
cnt_low <= 7'd0 ;
cnt_us <= 21'd0 ;
end
S_DLY2:
if(dht11_fall == 1'b1 && cnt_us >= 70)
cnt_us <= 21'd0 ;
else
cnt_us <= cnt_us + 1'b1;
S_RD_DATA:
if(dht11_fall == 1'b1 || dht11_rise == 1'b1)
cnt_us <= 21'd0 ;
else
cnt_us <= cnt_us + 1'b1;
default:
begin
cnt_low <= 7'd0 ;
cnt_us <= 21'd0 ;
end
endcase
//各狀態(tài)下的單總線賦值
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
dht11_out <= 1'b0 ;
dht11_en <= 1'b0 ;
end
else
case(state)
S_WAIT_1S:
begin
dht11_out <= 1'b0 ;
dht11_en <= 1'b0 ;
end
S_LOW_18MS: //拉低總線18ms
begin
dht11_out <= 1'b0 ;
dht11_en <= 1'b1 ;
end
//后面狀態(tài)釋放總線即可,由DHT11操控總線
S_DLY1:
begin
dht11_out <= 1'b0 ;
dht11_en <= 1'b0 ;
end
S_REPLY:
begin
dht11_out <= 1'b0 ;
dht11_en <= 1'b0 ;
end
S_DLY2:
begin
dht11_out <= 1'b0 ;
dht11_en <= 1'b0 ;
end
S_RD_DATA:
begin
dht11_out <= 1'b0 ;
dht11_en <= 1'b0 ;
end
default:;
endcase
//bit_cnt:讀出數(shù)據(jù)bit位數(shù)計數(shù)器
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_cnt <= 6'b0;
else if(bit_cnt == 40 && dht11_rise == 1'b1)
bit_cnt <= 6'b0;
else if(dht11_fall == 1'b1 && state == S_RD_DATA)
bit_cnt <= bit_cnt + 1'b1;
//data_tmp:將讀出的數(shù)據(jù)寄存在data_tmp中
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_tmp <= 40'b0;
else if(state == S_RD_DATA && dht11_fall == 1'b1 && cnt_us<=50)
data_tmp[39-bit_cnt] <= 1'b0;
else if(state == S_RD_DATA && dht11_fall == 1'b1 && cnt_us>50)
data_tmp[39-bit_cnt] <= 1'b1;
else
data_tmp <= data_tmp;
//data:校驗,若檢驗位正確,則數(shù)據(jù)值有效
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data <= 32'b0;
else if(data_tmp[7:0] == data_tmp[39:32] + data_tmp[31:24] +
data_tmp[23:16] + data_tmp[15:8])
data <= data_tmp[39:8];
else
data <= data;
//data_flag:數(shù)據(jù)變換標志信號的產(chǎn)生,按一次鍵變換一次 (系統(tǒng)時鐘)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_flag <= 1'b0;
else if(key_flag == 1'b1)
data_flag <= ~data_flag;
else
data_flag <= data_flag;
//data_out:對數(shù)碼管顯示的濕度和溫度進行賦值
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_out <= 20'b0;
else if(data_flag == 1'b0 ) //濕度小數(shù)位為0
data_out <= data[31:24] * 10; //為了兼容溫度顯示的小數(shù),將濕度的個
//位與十位擴大10倍,小數(shù)位為零
else if(data_flag == 1'b1) //溫度低四位顯示溫度小數(shù)數(shù)據(jù)
data_out <= data[15:8] * 10 + data[3:0];
//sign:符號位的顯示
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sign <= 1'b0;
else if(data[7] == 1'b1 && data_flag == 1'b1)//當溫度低八位最高位為1時,顯示負號
sign <= 1'b1;
else
sign <= 1'b0;
endmodule
2.3?上板驗證
當按鍵未被按下,濕度如下圖:
當按鍵被按下,溫度如下圖:
3. 總結(jié)
1. DH1T11溫濕度傳感器與DS18B20溫濕度傳感器非常類似,都是嚴格按照時序要求寫代碼。建議可以比較學(xué)習(xí)。
2. 顯示溫度與濕度部分的數(shù)據(jù)處理,采用 X10 進行在數(shù)碼管上的移一位顯示,配合了數(shù)碼管小數(shù)部分的顯示特點又區(qū)分了溫度與濕度。
3. 程序是按照一個接一個狀態(tài)及順序跳轉(zhuǎn)的,建議使用狀態(tài)機。
說明:
? ? ? ?本人使用的是野火家Xilinx Spartan6系列開發(fā)板及配套教程,以上內(nèi)容如有疑惑或錯誤歡迎評論區(qū)指出,或者移步B站觀看野火家視頻教程。
開發(fā)軟件:ise14.7? ? ?仿真:modelsim 10.5?文章來源:http://www.zghlxwxcb.cn/news/detail-461701.html
如需上述資料私信或留下郵箱文章來源地址http://www.zghlxwxcb.cn/news/detail-461701.html
到了這里,關(guān)于FPGA—DHT11數(shù)字溫濕度傳感器的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!