1、ds18b20_driver.v
/*
*
*@Author: X-Z
*@Date:2023-02-21 11:15:07
*@Function:DS18B20驱动模块,实现主机FPGA与从机ds18b20之间的单总线通信
*/
module ds18b20_driver (
input clk ,
input rst_n ,
input dq_in ,//数据输入端口
output reg dq_out ,//数据输出端口
output reg dq_out_en ,//数据输出使能端口
output reg [23:0] temp_out ,
output reg temp_out_vld,
output reg temp_sign //输出温度正负
);
//独热码对状态进行编码
//主状态机
localparam M_IDLE = 9'b000_000_001,//空闲状态,等待开始通信
M_RST = 9'b000_000_010,//发送复位脉冲
M_REL = 9'b000_000_100,//释放总线
M_RACK = 9'b000_001_000,//接收存在脉冲
M_RSKP = 9'b000_010_000,//发送跳过ROM命令
M_SCON = 9'b000_100_000,//发送温度转换命令
M_WAIT = 9'b001_000_000,//等待750ms
M_SRTM = 9'b010_000_000,//发送读取温度指令
M_RTMP = 9'b100_000_000;//读取温度值
//从状态机
localparam S_IDLE = 6'b000_001,//空闲状态,等待传输请求
S_LOW = 6'b000_010,//发送数据前先拉低至少1us
S_SEND = 6'b000_100,//发送1bit数据
S_SAMP = 6'b001_000,//接收1bit数据
S_RELE = 6'b010_000,//释放总线
S_DONE = 6'b100_000;//发送/接收一次数据完成
//参数定义
parameter TIME_1US = 50 ,//1us计数器
TIME_RST = 500 ,//复位480us
TIME_RELE = 20 ,//主机释放总线
TIME_PRE = 200 ,//从机发送存在脉冲
TIME_WAIT = 750_000 ,
TIME_LOW = 2 ,//主机拉低总线
TIME_RW = 60 ,//读写1bit
TIME_REC = 3 ;//释放
//命令定义
localparam CMD_SROM = 8'hCC ,//跳过ROM指令
CMD_CONT = 8'h44 ,//温度转换
CMD_RTMP = 8'hBE ;//读暂存器
//fsm状态定义
reg [8:0] m_state_c ;
reg [8:0] m_state_n ;
reg [5:0] s_state_c ;
reg [5:0] s_state_n ;
//主机状态转移条件定义
wire m_idle_2_m_rst ;
wire m_rst_2_m_rel ;
wire m_rel_2_m_rack ;
wire m_rack_2_m_rskp ;
wire m_rskp_2_m_scon ;
wire m_rskp_2_m_srtm ;
wire m_scon_2_m_wait ;
wire m_wait_2_m_rst ;
wire m_srtm_2_m_rtmp ;
wire m_rtmp_2_m_idle ;
//从状态转移条件定义
wire s_idle_2_s_low ;
wire s_low_2_s_send ;
wire s_low_2_s_samp ;
wire s_send_2_s_rele ;
wire s_rele_2_s_low ;
wire s_rele_2_s_done ;
wire s_samp_2_s_rele ;
//采样存在脉冲
reg dq_samp ;//60-240us的低电平,我们在200us处采样
//进入温度转换还是进入读取温度寄存器标志信号定义
reg cmd_flag ;//取0时进入温度转换指令,为1时进入都暂存器状态
//1us计数器参数定义
reg [5:0] cnt_1us ;
wire add_cnt_1us ;
wire end_cnt_1us ;
//主状态机计数器
reg [19:0] m_cnt ;
wire add_m_cnt ;
wire end_m_cnt ;
reg [19:0] M_X ;//存放不同状态下计数器的计数最大值
//从状态机计数器
reg [5:0] s_cnt ;
wire add_s_cnt ;
wire end_s_cnt ;
reg [5:0] S_X ;
//比特计数器参数定义
reg [3:0] cnt_bit ;
wire add_cnt_bit ;
wire end_cnt_bit ;
//发送或接收bit数定义
reg [3:0] S_BIT ;
//暂存指令
reg [7:0] cmd_r ;
//暂存读取的16位暂存器值
reg [15:0] temp_out_r ;
//暂存经过正负处理后的温度数据
reg [10:0] temp_data ;//除符号扩展位外的有效温度位
//暂存实际转换后的温度值
wire [23:0] temp_data_r ;//将temp_data*0.0625
//主机采样存在脉冲
//主状态机处于响应状态并且计数器计满40us时采样,低电平的时间为60-240us
//assign dq_samp = (m_state_c == M_RACK && m_cnt == 20'd40 && end_cnt_1us) ? dq_in : 1'b1;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
dq_samp <= 1;
else if(m_state_c == M_RACK && m_cnt == 40 && end_cnt_1us)
dq_samp <= dq_in;
end
//发送或接收的最大比特数赋值
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
S_BIT <= 0;
end
else begin
case(m_state_c)
M_RSKP : S_BIT = 4'd7;
M_SCON : S_BIT = 4'd7;
M_SRTM : S_BIT = 4'd7;
M_RTMP : S_BIT = 4'd15;//接收温度值,两个字节
default:;
endcase
end
end
//温度转换/读取温度暂存器标志信号赋值
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cmd_flag <= 1'b0;//初始时为温度转换指令
else if(m_wait_2_m_rst)//当它进入M_WAIT说明前面进行了温度转换,则下一次在跳过ROM后进入读暂存器状态
cmd_flag <= 1'b1;
else if(m_rtmp_2_m_idle)//因为第一次进入温度转换并完成后直接进入了M_REST状态,所以可以用M_IDLE状态时赋值为0,代表一次温度转换并读取完成
cmd_flag <= 1'b0;
end
//主状态机
//第一段
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
m_state_c <= M_IDLE;
else
m_state_c <= m_state_n;
end
//第二段
always @(*)begin
case(m_state_c)
M_IDLE : begin
if(m_idle_2_m_rst)begin
m_state_n = M_RST;
end
else begin
m_state_n = m_state_c;
end
end
M_RST : begin
if(m_rst_2_m_rel)begin
m_state_n = M_REL;
end
else begin
m_state_n = m_state_c;
end
end
M_REL : begin
if(m_rel_2_m_rack)begin
m_state_n = M_RACK;
end
else begin
m_state_n = m_state_c;
end
end
M_RACK : begin
if(m_rack_2_m_rskp)begin
m_state_n = M_RSKP;
end
else begin
m_state_n = m_state_c;
end
end
M_RSKP : begin
if(m_rskp_2_m_scon)begin
m_state_n = M_SCON;
end
else if(m_rskp_2_m_srtm)begin
m_state_n = M_SRTM;
end
else begin
m_state_n = m_state_c;
end
end
M_SCON : begin
if(m_scon_2_m_wait)begin
m_state_n = M_WAIT;
end
else begin
m_state_n = m_state_c;
end
end
M_WAIT : begin
if(m_wait_2_m_rst)begin
m_state_n = M_RST;
end
else begin
m_state_n = m_state_c;
end
end
M_SRTM : begin
if(m_srtm_2_m_rtmp)begin
m_state_n = M_RTMP;
end
else begin
m_state_n = m_state_c;
end
end
M_RTMP : begin
if(m_rtmp_2_m_idle)begin
m_state_n = M_IDLE;
end
else begin
m_state_n = m_state_c;
end
end
default : m_state_n = M_IDLE;
endcase
end
assign m_idle_2_m_rst = m_state_c == M_IDLE && 1'b1;
assign m_rst_2_m_rel = m_state_c == M_RST && end_m_cnt;
assign m_rel_2_m_rack = m_state_c == M_REL && end_m_cnt;
assign m_rack_2_m_rskp = m_state_c == M_RACK &&( dq_samp == 0) && end_m_cnt; //检测到存在脉冲
assign m_rskp_2_m_scon = m_state_c == M_RSKP && (s_state_c == S_DONE) && (cmd_flag == 1'b0);//主状态机处在跳过ROM状态,并且从状态机发送完了该指令,cmd_flag=0表示进入温度转换
assign m_rskp_2_m_srtm = m_state_c == M_RSKP && (s_state_c == S_DONE) && (cmd_flag == 1'b1);//发送完命令并且第二次进入跳过ROM
assign m_scon_2_m_wait = m_state_c == M_SCON && (s_state_c == S_DONE); //温度转换命令发送完
assign m_wait_2_m_rst = m_state_c == M_WAIT && end_m_cnt; //计数750ms结束
assign m_srtm_2_m_rtmp = m_state_c == M_SRTM && (s_state_c == S_DONE); //读取温度指令发送完
assign m_rtmp_2_m_idle = m_state_c == M_RTMP && (s_state_c == S_DONE); //读取2字节数据完成
//从状态机
//第一段时序逻辑描述状态转移
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
s_state_c <= S_IDLE ;
else
s_state_c <= s_state_n; //现态跟随次态
end
//第二段组合逻辑,描述状态跳转条件
always@(*)begin
case(s_state_c)
S_IDLE : begin
if(s_idle_2_s_low)begin
s_state_n = S_LOW;
end
else begin
s_state_n = s_state_c;
end
end
S_LOW : begin
if(s_low_2_s_send)begin
s_state_n = S_SEND;
end
else if(s_low_2_s_samp)begin
s_state_n = S_SAMP;
end
else begin
s_state_n = s_state_c;
end
end
S_SEND : begin
if(s_send_2_s_rele)begin
s_state_n = S_RELE;
end
else begin
s_state_n = s_state_c;
end
end
S_RELE : begin
if(s_rele_2_s_low)begin
s_state_n = S_LOW;
end
else if(s_rele_2_s_done)begin
s_state_n = S_DONE;
end
else begin
s_state_n = s_state_c;
end
end
S_SAMP : begin
if(s_samp_2_s_rele)begin
s_state_n = S_RELE;
end
else begin
s_state_n = s_state_c;
end
end
S_DONE : begin
s_state_n = S_IDLE;
end
default : s_state_n = S_IDLE;
endcase
end
//给转移条件赋值
//主状态机处在发送跳过ROM,发送温度转换,发送读暂存器,接收温度值时
assign s_idle_2_s_low = s_state_c == S_IDLE && (m_state_c == M_RSKP || m_state_c == M_SCON || m_state_c == M_SRTM || m_state_c == M_RTMP);
//跳过ROM,开始温度转换,发送读暂存器都是主机发送指令,并且拉低的2us计数结束
assign s_low_2_s_send = s_state_c == S_LOW && (end_s_cnt && (m_state_c == M_RSKP || m_state_c == M_SCON || m_state_c == M_SRTM));
assign s_low_2_s_samp = s_state_c == S_LOW && (end_s_cnt && (m_state_c == M_RTMP));//接收温度值时,主机开启的是接收时序
assign s_send_2_s_rele = s_state_c == S_SEND && end_s_cnt; //发送1bit数据60us计数完成
assign s_rele_2_s_low = s_state_c == S_RELE &&( (~end_cnt_bit) && end_s_cnt); //8bit数据未发完或16bit温度数据未接收完
assign s_rele_2_s_done = s_state_c == S_RELE && (end_cnt_bit && end_s_cnt); //发送完8bit数据指令或接收完16bit温度值
assign s_samp_2_s_rele = s_state_c == S_SAMP && (end_s_cnt); //接收完1bit数据
//1us计数器模块
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_1us <= 1'd0;//复位初始化计数器值为0
end
else if(add_cnt_1us)begin//满足计数器开启条件
if(end_cnt_1us)begin//满足计数器结束条件
cnt_1us <= 1'd0;//计数值清零
end
else begin//不满足结束条件,计数器加1
cnt_1us <= cnt_1us + 1'b1;
end
end
end
assign add_cnt_1us = (m_state_c != M_IDLE) || (s_state_c != S_IDLE); //只要主状态机或从状态机不处于IDLE状态就开启1us基准计数器
assign end_cnt_1us = add_cnt_1us && cnt_1us == TIME_1US - 1; //计数器结束计数条件
//根据主状态机所处的不同状态对M_X赋值
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
M_X <= 0;
end
else begin
case(m_state_c)
M_RST : M_X <= TIME_RST ;//主机发送复位
M_REL : M_X <= TIME_RELE;//主机释放总线时间
M_RACK : M_X <= TIME_PRE ;//从机响应存在脉冲
M_WAIT : M_X <= TIME_WAIT;//发送温度转换命令后需要等待750ms等待温度转换完成
default :;
endcase
end
end
//根据从状态机所处的不同状态对S_X赋值
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
S_X <= 0;
end
else begin
case(s_state_c)
S_LOW : S_X <= TIME_LOW;//发送或接收1bit数据前主机拉低2us
S_SEND : S_X <= TIME_RW ;//发送或接收1bit数据所需时间
S_SAMP : S_X <= TIME_RW ;
S_RELE : S_X <= TIME_REC;//发送完1bit数据后释放总线
default : ;
endcase
end
end
//主状态机计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
m_cnt <= 1'd0;//复位初始化计数器值为0
end
else if(add_m_cnt)begin//满足计数器开启条件
if(end_m_cnt)begin//满足计数器结束条件
m_cnt <= 1'd0;//计数值清零
end
else begin//不满足结束条件,计数器加1
m_cnt <= m_cnt + 1'b1;
end
end
end
assign add_m_cnt = end_cnt_1us && (m_state_c == M_RST || m_state_c == M_REL || m_state_c == M_RACK || m_state_c == M_WAIT);//计数器开始计数条件
assign end_m_cnt = add_m_cnt && m_cnt == M_X - 1;//计数器结束计数条件
//从状态机计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
s_cnt <= 1'd0;//复位初始化计数器值为0
end
else if(add_s_cnt)begin//满足计数器开启条件
if(end_s_cnt)begin//满足计数器结束条件
s_cnt <= 1'd0;//计数值清零
end
else begin//不满足结束条件,计数器加1
s_cnt <= s_cnt + 1'b1;
end
end
end
assign add_s_cnt = end_cnt_1us && (s_state_c == S_LOW || s_state_c == S_SEND || s_state_c == S_SAMP || s_state_c == S_RELE);//计数器开始计数条件
assign end_s_cnt = add_s_cnt && s_cnt == S_X - 1;//计数器结束计数条件
//比特计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_bit <= 1'd0;//复位初始化计数器值为0
end
else if(add_cnt_bit)begin//满足计数器开启条件
if(end_cnt_bit)begin//满足计数器结束条件
cnt_bit <= 1'd0;//计数值清零
end
else begin//不满足结束条件,计数器加1
cnt_bit <= cnt_bit + 1'b1;
end
end
end
assign add_cnt_bit = (s_state_c == S_RELE) && end_s_cnt;//从机释放一次总线代表发送/接收1bit数据完成
assign end_cnt_bit = add_cnt_bit && cnt_bit == S_BIT;//计数器结束计数条件
//dq_out_en
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
dq_out_en <= 1'b0;
end
else if(m_idle_2_m_rst || m_wait_2_m_rst || s_idle_2_s_low || s_rele_2_s_low)begin//将总线拉低输出需要使能
dq_out_en <= 1'b1;
end
else if(m_rst_2_m_rel || s_low_2_s_samp || s_send_2_s_rele)begin//释放总线将使能信号拉低,读取温度值时也将使能信号拉低
dq_out_en <= 1'b0;
end
end
//cmd_r更据不同的状态选择不同的指令
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cmd_r <= 1'b0;
end
else begin
case(m_state_c)
M_RSKP : cmd_r <= CMD_SROM;//跳过ROM
M_SCON : cmd_r <= CMD_CONT;//温度转换
M_SRTM : cmd_r <= CMD_RTMP;//读取暂存器
default :;
endcase
end
end
//dq_out
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
dq_out <= 1'b0;
end
else if(m_idle_2_m_rst || m_wait_2_m_rst || s_idle_2_s_low || s_rele_2_s_low)begin//复位,等待,发送或接收前将总线拉低
dq_out <= 1'b0;
end
else if(s_low_2_s_send)begin
dq_out <= cmd_r[cnt_bit];//每次发送1bit的数据,先发低位
end
end
//读取温度暂存器temp_out_r
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
temp_out_r <= 0;
end//在15us处采样,因为前面拉低总线时已经2us了,所以在s_cnt=12时采样刚好是15us,0-12是13us
else if(s_state_c == S_SAMP && s_cnt == 12 && end_cnt_1us)begin//从状态机处于读取状态下,在15us内进行采样,读时隙的有效时长为15us
temp_out_r[cnt_bit] <= dq_in;
end
end
//temp_data,处理后有效的温度数据位
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
temp_data <= 0;
end
else if(s_state_c == S_SAMP && cnt_bit == 15 && s_samp_2_s_rele)begin//16bit温度数据读取完
if(temp_out_r[15])begin //判读正负(0为正1为负),确定是否需要补码转原码
temp_data <= ~temp_out_r[10:0] + 1'b1; //温度为负时将补码转为原码
end
else begin//正温度
temp_data <= temp_out_r[10:0];//只要有效位
end
end
end
//输出转换后的温度值
assign temp_data_r = temp_data * 625;//应该*0.0625,为了保留小数点后4位扩大了10000倍
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
temp_out <= 0;
end
else if(m_rtmp_2_m_idle)begin//一次温度转换完将温度值输出
temp_out <= temp_data_r;
end
end
//temp_out_vld输出温度有效标志信号
always @(posedge clk or negedge rst_n)begin//数据有效后拉高一个时钟周期
if(!rst_n)begin
temp_out_vld <= 1'b0;
end
else if(m_rtmp_2_m_idle)begin
temp_out_vld <= 1'b1;
end
else begin
temp_out_vld <= 1'b0;
end
end
//temp_sign ---输出温度的正负
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
temp_sign <= 1'b0;
end
else if(s_state_c == S_SAMP && cnt_bit == 15 && s_samp_2_s_rele)begin
temp_sign <= temp_out_r[15];
end
end
endmodule
2、control.v
/*
*
*@Author: X-Z
*@Date:2023-02-21 11:17:32
*@Function:对驱动模块传进来的数据进行处理,然后送到数码管显示
*/
module control(
input clk ,
input rst_n ,
input sign_in ,
input [23:0] t_data ,
input t_data_vld ,
output sign_out ,
output wire [23:0] t_out
);
//定义信号存储数据的每一位
wire [3:0] temp_r0;//最高位
wire [3:0] temp_r1;
wire [3:0] temp_r2;
wire [3:0] temp_r3;
wire [3:0] temp_r4;
wire [3:0] temp_r5;//最低位
//暂存传进来的温度数据
reg [23:0] t_data_r;
//t_data_r
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
t_data_r <= 24'd0;
end
else if(t_data_vld)begin
t_data_r <= t_data;
end
end
//输出符号赋值
assign sign_out = sign_in;
//提取出数据的每一位
assign temp_r0 = t_data_r/1000_00;
assign temp_r1 = (t_data_r%1000_00)/1000_0;
assign temp_r2 = (t_data_r%1000_0)/1000;
assign temp_r3 = (t_data_r%1000)/100;
assign temp_r4 = (t_data_r%100)/10;
assign temp_r5 = t_data_r%10;
//输出24位宽的数据赋值
//assign t_out = {temp_r0,temp_r1,temp_r2,temp_r3,temp_r4,temp_r5};
assign t_out = {4'hf,temp_r0,temp_r1,temp_r2,temp_r3,temp_r4};
endmodule
3、dynamic_dig.v
/*
*
*@Author: X-Z
*@Date:2023-02-08 18:46:20
*@Function:数码管驱动
*/
module dynamic_dig (
input wire clk ,
input wire rst_n ,
input wire [23:0] data ,//输入24位宽的数据
input sign ,
output reg [5:0] sel ,//位选
output reg [7:0] seg //段选
);
//参数定义共阳极
parameter TIME_1MS = 49_999,
//1ms扫描一个数码管
ZERO = 7'b100_0000,
ONE = 7'b111_1001,
TWO = 7'b010_0100,
THREE = 7'b011_0000,
FOUR = 7'b001_1001,
FIVE = 7'b001_0010,
SIX = 7'b000_0010,
SEVEN = 7'b111_1000,
EIGHT = 7'b000_0000,
NINE = 7'b001_0000,
A = 7'b000_1000,
B = 7'b000_0011,
C = 7'b010_0011,
D = 7'b110_0011,
E = 7'b111_1110,//只亮g段
F = 7'b111_1111;//全灭,4'hf : seg = 8'b1000_1110;
//信号定义
reg [23:0] cnt_1ms ;
//扫描频率计数器
wire add_cnt_1ms;
wire end_cnt_1ms;
reg [3:0] disp_num ;//暂存数码管要显示的数值
wire [3:0] sign_r;//处理温度符号
reg dip ;//显示小数点
assign sign_r = sign ? 4'hE : 4'hF;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_1ms <= 1'b0;
else if(add_cnt_1ms)begin
if(end_cnt_1ms)
cnt_1ms <= 1'b0;
else
cnt_1ms <= cnt_1ms + 1'b1;
end
end
assign add_cnt_1ms = 1'b1;
assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == TIME_1MS;
//数码管位选信号
//时序电路
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sel <= 6'b111_110;//复位初始化
end
else if(end_cnt_1ms)begin
sel <= {sel[4:0],sel[5]};
end
end
always@(*)begin
case(sel)
//6'b111_110: disp_num <= data[23:20];
6'b111_110: dip <= 1'b1;//显示符号
6'b111_101: dip <= 1'b1;
6'b111_011: dip <= 1'b0;
6'b110_111: dip <= 1'b1;
6'b101_111: dip <= 1'b1;
6'b011_111: dip <= 1'b1;
default : dip <= 1'b1;
endcase
end
//每片数码管将要显示的数值
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
disp_num <= 4'd0;
end
else begin
case(sel)
//6'b111_110: disp_num <= data[23:20];
6'b111_110: disp_num <= sign_r ;//显示符号
6'b111_101: disp_num <= data[19:16];
6'b111_011: disp_num <= data[15:12];
6'b110_111: disp_num <= data[11:8] ;
6'b101_111: disp_num <= data[7:4] ;
6'b011_111: disp_num <= data[3:0] ;
default : disp_num <= 4'd0 ;
endcase
end
end
//seg 段选信号译码
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
seg <= {1'b0,ZERO};//复位数码管显示字符
end
else begin//不需要显示小数点
case(disp_num)
0 :seg <= {dip,ZERO } ;
1 :seg <= {dip,ONE } ;
2 :seg <= {dip,TWO } ;
3 :seg <= {dip,THREE } ;
4 :seg <= {dip,FOUR } ;
5 :seg <= {dip,FIVE } ;
6 :seg <= {dip,SIX } ;
7 :seg <= {dip,SEVEN } ;
8 :seg <= {dip,EIGHT } ;
9 :seg <= {dip,NINE } ;
10:seg <= {1'b1, A } ;
11:seg <= {1'b1, B } ;
12:seg <= {1'b1, C } ;
13:seg <= {1'b1, D } ;
14:seg <= {1'b1, E } ;
15:seg <= {1'b1, F } ;
//全灭
default :seg <= {1'b1,F} ;
endcase
end
end
endmodule
4、temp_detect.v
module temp_detect(
input clk ,
input rst_n ,
inout dq ,
output [5:0] sel ,
output [7:0] seg
);
//中间变量定义
wire dq_in ;
wire dq_out ;
wire out_en ;
wire sign ;
wire [23:0] t_out ;
wire t_out_vld ;
wire [23:0] data ;
wire sign_out ;
//inout口赋值
assign dq_in = dq;
assign dq = out_en == 1'b1 ? dq_out : 1'bz;//输出使能无效时,输出为高阻态,可以输入
//ds18b20驱动模块例化
ds18b20_driver u_ds18b20_driver(
.clk (clk ),
.rst_n (rst_n ),
.dq_in (dq_in ),
.dq_out (dq_out ),
.dq_out_en (out_en ),
.temp_sign (sign ),
.temp_out (t_out ),
.temp_out_vld (t_out_vld )
);
//控制模块例化
control u_control(
.clk (clk ),
.rst_n (rst_n ),
.sign_in (sign ),
.t_data (t_out ),
.t_data_vld (t_out_vld ),
.sign_out (sign_out ),
.t_out (data )
);
//数码管驱动模块例化
dynamic_dig u_dynamic_dig(
.clk (clk ),
.rst_n (rst_n ),
.data (data ),
.sign (sign_out ),
.sel (sel ),
.seg (seg )
);
endmodule
5、ds18b20_driver_tb.v
`timescale 1ns/1ns
module ds18b20_driver_tb();
defparam u_ds18b20_driver.TIME_RST = 200,
u_ds18b20_driver.TIME_PRE = 100,
u_ds18b20_driver.TIME_WAIT = 750;
//信号定义
reg clk ;
reg rst_n ;
reg dq_in ;
wire dq_out ;
wire dq_out_en ;
wire [23:0] temp_out ;
wire temp_out_vld ;
wire temp_sign ;
parameter CYCLE = 20;
integer i=0;
initial begin
clk = 1'b1;
rst_n = 1'b0;
dq_in = 0;
#2;
#(CYCLE*20)
rst_n = 1'b1;
repeat(5)begin
for(i=0;i<500000;i=i+1)begin
dq_in = {$random};
#(20*CYCLE);
end
#(20*CYCLE);
end
$stop;
end
always #(CYCLE/2) clk = ~clk;
ds18b20_driver u_ds18b20_driver(
.clk (clk ),
.rst_n (rst_n ),
.dq_in (dq_in ),//数据输入端口
.dq_out (dq_out ),//数据输出端口
.dq_out_en (dq_out_en ),//数据输出使能端口
.temp_out (temp_out ),
.temp_out_vld(temp_out_vld),
.temp_sign (temp_sign ) //输出温度正负
);
endmodule