DS18B20 温度传感器

DS18B20 温度传感器

一、DS18B20概述

DS18B20是一种数字温度传感器,应用非常广泛。它输出的是数字信号,同时具有体积小,硬件资源耗费少,抗干扰能力强,精度高等特点。
在这里插入图片描述

DS18B20温度传感器特点

1、采用单总线的接口方式 与微处理器连接时仅需要一条口线即可实现微处理器与 DS18B20 的双向通讯。单总线具有经济性好,抗干扰能力强,适合于恶劣环境的现场温度测量。

2、测温范围: DS18B20温度传感器的测温范围可达-55℃~+125℃,在-10℃到+85℃范围内误差为±0.4°。

3、支持多点组网功能:多个DS18B20温度传感器可以并联在一条数据线上,最多可以并联8个,实现多点测温。

4、工作电源: 3.0~5.5V/DC ,DS18B20温度传感器可以采用外部独立电源供电,也可以用数据线寄生电源供电,负压特性电源极性接反时,温度计不会因发热而烧毁,但不能正常工作。。

5、DS18B20温度传感器在应用过程中不需要任何外围元件

6、DS18B20温度传感器测量温度的结果以9~12位数字量方式串行传送。

7、掉电保护功能, DS18B20温度传感器内部含有 EEPROM ,通过配置寄存器可以设定数字转换精度和报警温度。在DS18B20温度传感器掉电以后仍可保存分辨率及报警温度的设定值。

8、DS18B20温度传感器返回16位二进制数代表此刻探测的温度值,其高五位代表正负。如果高五位全部为1,则代表返回的温度值为负值。如果高五位全部为0,则代表返回的温度值为正值。后面的11位数据代表温度的绝对值,将其转换为十进制数值之后,再乘以0.0625即可获得此时的温度值。

二、DS18B20手册提炼

2.1 引脚说明

在这里插入图片描述
在这里插入图片描述
只有三个引脚,说明ds18b20是单总线,使用三态门的方式去实现单总线,原理图如下:
![在这里插入图片描述](https://img-blog.csdnimg.cn/e56fb611f05142f39fbef2eadaebd5dc.png

	assign dq = dq_oe ? dq_out : 1'bz;
	assign dq_in = dq;

dq_in 就是ds18b20传感器发来的数据

dq_out就是主机发给ds18b20的数据

dq_oe就是主机发送使能,1能发,0不能发

2.2 数据说明

在这里插入图片描述在这里插入图片描述

img

数据[10:0]是温度数据

数据[15:11]是温度的正负,1代表负,0代表正

2.3 DS18B20暂存器数据

在这里插入图片描述

DS18B20的每个暂存器都有8bit存储空间,用来存储相应数据,

byte0和byte1分别为温度数据的低位和高位,用来储存测量到的温度值,且这两个字节都是只读的;

byte2和byte3为TH、TL告警触发值的拷贝,可以在从片内的电可擦可编程只读存储器EEPROM中读出,也可以通过总线控制器发出的[48H]指令将暂存器中TH、TL的值写入到EEPROM,掉电后EEPROM中的数据不会丢失;

byte4的配置寄存器用来配置温度转换的精确度(最大为12位精度);

byte5、6、7为保留位,禁止写入;

byte8亦为只读存储器,用来存储以上8字节的CRC校验码。

2.4 DS18B20需要的命令

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.5 初始化时序

机控制总线给从机发送复位脉冲480us,主机释放总线从机等待15-60us,从机控制总线给主机发送存在脉冲60-240us

img

写时隙(主机向从机传数据)

无论是写0还是写1,一开始都是主机控制总线拉低总线15us,如果是写0,需要在15us-60us内主机控制总线保持低电平,如果是写1,需要在15us-60us内主机释放总线,上拉电阻将总线拉高,

img

2.6 关键时间参数

在这里插入图片描述

三、DS18B20模块划分

DS18B20 的设计分为系统框架图如下:

在这里插入图片描述

四、ds18b20_drive模块

4.1 主从状态机设计

在这里插入图片描述

  1. M_IDLE :主状态机空闲状态,当enable信号有效时,复位脉冲持续时间M_REST 状态;**

  2. M_REST:发送复位脉冲,复位脉冲发送完成后,跳转至M_RELS 状态,复位脉冲持续时间为48us;

  3. M_RELS :释放总线15~60us后,跳转至M_RACK 状态;

  4. M_RACK :判断是否有存在脉冲,未收到存在脉冲跳转至M_IDLE状态,收到存在脉冲则跳转至M_ROMS状态;

  5. M_ROMS :发送ROM命令,跳过ROM,状态跳转至M_CONT发送温度转换命令,状态跳转至M_RCMD则发送读暂存器命令

  6. M_CONT :发送温度转换命令,温度转换命令发送完成后跳转至M_WAIT

  7. M_WAIT = :等待温度转化完成后,(等待时间为750ms),跳转至M_REST;

  8. M_RCMD =:发送读暂存器命令,读暂存器命令发送完成后跳转至M_RTMP

  9. M_RTMP = :接收温度数据,16bit温度数据读取完成后跳回M_IDLE。

    	assign m_idle2m_rest    =   m_state == M_IDLE &&  enable;         //温度采集一直工作
        assign m_rest2m_rels    =   m_state == M_REST && end_cnt;
        assign m_rels2m_rack    =   m_state == M_RELS && end_cnt;
    
        assign m_rack2m_idle    =   m_state == M_RACK && end_cnt && (rx_ack == 1);  //未收到存在脉冲,存在脉冲持续时间240us已到
        assign m_rack2m_roms    =   m_state == M_RACK && end_cnt && (rx_ack == 0);  //收到了存在脉冲
    
        assign m_roms2m_cont    =   m_state == M_ROMS && s_done2s_idle && (m_flag == 0);     //命令发送完成了
        assign m_roms2m_rcmd    =   m_state == M_ROMS && s_done2s_idle && (m_flag == 1);
    
        assign m_cont2m_wait    =   m_state == M_CONT && s_done2s_idle;
        assign m_wait2m_rest    =   m_state == M_WAIT && end_cnt;           //750ms计数完成
        assign m_rcmd2m_rtmp    =   m_state == M_RCMD && s_done2s_idle;
        assign m_rtmp2m_idle    =   m_state == M_RTMP && s_done2s_idle;
    

状态机主从互动:

/**************************************************************
                        从状态机flag
**************************************************************/
//辅助从状态机状态跳转
    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            s_flag = 0;
        else if(s_done2s_idle)
            s_flag = 0;
        else if(end_bit_cnt)
            s_flag = 1;

在这里插入图片描述

  1. S_IDLE :从状态机空闲状态,接收到cmd_vld信号时,从状态机相应;
  2. S_LOW :读写时隙拉低,此时主状态机在M_RTMP状态的前提下,1us的拉低时间后跳转至S_SAMP ,否则1us计时结束后 跳转至S_SEND;
  3. S_SEND :写时隙持续59us,一次写时隙最少60us,计时结束后跳转至S_RELS ;
  4. S_SAMP :读时隙,持续59us后跳转至S_RELS ;
  5. S_RELS :时隙之间的间隔时间,1us释放时间达到,并且数据已经传输完成,跳转至S_DONE 状态,则1us计时结束后跳转至S_LOW ;
  6. S_DONE :一次命令或者数据执行完成,无条件跳转回到S_IDLE 。
	assign  s_idle2s_low    =   s_state == S_IDLE   &&  cmd_vld;
    assign  s_low2s_samp    =   s_state == S_LOW    &&  end_cnt && m_state == M_RTMP;   //1us的拉低时间已到
    assign  s_low2s_send    =   s_state == S_LOW    &&  end_cnt;    //1us
    assign  s_send2s_rels   =   s_state == S_SEND   &&  end_cnt;    //59us
    assign  s_samp2s_rels   =   s_state == S_SAMP   &&  end_cnt;    //59us
    assign  s_rels2s_done   =   s_state == S_RELS   &&  end_cnt && s_flag;    //1us释放时间达到,并且数据已经传输完成
    assign  s_rels2s_low    =   s_state == S_RELS   &&  end_cnt;    //1us
    assign  s_done2s_idle   =   s_state == S_DONE   &&  1;

4.2 三态门设计

/**************************************************************
                        三态门控制
**************************************************************/
    assign dq = dq_oe? dq_out : 1'bz;
    assign dq_in = dq;

    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            dq_oe <= 0;
        else if(m_idle2m_rest || m_rack2m_roms || m_roms2m_cont || m_wait2m_rest || m_roms2m_rcmd || s_idle2s_low || s_rels2s_low)
            dq_oe <= 1;
        else if(m_rest2m_rels || m_cont2m_wait || s_low2s_samp || s_send2s_rels)
            dq_oe <= 0;

    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            dq_out <= 0;
        else if(m_idle2m_rest || m_wait2m_rest || s_idle2s_low || s_rels2s_low)
            dq_out <= 0;
        else if(s_low2s_send)
            dq_out <= cmd[cnt_bit];

4.3 时间参数

    parameter   T_CYC   	=   20  		,   //工作时钟周期
     			RST_T   	=   480_000     ,   //复位时间
                RELS_T  	=   15_000      ,   //复位时间释放时间
                RACK_T  	=   240_000     ,   //存在脉冲持续时间
                WAIT_T  	=   750_000_000 ,   //温度转换等待时间
                LOW_T  	 	=   1_000       ,   //时隙拉低1us,时隙间隔释放时间
                SLOT_T  	=   59_000      ,   //读写时隙存在时间
                RX_RACK_T   =   60_000  	,   //判断存在脉冲是否生效的时刻
                RX_DATA_T   =   12_000  	;   //读时隙接收数据点

4.4 计数器复用

/**************************************************************
                            计数器
**************************************************************/
    always@(posedge clk or negedge rst_n)	
        if(!rst_n)								
            cnt <= 'd0;						
        else    if(add_cnt) begin				
            if(end_cnt)						
                cnt <= 'd0;  				
            else									
                cnt <= cnt + 1'b1;		
        end											
    assign add_cnt = m_state != M_IDLE;
    assign end_cnt = add_cnt && cnt == cnt_max - 1;

    always@(*)
        case(m_state)
            M_REST  :   cnt_max = RST_T  / T_CYC;    //复位脉冲持续时间
            M_RELS  :   cnt_max = RELS_T / T_CYC;    //复位脉冲释放时间
            M_RACK  :   cnt_max = RACK_T / T_CYC;    //存在脉冲持续时间
            M_WAIT  :   cnt_max = WAIT_T / T_CYC;    //温度转换时间
            //实现命令/读取数据(从状态机工作)
            M_ROMS,M_CONT,M_RCMD,M_RTMP :
                case(s_state)
                    S_LOW,S_RELS    :   cnt_max = LOW_T     / T_CYC;    //1us拉低时间,或者时隙间隔时间
                    S_SEND,S_SAMP   :   cnt_max = SLOT_T    / T_CYC;    //59us时隙持续时间
                    default :   cnt_max = 1;
                endcase  
            default :   cnt_max = 1;
        endcase

4.5 接收存在脉冲

/**************************************************************
                        接收存在脉冲
**************************************************************/
    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            rx_ack <= 1;
        else if(m_state == M_REST)  //发送复位脉冲时,复位该信号
            rx_ack <= 1;
        else if(m_state == M_RACK && rx_ack == 1)    //在接收存在脉冲的状态下,在采样时刻点接收dq端的数据
            rx_ack <= dq_in;

4.6 发送命令控制

/**************************************************************
                        发送命令控制
**************************************************************/
	localparam  SKIP    =   8'hCC   ,   //跳过ROM命令
                CONV    =   8'h44   ,   //温度转换命令
                RSCR    =   8'hBE   ;   //读暂存器命令

    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            cmd <= 8'h00;
        else case(m_state)
            M_ROMS  :   cmd <= SKIP;
            M_CONT  :   cmd <= CONV;
            M_RCMD  :   cmd <= RSCR;
            default :   cmd <= 8'h00;
        endcase

    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            cmd_vld <= 0;
        else if(m_rack2m_roms || m_roms2m_cont || m_roms2m_rcmd || m_rcmd2m_rtmp)
            cmd_vld <= 1;
        else
            cmd_vld <= 0;

4.7 接收温度数据

/**************************************************************
                        接收数据
**************************************************************/
    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            rx_data <= 0;
        else if(s_state == S_SAMP && cnt == RX_DATA_T/T_CYC)
            rx_data <= {dq_in,rx_data[15:1]};
        else if(m_state == M_IDLE)
            rx_data <= 0;

    assign rx_data_vld = m_state == M_RTMP && s_done2s_idle;

//原始数据处理,补码转原码
    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            true_data <= 0;
        else if(rx_data_vld) begin
            if(rx_data[15]) //负数  补码转原码
                true_data <= ~rx_data[10:0] + 1;
            else 
                true_data <= rx_data[10:0];
        end

//扩大数据1000倍,根据温度精度,计算实际的温度值    *10000*0.0625
    assign temp_data = true_data * 625;

    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            temp_data_vld <= 0;
        else
            temp_data_vld <= rx_data_vld;

五、uart_tx_ctrl模块及hex2ascii模块

/**************************************功能介绍***********************************
Date	: 
Author	: linxiaoxiao.
Version	: 
Description: 温度数据处理后传输至串口进行显示
*********************************************************************************/
//---------<模块及端口声名>------------------------------------------------------
module uart_tx_ctrl( 
    input				clk		        ,
    input				rst_n	        ,
    input               enable          ,
    input               uart_tx_ready    ,
    input		[23:0]	bcd_data	    ,
    input		    	bcd_data_vld	,
    output	reg [7:0]	uart_tx_data	,
    output		        uart_tx_data_vld
   
);								 
//---------<参数定义>--------------------------------------------------------- 
    //状态机参数定义
    localparam  IDLE   = 'b01,//
                DATA   = 'b10;//

    parameter   NUM_MAX = 14;
//---------<内部信号定义>-----------------------------------------------------
    reg			[4:0]	    cnt_num	   	;
    wire					add_cnt_num,end_cnt_num	;
    
    wire                    ascii_data_vld;
    wire        [47:0]      ascii_data    ;

    reg 	    [1:0]	    state      ;//现态
/****************************************************************
                    例化
****************************************************************/
hex2ascii hex2ascii_inst( 
    /* input				 */.clk		       ( clk	        ) ,
    /* input				 */.rst_n	       ( rst_n          ) ,
    /* input		[23:0]	 */.hex_din	       ( bcd_data       ) ,
    /* input		    	 */.hex_din_vld	   ( bcd_data_vld   ) ,
    /* output		[47:0]	 */.ascii_dout	   ( ascii_data	    ) ,
    /* output		    	 */.ascii_dout_vld ( ascii_data_vld )	
);			

/****************************************************************
                    状态机
****************************************************************/   
    // 时序逻辑描述状态转移
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            state <= IDLE;
        end 
        else case(state)
                IDLE    : if(ascii_data_vld && enable) 
                           state <= DATA;
                DATA    : if(end_cnt_num) 
                           state <= IDLE;
                default :  state <= IDLE;
            endcase
        end
/****************************************************************
                    发送数据计数
****************************************************************/               
    
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_num <= 'd0;
        end 
        else if(add_cnt_num)begin 
            if(end_cnt_num)begin 
                cnt_num <= 'd0;
            end
            else begin 
                cnt_num <= cnt_num + 1'b1;
            end 
        end
    end 
    
    assign add_cnt_num = state == DATA && uart_tx_ready;
    assign end_cnt_num = add_cnt_num && cnt_num == NUM_MAX - 1;
    
always @(*)begin 
    case (cnt_num)
        0  :   uart_tx_data = 8'h00;
        1  :   uart_tx_data = 8'hce;    //温
        2  :   uart_tx_data = 8'hc2;
        3  :   uart_tx_data = 8'hb6;
        4  :   uart_tx_data = 8'hc8;
        5  :   uart_tx_data = 8'h3a;
        6  :   uart_tx_data = ascii_data[47-:8]; 
        7  :   uart_tx_data = ascii_data[39-:8]; 
        8  :   uart_tx_data = 8'h2e;  
        9  :   uart_tx_data = ascii_data[31-:8];  
        10 :   uart_tx_data = ascii_data[23-:8];  
        11 :   uart_tx_data = ascii_data[15-:8]; 
        12 :   uart_tx_data = ascii_data[7-:8];  
        13 :   uart_tx_data = 8'h0d;
        default: uart_tx_data = 0;
    endcase
end    

    assign  uart_tx_data_vld = state == DATA;

endmodule
/**************************************功能介绍***********************************
Date	: 
Author	: linxiaoxiao.
Version	: 
Description: 实现16进制转换成ASCII码
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module hex2ascii( 
    input				clk		        ,
    input				rst_n	        ,
    input		[23:0]	hex_din	        ,
    input		    	hex_din_vld	    ,
    output		[47:0]	ascii_dout	    ,
    output		    	ascii_dout_vld	
);								 

//---------<内部信号定义>-----------------------------------------------------
    wire         [47:0]       ascii_data      ;
    reg                       ascii_data_vld  ;

    assign  ascii_data[7:0]     = hex_din[3:0]   + 8'd48; 
    assign  ascii_data[15:8]    = hex_din[7:4]   + 8'd48;
    assign  ascii_data[23:16]   = hex_din[11:8]  + 8'd48;
    assign  ascii_data[31:24]   = hex_din[15:12] + 8'd48;
    assign  ascii_data[39:32]   = hex_din[19:16] + 8'd48;
    assign  ascii_data[47:40]   = hex_din[23:20] + 8'd48;
    
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            ascii_data_vld <= 'd0;
        end 
        else begin 
            ascii_data_vld <= hex_din_vld;
        end 
    end
    assign      ascii_dout      = ascii_data    ;
    assign      ascii_dout_vld  = ascii_data_vld;
    

六、顶层设计

/**************************************功能介绍***********************************
Date	: 
Author	: linxiaoxiao.
Version	: 
Description: 顶层文件
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module top( 
    input				clk		    ,
    input				rst_n	    ,
    input               rx          ,
    output              tx          ,
    inout               dq      
);								    
//---------<内部信号定义>-----------------------------------------------------
    wire    [20:0]      temp_data             ;
    wire    [23:0]      bcd_data              ;
    wire                temp_data_vld         ;
    reg     [5:0]       reg_seg_mask          ;
    wire    [5:0]       seg_mask              ;
    wire    [7:0]       data                  ;
    reg     [1:0]       enable                ;
    reg     [23:0]	    reg_bcd_data	      ;
    wire                bcd_data_vld          ;  
    wire                tx_ready              ; 
    wire    [7:0]       uart_tx_data	      ;   
    wire                uart_tx_data_vld      ;
/****************************************************************
                    模块例化
****************************************************************/
    ds18b20_drive ds18b20_drive_inst ( 
        /* input                */.clk           ( clk           ),
        /* input                */.rst_n         ( rst_n         ),
        /* input                */.enable        ( 1    ),
        /* output      [20:0]   */.temp_data     ( temp_data     ),
        /* output  reg          */.temp_data_vld ( temp_data_vld ),
        /* inout                */.dq            ( dq            )  
    );			
    
    control control_inst( 
        /* input				 */.clk		     ( clk		     ),
        /* input				 */.rst_n	     ( rst_n	     ),
        /* input		[23:0]   */.temp_out   	 ( temp_data   	 ),
        /* input		    	 */.temp_out_vld ( temp_data_vld ),
        /* output	    [23:0]   */.bcd_data	 ( bcd_data	     ),
        /* output                */.bcd_data_vld ( bcd_data_vld  )
    );								
    tx_fsm_uart #(
        .CHECK_BIT ("None"     ),  //校验方法,“None”无校验,“Odd”奇校验,“Even”偶校验
        .BPS       (115200    ),
        .CLK       (50_000_000) 
    )tx_fsm_uart_inst(
        /* input				 */.clk		    ( clk		       ),
        /* input				 */.rst_n	    ( rst_n	           ),
        /* input				 */.tx_data_vld	( uart_tx_data_vld ),
        /* input		[7:0]	 */.tx_data	    ( uart_tx_data     ),
        /* output	    	     */.ready	    ( tx_ready         ),
        /* output	reg	         */.tx	        ( tx	           )
    );	
    uart_tx_ctrl uart_tx_ctrl_inst( 
        /* input				 */.clk		         ( clk		        ),
        /* input				 */.rst_n	         ( rst_n	        ),
        /* input		[23:0]	 */.bcd_data	     ( bcd_data	        ),
        /* input		    	 */.bcd_data_vld	 ( bcd_data_vld	    ),
        /* input                 */.enable           ( 1        ),
        /* output	reg [7:0]	 */.uart_tx_data	 ( uart_tx_data	    ),
        /* output		         */.uart_tx_data_vld ( uart_tx_data_vld ),
        /* input                 */.uart_tx_ready    ( tx_ready         )   
    );						
    
endmodule

七、测试

7.1 信号抓取

在这里插入图片描述

7.2 串口显示

在这里插入图片描述

  • 26
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值