杭州 建设网站制作怎样下载优化大师
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是单总线,使用三态门的方式去实现单总线,原理图如下:
;
byte5、6、7为保留位,禁止写入;
byte8亦为只读存储器,用来存储以上8字节的CRC校验码。
2.4 DS18B20需要的命令
2.5 初始化时序
主机控制总线给从机发送复位脉冲480us,主机释放总线从机等待15-60us,从机控制总线给主机发送存在脉冲60-240us
写时隙(主机向从机传数据)
无论是写0还是写1,一开始都是主机控制总线拉低总线15us,如果是写0,需要在15us-60us内主机控制总线保持低电平,如果是写1,需要在15us-60us内主机释放总线,上拉电阻将总线拉高,
2.6 关键时间参数
三、DS18B20模块划分
DS18B20 的设计分为系统框架图如下:
四、ds18b20_drive模块
4.1 主从状态机设计
-
M_IDLE :主状态机空闲状态,当enable信号有效时,复位脉冲持续时间M_REST 状态;**
-
M_REST:发送复位脉冲,复位脉冲发送完成后,跳转至M_RELS 状态,复位脉冲持续时间为48us;
-
M_RELS :释放总线15~60us后,跳转至M_RACK 状态;
-
M_RACK :判断是否有存在脉冲,未收到存在脉冲跳转至M_IDLE状态,收到存在脉冲则跳转至M_ROMS状态;
-
M_ROMS :发送ROM命令,跳过ROM,状态跳转至M_CONT发送温度转换命令,状态跳转至M_RCMD则发送读暂存器命令
-
M_CONT :发送温度转换命令,温度转换命令发送完成后跳转至M_WAIT
-
M_WAIT = :等待温度转化完成后,(等待时间为750ms),跳转至M_REST;
-
M_RCMD =:发送读暂存器命令,读暂存器命令发送完成后跳转至M_RTMP
-
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;
- S_IDLE :从状态机空闲状态,接收到cmd_vld信号时,从状态机相应;
- S_LOW :读写时隙拉低,此时主状态机在M_RTMP状态的前提下,1us的拉低时间后跳转至S_SAMP ,否则1us计时结束后 跳转至S_SEND;
- S_SEND :写时隙持续59us,一次写时隙最少60us,计时结束后跳转至S_RELS ;
- S_SAMP :读时隙,持续59us后跳转至S_RELS ;
- S_RELS :时隙之间的间隔时间,1us释放时间达到,并且数据已经传输完成,跳转至S_DONE 状态,则1us计时结束后跳转至S_LOW ;
- 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; //1usassign s_send2s_rels = s_state == S_SEND && end_cnt; //59usassign s_samp2s_rels = s_state == S_SAMP && end_cnt; //59usassign s_rels2s_done = s_state == S_RELS && end_cnt && s_flag; //1us释放时间达到,并且数据已经传输完成assign s_rels2s_low = s_state == S_RELS && end_cnt; //1usassign 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;endcasealways@(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;elsecmd_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) beginif(rx_data[15]) //负数 补码转原码true_data <= ~rx_data[10:0] + 1;else true_data <= rx_data[10:0];end//扩大数据1000倍,根据温度精度,计算实际的温度值 *10000*0.0625assign temp_data = true_data * 625;always@(posedge clk or negedge rst_n)if(!rst_n)temp_data_vld <= 0;elsetemp_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)beginstate <= IDLE;end else case(state)IDLE : if(ascii_data_vld && enable) state <= DATA;DATA : if(end_cnt_num) state <= IDLE;default : state <= IDLE;endcaseend
/****************************************************************发送数据计数
****************************************************************/ always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_num <= 'd0;end else if(add_cnt_num)begin if(end_cnt_num)begin cnt_num <= 'd0;endelse begin cnt_num <= cnt_num + 1'b1;end endend 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)beginascii_data_vld <= 'd0;end else begin ascii_data_vld <= hex_din_vld;end endassign 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