一.、一.内部结构框图
1.管脚图
2.结构方框图
其中包括:GND接地引脚,VDD电源引脚,DQ总线(当上拉电阻拉高时为由DQ总线为设备供电,当拉低时则为电容向设备供电),CPP内部供电电容,一个64BIT的ROM,中间结果暂存器(温度传感器,报警高触发器,报警低触发器,配置寄存器,8bitCRC发生器)
二.温度测量
1.温度寄存器格式
由8bit的高八位(其中高5位为符号位),8bit低八位组成
DS18B20的温度输出数据时在摄氏度下校准的;若是在华氏度下应用的话,可以用查表法或者常规的数据换算。温度数据以一个16位标志扩展二进制补码数的形式存储在温度寄存器中(详见图2)。符号标志位(S)温度的正负极性:正数则S=0,负数则S=1。如果DS18B20被定义为12位的转换精度,温度寄存器中的所有位都将包含有效数据。若为11位转换精度,则bit 0为未定义的。若为10位转换精度,则bit 1和bit 0为未定义的。 若为9位转换精度,则bit 2、bit 1和bit 0为未定义的。表格1为在12位转换精度下温度输出数据与相对应温度之间的关系表
温度/数据对应关系
2.温度报警
只与温度寄存器数据的4——11位比较,且该寄存器是非易失性的,在每次温度转换完成后,得到的温度会与定义的温度作比较
3.在外部电源模式下
由外部电源供电,并且有一个上拉电阻在没有数据传输时将总线拉高
64bitrom
低8位为分类编码。中间48位为序列号,高8位为冗余校验
DS18B20内存映射
暂存寄存器中的Byte 0和Byte 1分别作为温度寄存器的低字节和高字节。同时这两个字节是只读的。Byte 2和Byte 3作为过温和低温(TH和TL)温度报警寄存器。Byte 4保存着配置寄存器的数据,Byte 5、6、7作为内部使用的字节而保留使用,不可被写入。
暂存寄存器中的Byte 4包含着配置寄存器;如图8所示。用户通过改变表2中R0和R1的值来配置DS18B20的分辨率。上电默认为R0=1及R1=1(12位分辨率)。需要注意的是,转换时间与分辨率之间是有制约关系的。Bit 7和Bit 0至Bit 4作为内部使用而保留使用,不可被写入。
测温流程:
这里只需要发送复位脉冲,并且跳过ROM指令
这里只需要温度转换,还有从寄存器中读取温度数据
三.数据时序
1.初始化时序
2.读写时序
写时序
写时段有两种情况:“写1”时段和“写0”时段。主设备通过写1时段来向DS18B20中写入逻辑1以及通过写0时段来向DS18B20中写入逻辑0。每个写时段最小必须有60us的持续时间且独立的写时段间至少有1us的恢复时间。两个写时段都是由主设备通过将1-Wire总线拉低来进行初始化。
为了形成写1时段,在将1-Wire总线拉低后,主设备必须在15us之内释放总线。当总线释放后,5kΩ的上拉电阻将总线拉至高。为了形成写0时段,在将1-Wire总线拉低后,在整个时段期间主设备必须一直拉低总线(至少60us)。
在主设备初始化写时段后,DS18B20将会在15us至60us的时间窗口内对总线进行采样。如果总线在采样窗口期间是高电平,则逻辑1被写入DS18B20;若总线是低电平,则逻辑0被写入DS18B20。
读时序
四.代码设计
1.状态机设计
2.代码
驱动模块,通过主从状态机实现,主状态机控制整个流程,从状态负责数据的发送接收
/**************************************功能介绍***********************************
Date :
Author : WZY.
Version :
Description: ws18d20驱动模块
*********************************************************************************/
//---------<模块及端口声名>------------------------------------------------------
module ws18d20_dirver(
input wire clk ,
input wire rst_n ,
input wire flag_ws18d20_dirver,
output reg [23:0] temp_data,
output reg temp_data_vld,
inout wire dp
);
//---------<参数定义>---------------------------------------------------------
//主状态机参数
localparam M_IDLE = 0,//空闲状态
M_REST = 1,//发送复位脉冲
M_RELS = 2,//释放总线15~60us
M_RACK = 3,//接收存在脉冲
M_ROMS = 4,//发送跳过ROM指令
M_CONT = 5,//发送温度转换指令
M_WAIT = 6,//等待温度转换完成
M_RCMD = 7,//发送读取温度命令
M_RTMP = 8;//接收温度数据
//副状态机参数
localparam S_IDLE = 0,//空闲状态等待传输请求
S_LOW = 1,//读写前拉低大于1us
S_SEND = 2,//发送1bit数据,持续59us
S_SAMP = 3,//接收1bit数据,持续59us
S_RELS = 4,//时隙间隔,大于1us
S_DOWN = 5;//一次命令或者数据执行完成
parameter T_CYC = 20;
//状态机计数器参数
parameter REST_T = 480_000,
RELS_T = 60_000,
RACK_T = 240_000,
WAIT_T = 750_000_000;
//从状态机计数器参数
parameter LOW_T = 1_000,
SEND_T = 60_000,
SAMP_T = 60_000,
S_RELS_T = 1_000;
parameter RX_RACK_T = 20_000;
parameter RX_SAMP_T = 12_000;
parameter SKIP = 8'hCC,
CONVER = 8'h44,
READ = 8'hBE;
//---------<内部信号定义>-----------------------------------------------------
//主状态机参数
reg [3:0] cstate_M ;//现态
reg [3:0] nstate_M ;//次态
wire midle2rest;
wire mrest2rels;
wire mrels2rack;
wire mrack2roms;
wire mrack2idle;
wire mroms2cont;
wire mroms2rcmd;
wire mcont2wait;
wire mwait2rest;
wire mrcmd2rtmp;
wire mrtmp2idle;
reg flag_S;//跳转使能
//从状态机参数
reg [5:0] cstate_S ;//现态
reg [5:0] nstate_S ;//次态
wire sidle2low;
wire slow2send;
wire slow2samp;
wire ssend2rels;
wire ssamp2rels;
wire srels2down;
wire srels2low;
wire sdown2idle;
reg cmd_vld;//跳转使能
//三态门判断
reg OE ;
wire din;
reg dout;
//数据传输
reg [7:0] dict;
//数据接收
reg [15:0] recept_data;//接收数据
reg [10:0] temp_data_w;//原码
wire [23:0] temp_data_r; //数据处理
//主状态机计数器参数
reg [25:0] cnt_num_M ;
wire add_cnt_num_M ;
wire end_cnt_num_M ;
reg [25:0] num_M ;
//从状态机计数器参数
reg [25:0] cnt_num_S ;
wire add_cnt_num_S ;
wire end_cnt_num_S ;
reg [25:0] num_S ;
reg slave_rac ;//数据输入
//bit计数器参数
reg [15:0] cnt_bit ;
wire add_cnt_bit ;
wire end_cnt_bit ;
reg [15:0] num_bit;
reg flag_bit;
//****************************************************************
// 主状态机
//****************************************************************
//第一段:时序逻辑描述状态转移
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cstate_M <= M_IDLE;
end
else begin
cstate_M <= nstate_M;
end
end
//第二段:组合逻辑描述状态转移规律和状态转移条件
always @(*) begin
case(cstate_M)
M_IDLE : begin
if (midle2rest) begin
nstate_M = M_REST;
end
else begin
nstate_M = cstate_M;
end
end
M_REST : begin
if (mrest2rels) begin
nstate_M = M_RELS;
end
else begin
nstate_M = cstate_M;
end
end
M_RELS : begin
if (mrels2rack) begin
nstate_M = M_RACK;
end
else begin
nstate_M = cstate_M;
end
end
M_RACK : begin
if (mrack2roms) begin
nstate_M = M_ROMS;
end
else if (mrack2idle) begin
nstate_M = M_IDLE;
end
else begin
nstate_M = cstate_M;
end
end
M_ROMS : begin
if (mroms2cont) begin
nstate_M = M_CONT;
end
else if (mroms2rcmd) begin
nstate_M = M_RCMD;
end
else begin
nstate_M = cstate_M;
end
end
M_CONT : begin
if (mcont2wait) begin
nstate_M = M_WAIT;
end
else begin
nstate_M = cstate_M;
end
end
M_WAIT : begin
if (mwait2rest) begin
nstate_M = M_REST;
end
else begin
nstate_M = cstate_M;
end
end
M_RCMD : begin
if (mrcmd2rtmp) begin
nstate_M = M_RTMP;
end
else begin
nstate_M = cstate_M;
end
end
M_RTMP : begin
if (mrtmp2idle) begin
nstate_M = M_IDLE;
end
else begin
nstate_M = cstate_M;
end
end
default : nstate_M = M_IDLE;
endcase
end
assign midle2rest = cstate_M == M_IDLE && flag_ws18d20_dirver;//主机上电后自动进入复位状态
assign mrest2rels = cstate_M == M_REST && end_cnt_num_M;//复位脉冲计数480us后跳转
assign mrels2rack = cstate_M == M_RELS && end_cnt_num_M;//释放总线
assign mrack2roms = cstate_M == M_RACK && end_cnt_num_M && (slave_rac == 0);//接收存在脉冲
assign mrack2idle = cstate_M == M_RACK && end_cnt_num_M ;//未接收到存在脉冲
assign mroms2cont = cstate_M == M_ROMS && sdown2idle&&(flag_S == 0);//发送完8bit数据指令
assign mroms2rcmd = cstate_M == M_ROMS && sdown2idle&&(flag_S == 1);//发送完8bit数据指令
assign mcont2wait = cstate_M == M_CONT && sdown2idle;//发送完8bit数据指令
assign mwait2rest = cstate_M == M_WAIT && end_cnt_num_M;
assign mrcmd2rtmp = cstate_M == M_RCMD && sdown2idle;//发送完8bit数据指令
assign mrtmp2idle = cstate_M == M_RTMP && sdown2idle;//接收完16bit温度数据
//第三段:描述输出,时序逻辑或组合逻辑皆可
//****************************************************************
// 从状态机
//****************************************************************
//第一段:时序逻辑描述状态转移
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cstate_S <= S_IDLE;
end
else begin
cstate_S <= nstate_S;
end
end
//第二段:组合逻辑描述状态转移规律和状态转移条件
always @(*) begin
case(cstate_S)
S_IDLE : begin
if (sidle2low) begin
nstate_S = S_LOW;
end
else begin
nstate_S = cstate_S;
end
end
S_LOW : begin
if (slow2send) begin
nstate_S = S_SEND;
end
else if (slow2samp) begin
nstate_S = S_SAMP;
end
else begin
nstate_S = cstate_S;
end
end
S_SEND : begin
if (ssend2rels) begin
nstate_S = S_RELS;
end
else begin
nstate_S = cstate_S;
end
end
S_SAMP : begin
if (ssamp2rels) begin
nstate_S = S_RELS;
end
else begin
nstate_S = cstate_S;
end
end
S_RELS : begin
if (srels2down) begin
nstate_S = S_DOWN;
end
else if (srels2low) begin
nstate_S = S_LOW;
end
else begin
nstate_S = cstate_S;
end
end
S_DOWN : begin
if (sdown2idle) begin
nstate_S = S_IDLE;
end
else begin
nstate_S = cstate_S;
end
end
default : ;
endcase
end
assign sidle2low = cstate_S == S_IDLE && cmd_vld;//主状态机在发送指令或者接收数据状态跳转
assign slow2send = cstate_S == S_LOW && end_cnt_num_S && (cstate_M != M_RTMP);//主状态为发送状态
assign slow2samp = cstate_S == S_LOW && end_cnt_num_S && (cstate_M == M_RTMP);//主状态为接收状态
assign ssend2rels = cstate_S == S_SEND && end_cnt_num_S;//1bit数据发送完成
assign ssamp2rels = cstate_S == S_SAMP && end_cnt_num_S;//1bit数据发送完成
assign srels2down = cstate_S == S_RELS && end_cnt_num_S && flag_bit;//时隙延迟1us且bit数已经发完
assign srels2low = cstate_S == S_RELS && end_cnt_num_S;//bit数未发完
assign sdown2idle = cstate_S == S_DOWN && 1;
//****************************************************************
// 从状态机跳转使能
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cmd_vld <= 0;
end
else if (mrack2roms||mroms2cont||mroms2rcmd||mrcmd2rtmp) begin
cmd_vld <= 1;
end
else begin
cmd_vld <= 0;
end
end
//****************************************************************
// 主状态机复用计数器
//****************************************************************
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_num_M <= 'd0;
end
else if(add_cnt_num_M)begin
if(end_cnt_num_M)begin
cnt_num_M <= 'd0;
end
else begin
cnt_num_M <= cnt_num_M + 1'b1;
end
end
end
assign add_cnt_num_M =( cstate_M == M_REST)||( cstate_M == M_RELS)||( cstate_M == M_RACK)||(cstate_M == M_WAIT);
assign end_cnt_num_M = add_cnt_num_M && cnt_num_M == num_M-1;
always @(*) begin
case (cstate_M)
M_REST : num_M = REST_T/T_CYC;
M_RELS : num_M = RELS_T/T_CYC;
M_RACK : num_M = RACK_T/T_CYC;
M_WAIT : num_M = WAIT_T/T_CYC;
default: num_M = 0;
endcase
end
//****************************************************************
// 从状态机复用计数器
//****************************************************************
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_num_S <= 'd0;
end
else if(add_cnt_num_S)begin
if(end_cnt_num_S)begin
cnt_num_S <= 'd0;
end
else begin
cnt_num_S <= cnt_num_S + 1'b1;
end
end
end
assign add_cnt_num_S =( cstate_S == S_LOW)||( cstate_S == S_SEND)||( cstate_S == S_SAMP)||(cstate_S == S_RELS);
assign end_cnt_num_S = add_cnt_num_S && cnt_num_S == num_S-1;
always @(*) begin
case (cstate_S)
S_LOW : num_S = LOW_T / T_CYC;
S_SEND : num_S = SEND_T / T_CYC;
S_SAMP : num_S = SAMP_T / T_CYC;
S_RELS : num_S = S_RELS_T/ T_CYC;
default: num_S = 0;
endcase
end
//****************************************************************
// 存在脉冲检测
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
slave_rac <= 1;
end
else if (cstate_M == M_REST) begin//每次发送复位脉冲时复位信号
slave_rac <= 1;
end
else if (cstate_M == M_RACK && slave_rac == 1) begin//未检测到存在脉冲就一直取样
slave_rac <= dp;
end
end
//****************************************************************
// flag使能
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
flag_S <= 0;
end
else if (mwait2rest) begin
flag_S <= 1;
end
else if (mrtmp2idle) begin
flag_S <= 0;
end
end
//****************************************************************
// bit计数器
//****************************************************************
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_bit <= 'd0;
end
else if(add_cnt_bit)begin
if(end_cnt_bit)begin
cnt_bit <= 'd0;
end
else begin
cnt_bit <= cnt_bit + 1'b1;
end
end
end
assign add_cnt_bit = ssend2rels||ssamp2rels;
assign end_cnt_bit = add_cnt_bit && cnt_bit == num_bit - 1;
always @(*) begin
case (cstate_M)
M_ROMS,M_CONT,M_RCMD: num_bit = 8;
M_RTMP : num_bit = 16;
default: num_bit = 1;
endcase
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
flag_bit <= 0;
end
else if (end_cnt_bit) begin
flag_bit <= 1;
end
else if (sdown2idle) begin
flag_bit <= 0;
end
end
//****************************************************************
// 三态门使能
//****************************************************************
assign din = dp;
assign dp = OE?dout:1'bz;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
OE <= 1;
end
else if (midle2rest||mrack2roms||mroms2cont||mwait2rest||mroms2rcmd||sidle2low||srels2low||slow2send ) begin
OE <= 1;
end
else if (mrest2rels||mcont2wait||slow2samp||ssend2rels) begin
OE <= 0 ;
end
else begin
OE <= OE;
end
end
//****************************************************************
// 信号发送
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
dout <= 0;
end
else if (midle2rest||mwait2rest||sidle2low||srels2low) begin
dout <= 0;
end
else if (slow2send) begin
dout <= dict[cnt_bit];
end
end
//****************************************************************
// 指令数据
//****************************************************************
always @(*) begin
case (cstate_M)
M_ROMS : dict = SKIP ;
M_CONT : dict = CONVER;
M_RCMD : dict = READ ;
default: dict = 8'h00;
endcase
end
//****************************************************************
// 数据接收
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
recept_data <= 16'd0;
end
else if ((cstate_S == S_SAMP) && (cnt_num_S == RX_SAMP_T/T_CYC)) begin
recept_data[cnt_bit] <= dp ;
end
end
//****************************************************************
// 数据处理
//****************************************************************
//原码处理
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
temp_data_w <= 11'b0;
end
else if ((cstate_S == S_SAMP)&&ssamp2rels) begin
if (recept_data[15]) begin
temp_data_w <= ~recept_data[10:0] + 1;//负数的原码等于补码处符号位取反+1
end
else begin
temp_data_w <= recept_data[10:0];//正数补码等于原码
end
end
end
assign temp_data_r = temp_data_w*625;//10000*0.0625
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
temp_data <= 24'd0;
end
else if ((cstate_M == M_RTMP)&&srels2down) begin
temp_data <= temp_data_r;
end
end
//****************************************************************
// 数据发送有效信号(脉冲信号)
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
temp_data_vld <= 0;
end
else if ((cstate_M == M_RTMP)&&srels2down) begin
temp_data_vld <= 1;
end
else begin
temp_data_vld <= 0;
end
end
endmodule
数据处理
/**************************************功能介绍***********************************
Date :
Author : WZY.
Version :
Description:
*********************************************************************************/
//---------<模块及端口声名>------------------------------------------------------
module ws18d20_ctrl(
input wire clk ,
input wire rst_n ,
input wire [23:0] temp_data,
input wire temp_data_vld,
output wire [23:0] data_out
);
//---------<参数定义>---------------------------------------------------------
reg [23:0] data_in;//数据寄存寄存器
reg [11:0] data_int;
reg [15:0] data_dot;
wire [3:0] data_int_w0;
wire [3:0] data_int_w1;
wire [3:0] data_int_w2;
wire [3:0] data_dot_w0;
wire [3:0] data_dot_w1;
wire [3:0] data_dot_w2;
reg temp_data_vld_0;
reg temp_data_vld_1;
//---------<内部信号定义>-----------------------------------------------------
//****************************************************************
// 数据寄存
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_in <= 24'd0;
end
else if (temp_data_vld) begin
data_in <= temp_data;
end
else begin
data_in <= data_in;
end
end
//****************************************************************
// 打拍
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
temp_data_vld_0 <= 0;
temp_data_vld_1 <= 0;
end
else begin
temp_data_vld_0 <= temp_data_vld;
temp_data_vld_1 <= temp_data_vld_0;
end
end
//****************************************************************
// 数据处理
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_int <= 12'd123;
end
else if (temp_data_vld_1) begin
data_int <= data_in/10000;
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_dot <= 12'd123;
end
else if (temp_data_vld_1) begin
data_dot <= data_in%10000;
end
end
// assign data_int = data_in/10000;
assign data_int_w0 = data_int/100;
assign data_int_w1 = data_int%100/10;
assign data_int_w2 = data_int%10;
// assign data_dot = data_in%10000;
assign data_dot_w0 = data_dot/1000;
assign data_dot_w1 = data_dot%1000/100;
assign data_dot_w2 = data_dot%100/10;
assign data_out = {data_int_w0,data_int_w1,data_int_w2,data_dot_w0,data_dot_w1,data_dot_w2};
endmodule
使能模块
/**************************************功能介绍***********************************
Date :
Author : WZY.
Version :
Description:
*********************************************************************************/
//---------<模块及端口声名>------------------------------------------------------
module flag_enable(
input wire clk ,
input wire rst_n ,
input wire [7:0] rx_data ,
input wire rx_data_vld,
output wire flag_ws18d20_dirver,
output wire [5:0] seg_mask,
output wire flag_ctrl
);
//---------<参数定义>---------------------------------------------------------
reg [7:0] data_in;
reg [5:0] seg_mask_r;
reg flag_ws18d20_dirver_r;
reg flag_ctrl_r;
//---------<内部信号定义>-----------------------------------------------------
//****************************************************************
// 数据寄存
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_in <= 8'd0;
end
else if (rx_data_vld) begin
data_in <= rx_data;
end
end
//****************************************************************
// 控制数码管两灭
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
seg_mask_r <= 6'b111111;
end
else if (data_in == 8'hAA|| data_in == 8'hEE) begin
seg_mask_r <= 6'b000000;
end
else if (data_in == 8'hAB|| data_in == 8'hEF) begin
seg_mask_r <= 6'b111111;
end
end
assign seg_mask = seg_mask_r;
//****************************************************************
//控制ws18d20是否传输数据
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
flag_ws18d20_dirver_r <= 1;
end
else if (data_in == 8'hBB|| data_in == 8'hEE) begin
flag_ws18d20_dirver_r <= 0;
end
else if (data_in == 8'hBC|| data_in == 8'hEF) begin
flag_ws18d20_dirver_r <= 1;
end
end
assign flag_ws18d20_dirver = flag_ws18d20_dirver_r;
//****************************************************************
//控制串口发送
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
flag_ctrl_r <= 1;
end
else if (data_in == 8'hCC|| data_in == 8'hEE) begin
flag_ctrl_r <= 0;
end
else if (data_in == 8'hCE|| data_in == 8'hEF) begin
flag_ctrl_r <= 1;
end
end
assign flag_ctrl = flag_ctrl_r;
endmodule
数码管模块
/**************************************************************
6位数码管驱动模块
date:2022/7/13
author:WangHaodong
note:C4开发板使用的是共阳的数码管
**************************************************************/
/* 例化模板 */
// seg_drive seg_drive_inst(
// /*input */.sys_clk (sys_clk),
// /*input */.sys_rst_n (sys_rst_n),
// /*input [5:0] */.seg_mask (6'b111111), //数码管掩码,高电平设置对应数码管有效
// /*input [23:0] */.display_data (), //{4'd0,4'd0,4'd0,4'd0,4'd0,4'd0}
// /*input [5:0] */.display_point(), //高电平有效
// /*output reg [5:0] */.seg_sel (seg_sel),
// /*output [7:0] */.seg_dig (seg_dig)
// );
/* 配合以下约束内容使用
#数码管选段
set_location_assignment PIN_B7 -to seg_dig[0]
set_location_assignment PIN_A8 -to seg_dig[1]
set_location_assignment PIN_A6 -to seg_dig[2]
set_location_assignment PIN_B5 -to seg_dig[3]
set_location_assignment PIN_B6 -to seg_dig[4]
set_location_assignment PIN_A7 -to seg_dig[5]
set_location_assignment PIN_B8 -to seg_dig[6]
set_location_assignment PIN_A5 -to seg_dig[7]
#数码管片选
set_location_assignment PIN_A4 -to seg_sel[5]
set_location_assignment PIN_B4 -to seg_sel[4]
set_location_assignment PIN_A3 -to seg_sel[3]
set_location_assignment PIN_B3 -to seg_sel[2]
set_location_assignment PIN_A2 -to seg_sel[1]
set_location_assignment PIN_B1 -to seg_sel[0]
*/
module seg_drive(
input sys_clk ,
input sys_rst_n ,
input [5:0] seg_mask , //数码管掩码,1有效
input [23:0] display_data , //{4'd0,4'd0,4'd0,4'd0,4'd0,4'd0}
input [5:0] display_point, //高电平有效
output reg [5:0] seg_sel ,
output [7:0] seg_dig
);
parameter NUM_0 = 7'b100_0000,
NUM_1 = 7'b111_1001,
NUM_2 = 7'b010_0100,
NUM_3 = 7'b011_0000,
NUM_4 = 7'b001_1001,
NUM_5 = 7'b001_0010,
NUM_6 = 7'b000_0010,
NUM_7 = 7'b111_1000,
NUM_8 = 7'b000_0000,
NUM_9 = 7'b001_0000,
A = 7'b000_1000,//
B = 7'b000_0011,//b
C = 7'b100_0110,//
D = 7'b010_0001,//d
E = 7'b000_0110,//
F = 7'b000_1110;//
//显示数据与小数点
reg [6:0] seg_data ;
reg seg_point ;
//2ms 余晖效应
parameter CNT_2MS = 20'd1_000_00;
reg [19:0] cnt_2ms;
wire add_2ms_cnt,end_2ms_cnt;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
cnt_2ms <= 'd0;
else if(add_2ms_cnt) begin
if(end_2ms_cnt)
cnt_2ms <= 'd0;
else
cnt_2ms <= cnt_2ms + 1'b1;
end
assign add_2ms_cnt = 1'b1;
assign end_2ms_cnt = add_2ms_cnt && cnt_2ms == CNT_2MS - 1;
//位选
reg [5:0] cnt_sel;
wire add_sel_cnt,end_sel_cnt;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
cnt_sel <= 'd0;
else if(add_sel_cnt) begin
if(end_sel_cnt)
cnt_sel <= 'd0;
else
cnt_sel <= cnt_sel + 1'b1;
end
assign add_sel_cnt = end_2ms_cnt;
assign end_sel_cnt = add_sel_cnt && cnt_sel == 6 - 1;
reg [3:0] display_reg;
reg [6:0] seg_data_reg;
reg seg_point_reg;
//数据输出
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
display_reg <= 4'd0; /* 默认选择第0个数码管 */
else case(cnt_sel)
6'd0 : display_reg <= display_data[3:0];
6'd1 : display_reg <= display_data[7:4];
6'd2 : display_reg <= display_data[11:8];
6'd3 : display_reg <= display_data[15:12];
6'd4 : display_reg <= display_data[19:16];
6'd5 : display_reg <= display_data[23:20];
default : display_reg <= 4'd0;
endcase
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
seg_data_reg <= 7'h7F; //不亮
else case(display_reg)
6'd0 : seg_data_reg <= NUM_0;
6'd1 : seg_data_reg <= NUM_1;
6'd2 : seg_data_reg <= NUM_2;
6'd3 : seg_data_reg <= NUM_3;
6'd4 : seg_data_reg <= NUM_4;
6'd5 : seg_data_reg <= NUM_5;
6'd6 : seg_data_reg <= NUM_6;
6'd7 : seg_data_reg <= NUM_7;
6'd8 : seg_data_reg <= NUM_8;
6'd9 : seg_data_reg <= NUM_9;
6'd10 : seg_data_reg <= A ;
6'd11 : seg_data_reg <= B ;
6'd13 : seg_data_reg <= D ;
6'd15 : seg_data_reg <= F ;
default : seg_data_reg <= 7'h7F;
endcase
//小数点输出
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
seg_point_reg <= 1'b1; //小数点不亮
else case(cnt_sel)
6'd0 : seg_point_reg <= !(display_point[0] && seg_mask[0]);
6'd1 : seg_point_reg <= !(display_point[1] && seg_mask[1]);
6'd2 : seg_point_reg <= !(display_point[2] && seg_mask[2]);
6'd3 : seg_point_reg <= !(display_point[3] && seg_mask[3]);
6'd4 : seg_point_reg <= !(display_point[4] && seg_mask[4]);
6'd5 : seg_point_reg <= !(display_point[5] && seg_mask[5]);
default : seg_point_reg <= 1'b1;
endcase
assign seg_dig = {seg_point_reg,seg_data_reg[6:0]}; /* 拼接小数点和数据 */
//位选输出
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
seg_sel <= 6'b11_1110; //默认选择第一个数码管
else case(cnt_sel)
6'd0 : seg_sel <= ~(6'b00_0001 & seg_mask);
6'd1 : seg_sel <= ~(6'b00_0010 & seg_mask);
6'd2 : seg_sel <= ~(6'b00_0100 & seg_mask);
6'd3 : seg_sel <= ~(6'b00_1000 & seg_mask);
6'd4 : seg_sel <= ~(6'b01_0000 & seg_mask);
6'd5 : seg_sel <= ~(6'b10_0000 & seg_mask);
default : seg_sel <= ~(6'b00_0000 & seg_mask); //不选择任何的数码管
endcase
endmodule
串口模块在之前有过再此不做赘述
顶层:
/**************************************功能介绍***********************************
Date :
Author : WZY.
Version :
Description:
*********************************************************************************/
//---------<模块及端口声名>------------------------------------------------------
module top
(
input wire clk ,
input wire rst_n ,
inout wire dp ,
input wire rx ,
output wire [5:0] seg_sel ,
output wire [7:0] seg_dig ,
output wire tx
);
//---------<参数定义>---------------------------------------------------------
wire [23:0] temp_data;
wire temp_data_vld;
wire [23:0] data_out;
wire ready;
wire tx_data_vld;
wire [7:0] tx_data;
wire [7:0] rx_data;
wire rx_data_vld;
wire [5:0] seg_mask;
wire flag_ws18d20_dirver;
wire flag_ctrl;
//---------<内部信号定义>-----------------------------------------------------
//ws18d20驱动模块
ws18d20_dirver ws18d20_dirver_inst(
.clk (clk),
.rst_n (rst_n),
.flag_ws18d20_dirver (flag_ws18d20_dirver),
.temp_data (temp_data),
.temp_data_vld (temp_data_vld),
.dp (dp)
);
//数据处理(数码管)
ws18d20_ctrl ws18d20_ctrl_inst(
.clk (clk),
.rst_n (rst_n),
.temp_data (temp_data),
.temp_data_vld(temp_data_vld),
.data_out (data_out)
);
//数码管驱动
seg_drive seg_drive_inst(
.sys_clk (clk),
.sys_rst_n (rst_n),
.seg_mask (seg_mask), //数码管掩码,1有效
.display_data (data_out), //{4'd0,4'd0,4'd0,4'd0,4'd0,4'd0}
.display_point(6'b001000), //高电平有效
.seg_sel (seg_sel),
.seg_dig (seg_dig)
);
tx_ctrl tx_ctrl_inst(
.clk (clk),
.rst_n (rst_n),
.temp_data (temp_data),
.temp_data_vld (temp_data_vld),
.ready (ready),
.flag_ctrl (flag_ctrl),
.tx_data (tx_data),
.tx_data_vld (tx_data_vld)
);
uart_tx#
(
.BPS (115200),
.CLK_FRE (50_000_000),
.CHECK_BIT ("NONE")//NONE 不校验 DDO奇数 EVEN偶数
)uart_tx_inst
(
.clk (clk),
.rst_n (rst_n),
.tx_data_vld (tx_data_vld),//数据发送标志
.tx_data (tx_data),//发送数据
.tx (tx),
.ready (ready)//准备好发送
);
uart_rx#
(
.BPS (115200),
.CLK_FRE (50_000_000),
.CHECK_BIT ("NONE")//NONE 不校验 DDO奇校验 EVEN偶校验
) uart_rx_inst
(
/*input wire */ .clk (clk),
/*input wire */ .rst_n (rst_n),
/*input wire */ .rx (rx),
/*output wire */ .ready (),
/*output wire [7:0]*/ .rx_data (rx_data),
/*output wire */ .rx_data_vld (rx_data_vld)
);
flag_enable flag_enable_inst(
.clk (clk),
.rst_n (rst_n),
.rx_data (rx_data),
.rx_data_vld (1),
.flag_ws18d20_dirver (flag_ws18d20_dirver),
.seg_mask (seg_mask),
.flag_ctrl (flag_ctrl)
);
endmodule
五.仿真
仿真模型
/* ================================================ *\
Filename : ds18b20_model.v
Author : Adolph
Description : DS18B20仿真模型
Called by :
Revision History : 2023-7-12 12:31:15
Revision : 1.0
Email : ***@gmail.com
Company : AWCloud...Std
NOTE:
2023-7-12 15:02:42 v1.0
仅考虑正数温度数据的读取,以及分辨率的设计;
ROM指令只支持8'hCC;
指令接收错误时,会打印消息,并暂停仿真系统的执行.
2023-8-22 11:06:50 V1.1
支持负数温度输入;
添加弱上拉操作;
修改最大等待时间支持自定义.
2023-8-22 17:16:48 V1.2
负数温度数据显示错乱修正.
2023-8-23 10:48:09 V1.3
修正:内部 cnt_bit_tx 未清空,导致第二次读出数据错乱的问题
\* ================================================ */
`timescale 1ns/1ps
module ds18b20_model #(parameter
SIG_DATA = 0 , //0:正数、1:负数
INT_DATA = 37 , //温度数据整数部分,有效输入 -40 ~ +125
DEC_DATA = 4'b0000 , //温度数据小数部分,仅接受4bit-binary输入
MAX_WAIT = 750_000//_000 //温度转换等待最长时间 12bit-750ms
)(
input Rst_n , //
inout dq //
);
//Parameter Declarations
localparam
tRstPluse = 24000 , //复位脉冲480us
tEPulse = 10000 , //存在脉冲200us
tSEND = 3000 , //数据发送持续时间60us
tSAMPLE = 2000 , //采样时间点 40us
tCONV = MAX_WAIT ; //最大等待750ms
localparam //独热码定义状态参数
IDLE = 8'b0000_0001 , // 空闲状态
INIT_RST = 8'b0000_0010 , // 接收复位脉冲状态
INIT_EXI = 8'b0000_0100 , // 发送存在脉冲状态
ROM_CMD = 8'b0000_1000 , // 接收ROM指令状态
DS_CMD = 8'b0001_0000 , // 接收功能指令状态
TX_DATA = 8'b0010_0000 , // 发送数据状态
WAIT = 8'b0100_0000 , // 温度转换等待状态
WR_DATA = 8'b1000_0000 ; // 修改暂存器内容
localparam
CMD_SKIP_ROM = 8'hCC,
CMD_COVT = 8'h44,
CMD_WRITE = 8'h4E,
CMD_READ = 8'hBE;
//Internal wire/reg declarations
reg [63:00] STC_MACHINE ; //
wire dq_in ;
reg dq_oe ; //
reg dq_out ; //
reg [01:00] dq_r ; //
wire dq_neg,dq_pos ;
reg [07:00] Memory [04:00] ; // temperature-2byte 、warning-2byte 、Resolution
reg [07:00] state_c, state_n ; //状态变量声明
reg init_flag ; //
reg sample_flag ; //
reg [07:00] data_rx_tmp ; //
reg [31:00] tDelay ; //
reg [07:00] data_tx_tmp ; //
reg [03:00] cnt_bit ; //Counter
wire add_cnt_bit ; //Counter Enable
wire end_cnt_bit ; //Counter Reset
reg [03:00] cnt_byte_rx ; //Counter
wire add_cnt_byte_rx ; //Counter Enable
wire end_cnt_byte_rx ; //Counter Reset
reg [03:00] cnt_bit_tx ;//Counter
wire add_cnt_bit_tx ;//Counter Enable
wire end_cnt_bit_tx ;//Counter Reset
reg [03:00] cnt_byte_tx ; //Counter
wire add_cnt_byte_tx ; //Counter Enable
wire end_cnt_byte_tx ; //Counter Reset
wire [10:00] Original_code ; //
wire [10:00] Inverse_code ; //
wire [10:00] Supplement_code ; //
reg [15:00] delay_cnt ;//Counter
wire add_delay_cnt ;//Counter Enable
wire end_delay_cnt ;//Counter Reset
reg [10:00] cnt_sample ; //Counter
wire add_cnt_sample ; //Counter Enable
wire end_cnt_sample ; //Counter Reset
reg [15:00] cnt_exi ; //Counter
wire add_cnt_exi ; //Counter Enable
wire end_cnt_exi ; //Counter Reset
reg [15:00] cnt_wr_delay ; //Counter
wire add_cnt_wr_delay ; //Counter Enable
wire end_cnt_wr_delay ; //Counter Reset
//Logic Description
// 生成时钟
reg Clk ;//50MHz
initial Clk = 0 ;
always #10 Clk = ~Clk ;
integer i = 0 ;
initial begin
$timeformat(-9,0," ns",15); //精度、小数位数、附带字符串内容、整体最小长度
i=0;
repeat(5) begin
#1;
case(i)
0 : begin Memory[0] = 8'h00; end
1 : begin Memory[1] = 8'h00; end
2 : begin Memory[2] = 8'h40; end
3 : begin Memory[3] = 8'h10; end
4 : begin Memory[4] = 8'h7F; end
default: ;
endcase
i = i + 1;
end
end
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
delay_cnt <= 'd0;
end
else if(add_delay_cnt)begin
if(end_delay_cnt)begin
delay_cnt <= 'd0;
end
else begin
delay_cnt <= delay_cnt + 1'b1;
end
end
else begin
delay_cnt <= 'd0;
end
end //always end
assign add_delay_cnt = ~dq;
assign end_delay_cnt = add_delay_cnt && delay_cnt >= tRstPluse;
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
cnt_sample <= 'd0;
end
else if(dq_neg)begin
cnt_sample <= 'd0;
end
else if(add_cnt_sample)begin
if(end_cnt_sample)begin
cnt_sample <= tSEND;
end
else begin
cnt_sample <= cnt_sample + 1'b1;
end
end
else begin
cnt_sample <= 'd0;
end
end //always end
assign add_cnt_sample = (state_c == ROM_CMD || state_c == DS_CMD || state_c == WR_DATA);
assign end_cnt_sample = add_cnt_sample && cnt_sample >= tSEND;
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
cnt_exi <= 'd0;
end
else if(add_cnt_exi)begin
if(end_cnt_exi)begin
cnt_exi <= tEPulse;
end
else begin
cnt_exi <= cnt_exi + 1'b1;
end
end
else begin
cnt_exi <= 'd0;
end
end //always end
assign add_cnt_exi = state_c == INIT_EXI;
assign end_cnt_exi = add_cnt_exi && cnt_exi >= tEPulse;
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
cnt_wr_delay <= 'd0;
end
else if(dq_neg)begin
cnt_wr_delay <= 'd0;
end
else if(add_cnt_wr_delay)begin
if(end_cnt_wr_delay)begin
cnt_wr_delay <= tSEND;
end
else begin
cnt_wr_delay <= cnt_wr_delay + 1'b1;
end
end
else begin
cnt_wr_delay <= 'd0;
end
end
assign add_cnt_wr_delay = state_c == TX_DATA;
assign end_cnt_wr_delay = add_cnt_wr_delay && cnt_wr_delay >= tSEND;
//三段式状态机
//第一段设置状态转移空间
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
state_c <= IDLE;
end
else if(init_flag)begin
state_c = INIT_EXI;
end
else begin
state_c <= state_n;
end
end //always end
//第二段、组合逻辑定义状态转移
always@(*)begin
case(state_c)
IDLE :begin
if(1'b1)begin
state_n = INIT_RST;
end
else begin
state_n = state_c;
end
end
INIT_RST:begin
if(init_flag && dq_pos == 1'b1)begin //检测到主机释放总线才接管总线控制权
state_n = INIT_EXI;
$display("%t: ds18b20.model: Reset Pulse is received. ",$realtime);
end
else begin
state_n = INIT_RST;
end
end
INIT_EXI:begin
// #(tEPulse * 20);
if(end_cnt_exi && dq_neg)begin
state_n = ROM_CMD;
end
else begin
state_n = state_c;
end
end
ROM_CMD :begin
if(end_cnt_bit)begin
if(data_rx_tmp == CMD_SKIP_ROM)begin
state_n = DS_CMD;
$display("%t: ds18b20.model: ROM Command received. ",$realtime);
end
else begin
state_n = IDLE;
#20;
$display("%t: ds18b20.model: Error received ROM Command !!! \n ",$realtime);
$stop(2);
end
end
else begin
state_n = state_c;
end
end
DS_CMD :begin
if(end_cnt_bit)begin
if(data_rx_tmp == CMD_WRITE)begin
state_n = WR_DATA;
$display("%t: ds18b20.model: Write data Command received. ",$realtime);
end
else if(data_rx_tmp == CMD_COVT)begin
state_n = WAIT;
$display("%t: ds18b20.model: Convert Command received. ",$realtime);
end
else if(data_rx_tmp == CMD_READ)begin
state_n = TX_DATA;
$display("%t: ds18b20.model: Read data Command received. ",$realtime);
end
else begin
state_n = IDLE;
#20;
$display("%t: ds18b20.model: Error received Function Command !!! \n ",$realtime);
$stop(0);
end
end
else begin
state_n = state_c;
end
end
TX_DATA :begin //read data
if(end_cnt_byte_tx)begin
state_n = IDLE;
end
else begin
state_n = TX_DATA;
end
end
WR_DATA :begin //write data
if(end_cnt_byte_rx)begin
state_n = IDLE;
$display("%t: ds18b20.model: Write data done. ",$realtime);
end
else begin
state_n = state_c;
end
end
WAIT :begin //convert time
# tDelay;
$display("%t: ds18b20.model: Convert time is OK. ",$realtime);
state_n = IDLE;
end
default: begin
state_n = IDLE;
end
endcase
end //always end
//第三段,定义状态机输出情况,可以时序逻辑,也可以组合逻辑
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
dq_r <= 2'b11;
end
else begin
dq_r <= {dq_r[0],dq};
end
end //always end
assign dq_pos = ~dq_r[1] & dq_r[0];
assign dq_neg = dq_r[1] & ~dq_r[0];
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
init_flag <= 1'b0;
end
else if(delay_cnt >= tRstPluse)begin //复位脉冲时间满足
init_flag <= 1'b1;
end
else begin
init_flag <= 1'b0;
end
end //always end
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
data_rx_tmp <= 8'd0;
end
else begin
data_rx_tmp[cnt_bit] <= (cnt_sample == tSAMPLE) ? dq : data_rx_tmp[cnt_bit];
end
end //always end
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
sample_flag <= 1'b0;
end
else begin
sample_flag <= cnt_sample == tSAMPLE;
end
end //always end
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
cnt_bit <= 'd0;
end
else if(init_flag)begin
cnt_bit <= 'd0;
end
else if(add_cnt_bit)begin
if(end_cnt_bit)begin
cnt_bit <= 'd0;
end
else begin
cnt_bit <= cnt_bit + 1'b1;
end
end
else begin
cnt_bit <= cnt_bit;
end
end //always end
assign add_cnt_bit = (state_c == ROM_CMD || state_c == DS_CMD || state_c == WR_DATA) && sample_flag;
assign end_cnt_bit = add_cnt_bit && cnt_bit >= 4'd7;
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
cnt_byte_rx <= 'd0;
end
else if(init_flag)begin
cnt_byte_rx <= 'd0;
end
else if(add_cnt_byte_rx)begin
if(end_cnt_byte_rx)begin
cnt_byte_rx <= 'd0;
end
else begin
cnt_byte_rx <= cnt_byte_rx + 1'b1;
end
end
else begin
cnt_byte_rx <= cnt_byte_rx;
end
end //always end
assign add_cnt_byte_rx = (state_c == WR_DATA) && end_cnt_bit;
assign end_cnt_byte_rx = add_cnt_byte_rx && cnt_byte_rx >= 4'd2;
always @(*)begin
case(Memory[4][6:5])
0: tDelay = tCONV >> 3;
1: tDelay = tCONV >> 2;
2: tDelay = tCONV >> 1;
3: tDelay = tCONV >> 0;
default: tDelay = tCONV;
endcase
end //always end
//Memory data
assign Original_code = {INT_DATA[6:0],DEC_DATA[3:0]};
assign Inverse_code = ~Original_code;
assign Supplement_code = Inverse_code + 11'd1;
always @(posedge Clk )begin
if(state_c == WR_DATA && end_cnt_bit)begin //数据写入
case(cnt_byte_rx)
0,1: Memory[cnt_byte_rx+2] <= data_rx_tmp;//预警值上下限
default:Memory[cnt_byte_rx+2] <= {1'b0,data_rx_tmp[6:5],5'h1f};//修改分辨率
endcase
end
else begin
if(|SIG_DATA)begin //负数温度数据
Memory[0] = Supplement_code[07:00];
Memory[1] = {{5{|SIG_DATA}},Supplement_code[10:08]};
end
else begin //正数温度数据
Memory[0] = Original_code[07:00];
Memory[1] = {{5{|SIG_DATA}},Original_code[10:08]};
end
end
end //always end
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
cnt_bit_tx <= 'd0;
end
else if(state_c == INIT_EXI)begin
cnt_bit_tx <= 'd0; //此处清空,可保证多次数据读取不错乱
end
else if(add_cnt_bit_tx)begin //有效计数范围 1-8
if(end_cnt_bit_tx)begin
cnt_bit_tx <= 'd1;
end
else begin
cnt_bit_tx <= cnt_bit_tx + 1'b1;
end
end
end //always end
assign add_cnt_bit_tx = state_c == TX_DATA && dq_neg;
assign end_cnt_bit_tx = add_cnt_bit_tx && cnt_bit_tx >= 4'd8;
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
cnt_byte_tx <= 'd0;
end
else if(init_flag)begin
cnt_byte_tx <= 'd0;
end
else if(add_cnt_byte_tx)begin
if(end_cnt_byte_tx)begin
cnt_byte_tx <= 'd0;
end
else begin
cnt_byte_tx <= cnt_byte_tx + 1'b1;
end
end
end //always end
assign add_cnt_byte_tx = end_cnt_bit_tx;
assign end_cnt_byte_tx = add_cnt_byte_tx && cnt_byte_tx >= 4'd4;
// 存在脉冲和数据发送
always @(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
dq_oe <= 1'b0;
dq_out <= 1'b0;
data_tx_tmp <= 8'd0;
end
else if(state_c == INIT_EXI && cnt_exi < tEPulse)begin
dq_oe <= 1'b1; //存在脉冲
dq_out <= 1'b0;
end
else if(state_c == TX_DATA)begin //发送数据
data_tx_tmp <= Memory[cnt_byte_tx];
if(/*cnt_wr_delay >= 100 && */cnt_wr_delay < tSEND && cnt_bit_tx != 0)begin
dq_oe <= 1'b1;
dq_out <= data_tx_tmp[cnt_bit_tx - 1];
end
else begin
dq_oe <= 1'b0;
dq_out <= 1'b0;
end
end
else begin
dq_oe <= 1'b0;
dq_out <= 1'b0;
end
end //always end
pullup (dq);//设置弱上拉操作
assign dq = dq_oe ? dq_out : 1'bz;
assign dq_in = dq;
// ASCII显示状态机现态变量
always @(*)begin
case(state_c)
IDLE :STC_MACHINE = "IDLE ";
INIT_RST:STC_MACHINE = "INIT_RST";
INIT_EXI:STC_MACHINE = "INIT_EXI";
ROM_CMD :STC_MACHINE = "ROM_CMD ";
DS_CMD :STC_MACHINE = "DS_CMD ";
TX_DATA :STC_MACHINE = "TX_DATA ";
WAIT :STC_MACHINE = "WAIT ";
WR_DATA :STC_MACHINE = "WR_DATA ";
default :STC_MACHINE = "IDLE ";
endcase
end //always end
endmodule
仿真文件
`timescale 1ns/1ns
module ws18d20_dirver_tb();
//激励信号定义
reg clk ;
reg rst_n ;
reg rx ;
//输出信号定义
wire [23:0] temp_data;
wire temp_data_vld;
wire dp;
wire [5:0] seg_sel ;
wire [7:0] seg_dig ;
wire tx;
//时钟周期参数定义
parameter CYCLE = 20;
pullup(dp);
parameter T_CYC = 20;
//状态机计数器参数
// defparam ws18d20_dirver_inst.REST_T = 480_00,
// ws18d20_dirver_inst.RELS_T = 60_00,
// ws18d20_dirver_inst.RACK_T = 240_00,
defparam top_inst.ws18d20_dirver_inst.WAIT_T = 75_000;
//从状态机计数器参数
// defparam ws18d20_dirver_inst.LOW_T = 1000,
// ws18d20_dirver_inst.SEND_T = 60_00,
// ws18d20_dirver_inst.SAMP_T = 60_00,
// ws18d20_dirver_inst.S_RELS_T = 1000;
// defparam ws18d20_dirver_inst.RX_RACK_T = 80_00;
// defparam ws18d20_dirver_inst.RX_SAMP_T = 30_00;
// defparam ds18b20_model_inst.tRstPluse = 24 , //复位脉冲480us
// ds18b20_model_inst.tEPulse = 10 , //存在脉冲200us
// ds18b20_model_inst.tSEND = 30 , //数据发送持续时间60us
// ds18b20_model_inst.tSAMPLE = 20 , //采样时间点 40us
// ds18b20_model_inst.tCONV = 75;//_000 ; //最大等待750ms
//模块例化
// ws18d20_dirver ws18d20_dirver_inst(
// .clk (clk),
// .rst_n (rst_n),
// .temp_data (temp_data),
// .temp_data_vld (temp_data_vld),
// .dp (dp)
// );
ds18b20_model ds18b20_model_inst(
.Rst_n (rst_n), //
.dq (dp) //
);
top top_inst
(
.clk (clk),
.rst_n (rst_n),
.rx (rx),
.dp (dp),
.tx (tx),
.seg_sel (seg_sel),
.seg_dig (seg_dig)
);
//产生时钟
initial clk = 1'b1;
always #( CYCLE/2) clk = ~ clk;
//产生激励
initial begin
rst_n = 1'b1;
#( CYCLE*2);
rst_n = 1'b0;
#( CYCLE*20);
rst_n = 1'b1;
#20
rx = 1 ;
#(CYCLE*10)
rx = 0 ; //开始位发送
#(CYCLE*10)
rx = 0 ; //发送数据1
#(CYCLE*10)
rx = 1 ; //发送数据0
#(CYCLE*10)
rx = 0 ; //发送数据1
#(CYCLE*10)
rx = 1 ; //发送数据0
#(CYCLE*10)
rx = 0 ; //发送数据1
#(CYCLE*10)
rx = 1 ; //发送数据0
#(CYCLE*10)
rx = 0 ; //发送数据1
#(CYCLE*10)
rx = 1 ; //发送数据0
#(CYCLE*10)
// rx = 1 ; //发送标志位0//偶校验
// #(CYCLE*10)
rx = 1 ; //发送结束位
#100000000;
$stop;
end
endmodule
仿真结果
串口发送AA表示数码管显示数据
状态机正常跳转且最后输出正确数据
数码管显示数据最后只显示五位
六.结果展示
由于器件问题再此不做过多展示,经测试代码是可以正常运行,上板结果正确