ds18B20 读取ID号

本篇结合上篇一起食用,本篇为DS18B20读取ID号。需要注意的是,只能在总线上有一个设备的时候使用。

module ds18b20_dri(
		//系统时钟_50M
        input clk_n,
        input clk_p,
	input				rst_n		,       //低电平有效的复位信号	
//	input 				clk			,
	inout				dq					// 符号使
);
 		//单濻线(双向信号)
	 reg [19:0]   temp_data  ;  	// 转换后得到的温度倿
    reg          sign 	;
//------------<参数定义>----------------------------------------------
 
 
 
INBUF_DIFF CLK
(
.PADN (clk_n),
.PADP (clk_p),
.Y (clk)
);
localparam	INIT1		= 6'b000001 ,
			WR_CMD      = 6'b000010 ,
		    RX_ID 		= 6'b001000 ;
//时间参数定义
localparam	T_INIT = 1000		,			//初始化最大时间,单位us
			T_WAIT = 780_000	;			//转换等待延时,单位us
	
//命令定义	
localparam 	WR_CMD_DATA = 16'heecc, 		//跳过 ROM 及温度转换命令,低位在前
			RD_CMD_DATA = 16'hbecc,		//跳过 ROM 及读取温度命令,低位在前
			READ_ROM=8'h33;	
//------------<reg定义>----------------------------------------------		
reg	[5:0]	cur_state	;					//现濿
reg	[5:0]	next_state	;					//次濿
reg	[6:0]	cnt			;					//50分频计数器,1Mhz(1us)
reg			dq_out		;					//双向总线输出
reg			dq_en		;					//双向总线输出使能_1则输出,0则高阻濿
reg			flag_ack	;					//从机响应标志信号
reg			clk_us		;					//us时钟
reg [19:0]	cnt_us		;					//us计数噿,朿大可表示1048ms
reg [5:0]	bit_cnt		;					//接收数据计数噿
reg [63:0]	data_temp	;					//读取的ID数据寄存
reg [63:0]	data		;					//ID
				
//------------<wire定义>----------------------------------------------				
wire		dq_in		;					//双向总线输入
 
//==================================================================
//===========================<main  code>===========================
//==================================================================
 
//-----------------------------------------------------------------------
//--双向端口使用方式
//-----------------------------------------------------------------------
assign	dq_in = dq;							//高阻态的话,则把总线上的数据赋给dq_in
assign	dq =  dq_en ? dq_out : 1'bz;		//使能1则输出,0则高阻濿
 
//-----------------------------------------------------------------------
//--us时钟生成,因为时序都是以us为单位,承以生成一丿1us的时钟会比较方便
//-----------------------------------------------------------------------
//50分频计数
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)
		cnt <= 7'd0;
	else if(cnt ==7'd49)					//毿25个时钿500ns清零
		cnt <= 7'd0;
	else
		cnt <= cnt + 1'd1;
end
//生成1us时钟
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)
	   begin
		clk_us <= 1'b0;
		//data_temp<=64'b0;
		end
	else  if(cnt == 7'd49)					//毿500ns
		clk_us <= ~clk_us;                  //时钟反转
	else
		clk_us <= clk_us;
end
 
//-----------------------------------------------------------------------
//--三段式状态机
//-----------------------------------------------------------------------
 
//状濁机第一段:同步时序描述状濁转秿
always @(posedge clk_us or negedge rst_n)begin
	if(!rst_n)		
		cur_state <= INIT1;	
	else
		cur_state <= next_state;
end
 
//状濁机第二段:组合逻辑判断状濁转移条件,描述状濁转移规律以及输凿
always @(*)begin
	next_state = INIT1;	
	case(cur_state)
		INIT1		:begin
			if(cnt_us == T_INIT && flag_ack)				//满足初始化时间且接收到了从机的响应信叿	
				next_state = WR_CMD;						//跳转到写状濿
			else	
				next_state = INIT1;							//不满足则保持原有状濿
		end	
		WR_CMD       :begin	
			if(bit_cnt == 6'd7 && cnt_us == 20'd62)		//写完亿16个数据,写跳过ROM和写温度转换命令	
				next_state = RX_ID;							//跳转到等待状态,等待温度转换完成 
			else	
				next_state = WR_CMD;						//不满足则保持原有状濿
		end	

		RX_ID  :begin	
			if(bit_cnt == 6'd63 && cnt_us == 20'd62)		//读取完了16个数捿
				next_state = INIT1;							//跳转到初始化状濁,弿始新丿轮温度采雿
			else	
				next_state = RX_ID;	
		end			
		default:next_state = INIT1;							//默认初始化状怿
	endcase
end	
 
//状濁机第三段:时序逻辑描述输出
always @(posedge clk_us or negedge rst_n)begin
	if(!rst_n)begin											//默认输出
		dq_en <= 1'b0;
		dq_out <= 1'b0;
		flag_ack <= 1'b0;
		cnt_us <= 20'd0;
		bit_cnt <= 6'd0;
	end
	else begin 	
		case(cur_state)
			INIT1	:begin
				if(cnt_us == T_INIT)begin					//时间计数到最大忼(初始化时间)
					cnt_us <= 20'd0;						//计数器清雿
					flag_ack <= 1'b0;						//从机响应标志信号拉低
				end
				else begin									//没有计数到最大忿
					cnt_us <= cnt_us + 1'd1;				//计数器计敿
					if(cnt_us <= 20'd499)begin				//小于500us旿
						dq_en <= 1'b1;						//控制总线
						dq_out <= 1'b0;						//输出0,即拉低总线
					end
					else begin								//圿500us夿
						dq_en <= 1'b0;						//释放总线,等待从机响庿						
						if (cnt_us == 20'd570 && !dq_in)	//圿570us处采集濻线电平,如果为0则说明从机响应了
							flag_ack <= 1'b1;				//拉高从机响应标志信号
					end	
				end
			end
			WR_CMD	:begin
				if(cnt_us == 20'd62)
					begin						//丿个写时隙周期63us,满足计时条件则
						cnt_us <= 20'd0;							//清空计数噿
						dq_en <= 1'b0;								//释放总线
						if(bit_cnt == 6'd7)					    	//如果数据已经写了15丿
							bit_cnt <= 6'd0;						//则清穿
						else										//没写15丿
							bit_cnt <= bit_cnt + 1'd1;				//则数据计数器+1,代表写入了丿个数捿
					end	
				else 
					begin										//丿个写时隙周期63us未完房
						cnt_us <= cnt_us + 1'd1;					//计数器一直计敿
						if(cnt_us <= 20'd1)
							begin					//0~1us(每两个写数据之间需要间隿2us_
								dq_en <= 1'b1;							//拉低总线
								dq_out <= 1'b0;
							end
						else 
							begin					
								if (READ_ROM[bit_cnt] == 1'b0)
									begin	//霿要写入的数据丿0
										dq_en <= 1'b1;						//拉低总线
										dq_out <= 1'b0;						//								
									end
								else
									if(READ_ROM[bit_cnt] == 1'b1)
										begin
											dq_en <= 1'b0;						//霿要写入的数据丿1
											dq_out <= 1'b0;						//释放总线						
										end
							end	
					end		
			end	
			


			RX_ID	:begin										//读ID,FAMILY-1BYTE,SERIAL-6BYTES,CRC-1BYTE
				if(cnt_us == 20'd62)begin						//丿个读时隙周期63us,满足计时条件则
					cnt_us <= 20'd0;							//清空计数噿
					dq_en <= 1'b0;								//释放总线
					if(bit_cnt == 6'd63)begin					//如果数据已经读取亿15丿
						bit_cnt <= 6'd0;						//则清穿
						data <= data_temp;						//临时的数据赋值给data
					end
					else begin									//如果数据没有读取15丿
						bit_cnt <= bit_cnt + 1'd1;				//则数据计数器+1,意味着读取了一个数捿
						data <= data;
					end
				end
				else begin										//丿个读时隙周期还没结束
					cnt_us <= cnt_us + 1'd1;					//计数器累势
					if(cnt_us <= 20'd1)begin					//0~1us(每两个读数据之间需要间隿2us_
						dq_en <= 1'b1;							//拉低总线
						dq_out <= 1'b0;
					end
					else begin									//2us吿
						dq_en <= 1'b0;							//释放总掉线					
						if (cnt_us == 20'd10)					//圿10us处读取濻线电平
							data_temp <= {dq,data_temp[63:1]};	//读取总线电平
					end	
				end
			end
			default:;		
		endcase
	end
end
 
//-----------------------------------------------------------------------
//--12位温度数据处琿
//-----------------------------------------------------------------------
always @(posedge clk_us or negedge rst_n)begin
	if(!rst_n)begin													//初始状濿
		temp_data <= 20'd0;	
		sign  <= 1'b0;	
	end	
	else begin	
		if(!data[15])begin											//朿高位丿0则温度为歿
			sign  <= 1'b0;											//标志位为歿
			temp_data <= data[10:0] * 11'd625 /7'd100;				//12位温度数据处琿
		end	
		else if(data[15])begin										//朿高位丿1则温度为贿
			sign  <= 1'b1;											//标志位为贿
			temp_data <= (~data[10:0] + 1'b1)* 11'd625 /7'd100;		//12位温度数据处琿			
		end
	end
end
 
 
endmodule

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值