硬件说明
DS18B20是我们日常设计中常用的一款温度传感器芯片,只需要一根总线就可以实现通信,非常的方便,我们的STEP-BaseBoard底板上就集成了温度传感器DS18B20Z,下面我们就一起来学习一下它的硬件链接及驱动方法。
DS18B20Z只有一根总线,硬件电路非常简单,但是一定记得总线需要做上拉处理,如下图总线上连接了10K(上拉电阻取值可以一定范围内自行调整)的上拉电阻,另外我们使用FPGA驱动,一定记得将FPGA对应的管脚同样作上拉配置,重要的事情说三遍,总线上拉,总线上拉,总线上拉。
聊完硬件连接,接下来简要介绍如何驱动(更加详细的信息需要大家参考数据手册),不同的功能需求对应不同寄存器配置,本设计执行的操作案例如下。
下面为大家展示上述案例中每个环节的时序要求:
Verilog代码
//-------------------------------------------------------------------- //>>>>>>>>>>>>>>>>>>>>>>>>>COPYRIGHTNOTICE<<<<<<<<<<<<<<<<<<<<<<<<< //-------------------------------------------------------------------- //Module:DS18B20Z // //Author:Step // //Description:DriveDS18B20Ztogettemperaturecode // //-------------------------------------------------------------------- //CodeRevisionHistory: //-------------------------------------------------------------------- //Version:|Mod.Date:|ChangesMade: //V1.0|2015/11/11|Initialver //-------------------------------------------------------------------- moduleDS18B20Z( input clk_in, //系统时钟 input rst_n_in, //系统复位,低有效 inout one_wire, //DS18B20Z传感器单总线,双向管脚 output reg [15:0] data_out //DS18B20Z有效温度数据输出) ; /* 本设计通过驱动DS18B20Z芯片获取温度数据, 需要了解inout类型的接口如何实现双向通信, 中间涉及各种不同的延时和寄存器指令操作,注释部分以作简要说明,更多详情需参考数据手册 */ localparam IDLE = 3'd0; localparam MAIN = 3'd1; localparam INIT = 3'd2; localparam WRITE = 3'd3; localparam READ = 3'd4; localparam DELAY = 3'd5; //计数器分频产生1MHz的时钟信号 reg clk_1mhz; reg [2:0] cnt_1mhz; always@(posedgeclk_inornegedgerst_n_in)begin if(!rst_n_in)begin cnt_1mhz<=3'd0; clk_1mhz<=1'b0; endelseif(cnt_1mhz>=3'd5)begin cnt_1mhz<=3'd0; clk_1mhz<=~clk_1mhz; //产生1MHz分频 endelsebegin cnt_1mhz<=cnt_1mhz+1'b1; end end reg [2:0] cnt; reg one_wire_buffer; reg [3:0] cnt_main; reg [7:0] data_wr; reg [7:0] data_wr_buffer; reg [2:0] cnt_init; reg [19:0] cnt_delay; reg [19:0] num_delay; reg [3:0] cnt_write; reg [2:0] cnt_read; reg [15:0] temperature; reg [7:0] temperature_buffer; reg [2:0] state=IDLE; reg [2:0] state_back=IDLE; //使用1MHz时钟信号做触发完成下面状态机的功能 always@(posedgeclk_1mhzornegedgerst_n_in)begin if(!rst_n_in)begin state<=IDLE; state_back<=IDLE; cnt<=1'b0; cnt_main<=1'b0; cnt_init<=1'b0; cnt_write<=1'b0; cnt_read<=1'b0; cnt_delay<=1'b0; one_wire_buffer<=1'bz; temperature<=16'h0; endelsebegin case(state) IDLE:begin //IDLE状态,程序设计的软复位功能,各状态异常都会跳转到此状态 state<=MAIN; //软复位完成,跳转之MAIN状态重新工作 state_back<=MAIN; cnt<=1'b0; cnt_main<=1'b0; cnt_init<=1'b0; cnt_write<=1'b0; cnt_read<=1'b0; cnt_delay<=1'b0; one_wire_buffer<=1'bz; end MAIN:begin //MAIN状态控制状态机在不同状态间跳转,实现完整的温度数据采集 if(cnt_main>=4'd11)cnt_main<=1'b0; elsecnt_main<=cnt_main+1'b1; case(cnt_main) 4'd0:beginstate<=INIT; end //跳转至INIT状态进行芯片的复位及验证 4'd1:begindata_wr<=8'hcc; state<=WRITE; end //主设备发出跳转ROM指令 4'd2:begindata_wr<=8'h44; state<=WRITE; end //主设备发出温度转换指令 4'd3:beginnum_delay<=20'd750000; state<=DELAY; state_back<=MAIN; end //延时750ms等待转换完成 4'd4:beginstate<=INIT; end //跳转至INIT状态进行芯片的复位及验证 4'd5:begindata_wr<=8'hcc; state<=WRITE; end //主设备发出跳转ROM指令 4'd6:begindata_wr<=8'hbe; state<=WRITE; end //主设备发出读取温度指令 4'd7:beginstate<=READ; end //跳转至READ状态进行单总线数据读取 4'd8:begintemperature[7:0]<=temperature_buffer; end //先读取的为低8位数据 4'd9:beginstate<=READ; end //跳转至READ状态进行单总线数据读取 4'd10:begintemperature[15:8]<=temperature_buffer; end //后读取的为高8为数据 4'd11:beginstate<=IDLE; data_out<=temperature; end //将完整的温度数据输出并重复以上所有操作 default:state<=IDLE; endcase end INIT:begin //INIT状态完成DS18B20Z芯片的复位及验证功能 if(cnt_init>=3'd6)cnt_init<=1'b0; elsecnt_init<=cnt_init+1'b1; case(cnt_init) 3'd0:beginone_wire_buffer<=1'b0; end //单总线复位脉冲拉低 3'd1:beginnum_delay<=20'd500; state<=DELAY; state_back<=INIT;end //复位脉冲保持拉低500us时间 3'd2:beginone_wire_buffer<=1'bz; end //单总线复位脉冲释放,自动上拉 3'd3:beginnum_delay<=20'd100; state<=DELAY; state_back<=INIT;end //复位脉冲保持释放100us时间 3'd4:beginif(one_wire)state<=IDLE; elsestate<=INIT; end //根据单总线的存在检测结果判定是否继续 3'd5:beginnum_delay<=20'd400; state<=DELAY; state_back<=INIT; end //如果检测正常继续保持释放400us时间 3'd6:beginstate<=MAIN; end //INIT状态操作完成,返回MAIN状态 default:state<=IDLE; endcase end WRITE:begin //按照DS18B20Z芯片单总线时序进行写操作 if(cnt<=3'd6)begin //共需要发送8bit的数据,这里控制循环的次数 if(cnt_write>=4'd6)begincnt_write<=1'b1; cnt<=cnt+1'b1; end elsebegincnt_write<=cnt_write+1'b1; cnt<=cnt;end endelsebegin if(cnt_write>=4'd8)begincnt_write<=1'b0; cnt<=1'b0; end //两个变量都恢复初值 elsebegincnt_write<=cnt_write+1'b1; cnt<=cnt; end end //对于WRITE状态中cnt_write来讲,执行过程为:0;[1~6]*8;7;8; case(cnt_write) //lockdata_wr 4'd0:begindata_wr_buffer<=data_wr; end //将需要写出的数据缓存 //发送1bit数据的用时在60~120us之间,参考数据手册 4'd1:beginone_wire_buffer<=1'b0;end //总线拉低 4'd2:beginnum_delay<=20'd2; state<=DELAY; state_back<=WRITE; end //延时2us时间,保证15us以内 4'd3:beginone_wire_buffer<=data_wr_buffer[cnt]; end //先发送数据最低位 4'd4:beginnum_delay<=20'd80; state<=DELAY; state_back<=WRITE;end //延时80us时间 4'd5:beginone_wire_buffer<=1'bz; end //总线释放 4'd6:beginnum_delay<=20'd2; state<=DELAY; state_back<=WRITE; end //延时2us时间 //backtomain 4'd7:beginnum_delay<=20'd80; state<=DELAY; state_back<=WRITE; end //延时80us时间 4'd8:beginstate<=MAIN;end //返回MAIN状态 default:state<=IDLE; endcase end READ:begin //按照DS18B20Z芯片单总线时序进行读操作 if(cnt<=3'd6)begin //共需要接收8bit的数据,这里控制循环的次数 if(cnt_read>=3'd5)begincnt_read<=1'b0; cnt<=cnt+1'b1;end elsebegincnt_read<=cnt_read+1'b1; cnt<=cnt;end endelsebegin if(cnt_read>=3'd6)begincnt_read<=1'b0; cnt<=1'b0;end //两个变量都恢复初值 elsebegincnt_read<=cnt_read+1'b1;cnt<=cnt; end end case(cnt_read) //读取1bit数据的用时在60~120us之间,总线拉低后15us时间内读取数据,参考数据手册 3'd0:beginone_wire_buffer<=1'b0; end //总线拉低 3'd1:beginnum_delay<=20'd2; state<=DELAY; state_back<=READ; end //延时2us时间 3'd2:beginone_wire_buffer<=1'bz; end //总线释放 3'd3:beginnum_delay<=20'd5; state<=DELAY; state_back<=READ; end //延时5us时间 3'd4:begintemperature_buffer[cnt]<=one_wire; end //读取DS18B20Z返回的总线数据,先收最低位 3'd5:beginnum_delay<=20'd60; state<=DELAY; state_back<=READ; end //延时60us时间 //backtomain 3'd6:beginstate<=MAIN; end //返回MAIN状态 default:state<=IDLE; endcase end DELAY:begin //延时控制 if(cnt_delay>=num_delay)begin //延时控制,延时时间由num_delay指定 cnt_delay<=1'b0; state<=state_back; //很多状态都需要延时,延时后返回哪个状态由state_back指定 endelsecnt_delay<=cnt_delay+1'b1; end endcase end end assign one_wire=one_wire_buffer; endmodule
小结
本节主要为大家讲解了DS18B20Z的驱动方法及软件实现,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。