差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 后一修订版 两侧同时换到之后的修订记录 | ||
温度传感器模块 [2017/06/07 17:06] anran [硬件说明] |
温度传感器模块 [2017/06/07 17:15] anran [小结] |
||
---|---|---|---|
行 36: | 行 36: | ||
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< | // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< | ||
// -------------------------------------------------------------------- | // -------------------------------------------------------------------- | ||
- | // Module:Segment_scan | + | // Module:DS18B20Z |
// | // | ||
// Author: Step | // Author: Step | ||
// | // | ||
- | // Description: Display with Segment tube | + | // Description: Drive DS18B20Z to get temperature code |
// | // | ||
// Web: www.stepfpga.com | // Web: www.stepfpga.com | ||
行 50: | 行 50: | ||
// V1.0 |2015/11/11 |Initial ver | // V1.0 |2015/11/11 |Initial ver | ||
// -------------------------------------------------------------------- | // -------------------------------------------------------------------- | ||
- | module Segment_scan | + | module DS18B20Z |
( | ( | ||
- | input clk_in, //系统时钟 | + | input clk_in, //系统时钟 |
- | input rst_n_in, //系统复位,低有效 | + | input rst_n_in, //系统复位,低有效 |
- | input [3:0] seg_data_1, //SEG1 数码管要显示的数据 | + | inout one_wire, //DS18B20Z传感器单总线,双向管脚 |
- | input [3:0] seg_data_2, //SEG2 数码管要显示的数据 | + | output reg [15:0] data_out //DS18B20Z有效温度数据输出 |
- | input [3:0] seg_data_3, //SEG3 数码管要显示的数据 | + | |
- | input [3:0] seg_data_4, //SEG4 数码管要显示的数据 | + | |
- | input [3:0] seg_data_5, //SEG5 数码管要显示的数据 | + | |
- | input [3:0] seg_data_6, //SEG6 数码管要显示的数据 | + | |
- | input [5:0] seg_data_en, //各位数码管数据显示使能,[MSB~LSB]=[SEG6~SEG1] | + | |
- | input [5:0] seg_dot_en, //各位数码管小数点显示使能,[MSB~LSB]=[SEG6~SEG1] | + | |
- | output reg rclk_out, //74HC595的RCK管脚 | + | |
- | output reg sclk_out, //74HC595的SCK管脚 | + | |
- | output reg sdio_out //74HC595的SER管脚 | + | |
); | ); | ||
- | |||
- | parameter CLK_DIV_PERIOD = 600; //分频系数 | ||
- | |||
- | localparam IDLE = 3'd0; | ||
- | localparam MAIN = 3'd1; | ||
- | localparam WRITE = 3'd2; | ||
- | |||
- | localparam LOW = 1'b0; | ||
- | localparam HIGH = 1'b1; | ||
- | |||
- | //创建数码管的字库,字库数据依段码顺序有关 | ||
- | //这里字库数据[MSB~LSB]={DP,G,F,E,D,C,B,A} | ||
- | reg[7:0] seg [15:0]; | ||
- | initial begin | ||
- | seg[0] = 8'h3f; // 0 | ||
- | seg[1] = 8'h06; // 1 | ||
- | seg[2] = 8'h5b; // 2 | ||
- | seg[3] = 8'h4f; // 3 | ||
- | seg[4] = 8'h66; // 4 | ||
- | seg[5] = 8'h6d; // 5 | ||
- | seg[6] = 8'h7d; // 6 | ||
- | seg[7] = 8'h07; // 7 | ||
- | seg[8] = 8'h7f; // 8 | ||
- | seg[9] = 8'h6f; // 9 | ||
- | seg[10] = 8'h77; // A | ||
- | seg[11] = 8'h7c; // b | ||
- | seg[12] = 8'h39; // C | ||
- | seg[13] = 8'h5e; // d | ||
- | seg[14] = 8'h79; // E | ||
- | seg[15] = 8'h71; // F | ||
- | end | ||
- | //计数器对系统时钟信号进行计数 | + | /* |
- | reg[9:0] cnt=0; | + | 本设计通过驱动DS18B20Z芯片获取温度数据, |
- | always@(posedge clk_in or negedge rst_n_in) begin | + | 需要了解inout类型的接口如何实现双向通信, |
- | if(!rst_n_in) begin | + | 中间涉及各种不同的延时和寄存器指令操作,注释部分以作简要说明,更多详情需参考数据手册 |
- | cnt <= 1'b0; | + | */ |
- | end else begin | + | |
- | if(cnt>=(CLK_DIV_PERIOD-1)) cnt <= 1'b0; | + | localparam IDLE = 3'd0; |
- | else cnt <= cnt + 1'b1; | + | 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@(posedge clk_in or negedge rst_n_in) begin | ||
+ | if(!rst_n_in) begin | ||
+ | cnt_1mhz <= 3'd0; | ||
+ | clk_1mhz <= 1'b0; | ||
+ | end else if(cnt_1mhz >= 3'd5) begin | ||
+ | cnt_1mhz <= 3'd0; | ||
+ | clk_1mhz <= ~clk_1mhz; //产生1MHz分频 | ||
+ | end else begin | ||
+ | cnt_1mhz <= cnt_1mhz + 1'b1; | ||
+ | end | ||
end | end | ||
- | end | + | |
- | + | reg [2:0] cnt; | |
- | //根据计数器计数的周期产生分频的脉冲信号 | + | reg one_wire_buffer; |
- | reg clk_div; | + | reg [3:0] cnt_main; |
- | always@(posedge clk_in or negedge rst_n_in) begin | + | reg [7:0] data_wr; |
- | if(!rst_n_in) begin | + | reg [7:0] data_wr_buffer; |
- | clk_div <= 1'b0; | + | reg [2:0] cnt_init; |
- | end else begin | + | reg [19:0] cnt_delay; |
- | if(cnt==(CLK_DIV_PERIOD-1)) clk_div <= 1'b1; | + | reg [19:0] num_delay; |
- | else clk_div <= 1'b0; | + | reg [3:0] cnt_write; |
- | end | + | reg [2:0] cnt_read; |
- | end | + | reg [15:0] temperature; |
- | + | reg [7:0] temperature_buffer; | |
- | //使用状态机完成数码管的扫描和74HC595时序的实现 | + | reg [2:0] state = IDLE; |
- | reg [15:0] data_reg; | + | reg [2:0] state_back = IDLE; |
- | reg [2:0] cnt_main; | + | //使用1MHz时钟信号做触发完成下面状态机的功能 |
- | reg [5:0] cnt_write; | + | always@(posedge clk_1mhz or negedge rst_n_in) begin |
- | reg [2:0] state = IDLE; | + | if(!rst_n_in) begin |
- | always@(posedge clk_in or negedge rst_n_in) begin | + | state <= IDLE; |
- | if(!rst_n_in) begin //复位状态下,各寄存器置初值 | + | state_back <= IDLE; |
- | state <= IDLE; | + | cnt <= 1'b0; |
- | cnt_main <= 3'd0; | + | cnt_main <= 1'b0; |
- | cnt_write <= 6'd0; | + | cnt_init <= 1'b0; |
- | sdio_out <= 1'b0; | + | cnt_write <= 1'b0; |
- | sclk_out <= LOW; | + | cnt_read <= 1'b0; |
- | rclk_out <= LOW; | + | cnt_delay <= 1'b0; |
- | end else begin | + | one_wire_buffer <= 1'bz; |
- | case(state) | + | temperature <= 16'h0; |
- | IDLE:begin //IDLE作为第一个状态,相当于软复位 | + | end else begin |
- | state <= MAIN; | + | case(state) |
- | cnt_main <= 3'd0; | + | IDLE:begin //IDLE状态,程序设计的软复位功能,各状态异常都会跳转到此状态 |
- | cnt_write <= 6'd0; | + | state <= MAIN; //软复位完成,跳转之MAIN状态重新工作 |
- | sdio_out <= 1'b0; | + | state_back <= MAIN; |
- | sclk_out <= LOW; | + | cnt <= 1'b0; |
- | rclk_out <= LOW; | + | cnt_main <= 1'b0; |
- | end | + | cnt_init <= 1'b0; |
- | MAIN:begin | + | cnt_write <= 1'b0; |
- | if(cnt_main >= 3'd5) cnt_main <= 1'b0; | + | cnt_read <= 1'b0; |
- | else cnt_main <= cnt_main + 1'b1; | + | cnt_delay <= 1'b0; |
- | case(cnt_main) | + | one_wire_buffer <= 1'bz; |
- | //对6位数码管逐位扫描 | + | end |
- | 3'd0: begin | + | MAIN:begin //MAIN状态控制状态机在不同状态间跳转,实现完整的温度数据采集 |
- | state <= WRITE; //在配置完发给74HC595的数据同时跳转至WRITE状态,完成串行时序 | + | if(cnt_main >= 4'd11) cnt_main <= 1'b0; |
- | data_reg <= {seg[seg_data_1]|(seg_dot_en[0]?8'h80:8'h00),seg_data_en[0]?8'hfe:8'hff}; | + | else cnt_main <= cnt_main + 1'b1; |
- | //data_reg[15:8]为段选,data_reg[7:0]为位选 | + | case(cnt_main) |
- | //seg[seg_data_1] 是根据端口的输入获取相应字库数据 | + | 4'd0: begin state <= INIT; end //跳转至INIT状态进行芯片的复位及验证 |
- | //seg_dot_en[0]?8'h80:8'h00 是根据小数点显示使能信号 控制SEG1数码管的小数点DP段的电平 | + | 4'd1: begin data_wr <= 8'hcc;state <= WRITE; end //主设备发出跳转ROM指令 |
- | //seg_data_en[0]?8'hfe:8'hff 是根据数据显示使能信号 控制SEG1数码管的位选引脚的电平 | + | 4'd2: begin data_wr <= 8'h44;state <= WRITE; end //主设备发出温度转换指令 |
- | end | + | 4'd3: begin num_delay <= 20'd750000;state <= DELAY;state_back <= MAIN; end //延时750ms等待转换完成 |
- | 3'd1: begin | + | |
- | state <= WRITE; | + | 4'd4: begin state <= INIT; end //跳转至INIT状态进行芯片的复位及验证 |
- | data_reg <= {seg[seg_data_2]|(seg_dot_en[1]?8'h80:8'h00),seg_data_en[1]?8'hfd:8'hff}; | + | 4'd5: begin data_wr <= 8'hcc;state <= WRITE; end //主设备发出跳转ROM指令 |
- | end | + | 4'd6: begin data_wr <= 8'hbe;state <= WRITE; end //主设备发出读取温度指令 |
- | 3'd2: begin | + | |
- | state <= WRITE; | + | 4'd7: begin state <= READ; end //跳转至READ状态进行单总线数据读取 |
- | data_reg <= {seg[seg_data_3]|(seg_dot_en[2]?8'h80:8'h00),seg_data_en[2]?8'hfb:8'hff}; | + | 4'd8: begin temperature[7:0] <= temperature_buffer; end //先读取的为低8位数据 |
- | end | + | |
- | 3'd3: begin | + | 4'd9: begin state <= READ; end //跳转至READ状态进行单总线数据读取 |
- | state <= WRITE; | + | 4'd10: begin temperature[15:8] <= temperature_buffer; end //后读取的为高8为数据 |
- | data_reg <= {seg[seg_data_4]|(seg_dot_en[3]?8'h80:8'h00),seg_data_en[3]?8'hf7:8'hff}; | + | |
- | end | + | 4'd11: begin state <= IDLE;data_out <= temperature; end //将完整的温度数据输出并重复以上所有操作 |
- | 3'd4: begin | + | default: state <= IDLE; |
- | state <= WRITE; | + | endcase |
- | data_reg <= {seg[seg_data_5]|(seg_dot_en[4]?8'h80:8'h00),seg_data_en[4]?8'hef:8'hff}; | + | end |
- | end | + | INIT:begin //INIT状态完成DS18B20Z芯片的复位及验证功能 |
- | 3'd5: begin | + | if(cnt_init >= 3'd6) cnt_init <= 1'b0; |
- | state <= WRITE; | + | else cnt_init <= cnt_init + 1'b1; |
- | data_reg <= {seg[seg_data_6]|(seg_dot_en[5]?8'h80:8'h00),seg_data_en[5]?8'hdf:8'hff}; | + | case(cnt_init) |
- | end | + | 3'd0: begin one_wire_buffer <= 1'b0; end //单总线复位脉冲拉低 |
- | default: state <= IDLE; | + | 3'd1: begin num_delay <= 20'd500;state <= DELAY;state_back <= INIT; end //复位脉冲保持拉低500us时间 |
- | endcase | + | 3'd2: begin one_wire_buffer <= 1'bz; end //单总线复位脉冲释放,自动上拉 |
- | end | + | 3'd3: begin num_delay <= 20'd100;state <= DELAY;state_back <= INIT; end //复位脉冲保持释放100us时间 |
- | WRITE:begin | + | 3'd4: begin if(one_wire) state <= IDLE; else state <= INIT; end //根据单总线的存在检测结果判定是否继续 |
- | if(clk_div) begin //74HC595的串行时钟有速度要求,需要按照分频后的节拍 | + | 3'd5: begin num_delay <= 20'd400;state <= DELAY;state_back <= INIT; end //如果检测正常继续保持释放400us时间 |
- | if(cnt_write >= 6'd33) cnt_write <= 1'b0; | + | 3'd6: begin state <= MAIN; end //INIT状态操作完成,返回MAIN状态 |
- | else cnt_write <= cnt_write + 1'b1; | + | default: state <= IDLE; |
+ | endcase | ||
+ | end | ||
+ | WRITE:begin //按照DS18B20Z芯片单总线时序进行写操作 | ||
+ | if(cnt <= 3'd6) begin //共需要发送8bit的数据,这里控制循环的次数 | ||
+ | if(cnt_write >= 4'd6) begin cnt_write <= 1'b1; cnt <= cnt + 1'b1; end | ||
+ | else begin cnt_write <= cnt_write + 1'b1; cnt <= cnt; end | ||
+ | end else begin | ||
+ | if(cnt_write >= 4'd8) begin cnt_write <= 1'b0; cnt <= 1'b0; end //两个变量都恢复初值 | ||
+ | else begin cnt_write <= cnt_write + 1'b1; cnt <= cnt; end | ||
+ | end | ||
+ | //对于WRITE状态中cnt_write来讲,执行过程为:0;[1~6]*8;7;8; | ||
case(cnt_write) | case(cnt_write) | ||
- | //74HC595是串行转并行的芯片,3路输入可产生8路输出,而且可以级联使用 | + | //lock data_wr |
- | //74HC595的时序实现,参考74HC595的芯片手册 | + | 4'd0: begin data_wr_buffer <= data_wr; end //将需要写出的数据缓存 |
- | 6'd0: begin sclk_out <= LOW; sdio_out <= data_reg[15]; end //SCK下降沿时SER更新数据 | + | //发送 1bit 数据的用时在60~120us之间,参考数据手册 |
- | 6'd1: begin sclk_out <= HIGH; end //SCK上升沿时SER数据稳定 | + | 4'd1: begin one_wire_buffer <= 1'b0; end //总线拉低 |
- | 6'd2: begin sclk_out <= LOW; sdio_out <= data_reg[14]; end | + | 4'd2: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end //延时2us时间,保证15us以内 |
- | 6'd3: begin sclk_out <= HIGH; end | + | 4'd3: begin one_wire_buffer <= data_wr_buffer[cnt]; end //先发送数据最低位 |
- | 6'd4: begin sclk_out <= LOW; sdio_out <= data_reg[13]; end | + | 4'd4: begin num_delay <= 20'd80;state <= DELAY;state_back <= WRITE; end //延时80us时间 |
- | 6'd5: begin sclk_out <= HIGH; end | + | 4'd5: begin one_wire_buffer <= 1'bz; end //总线释放 |
- | 6'd6: begin sclk_out <= LOW; sdio_out <= data_reg[12]; end | + | 4'd6: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end //延时2us时间 |
- | 6'd7: begin sclk_out <= HIGH; end | + | //back to main |
- | 6'd8: begin sclk_out <= LOW; sdio_out <= data_reg[11]; end | + | 4'd7: begin num_delay <= 20'd80;state <= DELAY;state_back <= WRITE; end //延时80us时间 |
- | 6'd9: begin sclk_out <= HIGH; end | + | 4'd8: begin state <= MAIN; end //返回MAIN状态 |
- | 6'd10: begin sclk_out <= LOW; sdio_out <= data_reg[10]; end | + | |
- | 6'd11: begin sclk_out <= HIGH; end | + | |
- | 6'd12: begin sclk_out <= LOW; sdio_out <= data_reg[9]; end | + | |
- | 6'd13: begin sclk_out <= HIGH; end | + | |
- | 6'd14: begin sclk_out <= LOW; sdio_out <= data_reg[8]; end | + | |
- | 6'd15: begin sclk_out <= HIGH; end | + | |
- | 6'd16: begin sclk_out <= LOW; sdio_out <= data_reg[7]; end | + | |
- | 6'd17: begin sclk_out <= HIGH; end | + | |
- | 6'd18: begin sclk_out <= LOW; sdio_out <= data_reg[6]; end | + | |
- | 6'd19: begin sclk_out <= HIGH; end | + | |
- | 6'd20: begin sclk_out <= LOW; sdio_out <= data_reg[5]; end | + | |
- | 6'd21: begin sclk_out <= HIGH; end | + | |
- | 6'd22: begin sclk_out <= LOW; sdio_out <= data_reg[4]; end | + | |
- | 6'd23: begin sclk_out <= HIGH; end | + | |
- | 6'd24: begin sclk_out <= LOW; sdio_out <= data_reg[3]; end | + | |
- | 6'd25: begin sclk_out <= HIGH; end | + | |
- | 6'd26: begin sclk_out <= LOW; sdio_out <= data_reg[2]; end | + | |
- | 6'd27: begin sclk_out <= HIGH; end | + | |
- | 6'd28: begin sclk_out <= LOW; sdio_out <= data_reg[1]; end | + | |
- | 6'd29: begin sclk_out <= HIGH; end | + | |
- | 6'd30: begin sclk_out <= LOW; sdio_out <= data_reg[0]; end | + | |
- | 6'd31: begin sclk_out <= HIGH; end | + | |
- | 6'd32: begin rclk_out <= HIGH; end //当16位数据传送完成后RCK拉高,输出生效 | + | |
- | 6'd33: begin rclk_out <= LOW; state <= MAIN; end | + | |
default: state <= IDLE; | default: state <= IDLE; | ||
endcase | endcase | ||
- | end else begin | ||
- | sclk_out <= sclk_out; | ||
- | sdio_out <= sdio_out; | ||
- | rclk_out <= rclk_out; | ||
- | cnt_write <= cnt_write; | ||
- | state <= state; | ||
end | end | ||
- | end | + | READ:begin //按照DS18B20Z芯片单总线时序进行读操作 |
- | default: state <= IDLE; | + | if(cnt <= 3'd6) begin //共需要接收8bit的数据,这里控制循环的次数 |
- | endcase | + | if(cnt_read >= 3'd5) begin cnt_read <= 1'b0; cnt <= cnt + 1'b1; end |
+ | else begin cnt_read <= cnt_read + 1'b1; cnt <= cnt; end | ||
+ | end else begin | ||
+ | if(cnt_read >= 3'd6) begin cnt_read <= 1'b0; cnt <= 1'b0; end //两个变量都恢复初值 | ||
+ | else begin cnt_read <= cnt_read + 1'b1; cnt <= cnt; end | ||
+ | end | ||
+ | case(cnt_read) | ||
+ | //读取 1bit 数据的用时在60~120us之间,总线拉低后15us时间内读取数据,参考数据手册 | ||
+ | 3'd0: begin one_wire_buffer <= 1'b0; end //总线拉低 | ||
+ | 3'd1: begin num_delay <= 20'd2;state <= DELAY;state_back <= READ; end //延时2us时间 | ||
+ | 3'd2: begin one_wire_buffer <= 1'bz; end //总线释放 | ||
+ | 3'd3: begin num_delay <= 20'd5;state <= DELAY;state_back <= READ; end //延时5us时间 | ||
+ | 3'd4: begin temperature_buffer[cnt] <= one_wire; end //读取DS18B20Z返回的总线数据,先收最低位 | ||
+ | 3'd5: begin num_delay <= 20'd60;state <= DELAY;state_back <= READ; end //延时60us时间 | ||
+ | //back to main | ||
+ | 3'd6: begin state <= 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指定 | ||
+ | end else cnt_delay <= cnt_delay + 1'b1; | ||
+ | end | ||
+ | endcase | ||
+ | end | ||
end | end | ||
- | end | + | |
+ | assign one_wire = one_wire_buffer; | ||
+ | |||
endmodule | endmodule | ||
行 244: | 行 230: | ||
====小结==== | ====小结==== | ||
------ | ------ | ||
- | 本节主要为大家讲解了数码管显示的相关原理及软件设计,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。 | + | 本节主要为大家讲解了DS18B20Z的驱动方法及软件实现,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。 |
\\ | \\ | ||
如果你对Diamond软件的使用不了解,请参考这里:[[lattice_diamond的使用|Diamond的使用]]。 | 如果你对Diamond软件的使用不了解,请参考这里:[[lattice_diamond的使用|Diamond的使用]]。 |