当前位置:网站首页>【FPGA】day18-ds18b20实现温度采集
【FPGA】day18-ds18b20实现温度采集
2022-08-11 03:28:00 【春风浅作序】
目录
一、项目概述
1、系统需求
2、模块框图
3、设计思路
二、状态机设计
1、状态机结构
发送数据:写时隙
采样数据:读时隙
发ROM指令需要写时隙
发温度转换指令需要写时隙
温度读取指令需要写时隙
读取温度需要读时隙
综上,四个状态均需用到从状态机
2、总体设计
S_SEND:写时隙
S_SAMP:读时隙
三、项目源码
1、顶层模块
module temp_detect(
input clk ,//时钟信号
input rst_n ,//复位信号
inout dq ,//传感器总线
output [5:0] sel ,
output [7:0] dig
);
//信号定义
wire dq_in ;
wire dq_out ;
wire dq_out_en ;
wire temp_sign ;
wire [23:0] temp_out ;
wire temp_out_vld;
wire dout_sign ;
wire [23:0] dout ;
wire dout_vld ;
assign dq = dq_out_en?dq_out:1'bz;
assign dq_in = dq;
//模块例化
ds18b20_driver u_ds18b20_driver(
.clk (clk ),
.rst_n (rst_n ),
.dq_in (dq_in ),//dq总线DS18B20输出
.dq_out (dq_out ),//dq总线FPGA输出,DS18B20输入
.dq_out_en (dq_out_en ),//dq总线输出使能控制信号
.temp_sign (temp_sign ),//温度的正负
.temp_out (temp_out ),//输出十进制温度
.temp_out_vld (temp_out_vld ) //温度采集数据有效
);
control u_control(
.clk (clk ),
.rst_n (rst_n ),
.din_sign (temp_sign ),
.din (temp_out ),
.din_vld (temp_out_vld ),
.dout_sign (dout_sign ),
.dout (dout ),//输出温度值数码管对应位置的bcd码
.dout_vld (dout_vld )
);
seg_driver seg_driver(
.clk (clk ),
.rst_n (rst_n ),
.din_sign (temp_sign ),
.din (dout ),
.din_vld (dout_vld ),
.sel (sel ),
.dig (dig )
);
endmodule
2、ds18b20使能模块
module ds18b20_driver(
input clk ,//时钟信号
input rst_n ,//复位信号
input dq_in ,
output reg dq_out ,//dq总线FPGA输出
output reg dq_out_en ,//输出数据有效信号
output reg temp_sign ,//温度值符号位 0:正 1:负
output reg [23:0] temp_out ,//温度输出
output reg temp_out_vld //温度输出有效信号
);
//状态机参数
localparam
//主机状态参数
M_IDLE = 9'b0_0000_0001 ,//空闲状态
M_REST = 9'b0_0000_0010 ,//复位
M_RELE = 9'b0_0000_0100 ,//释放总线 -- ds18b20等待
M_RACK = 9'b0_0000_1000 ,//接收应答 -- 主机接收存在脉冲
M_ROMS = 9'b0_0001_0000 ,//ROM命令 -- 跳过ROM命令
M_CONT = 9'b0_0010_0000 ,//转化
M_WAIT = 9'b0_0100_0000 ,//等待 -- 12bit分辨率下的温度转化时间
M_RCMD = 9'b0_1000_0000 ,//读命令 -- 读暂存器命令
M_RTMP = 9'b1_0000_0000 ,//读温度 -- 产生读时隙 -- 接收2字节带符号位的补码温度
//从机状态参数
S_IDLE = 6'b00_0001 ,//空闲状态
S_LOW = 6'b00_0010 ,//拉低总线 -- 时隙的开始
S_SEND = 6'b00_0100 ,//发送 -- 15us内
S_SAMP = 6'b00_1000 ,//采样 -- 在15us内
S_RELE = 6'b01_0000 ,//释放 -- 时隙的恢复时间
S_DONE = 6'b10_0000 ;//
parameter
TIME_1US = 50 ,//基本时间1us
//主状态机延时
TIME_RST = 500 ,//复位脉冲 500us (至少480us)
TIME_REL = 20 ,//主机释放总线 20us (15-60us内)
TIME_PRE = 200 ,//主机接收存在脉冲 200us (60-240us)
TIME_WAIT= 750000 ,//主机发完温度转换命令 等待750ms
//从状态机延时
TIME_LOW = 2 ,//主机拉低总线 2us (大于1us)
TIME_RW = 60 ,//主机读、写1bit 60us (至少60us)
TIME_REC = 3 ;//主机读、写完1bit释放总线 3us (至少1us)
localparam
CMD_ROMS = 8'hCC ,//跳过ROM指令
CMD_CONT = 8'h44 ,//温度转化指令
CDM_RTMP = 8'hBE ;//读暂存器指令
//信号定义
reg [8:0] m_state_c ;//主机现态
reg [8:0] m_state_n ;//主机次态
reg [5:0] s_state_c ;//从机现态
reg [5:0] s_state_n ;//从机次态
reg [5:0] cnt_1us ;//1us计数器
wire add_cnt_1us ;
wire end_cnt_1us ;
reg [19:0] cnt0 ;//复位脉冲、释放、存在脉冲、等待750ms
wire add_cnt0 ;
wire end_cnt0 ;
reg [19:0] X ;
reg [5:0] cnt1 ;//计数从机状态机每个状态持续时间
wire add_cnt1 ;
wire end_cnt1 ;
reg [5:0] Y ;
reg [4:0] cnt_bit ;
wire add_cnt_bit ;
wire end_cnt_bit ;
reg slave_ack ;//接收存在脉冲 0:存在 1:不存在
reg flag ;//0:发送温度转换命令 1:发送温度读取命令
reg [7:0] wr_data ;//缓存3个指令
reg [15:0] orign_data ;//采样温度值寄存器
reg [10:0] temp_data ;//二进制原码
wire [23:0] temp_data_w ;//组合逻辑计算实际温度值 十进制
wire m_idle2m_rest ;
wire m_rest2m_rele ;
wire m_rele2m_rack ;
wire m_rack2m_roms ;
wire m_roms2m_cont ;
wire m_roms2m_rcmd ;
wire m_cont2m_wait ;
wire m_wait2m_rest ;
wire m_rcmd2m_rtmp ;
wire m_rtmp2m_idle ;
wire s_idle2s_low ;
wire s_low2s_send ;
wire s_low2s_samp ;
wire s_send2s_rele ;
wire s_samp2s_rele ;
wire s_rele2s_low ;
wire s_rele2s_done ;
//主机状态机设计 描述状态转移
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
m_state_c <= M_IDLE;
end
else begin
m_state_c <= m_state_n;
end
end
//主机状态转移条件
always @(*) begin
case(m_state_c)
M_IDLE:begin
if(m_idle2m_rest)
m_state_n = M_REST;
else
m_state_n = m_state_c;
end
M_REST:begin
if(m_rest2m_rele)
m_state_n = M_RELE;
else
m_state_n = m_state_c;
end
M_RELE:begin
if(m_rele2m_rack)
m_state_n = M_RACK;
else
m_state_n = m_state_c;
end
M_RACK:begin
if(m_rack2m_roms)
m_state_n = M_ROMS;
else
m_state_n = m_state_c;
end
M_ROMS:begin
if(m_roms2m_cont)
m_state_n = M_CONT;
else if(m_roms2m_rcmd)
m_state_n = M_RCMD;
else
m_state_n = m_state_c;
end
M_CONT:begin
if(m_cont2m_wait)
m_state_n = M_WAIT;
else
m_state_n = m_state_c;
end
M_WAIT:begin
if(m_wait2m_rest)
m_state_n = M_REST;
else
m_state_n = m_state_c;
end
M_RCMD:begin
if(m_rcmd2m_rtmp)
m_state_n = M_RTMP;
else
m_state_n = m_state_c;
end
M_RTMP:begin
if(m_rtmp2m_idle)
m_state_n = M_IDLE;
else
m_state_n = m_state_c;
end
default:m_state_n = M_IDLE;
endcase
end
assign m_idle2m_rest = m_state_c == M_IDLE && (1'b1) ;//主机IDLE状态直接转换成复位状态
assign m_rest2m_rele = m_state_c == M_REST && (end_cnt0);//500us复位脉冲
assign m_rele2m_rack = m_state_c == M_RELE && (end_cnt0);//20us释放总线
assign m_rack2m_roms = m_state_c == M_RACK && (end_cnt0 && slave_ack == 1'b0);//200us,主机接收存在脉冲
assign m_roms2m_cont = m_state_c == M_ROMS && (s_state_c == S_DONE && flag == 1'b0);//主机发送完8bit跳过ROM命令 0:温度转化命令
assign m_roms2m_rcmd = m_state_c == M_ROMS && (s_state_c == S_DONE && flag == 1'b1);//主机发送完8bit跳过ROM命令 1:读温度命令
assign m_cont2m_wait = m_state_c == M_CONT && (s_state_c == S_DONE);//主机发送8bit温度转化命令
assign m_wait2m_rest = m_state_c == M_WAIT && (end_cnt0);//等待750ms转换完成
assign m_rcmd2m_rtmp = m_state_c == M_RCMD && (s_state_c == S_DONE);//主机发送8bit读命令 --等待从机接收数据完成
assign m_rtmp2m_idle = m_state_c == M_RTMP && (s_state_c == S_DONE);//主机读温度 --等待从机发送数据完成
//从机状态机设计 描述状态转移
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
s_state_c <= S_IDLE;
end
else begin
s_state_c <= s_state_n;
end
end
//从机状态转移条件
always @(*) begin
case(s_state_c)
S_IDLE:begin
if(s_idle2s_low)
s_state_n = S_LOW;
else
s_state_n = s_state_c;
end
S_LOW :begin
if(s_low2s_send)
s_state_n = S_SEND;
else if(s_low2s_samp)
s_state_n = S_SAMP;
else
s_state_n = s_state_c;
end
S_SEND:begin
if(s_send2s_rele)
s_state_n = S_RELE;
else
s_state_n = s_state_c;
end
S_SAMP:begin
if(s_samp2s_rele)
s_state_n = S_RELE;
else
s_state_n = s_state_c;
end
S_RELE:begin
if(s_rele2s_done)
s_state_n = S_DONE;
else if(s_rele2s_low)
s_state_n = S_LOW;
else
s_state_n = s_state_c;
end
S_DONE:begin
s_state_n = S_IDLE;
end
default:s_state_n = S_IDLE;
endcase
end
assign s_idle2s_low = s_state_c == S_IDLE && (m_state_c == M_ROMS ||
m_state_c == M_CONT || m_state_c == M_RCMD || m_state_c == M_RTMP);//从机发送接收数据检测到总线拉低 从机发送0或1告知主机是否任务完成 发送温度数据
assign s_low2s_send = s_state_c == S_LOW && (m_state_c == M_ROMS ||
m_state_c == M_CONT || m_state_c == M_RCMD) && end_cnt1;//从机发送数据 2us 从机发送0或1告知主机是否任务完成
assign s_low2s_samp = s_state_c == S_LOW && (m_state_c == M_RTMP && end_cnt1);//发送温度数据 2us 从机采样得到主机发送的命令码
assign s_send2s_rele = s_state_c == S_SEND && (end_cnt1);//主机读1bit (60us内完成)
assign s_samp2s_rele = s_state_c == S_SAMP && (end_cnt1);//主机写1bit (60us内完成)
assign s_rele2s_low = s_state_c == S_RELE && (end_cnt1 && end_cnt_bit == 1'b0);//主机读写完1bit (3us) 继续下一bit
assign s_rele2s_done = s_state_c == S_RELE && (end_cnt1 && end_cnt_bit == 1'b1);//主机读写完1bit (3us) bit写完
//1us计数器
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_1us <= 0;
end
else if(add_cnt_1us) begin
if(end_cnt_1us)begin
cnt_1us <= 0;
end
else begin
cnt_1us <= cnt_1us + 1;
end
end
end
assign add_cnt_1us = m_state_c != M_IDLE;//非IDLE状态持续计数
assign end_cnt_1us = add_cnt_1us && cnt_1us == TIME_1US - 1;
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt0 <= 0;
end
else if(add_cnt0) begin
if(end_cnt0)begin
cnt0 <= 0;
end
else begin
cnt0 <= cnt0 + 1;
end
end
end
assign add_cnt0 = (m_state_c == M_REST || m_state_c == M_RELE || m_state_c == M_RACK || m_state_c == M_WAIT) && end_cnt_1us;
assign end_cnt0 = add_cnt0 && cnt0 == X - 1;
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
X <= 0;
end
else if(m_state_c == M_REST)begin//复位:500us (480us)
X <= TIME_RST;
end
else if(m_state_c == M_RELE)begin//释放总线:20us (15-60us内)
X <= TIME_REL;
end
else if(m_state_c == M_RACK)begin//接收应答:200us (60-240us)
X <= TIME_PRE;
end
else if(m_state_c == M_WAIT) begin//等待:750ms (等待转换完成)
X <= TIME_WAIT;
end
end
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt1 <= 0;
end
else if(add_cnt1) begin
if(end_cnt1)begin
cnt1 <= 0;
end
else begin
cnt1 <= cnt1 + 1;
end
end
end
assign add_cnt1 = (s_state_c == S_LOW || s_state_c == S_SEND ||
s_state_c == S_SAMP || s_state_c == S_RELE) && end_cnt_1us;
assign end_cnt1 = add_cnt1 && cnt1 == Y - 1;
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
Y <= 0;
end
else if(s_state_c == S_LOW)begin
Y <= TIME_LOW;//主机拉低总线 2us (大于1us)
end
else if(s_state_c == S_SEND || s_state_c == S_SAMP) begin
Y <= TIME_RW;//主机读写1bit 60us (至少60us)
end
else begin
Y <= TIME_REC;//主机读写完1bit释放总线 3us (至少1us)
end
end
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_bit <= 0;
end
else if(add_cnt_bit) begin
if(end_cnt_bit)begin
cnt_bit <= 0;
end
else begin
cnt_bit <= cnt_bit + 1;
end
end
end
assign add_cnt_bit = s_state_c == S_RELE && end_cnt1;
assign end_cnt_bit = add_cnt_bit && cnt_bit == ((m_state_c == M_RTMP)?16-1:8-1);//读温度状态有16bit数据,其余状态8bit数据
//slave_ack 采样传感器的存在脉冲
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
slave_ack <= 1'b1;
end//接收应答状态 计数器计到60us 进行采样
else if(m_state_c == M_RACK && cnt0 == 60 && end_cnt_1us)begin
slave_ack <= dq_in;
end
end
[email protected](posedge clk or negedge rst_n)begin//命令发送标志 (区分温度转换和温度读取命令)
if(!rst_n)begin
flag <= 0;
end
else if(m_wait2m_rest)begin
flag <= 1'b1;
end
else if(m_rtmp2m_idle) begin
flag <= 1'b0;
end
end
//输出信号
//dq_out
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
dq_out <= 0;
end
else if(m_idle2m_rest | s_idle2s_low | s_rele2s_low | m_wait2m_rest)begin
dq_out <= 1'b0;
end
else if(s_low2s_send) begin
dq_out <= wr_data[cnt_bit];
end
end
//dq_out_en
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
dq_out_en <= 0;
end
else if(m_idle2m_rest | s_idle2s_low | s_rele2s_low | m_wait2m_rest)begin
dq_out_en <= 1'b1;//输出 dq_out
end
else if(m_rest2m_rele | s_send2s_rele | s_low2s_samp) begin
dq_out_en <= 1'b0;//不输出dq_out
end
end
//wr_data 命令
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
wr_data <= 0;
end
else if(m_rack2m_roms)begin///ROM跳过命令
wr_data <= CMD_ROMS;
end
else if(m_roms2m_cont) begin//温度转换命令
wr_data <= CMD_CONT;
end
else if(m_roms2m_rcmd)begin//读暂存器温度命令
wr_data <= CDM_RTMP;
end
end
//orign_data 温度采集
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
orign_data <= 0;
end
else if(s_state_c == S_SAMP && cnt1 == 12 && end_cnt_1us)begin
orign_data[cnt_bit] <= dq_in;
end
end
//temp_data 温度判断
[email protected](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_samp2s_rele)begin
if(orign_data[15])
temp_data <= ~orign_data[10:0] + 1'b1;//负数,取反加一
else
temp_data <= orign_data[10:0];//正数
end
end
/*实际的温度值为 temp_data * 0.0625; 为了保留4位小数精度,将实际温度值放大了10000倍, 即temp_data * 625;*/
assign temp_data_w = temp_data * 625;
//temp_out
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
temp_out <= 0;
end
else if(m_state_c == M_RTMP && s_rele2s_done)begin
temp_out <= temp_data_w;
end
end
//temp_out_vld
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
temp_out_vld <= 0;
end
else begin
temp_out_vld <= m_state_c == M_RTMP && s_rele2s_done;
end
end
//temp_sign
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
temp_sign <= 0;
end
else if(s_state_c == S_SAMP && cnt_bit == 15 && s_samp2s_rele)begin
temp_sign <= orign_data[15];
end
end
endmodule
3、控制模块
module control(
input clk ,//时钟信号
input rst_n ,//复位信号
input din_sign,
input [23:0] din ,
input din_vld ,
output dout_sign,
output [23:0] dout ,
output reg dout_vld
);
//中间信号定义
reg [23:0] din_r ;
reg din_vld_r0 ;
reg din_vld_r1 ;
wire [7:0] tmp_int_w ;//整数部分
reg [7:0] tmp_int_r ;
wire [3:0] tmp_int_w2 ;
wire [3:0] tmp_int_w1 ;
wire [3:0] tmp_int_w0 ;
reg [3:0] tmp_int_r2 ;
reg [3:0] tmp_int_r1 ;
reg [3:0] tmp_int_r0 ;
wire [15:0] tmp_dot_w ;//小数部分
reg [15:0] tmp_dot_r ;
wire [3:0] tmp_dot_w3 ;
wire [3:0] tmp_dot_w2 ;
wire [3:0] tmp_dot_w1 ;
wire [3:0] tmp_dot_w0 ;
reg [3:0] tmp_dot_r3 ;
reg [3:0] tmp_dot_r2 ;
reg [3:0] tmp_dot_r1 ;
reg [3:0] tmp_dot_r0 ;
//din_r
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
din_r <= 0;
end
else if(din_vld)begin
din_r <= din;
end
end
//din_vld_r0 din_vld_r1 打拍
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
din_vld_r0 <= 0;
din_vld_r1 <= 0;
end
else begin
din_vld_r0 <= din_vld;
din_vld_r1 <= din_vld_r0;
end
end
assign tmp_int_w = din_r/10000;
assign tmp_dot_w = din_r%10000;
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
tmp_int_r <= 0;
end
else if(din_vld_r0)begin
tmp_int_r <= tmp_int_w;
tmp_dot_r <= tmp_dot_w;
end
end
assign tmp_int_w2 = tmp_int_r/100;//百位
assign tmp_int_w1 = tmp_int_r/10%10;//十位
assign tmp_int_w0 = tmp_int_r%10;//个位
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
tmp_int_r2 <= 0;
tmp_int_r1 <= 0;
tmp_int_r0 <= 0;
end
else if(din_vld_r1)begin
tmp_int_r2 <= tmp_int_w2;
tmp_int_r1 <= tmp_int_w1;
tmp_int_r0 <= tmp_int_w0;
end
end
assign tmp_dot_w0 = tmp_dot_r/1000;
assign tmp_dot_w1 = tmp_dot_r/100%10;
assign tmp_dot_w2 = tmp_dot_r/10%10;
assign tmp_dot_w3 = tmp_dot_r%10;
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
tmp_dot_r0 <= 0;
tmp_dot_r1 <= 0;
tmp_dot_r2 <= 0;
tmp_dot_r3 <= 0;
end
else if(din_vld_r1)begin
tmp_dot_r0 <= tmp_dot_w0;
tmp_dot_r1 <= tmp_dot_w1;
tmp_dot_r2 <= tmp_dot_w2;
tmp_dot_r3 <= tmp_dot_w3;
end
end
assign dout = {
tmp_int_r1,tmp_int_r0,tmp_dot_r0,tmp_dot_r1,tmp_dot_r2,tmp_dot_r3};
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
dout_vld <= 1'b0;
end
else begin
dout_vld <= din_vld_r1;
end
end
assign dout_sign = din_sign;
endmodule
4、数码管译码模块
module seg_driver(
input clk ,//时钟信号
input rst_n ,//复位信号
input din_sign,
input [23:0] din ,
input din_vld ,
output reg [5:0] sel ,
output reg [7:0] dig
);
//参数定义
parameter TIME_1MS = 25_000,
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,
P = 7'b000_1111,
N = 7'b011_1111;
//信号定义
reg [19:0] cnt_1ms;//扫描频率计数器
wire add_cnt_1ms;
wire end_cnt_1ms;
reg [3 :0] disp_num;
reg dot;
//数码管扫描频率计数
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_1ms <= 0;
end
else if(add_cnt_1ms) begin
if(end_cnt_1ms)begin
cnt_1ms <= 0;
end
else begin
cnt_1ms <= cnt_1ms + 1;
end
end
end
assign add_cnt_1ms = 1'b1;
assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == TIME_1MS - 1;
//seg_sel 数码管片选信号
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
sel <= 6'b111110;
end
else if(end_cnt_1ms) begin
sel <= {
sel[4:0],sel[5]};
end
end
//译码
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
disp_num <= 0;
end
else begin
case(sel)
6'b111_110:begin disp_num <= din_sign?4'ha:4'hb;dot <= 1; end
6'b111_101:begin disp_num <= din[23:20];dot <= 1;end
6'b111_011:begin disp_num <= din[19:16];dot <= 0;end
6'b110_111:begin disp_num <= din[15:12];dot <= 1;end
6'b101_111:begin disp_num <= din[11:8] ;dot <= 1;end
6'b011_111:begin disp_num <= din[7 :4] ;dot <= 1;end
default :begin disp_num <= 4'hF ;end
endcase
end
end
//segment 段选译码
[email protected](posedge clk or negedge rst_n)begin
if(!rst_n)begin
dig <= 8'hff;
end
else begin//显示小数点
case(disp_num)
4'h0:dig <= {
dot,ZERO } ;
4'h1:dig <= {
dot,ONE } ;
4'h2:dig <= {
dot,TWO } ;
4'h3:dig <= {
dot,THREE} ;
4'h4:dig <= {
dot,FOUR } ;
4'h5:dig <= {
dot,FIVE } ;
4'h6:dig <= {
dot,SIX } ;
4'h7:dig <= {
dot,SEVEN} ;
4'h8:dig <= {
dot,EIGHT} ;
4'h9:dig <= {
dot,NINE } ;
4'ha:dig <= {
dot,N } ;
4'hb:dig <= {
dot,P } ;
default:dig <= 8'hff ;
endcase
end
end
endmodule
四、功能仿真
1、对ds18b20模块进行仿真
`timescale 1ns/1ps
module ds18b20_driver_tb ();
//激励信号定义
reg clk ;
reg rst_n ;
reg dq_in ;
//输出信号定义
wire dq_out ;
wire dq_out_en ;
wire temp_sign ;
wire [23:0] temp_out ;
wire temp_out_vld;
//时钟周期参数定义
parameter CYCLE = 20;
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_sign (temp_sign ), //温度值的正负
.temp_out (temp_out ), //输出十进制温度数据
.temp_out_vld (temp_out_vld ) //温度采集数据有效
);
defparam u_ds18b20_driver.TIME_RST = 200 ,
u_ds18b20_driver.TIME_PRE = 100 ,
u_ds18b20_driver.TIME_WAIT = 750 ;
//产生时钟
initial clk = 1'b0;
always #(CYCLE/2) clk = ~clk;
integer i=0;
//产生激励
initial begin
rst_n = 1'b0;
dq_in = 0 ;
#(CYCLE*20);
rst_n = 1'b1;
repeat(5)begin
for(i=0;i<500000;i=i+1)begin
dq_in = {
$random};
#(CYCLE*20);
end
#(CYCLE*20);
end
$stop;
end
endmodule
2、对总体进行仿真
`timescale 1ns/1ps
module temp_detect_tb ();
//激励信号定义
reg clk ;
reg rst_n ;
reg dq_in ;
//输出信号定义
wire dq_out ;
wire dq_out_en ;
wire temp_sign ;
wire [23:0] temp_out ;
wire temp_out_vld;
//信号定义
wire [23:0] dout ;
wire dout_vld ;
wire [5:0] sel ;
wire [7:0] dig ;
//时钟周期参数定义
parameter CYCLE = 20;
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_sign (temp_sign ), //温度值的正负
.temp_out (temp_out ), //输出十进制温度数据
.temp_out_vld (temp_out_vld ) //温度采集数据有效
);
control u_control(
.clk (clk ),
.rst_n (rst_n ),
.din_sign (temp_sign ),
.din (temp_out ),
.din_vld (temp_out_vld ),
.dout (dout ), //输出温度值数码管对应位置的bcd码
.dout_vld (dout_vld ),
.dout_sign ( )
);
seg_driver u_seg_driver(
.clk (clk ),
.rst_n (rst_n ),
.din_sign (temp_sign ),
.din (dout ),
.din_vld (dout_vld ), //数码管显示数据切换
.sel (sel ),
.dig (dig )
);
defparam u_ds18b20_driver.TIME_RST = 200 ,
u_ds18b20_driver.TIME_PRE = 100 ,
u_ds18b20_driver.TIME_WAIT = 750 ;
//产生时钟
initial clk = 1'b0;
always #(CYCLE/2) clk = ~clk;
integer i=0;
//产生激励
initial begin
rst_n = 1'b0;
dq_in = 0 ;
#(CYCLE*20);
rst_n = 1'b1;
repeat(5)begin
for(i=0;i<500000;i=i+1)begin
dq_in = {
$random};
#(CYCLE*20);
end
#(CYCLE*20);
end
$stop;
end
endmodule
五、仿真波形
边栏推荐
- 程序化交易与主观交易对盈利曲线的影响!
- QueryDet:级联稀疏query加速高分辨率下的小目标检测
- 【LeetCode】Day112-重复的DNA序列
- Environment configuration of ESP32 (arduino arduino2.0 VScode platform which is easy to use?)
- oracle的基数会影响到查询速度吗?
- 用户如何克服程序化交易中的情绪问题?
- STC8H开发(十五): GPIO驱动Ci24R1无线模块
- C语言 recv()函数、recvfrom()函数、recvmsg()函数
- Qnet弱网测试工具操作指南
- 2022-08-10 第六小组 瞒春 学习笔记
猜你喜欢
随机推荐
Qnet Weak Network Test Tool Operation Guide
uni-app - 获取汉字拼音首字母(根据中文获取拼音首字母)
What is third-party payment?
leetcode: 358. Reorder strings at K distance intervals
【愚公系列】2022年08月 Go教学课程 035-接口和继承和转换与空接口
程序化交易的策略类型可以分为哪几种?
互换性与测量技术——表面粗糙度选取和标注方法
"How to kick a bad habit to read notes?
[yu gong series] Go program 035-08 2022 interfaces and inheritance and transformation and empty interface
QueryDet: Cascading Sparse Query Accelerates Small Object Detection at High Resolution
QueryDet:级联稀疏query加速高分辨率下的小目标检测
CSDN blog replacement skin
FTP错误代码列表
console.log alternatives you didn't know about
2022-08-10 The sixth group Hiding spring study notes
Official release丨VS Code 1.70
The 125th day of starting a business - a note
A large horse carries 2 stone of grain, a middle horse carries 1 stone of grain, and two ponies carry one stone of grain. It takes 100 horses to carry 100 stone of grain. How to distribute it?
pathman_config、pathman_config_params 删除后,如何重建?
The development of the massage chair control panel makes the massage chair simple and intelligent