特点基础介绍
懒得写,可以看这位大哥的基础介绍:https://blog.csdn.net/as480133937/article/details/112604303
注意事项
- 硬件连接一定记得输出口要用上拉电阻,要不然释放总线无法拉高。
- 供电方式:两种供电方式(官方文档,或者看上面老哥的文档)都可以,无所谓。
- ds18b20的输入输出是一根线所以需要用到三态门来控制输入输出。如下
wire dq_in;
reg dq_out;
reg dq_en;
assign dq_in = (!dq_en)&dq; //高阻态,总线输入给到dq_in
assign dq = (dq_en) ? dq_out : 1'bz; //使能总线则输出,释放总线则为高阻
代码书写重点
1. rom查询命令的流程
上图是官方文档中给出rom命令的使用流程,从图中总结出IDd读取的流程就是:
复位---->写rom[33h]命令---->读出ID,整体的步骤就这三步。
2. 复位、读写时序
- 复位时序
上图是官方文档中的复位时序图,
其中前半部分是我们需要输出的复位信号,首先是使能总线dq_en=1,同时拉低总线dq_out=0,在文档中要求主机复位低电平必须大于480us,最大值没有说,但是适当的大于480us就可以。此时需要释放总线dq_en=0,在释放总线后上拉电阻会将总线拉高,ds18b20在检测到这个高电平时会等待15-60us后,将总线拉低60-240us,所以在释放总线15-60us后我们只需要检测输入信号dq_in是否为低电平(因为刚才已经释放总线了所以输出变输入了),只要是低电平就说明复位成功。复位代码如下
INIT_1 : begin
if (t_cnt_us == T_INIT) begin
t_cnt_us <= 0;
flag_ack <= 0;
end
else begin
t_cnt_us <= t_cnt_us + 1'b1;
if (t_cnt_us <= 20'd499) begin
dq_en <= 1;
dq_out <= 0;
end
else begin
dq_en <= 0;
if (t_cnt_us == 20'd570 && !dq_in)
flag_ack <= 1;
end
end
end
这个是我状态机的一部分,时序逻辑可以看出,我这边复位总共用了T_INIT=1000us,(拉低总线等待了500us,然后等待响应500us,两边只要都大于480us就可)。
2. 写时序
写0和写1都要求持续时间必须大于60us小于120us,写0很简单,就是控制总线dq_en=1,拉低输出dq_out=0,然后维持时间控制在时序要求的那个范围就可以。写1,首先控制总线dq_en=1,拉低输出dq_out=0维持时间大于1us小于15us,然后释放总线dq_en=0。图中还显示在一次写完后必须释放总线dq_en=0,而且时间要大于1us。到此写0和写1的时序就可,代码如下
WR_CMD : begin
if (t_cnt_us == 20'd69) begin
t_cnt_us <= 0;
dq_en <= 0;
if (bit_cnt == 7'd7)
bit_cnt <= 0;
else
bit_cnt <= bit_cnt + 1;
end
else begin
t_cnt_us <= t_cnt_us + 1;
if (t_cnt_us <= 1) begin //两次写的间隙释放总线,这里维持了2us
dq_en <= 0;
dq_out <= 0;
end
else if (t_cnt_us <= 3 && t_cnt_us >= 2) begin //写1需要先拉低总线1-15us,写0都是拉低,所以先拉低个2us
dq_en <= 1;
dq_out <= 0;
end
else begin
if (READ_ROM[bit_cnt] == 0) begin //写0,拉低总线
dq_en <= 1;
dq_out <= 0;
end
else begin //写1,已经拉低过总线所以这直接释放总线
dq_en <= 0;
dq_out <= 0;
end
end
end
end
- 读时序
读0和读1的维持时间是一样的都是60-120us之间就可以,无论读1还是读0两个读取操作之间都得先控制总线dq_en=1,拉低输出dq_out=0,维持至少1us然后释放总线dq_en=0,然后就可以读0或者读1,当然读取操作必须在15us以内读取。代码如下</