基于FPGA的DS18B20控制程序设计及其Verilog实现(汇编)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
基于FPGA的DS18B20控制程序设计及其Verilog实现
一,总体介绍
DS18B20是一个1-wire总线,12bit的数字温度传感器,其详细的参数这里不做具体的介绍,只讨论其基于Verilog的控制程序的设计。
实际上,对DS18B20的控制,主要是实现1-wire总线的初始化,读,写等操作,然后再根据DS18B20的控制要求,实现对其控制的verilog逻辑。
在1-Wire总线上,有一个master,可以有1个或者多个slave。而对于FPGA+DS18B20的温度测试设计来讲,需要在FPGA上实现一个1-Wire总线的master。DS18B20作为1-wire 总线的slave设备存在,可以有一个或者多个,不过为了简化程序,例程里假定只存在一个DS18B2020。
1-Wire总线的操作形式上相对简单,但操作本身相对却又比较复杂。用Verilog做控制程序设计时,可以采用多层次嵌套的状态机来实现。
二,FPGA + DS18B20的硬件设计
硬件的设计非常简单,只需要将DS18B20的DQ与FPGA的一个IO连接,并加4.7K左右的上拉电阻就可以了。VDD和VPU可以为3.0~5.0V。这里我们参照FPGA本身的IO电压,选择3.3V。
另外要注意的一点是,由于DQ的数据是双向的,所以FPGA的该IO要设定为inout类型。
三,1-Wire总线的基本操作及Verilog实现。
根据1-Wire总线的特点,可以把1-Wire总线的操作归结为初始化,单bit读操作,单bit写操作等最基础的几种。下面分别是几种基本操作的介绍和verilog实现。由于DS18B20的时序操作的最小单位基本上是1us,所以在该设计中,全部采用1MHz的时钟。
1. 初始化
初始化实际上就是1-wire总线上的Reset操作。由master发出一定长度的初始化信号。Slave 看到该初始化信号后,在一定时间内发出规定长度的响应信号,然后初始化操作就结束了。下图是DS18B20的datasheet上给出的初始化的时序要求图示。
我们用一个简单的状态机来实现对DS18B20初始化的操作。根据初始化的时序要求,设计一个有3个状态的简单的状态机,这三个状态分别是RST_IDLE,RST_MINIT和RST_SINIT。系统初始化时,处于RST_IDLE状态,当RST_EN信号有效时,进入RST_MINIT状态,由master发出初始化信号。当master的初始化信号发出一定时间以后,直接进入RST_SINIT 状态。在RST_SINIT状态时,master去观察slave是否输出了正确的状态:如果slave没有输出正确的状态,则状态机重新回到RST_MINIT状态,由master重新发出初始化信号;如果slave输出了正确的状态,则意味着初始化正确完成,状态机回到RST_IDLE状态,整个初始化过程完成(这个文章里涉及到比较多的状态机,但状态机的转换都很简单,所以不会给出状态机的状态转换图,仅仅会用文字做简单叙述,有疑问的地方,可以仔细阅读相关代码)。
wire RST_EN;
wire RST_OVER;
parameter RST_IDLE = 3'b001, //IDLE 状态
RST_MINIT = 3'b010, //master 初始化操作
RST_SINIT = 3'b100; //slave 初始化应答
reg [2:0] RSTSM, RSTSMNXT;
wire PHASE_RST_IDLE = RSTSM[0];
wire PHASE_RST_MINIT = RSTSM[1];
wire PHASE_RST_SINIT = RSTSM[2];
wire PHASENXT_RST_IDLE = RSTSMNXT[0];
always @(posedge CLK1MHZ or negedge RESET)
begin
if(~RESET)
RSTSM <= RST_IDLE;
else
RSTSM <= RSTSMNXT;
end
reg [9:0] MASTER_CNT; //用来控制master发出初始化信号的长度
always @(posedge CLK1MHZ or negedge RESET)
begin
if(~RESET)
MASTER_CNT <= 10'b0;
else if(~PHASE_RST_MINIT)
MASTER_CNT <= 10'b0;
else
MASTER_CNT <= MASTER_CNT + 10'b1;
end
reg [9:0] SLAVE_CNT; //用来判断slave是否在恰当时间返回初始化结束的信号
always @(posedge CLK1MHZ or negedge RESET)
begin
if(~RESET)
SLAVE_CNT <= 10'b0;
else if(~PHASE_RST_SINIT)
SLAVE_CNT <= 10'b0;
else
SLAVE_CNT <= SLAVE_CNT + 10'b1;
end
reg SLAVE_IS_INIT; //采集并保存slave发出的初始化结束信号
always @(posedge CLK1MHZ or negedge RESET)
begin
if(~RESET)
SLAVE_IS_INIT <= 1'b1;
else if(SLAVE_CNT == 10'd70)
SLAVE_IS_INIT <= DQ_IN;
else if(PHASE_RST_MINIT)
SLAVE_IS_INIT <= 1'b1;
else
SLAVE_IS_INIT <= SLAVE_IS_INIT;
end
always @(RSTSM or RST_EN or MASTER_CNT or SLAVE_CNT or SLAVE_IS_INIT ) begin case(RSTSM)
RST_IDLE:
if(RST_EN)
RSTSMNXT = RST_MINIT;
else
RSTSMNXT = RST_IDLE;
RST_MINIT:
if(MASTER_CNT == 10'd500)
RSTSMNXT = RST_SINIT;
else
RSTSMNXT = RST_MINIT;
RST_SINIT: