您的位置:首页 > 财经 > 金融 > 设计店名logo_成都到西安需要核酸检测吗_四川疫情最新情况_百度推广管理

设计店名logo_成都到西安需要核酸检测吗_四川疫情最新情况_百度推广管理

2025/4/3 6:02:55 来源:https://blog.csdn.net/weixin_60610210/article/details/146480060  浏览:    关键词:设计店名logo_成都到西安需要核酸检测吗_四川疫情最新情况_百度推广管理
设计店名logo_成都到西安需要核酸检测吗_四川疫情最新情况_百度推广管理

 经过阅读DS18B20温度传感器的datasheet,知道它的驱动主要是靠状态机的编写去控制。下面记录了一些基本知识。

因为DQ线旁边的4.7k上拉电阻的影响,单总线(1-WIRE)释放均保持高电平,受激发时为低电平。如下图所示

本次读数据只用读出缓存器9位数据中的前两位温度数据就可以了,如下图: 

数据的格式:

一、初始化序列:

主机和从机(DS18B20)间的任何通讯都需要以初始化序列开始。初始化时序如图:

默认情况下数据线是由一个上拉电阻拉高保持在高电平,主机需要先发送一个低电平的复位脉冲给数据线拉低,该复位脉冲需要保持在480us-960us之间,拉低后主机释放该单总线15-60us由上拉电阻把总线拉高,释放(等待延时)完成后等待18B20发出一个低电平脉冲响应信号,该响应信号响应时间维持在60-240us之间,如果主机检测到该响应信号,主机才可以继续后面的操作。

初始化代码(有注解)按照该时序图编写:

    //根据上述四个温度读取过程编写状态机always@(posedge clk_1us or negedge rst_n)beginif(!rst_n)beginflow_cnt   <= 4'b0;init_done  <= 4'b0;cnt_1us_en <= 1'b1;sta_done   <= 1'b0;endelse beginsta_done   <= 1'b0;case(nxt_state)init:begininit_done <= 1'b0;case(flow_cnt)4'd0:flow_cnt <= flow_cnt + 1;4'd1:beginclk_1us_en <= 1'b1;if(cnt_1us < 20'd500)dq_out <= 1'b0;else begindq_out <= 1'bz;             //高阻则释放总线clk_1us_en <= 1'b0;         //微秒使能计数器从1置为0时会清空cnt_1usflow_cnt   <=  flow_cnt + 1;endend4'd2:begin                          //释放总线15-60us,设置为30uscnt_lus_en <= 1'b1;if(cnt_1us < 20'd30)dq_out <= 1'bz; else begin flow_cnt <= flow_cnt + 1'b1;//cnt_lus_en <= 1'b0;end                                end  4'd3:beginif(dq == 0 )  //dq为低表示主机检测到该响应信号flow_cnt <= flow_cnt + 1'b1;else flow_cnt <= flow_cnt;end4'd4:begin   //cnt_lus_en <= 1'b1if(cnt_1us == 20'd500)begincnt_1us_en <= 1'b0;//dq_out <= 1'bz;init_done <= 1'b0;flow_cnt<= 4'd0;  endelse flow_cnt <= flow_cnt;enddefault:flow_cnt <= 4'd0;                         endcaseend

注意:最后的4’d4部分用于等待初始化完成,在这个阶段,总线的状态应该是由外部上拉电阻维持的高电平,因此主机不需要再次显式地将 dq_out 在if语句里设置为高阻态(1'bz)。

二、写数据到DS18B20

写、读数据时序(datasheet):

后续代码汇总:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2025/03/24 13:46:48
// Design Name: 
// Module Name: dss18b20
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
module dss18b20(//module clockinput              clk        ,          //产生50MHz,对应时钟周期0.02usinput              rst_n      ,         // 复位信号//user interfaceinout              dq         ,         // DS18B20的DQ引脚数据output reg [19:0]  temp_data  ,         // 转换后的温度output reg         sign                 // 正负
);//DS18B20的四个温度读取过程:
// 1'跳过ROM命令 2'发温度转换命令 3'跳过ROM命令 4'发读温度暂存器命令
localparam  ROM_SKIP_CMD = 8'hcc;     // 1'跳过ROM命令          
localparam  CONVERT_CMD  = 8'h44;     // 2'发温度转换命令          
localparam  READ_TEMP    = 8'hbe;     // 3'读 DS1820 温度暂存器命令 //整个的状态定义、流程
localparam  init         = 3'd1 ;       //初始化状态         
localparam  rom_skip     = 3'd2 ;      //跳过rom          
localparam  wr_byte      = 3'd3 ;       //写             
localparam  temp_convert = 3'd4 ;      //加载温度转换命令       
localparam  delay        = 3'd5 ;      //等温度转换完成        
localparam  rd_temp      = 3'd6 ;           
localparam  rd_byte      = 3'd7 ;           //reg define
reg     [ 4:0]         cnt         ;        
reg                    clk_1us     ;        
reg     [19:0]         cnt_1us     ;  reg     [ 2:0]         cur_state   ;        
reg     [ 2:0]         next_state  ;  reg     [ 3:0]         flow_cnt    ;        
reg     [ 3:0]         wr_cnt      ;        
reg     [ 4:0]         rd_cnt      ;        
reg     [ 7:0]         wr_data     ;        //写入18b20数据  
reg     [ 4:0]         bit_width   ;        //读取的数据位宽
reg     [15:0]         rd_data     ;        //采集到的温度数据
reg     [15:0]         all_data    ;        //通过rd_data寄存器读取到的数据
reg     [10:0]         data1       ;  reg     [ 3:0]         cmd_cnt     ;        
reg                    init_done   ;        
reg                    st_done     ;        
reg                    cnt_1us_en  ;        
reg                    dq_out      ;       //主机输出给DS18B20wire    [19:0]         data2       ;        assign dq = dq_out;//时钟分频
always @ (posedge clk or negedge rst_n) beginif (!rst_n) begincnt     <= 5'b0;clk_1us <= 1'b0;endelse if(cnt < 5'd24) begin      //25x0.02usx2=1uscnt     <= cnt + 1'b1;clk_1us <= clk_1us;endelse begincnt     <= 5'b0;clk_1us <= ~clk_1us;end
end//计数多少微秒
always @ (posedge clk_1us or negedge rst_n) beginif (!rst_n)cnt_1us <= 20'b0;else if (cnt_1us_en)cnt_1us <= cnt_1us + 1'b1;     //控制主机发送低电平的时间和发送高电平的时间elsecnt_1us <= 20'b0;
endalways @ (posedge clk_1us or negedge rst_n) beginif(!rst_n)cur_state <= init;else cur_state <= next_state;
endalways @( * ) begincase(cur_state)init: begin                             if (init_done)next_state = rom_skip;elsenext_state = init;endrom_skip: begin                         // 加载跳过ROM命令if(st_done)next_state = wr_byte;elsenext_state = rom_skip;endwr_byte: begin                          // 发送命令if(st_done)case(cmd_cnt)                   // 根据命令序号,判断下个状态4'b1: next_state = temp_convert;4'd2: next_state = delay;4'd3: next_state = rd_temp;4'd4: next_state = rd_byte;default: next_state = temp_convert;endcaseelsenext_state = wr_byte;endtemp_convert: begin                     // 加载温度转换命令if(st_done)next_state = wr_byte;elsenext_state = temp_convert;enddelay: begin                            // 延时等待温度转换结束if(st_done)next_state = init;elsenext_state = delay;endrd_temp: begin                          // 加载读温度命令if(st_done)next_state = wr_byte;elsenext_state = rd_temp;endrd_byte: begin                          // 读数据线上的数据if(st_done)next_state = init;elsenext_state = rd_byte;enddefault: next_state = init;endcase
end//根据上述四个温度读取过程编写状态机
always @ (posedge clk_1us or negedge rst_n) beginif(!rst_n) beginflow_cnt     <=  4'b0;init_done    <=  1'b0;cnt_1us_en   <=  1'b1;dq_out       <=  1'bZ;st_done      <=  1'b0;rd_data      <= 16'b0;rd_cnt       <=  5'd0;wr_cnt       <=  4'd0;cmd_cnt      <=  3'd0;endelse beginst_done <= 1'b0;case (next_state)init:begin                              //初始化init_done <= 1'b0;case(flow_cnt)4'd0:flow_cnt <= flow_cnt + 1'b1;4'd1: begin                 //主机发出500us复位脉冲cnt_1us_en <= 1'b1;         if(cnt_1us < 20'd500)dq_out <= 1'b0;         else begincnt_1us_en <= 1'b0;     //微秒使能计数器从1置为0时会清空cnt_1usdq_out <= 1'bz;         //高阻则释放总线flow_cnt <= flow_cnt + 1'b1;endend 4'd2:begin                      //释放总线15-60us,设置为30uscnt_1us_en <= 1'b1;if(cnt_1us < 20'd30)dq_out <= 1'bz;elseflow_cnt <= flow_cnt + 1'b1;end//当主机发送复位脉冲后,DS18B20 会在释放总线后拉低 dq 引脚(60-240μs)作为应答//dq_out 是主机的输出状态:此时 dq_out 已被主机释放总线,但实际引脚电平由 DS18B20 控制,因此必须读取物理引脚dq。4'd3: begin                     if(dq ==0 )         //dq为低表示主机检测到该响应信号flow_cnt <= flow_cnt + 1'b1;elseflow_cnt <= flow_cnt;end4'd4: begin                     //该部分用于等待初始化完成if(cnt_1us == 20'd500) begincnt_1us_en <= 1'b0;//在这个阶段,总线的状态应该是由外部上拉电阻维持的高电平,因此主机不需要再次显式地将 dq_out 设置为高阻态(1'bz)。//dq_out <= 1'bz;init_done  <= 1'b1;     flow_cnt   <= 4'd0;endelseflow_cnt <= flow_cnt;enddefault: flow_cnt <= 4'd0;endcaseendrom_skip: begin                         //加载跳过rom指令wr_data  <= ROM_SKIP_CMD;flow_cnt <= 4'd0;st_done  <= 1'b1;endwr_byte: begin                          //写数据有8个位宽if(wr_cnt <= 4'd7) begincase (flow_cnt)4'd0: begindq_out <= 1'b0;         //拉低数据线,开始写操作cnt_1us_en <= 1'b1;     flow_cnt <= flow_cnt + 1'b1;end4'd1: begin                 //数据线拉低1usflow_cnt <= flow_cnt + 1'b1;end4'd2: beginif(cnt_1us < 20'd60)    dq_out <= wr_data[wr_cnt];else if(cnt_1us < 20'd63)   dq_out <= 1'bz;     //延时63微秒释放总线elseflow_cnt <= flow_cnt + 1'b1;end4'd3: begin                 //发送1位数据完成flow_cnt <= 0;cnt_1us_en <= 1'b0;wr_cnt <= wr_cnt + 1'b1;//写计数器加1enddefault : flow_cnt <= 0;endcaseendelse begin                         st_done <= 1'b1;wr_cnt <= 4'd0;cmd_cnt <= (cmd_cnt == 3'd4) ?  3'd1 : (cmd_cnt+ 1'b1);endendtemp_convert: begin                     //加载温度转换命令wr_data <= CONVERT_CMD;st_done <= 1'b1;enddelay: begin                           //延时500ms等待温度转换结束cnt_1us_en <= 1'b1;if(cnt_1us == 20'd500000) beginst_done <= 1'b1;cnt_1us_en <= 1'b0;end end rd_temp: begin                          wr_data <= READ_TEMP;bit_width <= 5'd16;                 st_done <= 1'b1;endrd_byte: begin                          //接收16位温度数据if(rd_cnt < bit_width) begincase(flow_cnt)4'd0: begincnt_1us_en <= 1'b1;dq_out <= 1'b0;         //主机拉低数据线flow_cnt <= flow_cnt + 1'b1; end
//                  4'd1:begin
//                     flow_cnt   <= flow_cnt + 1'd1; //延迟1us
//                     end4'd1: begindq_out <= 1'bz;         //释放总线并在15us内接收数据if(cnt_1us == 20'd14) beginrd_data <= {dq,rd_data[15:1]};//数据右移进来,dq脚先出低位数据flow_cnt <= flow_cnt + 1'b1 ;endend4'd2: beginif (cnt_1us <= 20'd64)  //一位数据读取完成dq_out <= 1'bz;     //15-60us接着释放总线else beginflow_cnt <= 4'd0;   rd_cnt <= rd_cnt + 1'b1;//读计数器加1cnt_1us_en <= 1'b0;endenddefault : flow_cnt <= 4'd0;endcaseendelse beginst_done <= 1'b1;all_data  <= rd_data;rd_cnt <= 5'b0;endenddefault: ;endcaseend 
end//截位前11位数据
always @(posedge clk_1us or negedge rst_n) beginif(!rst_n) beginsign  <=  1'b0;data1 <= 11'b0;endelse if(all_data[15] == 1'b0) beginsign  <= 1'b0;data1 <= all_data[10:0];endelse if(all_data[15] == 1'b1) beginsign  <= 1'b1;data1 <= ~all_data[10:0] + 1'b1;end
end//转换温度
assign data2 = (data1 * 11'd625)/ 7'd100;// reg [19:0] temp_data;//温度输出
always @(posedge clk_1us or negedge rst_n) beginif(!rst_n)temp_data <= 20'b0;elsetemp_data <= data2;
endendmodule

上板验证:

利用ILA抓取数据:

记录将三段式状态机改为一段式状态机:

// 状态机部分改为一段式
always @ (posedge clk_1us or negedge rst_n) beginif(!rst_n) begincur_state   <= init;flow_cnt    <= 4'b0;init_done   <= 1'b0;cnt_1us_en  <= 1'b1;dq_out      <= 1'bZ;st_done     <= 1'b0;rd_data     <= 16'b0;rd_cnt      <= 5'd0;wr_cnt      <= 4'd0;cmd_cnt     <= 3'd0;endelse beginst_done <= 1'b0;case (cur_state)init: begin                              //初始化init_done <= 1'b0;case(flow_cnt)4'd0:flow_cnt <= flow_cnt + 1'b1;4'd1: begin                 //主机发出500us复位脉冲cnt_1us_en <= 1'b1;         if(cnt_1us < 20'd500)dq_out <= 1'b0;         else begincnt_1us_en <= 1'b0;     //微秒使能计数器从1置为0时会清空cnt_1usdq_out <= 1'bz;         //高阻则释放总线flow_cnt <= flow_cnt + 1'b1;endend 4'd2:begin                      //释放总线15-60us,设置为30uscnt_1us_en <= 1'b1;if(cnt_1us < 20'd30)dq_out <= 1'bz;elseflow_cnt <= flow_cnt + 1'b1;end4'd3: begin                     if(dq ==0 )         //dq为低表示主机检测到该响应信号flow_cnt <= flow_cnt + 1'b1;elseflow_cnt <= flow_cnt;end4'd4: begin                     //该部分用于等待初始化完成if(cnt_1us == 20'd500) begincnt_1us_en <= 1'b0;init_done  <= 1'b1;     flow_cnt   <= 4'd0;cur_state  <= rom_skip;endelseflow_cnt <= flow_cnt;enddefault: flow_cnt <= 4'd0;endcaseendrom_skip: begin                         //加载跳过rom指令wr_data  <= ROM_SKIP_CMD;flow_cnt <= 4'd0;st_done  <= 1'b1;cur_state <= wr_byte;endwr_byte: begin                          //写数据有8个位宽if(wr_cnt <= 4'd7) begincase (flow_cnt)4'd0: begindq_out <= 1'b0;         //拉低数据线,开始写操作cnt_1us_en <= 1'b1;     flow_cnt <= flow_cnt + 1'b1;end4'd1: begin                 //数据线拉低1usflow_cnt <= flow_cnt + 1'b1;end4'd2: beginif(cnt_1us < 20'd60)    dq_out <= wr_data[wr_cnt];else if(cnt_1us < 20'd63)   dq_out <= 1'bz;     //延时63微秒释放总线elseflow_cnt <= flow_cnt + 1'b1;end4'd3: begin                 //发送1位数据完成flow_cnt <= 0;cnt_1us_en <= 1'b0;wr_cnt <= wr_cnt + 1'b1;//写计数器加1enddefault : flow_cnt <= 0;endcaseendelse begin                         st_done <= 1'b1;wr_cnt <= 4'd0;cmd_cnt <= (cmd_cnt == 3'd4) ? 3'd1 : (cmd_cnt + 1'b1);case(cmd_cnt)                   // 根据命令序号,判断下个状态4'b1: cur_state <= temp_convert;4'd2: cur_state <= delay;4'd3: cur_state <= rd_temp;4'd4: cur_state <= rd_byte;default: cur_state <= temp_convert;endcaseendendtemp_convert: begin                     //加载温度转换命令wr_data <= CONVERT_CMD;st_done <= 1'b1;cur_state <= wr_byte;enddelay: begin                           //延时500ms等待温度转换结束cnt_1us_en <= 1'b1;if(cnt_1us == 20'd500000) beginst_done <= 1'b1;cnt_1us_en <= 1'b0;cur_state <= init;end end rd_temp: begin                          wr_data <= READ_TEMP;bit_width <= 5'd16;                 st_done <= 1'b1;cur_state <= wr_byte;endrd_byte: begin                          //接收16位温度数据if(rd_cnt < bit_width) begincase(flow_cnt)4'd0: begincnt_1us_en <= 1'b1;dq_out <= 1'b0;         //主机拉低数据线flow_cnt <= flow_cnt + 1'b1; end4'd1: begindq_out <= 1'bz;         //释放总线并在15us内接收数据if(cnt_1us == 20'd14) beginrd_data <= {dq,rd_data[15:1]};//数据右移进来,dq脚先出低位数据flow_cnt <= flow_cnt + 1'b1 ;endend4'd2: beginif (cnt_1us <= 20'd64)  //一位数据读取完成dq_out <= 1'bz;     //15-60us接着释放总线else beginflow_cnt <= 4'd0;   rd_cnt <= rd_cnt + 1'b1;//读计数器加1cnt_1us_en <= 1'b0;endenddefault : flow_cnt <= 4'd0;endcaseendelse beginst_done <= 1'b1;all_data  <= rd_data;rd_cnt <= 5'b0;cur_state <= init;endenddefault: cur_state <= init;endcaseend 
end

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com