一.、一.内部结构框图
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 =