生活随笔
收集整理的這篇文章主要介紹了
数字温度传感器
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
1. DS18B20簡介
DS18B20是常用的數字溫度傳感器,其輸出數字信號來表示溫度,具有體積小,硬件開發開銷低,抗干擾能力強,精度高的特點。
由于封裝形式多樣,適用于各種狹小空間設備數字測溫和控制領域,也可應用于鍋爐測溫,機房測溫,農業大棚測溫,潔凈室測溫,彈藥庫測溫等各種場合。
DS18B20測量溫度范圍為-55~+125℃,精度為+/-0.5℃,最大轉換時間為750ms。
1.1 命令
DS18B20的命令分為兩類,分別是ROM功能命令和RAM功能命令。
ROM功能命令是對64位ROM進行操作:
33H:讀ROM
55H:匹配ROM
CCH:跳過ROM
F0H:搜索ROM
ECH:報警搜索命令
如果主機只對一個DS18B20進行操作,就不需要讀取ROM編碼以及匹配ROM編碼,只要用跳過ROM(CCH),就可以進行下一步對高速緩存器的操作。
主機發出對ROM的操作命令之后,就進一步發出對RAM的命令。
如果使用寄生電源,總控制器必須在發出溫度轉換后立即啟動強上拉,并保持500ms
1.2 數據格式
DS18B20在出廠時默認配置溫度數據位為12位(補碼),其中最高位為符號位。即溫度值共11位,最低四位為小數位;低11位的二進制數轉化為十進制數后再乘以0.0625得到所測的實際溫度值。BYTE1前5位同時變化,前5位均為1時,讀取的溫度為負值。
1.3 數據時序
主機和從機(DS18B20)間的任何通訊都需要以初始化序列開始:
每次讀寫操作至少需要60us,在兩次寫操作之間至少需要1us的恢復時間;
寫操作起始于主機拉低數據總線:
寫0:在主機拉低數據線后,保持低電平即可(至少60us);
寫1:主機拉低總線(至少1us)后,接著必須在15us之內釋放總線
在寫操作開始后15us~60us期間,單總線期間采樣總電平狀態。
如果在此期間采樣值為高電平,則邏輯1寫入期間;如果為0,寫入邏輯0。
每次讀操作至少要60us,在兩次讀操作期間至少需要1us的恢復時間;
讀操作由主機發起,至少拉低總線1us。
在主機發起讀操作之后,單總線器件才開始在總線上發送0或1.
若主機發送1,則保持總線為高電平;若發出0,則拉低總線。
從機發出的數據在其實時隙之后,保持有效時間15us,因此主機在讀時隙器件必須釋放總線,并且在時隙起始后的15us之內采樣總線狀態。
DS18B20的典型溫度讀取過程:
初始化->發跳過ROM命令(CCH)->發溫度轉換命令(44H)->延時->初始化->發跳過ROM命令(CCH)->發讀存儲器命令(BEH)->連續讀出兩個字節溫度數據->結束或開始下一循環。
2. 程序設計
使用FOGA開發板通過DS18B20采集溫度,并將采集的溫度值(帶符號位)用數碼管顯示。
系統框圖
代碼
module
temp_disp(input sys_clk
, input sys_rst_n
, inout dq
, output
[5:0] sel
, output
[7:0] seg_led
);
parameter POINT
= 6'b000100
;
wire
[19:0] temp_data
;
wire sign
;
seg_led
u_seg_led(.clk
(sys_clk
), .rst_n
(sys_rst_n
), .seg_sel
(sel
), .seg_led
(seg_led
), .data
(temp_data
), .point
(POINT
), .en
(1'b1
), .sign
(sign
)
);
ds18b20_dri
u1_ds18b20_dri(.clk
(sys_clk
), .rst_n
(sys_rst_n
), .dq
(dq
), .temp_data
(temp_data
), .sign
(sign
)
);endmodule
module
ds18b20_dri(input clk
, input rst_n
, inout dq
, output reg
[19:0] temp_data
, output reg sign
);
localparam ROM_SKIP_CMD
= 8'hcc
;
localparam CONVERT_CMD
= 8'h44
;
localparam READ_TEMP
= 8'hbe
;
localparam init
= 3'd1
;
localparam rom_skip
= 3'd2
;
localparam wr_byte
= 3'd3
;
localparam temp_convert
= 3'd4
;
localparam delay
= 3'd5
;
localparam rd_temp
= 3'd6
;
localparam rd_byte
= 3'd7
;
reg
[ 4:0] cnt
;
reg clk_1us
;
reg
[19:0] cnt_1us
;
reg
[ 2:0] cur_state
;
reg
[ 2:0] next_state
;
reg
[ 3:0] flow_cnt
;
reg
[ 3:0] wr_cnt
;
reg
[ 4:0] rd_cnt
;
reg
[ 7:0] wr_data
;
reg
[ 4:0] bit_width
;
reg
[15:0] rd_data
;
reg
[15:0] org_data
;
reg
[10:0] data1
;
reg
[ 3:0] cmd_cnt
;
reg init_done
;
reg st_done
;
reg cnt_1us_en
;
reg dq_out
;
wire
[19:0] data2
;
assign dq
= dq_out
;
always @
(posedge clk or negedge rst_n
) begin
if (!rst_n
) begincnt
<= 5'b0
;clk_1us
<= 1'b0
;end
else if(cnt
< 5'd24
) begincnt
<= cnt
+ 1'b1
;clk_1us
<= clk_1us
;end
else begincnt
<= 5'b0
;clk_1us
<= ~clk_1us
;end
end
always @
(posedge clk_1us or negedge rst_n
) begin
if (!rst_n
)cnt_1us
<= 20'b0
;else if (cnt_1us_en
)cnt_1us
<= cnt_1us
+ 1'b1
;elsecnt_1us
<= 20'b0
;
end
always @
(posedge clk_1us or negedge rst_n
) begin
if(!rst_n
)cur_state
<= init
;else cur_state
<= next_state
;
end
always @
( * ) begin
case(cur_state
)init
: begin
if (init_done
)next_state
= rom_skip
;elsenext_state
= init
;endrom_skip
: begin
if(st_done
)next_state
= wr_byte
;elsenext_state
= rom_skip
;endwr_byte
: begin
if(st_done
)case(cmd_cnt
) 4'b1
: next_state
= temp_convert
;4'd2
: next_state
= delay
;4'd3
: next_state
= rd_temp
;4'd4
: next_state
= rd_byte
;default: next_state
= temp_convert
;endcase
elsenext_state
= wr_byte
;endtemp_convert
: begin
if(st_done
)next_state
= wr_byte
;elsenext_state
= temp_convert
;enddelay
: begin
if(st_done
)next_state
= init
;elsenext_state
= delay
;endrd_temp
: begin
if(st_done
)next_state
= wr_byte
;elsenext_state
= rd_temp
;endrd_byte
: begin
if(st_done
)next_state
= init
;elsenext_state
= rd_byte
;end
default: next_state
= init
;endcase
end
always @
(posedge clk_1us or negedge rst_n
) begin
if(!rst_n
) beginflow_cnt
<= 4'b0
;init_done
<= 1'b0
;cnt_1us_en
<= 1'b1
;dq_out
<= 1'bZ
;st_done
<= 1'b0
;rd_data
<= 16'b0
;rd_cnt
<= 5'd0
;wr_cnt
<= 4'd0
;cmd_cnt
<= 3'd0
;end
else beginst_done
<= 1'b0
;case (next_state
)init
:begin init_done
<= 1'b0
;case(flow_cnt
)4'd0
:flow_cnt
<= flow_cnt
+ 1'b1
;4'd1
: begin cnt_1us_en
<= 1'b1
; if(cnt_1us
< 20'd500
)dq_out
<= 1'b0
; else begincnt_1us_en
<= 1'b0
;dq_out
<= 1'bz
;flow_cnt
<= flow_cnt
+ 1'b1
;endend
4'd2
:begin cnt_1us_en
<= 1'b1
;if(cnt_1us
< 20'd30
)dq_out
<= 1'bz
;elseflow_cnt
<= flow_cnt
+ 1'b1
;end
4'd3
: begin
if(!dq
)flow_cnt
<= flow_cnt
+ 1'b1
;elseflow_cnt
<= flow_cnt
;end
4'd4
: begin
if(cnt_1us
== 20'd500
) begincnt_1us_en
<= 1'b0
;init_done
<= 1'b1
; flow_cnt
<= 4'd0
;end
elseflow_cnt
<= flow_cnt
;end
default: flow_cnt
<= 4'd0
;endcaseendrom_skip
: begin wr_data
<= ROM_SKIP_CMD
;flow_cnt
<= 4'd0
;st_done
<= 1'b1
;endwr_byte
: begin
if(wr_cnt
<= 4'd7
) begin
case (flow_cnt
)4'd0
: begindq_out
<= 1'b0
; cnt_1us_en
<= 1'b1
; flow_cnt
<= flow_cnt
+ 1'b1
;end
4'd1
: begin flow_cnt
<= flow_cnt
+ 1'b1
;end
4'd2
: begin
if(cnt_1us
< 20'd60
) dq_out
<= wr_data
[wr_cnt
];else if(cnt_1us
< 20'd63
) dq_out
<= 1'bz
; elseflow_cnt
<= flow_cnt
+ 1'b1
;end
4'd3
: begin flow_cnt
<= 0;cnt_1us_en
<= 1'b0
;wr_cnt
<= wr_cnt
+ 1'b1
;end
default : flow_cnt
<= 0;endcaseend
else begin st_done
<= 1'b1
;wr_cnt
<= 4'b0
;cmd_cnt
<= (cmd_cnt
== 3'd4
) ? 3'd1 : (cmd_cnt+ 1'b1
);endendtemp_convert
: begin wr_data
<= CONVERT_CMD
;st_done
<= 1'b1
;enddelay
: begin cnt_1us_en
<= 1'b1
;if(cnt_1us
== 20'd500000
) beginst_done
<= 1'b1
;cnt_1us_en
<= 1'b0
;end end rd_temp
: begin wr_data
<= READ_TEMP
;bit_width
<= 5'd16
; st_done
<= 1'b1
;endrd_byte
: begin
if(rd_cnt
< bit_width
) begin
case(flow_cnt
)4'd0
: begincnt_1us_en
<= 1'b1
;dq_out
<= 1'b0
; flow_cnt
<= flow_cnt
+ 1'b1
;end
4'd1
: begindq_out
<= 1'bz
; if(cnt_1us
== 20'd14
) beginrd_data
<= {dq
,rd_data
[15:1]};flow_cnt
<= flow_cnt
+ 1'b1
;endend
4'd2
: begin
if (cnt_1us
<= 20'd64
) dq_out
<= 1'bz
;else beginflow_cnt
<= 4'd0
; rd_cnt
<= rd_cnt
+ 1'b1
;cnt_1us_en
<= 1'b0
;endend
default : flow_cnt
<= 4'd0
;endcaseend
else beginst_done
<= 1'b1
;org_data
<= rd_data
;rd_cnt
<= 5'b0
;endend
default: ;endcaseend
end
always @
(posedge clk_1us or negedge rst_n
) begin
if(!rst_n
) beginsign
<= 1'b0
;data1
<= 11'b0
;end
else if(org_data
[15] == 1'b0
) beginsign
<= 1'b0
;data1
<= org_data
[10:0];end
else if(org_data
[15] == 1'b1
) beginsign
<= 1'b1
;data1
<= ~org_data
[10:0] + 1'b1
;end
end
assign data2
= (data1
* 11'd625)/ 7'd100
;
always @
(posedge clk_1us or negedge rst_n
) begin
if(!rst_n
)temp_data
<= 20'b0
;elsetemp_data
<= data2
;
endendmodule
module
seg_led(input clk
, input rst_n
, input
[19:0] data
, input
[5:0] point
, input en
, input sign
, output reg
[5:0] seg_sel
, output reg
[7:0] seg_led
);
localparam CLK_DIVIDE
= 4'd10
;
localparam MAX_NUM
= 13'd5000
;
reg
[ 3:0] clk_cnt
;
reg dri_clk
;
reg
[23:0] num
;
reg
[12:0] cnt0
;
reg flag
;
reg
[2:0] cnt_sel
;
reg
[3:0] num_disp
;
reg dot_disp
;
wire
[3:0] data0
;
wire
[3:0] data1
;
wire
[3:0] data2
;
wire
[3:0] data3
;
wire
[3:0] data4
;
wire
[3:0] data5
;
assign data0
= data
% 4'd10
;
assign data1
= data
/ 4'd10 % 4'd10
;
assign data2
= data
/ 7'd100 % 4'd10
;
assign data3
= data
/ 10'd1000 % 4'd10
;
assign data4
= data
/ 14'd10000 % 4'd10
;
assign data5
= data
/ 17'd100000
;
always @
(posedge clk or negedge rst_n
) begin
if(!rst_n
) beginclk_cnt
<= 4'd0
;dri_clk
<= 1'b1
;end
else if(clk_cnt
== CLK_DIVIDE
/2 - 1'd1
) beginclk_cnt
<= 4'd0
;dri_clk
<= ~dri_clk
;end
else beginclk_cnt
<= clk_cnt
+ 1'b1
;dri_clk
<= dri_clk
;end
end
always @
(posedge dri_clk or negedge rst_n
) begin
if (!rst_n
)num
<= 24'b0
;else begin
if (data5
|| point
[5]) begin num
[23:20] <= data5
; num
[19:16] <= data4
;num
[15:12] <= data3
;num
[11:8] <= data2
;num
[ 7:4] <= data1
;num
[ 3:0] <= data0
;end
else begin
if (data4
|| point
[4]) begin num
[19:0] <= {data4
,data3
,data2
,data1
,data0
};if(sign
) num
[23:20] <= 4'd11
; elsenum
[23:20] <= 4'd10
; end
else begin
if (data3
|| point
[3]) beginnum
[15: 0] <= {data3
,data2
,data1
,data0
};num
[23:20] <= 4'd10
; if(sign
) num
[19:16] <= 4'd11
;else num
[19:16] <= 4'd10
;end
else begin
if (data2
|| point
[2]) beginnum
[11: 0] <= {data2
,data1
,data0
};num
[23:16] <= {2{4'd10
}};if(sign
) num
[15:12] <= 4'd11
;else num
[15:12] <= 4'd10
;end
else begin
if (data1
|| point
[1]) beginnum
[ 7: 0] <= {data1
,data0
};num
[23:12] <= {3{4'd10
}};if(sign
) num
[11:8] <= 4'd11
;else num
[11:8] <= 4'd10
;end
else begin num
[3:0] <= data0
;num
[23:8] <= {4{4'd10
}};if(sign
) num
[7:4] <= 4'd11
;else num
[7:4] <= 4'd10
;endendendendendend
end
always @
(posedge dri_clk or negedge rst_n
) begin
if (rst_n
== 1'b0
) begincnt0
<= 13'b0
;flag
<= 1'b0
;end
else if (cnt0
< MAX_NUM
- 1'b1
) begincnt0
<= cnt0
+ 1'b1
;flag
<= 1'b0
;end
else begincnt0
<= 13'b0
;flag
<= 1'b1
;end
end
always @
(posedge dri_clk or negedge rst_n
) begin
if (rst_n
== 1'b0
)cnt_sel
<= 3'b0
;else if(flag
) begin
if(cnt_sel
< 3'd5
)cnt_sel
<= cnt_sel
+ 1'b1
;elsecnt_sel
<= 3'b0
;end
elsecnt_sel
<= cnt_sel
;
end
always @
(posedge dri_clk or negedge rst_n
) begin
if(!rst_n
) beginseg_sel
<= 6'b111111
; num_disp
<= 4'b0
; dot_disp
<= 1'b1
; end
else begin
if(en
) begin
case (cnt_sel
)3'd0
:beginseg_sel
<= 6'b111110
; num_disp
<= num
[3:0] ; dot_disp
<= ~point
[0]; end
3'd1
:beginseg_sel
<= 6'b111101
; num_disp
<= num
[7:4] ;dot_disp
<= ~point
[1];end
3'd2
:beginseg_sel
<= 6'b111011
; num_disp
<= num
[11:8];dot_disp
<= ~point
[2];end
3'd3
:beginseg_sel
<= 6'b110111
; num_disp
<= num
[15:12];dot_disp
<= ~point
[3];end
3'd4
:beginseg_sel
<= 6'b101111
; num_disp
<= num
[19:16];dot_disp
<= ~point
[4];end
3'd5
:beginseg_sel
<= 6'b011111
; num_disp
<= num
[23:20];dot_disp
<= ~point
[5];end
default :beginseg_sel
<= 6'b111111
;num_disp
<= 4'b0
;dot_disp
<= 1'b1
;endendcaseend
else beginseg_sel
<= 6'b111111
; num_disp
<= 4'b0
;dot_disp
<= 1'b1
;endend
end
always @
(posedge dri_clk or negedge rst_n
) begin
if (!rst_n
)seg_led
<= 8'hc0
;else begin
case (num_disp
)4'd0 : seg_led <= {dot_disp,7'b1000000
}; 4'd1 : seg_led <= {dot_disp,7'b1111001
}; 4'd2 : seg_led <= {dot_disp,7'b0100100
}; 4'd3 : seg_led <= {dot_disp,7'b0110000
}; 4'd4 : seg_led <= {dot_disp,7'b0011001
}; 4'd5 : seg_led <= {dot_disp,7'b0010010
}; 4'd6 : seg_led <= {dot_disp,7'b0000010
}; 4'd7 : seg_led <= {dot_disp,7'b1111000
}; 4'd8 : seg_led <= {dot_disp,7'b0000000
}; 4'd9 : seg_led <= {dot_disp,7'b0010000
}; 4'd10: seg_led <= 8'b11111111
; 4'd11: seg_led <= 8'b10111111
; default: seg_led
<= {dot_disp
,7'b1000000
};endcaseend
endendmodule
總結
以上是生活随笔為你收集整理的数字温度传感器的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。