Делал на SV, но переписать на обычный Verilog не очень сложно.
CODE
`timescale 1 ns / 1 ps
module DS18X20_CTRL
#(
parameter [8:0] CLKDIV = 9'd80
)
(
input clk,
input read,
output reg [15:0] temp,
output error,
inout IO
) ;
localparam start = 3'd0, reset_1wire = 3'd1, check_termometer = 3'd2, write_cmd = 3'd3, wait_convert = 3'd4, read_scratchpad = 3'd5 ;
reg [2:0] state = start ;
reg [2:0] next_state = start ;
reg [8:0] divider = 0 ;
wire divider_cout ;
reg divider_cout_clk = 1'b0 ;
reg [8:0] timer = 0 ;
wire timer_cout ;
reg [8:0] toggle_cmp = 0 ;
wire toggle ;
wire read_1wire ;
reg [15:0] shift = 0 ;
reg [15:0] buffer = 0 ;
reg error_n = 1'b0 ;
reg [6:0] bit_cnt = 0 ;
wire bit_cnt_cout ;
reg out_reg_n = 1'b0 ;
reg [1:0] in_reg = 0 ;
reg [7:0] CRC = 0 ;
wire XOR0 ;
initial begin
temp <= 0 ;
end
assign error = ~error_n ;
assign IO = (out_reg_n)? 1'b0:1'bZ ;
assign divider_cout = (divider == 0) ;
assign timer_cout = (timer == 0) ;
assign toggle = (timer == toggle_cmp) ;
assign read_1wire = (timer == 9'd60) ;
assign bit_cnt_cout = (bit_cnt == 0) ;
assign XOR0 = CRC[0] ^ in_reg[1] ;
always_ff @(posedge clk) begin
if (read) temp <= buffer ;
end
always_ff @(posedge clk) begin
in_reg <= (in_reg << 1) | IO ;
end
always_ff @(posedge clk) begin
if (divider_cout) divider <= CLKDIV ;
else divider <= divider - 1'b1 ;
divider_cout_clk <= divider_cout ;
end
always_ff @(posedge clk) begin
if (divider_cout_clk) begin
case (state)
start:
if (timer_cout) begin
state <= reset_1wire ;
next_state <= wait_convert ;
timer <= 9'd500 ;
shift <= 16'h44CC ;
bit_cnt <= 7'd16 ;
out_reg_n <= 1'b1 ;
end
else begin
timer <= timer - 1'b1 ;
end
reset_1wire:
if (timer_cout) begin
state <= check_termometer ;
timer <= 9'd500 ;
toggle_cmp <= 9'd432 ;
out_reg_n <= 1'b0 ;
end
else begin
timer <= timer - 1'b1 ;
end
check_termometer:
if (timer_cout) begin
state <= write_cmd ;
end
else begin
timer <= timer - 1'b1 ;
if (toggle & in_reg[1]) begin
state <= start ;
error_n <= 1'b0 ;
end
end
write_cmd:
begin
if (timer_cout) begin
if (bit_cnt_cout) begin
state <= next_state ;
end
else begin
timer <= 9'd70 ;
if (shift[0]) toggle_cmp <= 9'd65 ;
else toggle_cmp <= 9'd5 ;
shift[15:0] <= {in_reg[1], shift[15:1]} ;
bit_cnt <= bit_cnt - 1'b1 ;
out_reg_n <= 1'b1 ;
end
end
else begin
timer <= timer - 1'b1 ;
if (toggle) out_reg_n <= 1'b0 ;
end
end
wait_convert:
begin
if (timer_cout) begin
if (next_state == read_scratchpad) begin
state <= reset_1wire ;
timer <= 9'd500 ;
shift <= 16'hBECC ;
bit_cnt <= 7'd16 ;
end
else begin
timer <= 9'd70 ;
toggle_cmp <= 9'd65 ;
end
out_reg_n <= 1'b1 ;
end
else begin
timer <= timer - 1'b1 ;
if (read_1wire & in_reg[1]) next_state <= read_scratchpad ;
if (toggle) out_reg_n <= 1'b0 ;
end
end
read_scratchpad:
begin
if (timer_cout) begin
if (bit_cnt_cout & (next_state == start)) begin
state <= start ;
if (CRC != 0) begin
error_n <= 1'b0 ;
end
else begin
error_n <= 1'b1 ;
buffer <= shift ;
end
end
else begin
timer <= 9'd70 ;
if (next_state != start) begin
bit_cnt <= 7'd71 ;
CRC <= 0 ;
end
else begin
bit_cnt <= bit_cnt - 1'b1 ;
end
out_reg_n <= 1'b1 ;
end
next_state <= start ;
end
else begin
timer <= timer - 1'b1 ;
if (read_1wire) begin
if (bit_cnt > 7'd55) shift[15:0] <= {in_reg[1], shift[15:1]} ;
CRC <= {XOR0, CRC[7:5], CRC[4] ^ XOR0, CRC[3] ^ XOR0, CRC[2:1]} ;
end
if (toggle) out_reg_n <= 1'b0 ;
end
end
default:
state <= start ;
endcase
end
end
endmodule