简单ds18b20传感器驱动的三段式状态机描述

232 阅读4分钟

一、ds18b20基本时序

  1. ds18b20器件为单wire通信模式,即采用三态进行输入输出的控制。三态控制原理如下:

图片.png

  1. ds18b20器件的三种时序关系如下:

图片.png

图片.png

图片.png 相关器件的时序关系,网上资料比较多,笔者这里就只给出关键部分了。

3.三段式状态机具体代码如下(参考了相关资料)

    /* 
        相较于一段式、二段式状态机,三段式状态机更易于优化和理解,笔者参考相关资料,
        剔除了一些先入为主的思想,而且做到了一个always只给一个变量赋值,而且使用全局时钟,
        不使用简单分频出来的“时钟“作为其主时钟    
    */
timescale  1ns/1ns
module ds18b20_ctrl(

	input		wire 		sys_clk		,
	input		wire 		sys_rst_n	,
	inout		wire		dq		,
	output		reg	 [19:0]	data_out	,
	output		reg 		sign	
);

	parameter		INIT_1	=	6'b000_001;
	parameter		WR_CMD	=	6'b000_010;
	parameter		WAIT	=	6'b000_100; 
	parameter		INIT_2	=	6'b001_000;
	parameter		RD_CMD	=	6'b010_000;
	parameter		RD_TEM	=	6'b100_000;
	
	parameter		WR_CMD_DATA = 16'h44cc;
	parameter		RD_CMD_DATA = 16'hbecc;
	
	reg		[5:0]	cur_state	;
	reg		[5:0]	next_state	;
	
	
	parameter		CNT_DIV_1US	=	6'd49;

	reg		[5:0]		cnt_div_1us;		
	reg					en_1us;	
	reg		[19:0]		cnt_1us;	
	
	reg				dq_en	;
	reg				dq_out	;
	reg		[3:0]	cnt_bit	;
	reg				flag	;
	reg		[15:0]	data_reg;
	reg	    [10:0]	temp_reg;
	
	assign dq = ((dq_en==1'b1)?(dq_out):(1'bz));
	
	always@(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			cnt_div_1us <= 6'd0;
		end else if(cnt_div_1us==CNT_DIV_1US) begin
			cnt_div_1us <= 6'd0;
		end else begin
			cnt_div_1us <= cnt_div_1us + 1'b1;
		end
	end
	
	
	always@(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			en_1us <= 1'b0;
		end else if(cnt_div_1us==(CNT_DIV_1US-1'b1)) begin
			en_1us <= 1'b1;
		end else begin
			en_1us <= 1'b0;
		end
	end
	
	
	always@(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			cnt_1us <= 20'd0;
		end else if((((cur_state==INIT_1)||(cur_state==INIT_2)))&&
                (cnt_1us==20'd999)&&(en_1us==1'b1)) begin
			cnt_1us <= 20'd0;
		end else if((cur_state==WAIT) &&(cnt_1us==20'd74_9999)&&(en_1us==1'b1)) 
                begin
			cnt_1us <= 20'd0;
		end else if((((cur_state==WR_CMD)||(cur_state==RD_CMD)))&&
                (cnt_1us==20'd64)&&(cnt_bit==4'd15)&&(en_1us==1'b1)) begin
			cnt_1us <= 20'd0;
		end else if((((cur_state==WR_CMD)||(cur_state==RD_CMD)))&&
                (cnt_1us==20'd64)&&(en_1us==1'b1)) begin
			cnt_1us <= 20'd0;
		end else if(en_1us==1'b1) begin
			cnt_1us <= cnt_1us + 1'b1;
		end else begin
			cnt_1us <= cnt_1us;
		end
	end
	
	
	always@(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			cnt_bit <= 4'd0;
		end else if(((cur_state==WR_CMD)||(cur_state==RD_CMD))&&(cnt_1us==20'd64)&&
                (cnt_bit==4'd15)&&(en_1us==1'b1)) begin
			cnt_bit <= 4'd0;
		end else if(((cur_state==WR_CMD)||(cur_state==RD_CMD))&&(cnt_1us==20'd64)&&
                (en_1us==1'b1)) begin
			cnt_bit <= cnt_bit + 1'b1;
		end else begin
			cnt_bit <= cnt_bit;
		end
	end
	
	
	always@(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			flag <= 1'b0;
		end else if(((cur_state==INIT_1)||(cur_state==INIT_2))&&(cnt_1us==20'd570)&&
                (dq==1'b0)&&(en_1us==1'b1)) begin
			flag <= 1'b1;
		end else if(((cur_state==INIT_1)||(cur_state==INIT_2))&&(cnt_1us==20'd999)&&
                (en_1us==1'b1)) begin
			flag <= 1'b0;
		end else begin
			flag <= flag;
		end
	end
	
	
	always@(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			cur_state <= INIT_1;
		end else begin
			cur_state <= next_state;
		end
	end
	
	
	always@(*) begin
		next_state = INIT_1;
		case(cur_state)
		INIT_1	: begin
			if((cnt_1us==20'd999)&&(flag==1'b1)&&(en_1us==1'b1)) begin
				next_state = WR_CMD;
			end else begin
				next_state = INIT_1;
			end
		end
		
	    WR_CMD	: begin
				if((cnt_bit==4'd15)&&(cnt_1us==20'd64)&&(en_1us==1'b1)) begin
					next_state = WAIT;
				end else begin
					next_state = WR_CMD;
				end
		end
		
	    WAIT	: begin
				if(cnt_1us==20'd74_9999) begin
					next_state = INIT_2;
				end else begin
					next_state = WAIT;
				end
				
		end
		
	    INIT_2	: begin
				if((cnt_1us==20'd999)&&(flag==1'b1)&&(en_1us==1'b1)) begin
					next_state = RD_CMD;
				end else begin
					next_state = INIT_2;
				end
		
		end
		
	    RD_CMD	: begin
				if((cnt_bit==4'd15)&&(cnt_1us==20'd64)&&(en_1us==1'b1)) begin
					next_state = RD_TEM;
				end else begin
					next_state = WR_CMD;
				end
		
		end
		
	    RD_TEM	: begin
				if((cnt_bit==4'd15)&&(cnt_1us==20'd64)&&(en_1us==1'b1)) begin
					next_state = INIT_1;
				end else begin
					next_state = RD_TEM;
				end
		end
			default: next_state = INIT_1;
				endcase		
	end

	
	always@(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			dq_en 	<= 1'b0;
			dq_out 	<= 1'b0;
		end else begin
			case(next_state) 
				INIT_1	: begin
					if(cnt_1us<=20'd499) begin
						dq_en 	<= 1'b1;
						dq_out 	<= 1'b0;
					end else begin
						dq_en 	<= 1'b0;
						dq_out 	<= 1'b0;
					end
				end
				
				WR_CMD	: begin
						if(WR_CMD_DATA[cnt_bit]==1'b0) begin
							if(cnt_1us<=10'd62) begin
								dq_en 	<= 1'b1;
								dq_out 	<= 1'b0;
							end else begin
								dq_en 	<= 1'b0;
								dq_out 	<= 1'b0;	
							end
						end else begin
							if(cnt_1us<=10'd1) begin
								dq_en 	<= 1'b1;
								dq_out 	<= 1'b0;	
							end else begin
								dq_en 	<= 1'b0;
								dq_out 	<= 1'b0;	
							end
						end
				end
				
				WAIT	: begin
						dq_en 	<= 1'b1;
						dq_out 	<= 1'b1;	
				end
				
				INIT_2	: begin
					if(cnt_1us<=20'd499) begin
						dq_en 	<= 1'b1;
						dq_out 	<= 1'b0;
					end else begin
						dq_en 	<= 1'b0;
						dq_out 	<= 1'b0;
					end
				end
				
				RD_CMD	: begin
					if(RD_CMD_DATA[cnt_bit]==1'b0) begin
							if(cnt_1us<=10'd62) begin
								dq_en 	<= 1'b1;
								dq_out 	<= 1'b0;
							end else begin
								dq_en 	<= 1'b0;
								dq_out 	<= 1'b0;	
							end
						end else begin
							if(cnt_1us<=10'd1) begin
								dq_en 	<= 1'b1;
								dq_out 	<= 1'b0;	
							end else begin
								dq_en 	<= 1'b0;
								dq_out 	<= 1'b0;	
							end
						end
				end
				
				RD_TEM	: begin
					if(cnt_1us<=20'd1) begin
						dq_en 	<= 1'b1;
						dq_out 	<= 1'b0;
					end else begin
						dq_en 	<= 1'b0;
						dq_out 	<= 1'b0;	
					end
				end
				
				default: begin
					dq_en 	<= 1'b0;
					dq_out 	<= 1'b0;	
				end
					endcase
		end
	end
	

	always@(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			data_reg <= 16'd0;
		end else if((cur_state==RD_TEM)&&(cnt_1us==20'd10)) begin
			data_reg <= {dq,data_reg[15:1]};
		end else begin
			data_reg <= data_reg;
		end
	end
	
	always@(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			temp_reg <= 11'd0;
		end else if((data_reg[15]==1'b0)&&(cur_state==RD_TEM)&&(cnt_bit==4'd15)&&(cnt_1us==20'd60)) begin
			temp_reg <= data_reg[10:0];
		end else if((data_reg[15]==1'b1)&&(cur_state==RD_TEM)&&(cnt_bit==4'd15)&&(cnt_1us==20'd60)) begin
			temp_reg <= ~data_reg[10:0] + 1'b1;
		end else begin
			temp_reg <= temp_reg;
		end
	end
	
	always@(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			data_out <= 20'd0;
		end	else begin
			data_out <= temp_reg * 625 / 10;
		end
	end
	
	
	always@(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			sign <= 1'b0;
		end else if((data_reg[15]==1'b1)&&(cur_state==RD_TEM)&&(cnt_bit==4'd15)&&(cnt_1us==20'd60)) begin
			sign <= 1'b1;
		end else if((data_reg[15]==1'b0)&&(cur_state==RD_TEM)&&(cnt_bit==4'd15)&&(cnt_1us==20'd60))  begin
			sign <= 1'b0;
		end else begin
			sign <= sign;
		end
	end


endmodule
```
4.后续出现的几个问题(待解决)
-     WAIT状态下是需等待750000us,即cnt_1us计数到749999,由于时序逻辑,
      输出滞后状态一个系统时钟,而且dq_en,dq_out应该全为高,可是抓出来的两个信号,
      ***却在WAIT和INIT_2交替处,拉低了一个系统时钟***,百思不得其解~~

- 编译时出现warnings:
            Warning (332060): Node: sys_clk was determined to be a clock 
            but was found without an associated clock assignment.
            
            Critical Warning (332168): The following clock transfers have no clock 
            uncertainty assignment. For more accurate results, apply clock uncertainty 
            assignments or use the derive_clock_uncertainty command.
            Critical Warning (332169): From altera_reserved_tck (Rise) to 
            altera_reserved_tck (Rise) (setup and hold)
            Critical Warning (332169): From altera_reserved_tck (Rise) to 
            altera_reserved_tck (Fall) (setup and hold)
整个工程编写花了较少时间,大部分时间都花在了调试debug上~~