这是我在CSDN的第一篇文章,如果文章排版不好或者存在其它的一些问题,希望大家海涵。

FPGA与各器件的连接如图所示:

dq为DS18B20的单总线

dtube_cs_n为数码管的4位

dtube_data为数码管的8段

ext_clk_25m为时钟输入

ext_rst_n为复位输入

顶层文件:

module DS18B20(
            input ext_clk_25m,        //外部输入25MHz时钟信号
            input ext_rst_n,        //外部输入复位信号,低电平有效
            inout dq,                //DS18B20的单总线接口    
            output[3:0] dtube_cs_n,    //7段数码管位选信号
            output[7:0] dtube_data    //7段数码管段选信号(包括小数点为8段)                
        );
wire CLK_1MHz;
wire sys_rst_n;
pll_controller    pll_controller_inst                 (
                                                .areset ( !ext_rst_n ),
                                                .inclk0 ( ext_clk_25m),
                                                .c0 (CLK_1MHz),
                                                .locked ( sys_rst_n )
                                                    );
wire[15:0] num_temp;
ds18b20_demo  uut_ds18b20_demo                        (
                                                .clk(CLK_1MHz),
                                                .rst_n(sys_rst_n),
                                                .pin_ds18b20(dq),
                                                .temp(num_temp)
                                                    );
wire[15:0] temperature;                               
temperature_calculation  uut_temperature_calculation(
                                                .clk(ext_clk_25m),
                                                .rst_n(sys_rst_n),
                                                .two_byte_temp(num_temp),
                                                .temperature(temperature)
                                                    );
digital_tube_display  uut_digital_tube_display(
                                                .clk(ext_clk_25m),    
                                                .rst_n(sys_rst_n),    
                                                .display_num(temperature),    
                                                .dtube_cs_n(dtube_cs_n),    
                                                .dtube_data(dtube_data)    
                                               );
                            
endmodule

其次是DS18B20的控制代码:

module ds18b20_demo(
                           input clk,
                           input rst_n,
                           inout pin_ds18b20,
                           output [15:0] temp
                          );
//*************************************************************                          
//DS18B20状态机各个阶段                          
parameter STATE_1 = 4'd1,//等待initen_cnt计数到10(即10us)才使能初始化    
          STATE_2 = 4'd2,//主机把总线电平拉低500us,等待DS18B20回应
          STATE_3 = 4'd3,//DS18B20作出回应阶段
          STATE_4 = 4'd4,//向DS18B20写0X44CCH跳过ROM操作和进行温度转换
          STATE_5 = 4'd5,//等待2ms,等DS18B20把温度转换完成
          STATE_6 = 4'd6,//回到STATE_2~STATE_3,再来一遍初始化
          STATE_7 = 4'd7,//向DS18B20写0XBECCH跳过ROM操作和读取温度数据
          STATE_8 = 4'd8,//读取DS18B20的两个字节温度数据
          STATE_9 = 4'd9;//等待1S,重新开始上述过程
//*************************************************************
//1S计数器
reg[19:0] one_second_cnt;
always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            one_second_cnt <= 20'd0;
        else if(DS18b20_state == STATE_9)
            one_second_cnt <= one_second_cnt + 1'b1;
        else
            one_second_cnt <= 20'd0;
    end      
//*************************************************************
//初始化计数器,计数到10(即10us)才使能初始化过程
reg[9:0] initen_cnt;
always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            initen_cnt <= 10'd0;
        else if(DS18b20_state == STATE_1)//只在第一阶段自递增
            initen_cnt <= initen_cnt + 1'b1;
        else
            initen_cnt <= 10'd0;
    end    
//*************************************************************    
//用来控制主机发出的初始化信号长度
reg[9:0] master_cnt;
always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            master_cnt <= 10'd0;
        else if(DS18b20_state == STATE_2)//在第二阶段自递增
            master_cnt <= master_cnt + 1'd1;
        else
            master_cnt <= 10'd0;
    end
//*************************************************************    
//用来控制何时获得从机的应答信号        
reg[9:0] slave_cnt;
always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            slave_cnt <= 10'd0;
        else if(DS18b20_state == STATE_3)//只在STATE_3自递增,即主机把总线拉低500us之后
            slave_cnt <= slave_cnt + 1'd1;
        else    
            slave_cnt <= 10'd0;
    end
//*************************************************************
//写一个比特周期计数器,每个写周期62us,60us写数据+2us高电平间隔
reg[6:0] write_cnt;
always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            write_cnt <= 7'd0;
        else if((DS18b20_state == STATE_4) || (DS18b20_state == STATE_7))
            write_cnt <= write_cnt + 1'd1;
        else if(write_cnt > 7'd62)
            write_cnt <= 7'd0;
        else
            write_cnt <= 7'd0;
    end    
//*************************************************************
//读一个比特周期计数器,每个读周期62us,60us读数据+2us高电平间隔
reg[5:0] read_cnt;
always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            read_cnt <= 6'b0;
        else if(DS18b20_state == STATE_8)
            read_cnt <= read_cnt + 1'b1;
        else if(read_cnt > 6'd62)
            read_cnt <= 6'b0;
        else
            read_cnt <= 6'b0;
    end    
//*************************************************************    
reg [23:0] wait_cnt;//等待温度转换完成
always @ (posedge clk or negedge rst_n)
    begin    
        if(!rst_n)
            wait_cnt <= 24'b0;
        else if(DS18b20_state == STATE_5)
            wait_cnt <= wait_cnt + 1'b1;
        else
            wait_cnt <= 24'b0;
    end    
//*************************************************************    
//DS18b20_state,DS18b20_next_state赋值,后面的初始化状态机的状态判断要用到
reg [3:0] DS18b20_state,DS18b20_next_state;
always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            DS18b20_state <= STATE_1;
        else
            DS18b20_state <= DS18b20_next_state;
    end
//*************************************************************    
//两个字节的数据一起写进DS18B20
reg[15:0] hex_write;
always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            hex_write <= 16'h0000;
        else if(DS18b20_state == STATE_4)
            hex_write <= 16'h44cc;
        else if(DS18b20_state == STATE_7)
            hex_write <= 16'hbecc;
        else
            hex_write <= 16'h0000;
    end
//*************************************************************
//选择写入字节中的第几位
reg[4:0] write_bit_num;//对当前写的位进行计数,一个字节8位
reg write_over;//一个字节写完标志位
always @ (posedge clk or negedge rst_n)
    begin
    
        if(!rst_n)
            begin
                write_bit_num <= 5'd0;
                write_over <= 1'b0;
            end
        else if(write_cnt == 7'd60)
            write_bit_num <= write_bit_num + 1'd1;
        else if(write_bit_num == 5'd16)
            begin
                write_bit_num <= 5'd0;
                write_over <= 1'b1;
            end
        else if(DS18b20_state != STATE_4 || DS18b20_state != STATE_7)
            write_over <= 1'b0;
        else;
    end    
//*************************************************************
reg bit_write;   //当前需要写入的一个比特数据
always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            bit_write <= 1'b0;
        else if(write_cnt <= 7'd2)
            bit_write <= 1'b0;//每次写1bit拉低总线>1us
        else if(write_cnt > 7'd3 && write_cnt < 7'd60)//传输当前bit
            begin
                     if(write_bit_num == 5'd0)   bit_write <= hex_write[0];
                else if(write_bit_num == 5'd1)   bit_write <= hex_write[1];
                else if(write_bit_num == 5'd2)   bit_write <= hex_write[2];
                else if(write_bit_num == 5'd3)   bit_write <= hex_write[3];
                else if(write_bit_num == 5'd4)   bit_write <= hex_write[4];
                else if(write_bit_num == 5'd5)   bit_write <= hex_write[5];
                else if(write_bit_num == 5'd6)   bit_write <= hex_write[6];
                else if(write_bit_num == 5'd7)   bit_write <= hex_write[7];
                else if(write_bit_num == 5'd8)   bit_write <= hex_write[8];
                else if(write_bit_num == 5'd9)   bit_write <= hex_write[9];
                else if(write_bit_num == 5'd10)  bit_write <= hex_write[10];
                else if(write_bit_num == 5'd11)  bit_write <= hex_write[11];
                else if(write_bit_num == 5'd12)  bit_write <= hex_write[12];
                else if(write_bit_num == 5'd13)  bit_write <= hex_write[13];
                else if(write_bit_num == 5'd14)  bit_write <= hex_write[14];
                else if(write_bit_num == 5'd15)  bit_write <= hex_write[15];
            end
        else if(write_cnt >= 7'd60 && write_cnt < 7'd62)
            bit_write <= 1'b1;//写1bit末都需要把总线拉高>1us
        else;    
    end
//*************************************************************
//对当前读的位进行计数,一个字节8位,两个一起读16位
reg[4:0] read_bit_num;
always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            read_bit_num <= 5'd0;
        else if(read_cnt == 6'd60 && DS18b20_state == STATE_8)
            read_bit_num <= read_bit_num + 5'd1;
        else if(DS18b20_state != STATE_8)
            read_bit_num <= 5'd0;
        else;
    end    
//*************************************************************
//读DS18B20的两个字节数据,一起读
reg[15:0] read_two_byte;
always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            read_two_byte <= 16'd0;
        else if(read_cnt == 6'd12 && read_bit_num <= 5'd15)
            begin
                read_two_byte <= {1'b0, read_two_byte[15:1]};            
                read_two_byte[15] <= pin_ds18b20;
            end
        else;
    end    
assign temp[15:0] = read_two_byte[15:0];
//*************************************************************
//读两个字节完成标志
reg read_over;//两个字节读完标志位
always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            read_over <= 1'b0;
        else if(read_bit_num == 5'd16)
            begin
                read_over <= 1'b1;
            end
        else
            read_over <= 1'b0;
    end    
//*************************************************************    
//DS18B20初始化状态机,完成整个初始化过程的调度
reg rece_dat;
reg re_init_en;
//reg[15:0] test;//测试用,与之相关的代码行可以忽略
always @ (DS18b20_state or DS18b20_next_state or master_cnt or slave_cnt or initen_cnt or wait_cnt or write_over or read_over or one_second_cnt or rece_dat or re_init_en or pin_ds18b20)
    begin
        case(DS18b20_state)
            STATE_1:
                        if(initen_cnt == 10'd100)
                          DS18b20_next_state <= STATE_2;
                        else
                          DS18b20_next_state <= STATE_1;
            STATE_2:    
                        if(master_cnt == 10'd702)//主机把总线电平拉低480~960us,这里是700us
                            DS18b20_next_state <= STATE_3;
                        else
                            DS18b20_next_state <= STATE_2;
            STATE_3:
                        if(slave_cnt == 10'd100)//接收DS18B20的低电平应答
                            rece_dat <= pin_ds18b20;
                        else if(slave_cnt == 10'd480 && rece_dat == 1'b1)
                            begin
                                DS18b20_next_state <= STATE_1;
                                //test <= 16'hFAFA;
                            end
                        else if(slave_cnt == 10'd480 && rece_dat == 1'b0 && re_init_en == 1'b0)
                            begin
                                DS18b20_next_state <= STATE_4;
                                //test <= 16'hD0D0;
                            end
                        else if(slave_cnt == 10'd480 && rece_dat == 1'b0 && re_init_en == 1'b1)
                                DS18b20_next_state <= STATE_7;
                        else
                           DS18b20_next_state <= STATE_3;
            STATE_4:
                        if(write_over == 1'b1)
                            DS18b20_next_state <= STATE_5;
                        else
                            DS18b20_next_state <= STATE_4;
            STATE_5:
                        if(wait_cnt == 24'd3000)
                            DS18b20_next_state <= STATE_6;
                        else
                            DS18b20_next_state <= STATE_5;
            STATE_6:
                        begin
                              re_init_en <= 1'b1;
                              DS18b20_next_state <= STATE_1;
                        end
            STATE_7:
                        if(write_over == 1'b1)
                            DS18b20_next_state <= STATE_8;
                        else
                            begin
                                DS18b20_next_state <= STATE_7;
                                re_init_en <= 1'b0;
                            end
            STATE_8:
                        if(read_over == 1'b1)
                            DS18b20_next_state <= STATE_9;
                        else
                            DS18b20_next_state <= STATE_8;
            STATE_9:
                        if(one_second_cnt == 20'd30_000)
                            DS18b20_next_state <= STATE_1;
                        else
                            DS18b20_next_state <= STATE_9;
            default:
                        DS18b20_next_state <= STATE_1;
        endcase
    end
//assign temp[15:0] = test[15:0];
//*************************************************************    
//DS18B20的单总线信号方向以及读写控制
reg dq;
always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            dq <= 1'b1;
        else if(master_cnt >= 10'd2 && master_cnt <= 10'd702)//把总线拉低700us,初始化DS18B20
            dq <= 1'b0;
        else if(slave_cnt >= 10'd15 && slave_cnt <= 10'd320)//接收DS18B20时设为高阻态
            dq <= 1'bz;
        else if (DS18b20_state == STATE_4 || DS18b20_state == STATE_7)//向DS18B20写数据
            dq <= bit_write;
        else if(DS18b20_state == STATE_8 && read_cnt <= 2)//读周期一开始做为主机先把总线拉低1微秒表示读周期开始
            dq <= 1'b0;
        else if(read_cnt > 2 && read_cnt <= 60)//60us的窗口内保持高阻态
            dq <= 1'bz;
        else
            dq <= 1'b1;
    end
assign pin_ds18b20 = dq;

endmodule

数据处理代码:

module temperature_calculation(
                                input clk,
                                input rst_n,
                                input[15:0]  two_byte_temp,
                                output[15:0] temperature
                              );
wire[13:0]    result_sig;                         
mul    mul_inst (
    .clock ( clk ),
    .dataa ( two_byte_temp[3:0]),
    .datab ( 10'd625 ),
    .result ( result_sig )
    );
wire [13:0] one_decimal,remain_sig;
div_14bit    div_14bit_inst_one (
    .clock ( clk ),
    .denom ( 14'd1000 ),
    .numer ( result_sig ),
    .quotient ( one_decimal ),
    .remain ( remain_sig )
    );
wire [13:0] two_decimal;
div_14bit    div_14bit_inst_two (
    .clock ( clk ),
    .denom ( 14'd100 ),
    .numer ( remain_sig ),
    .quotient ( two_decimal ),
    .remain ( remain_sig_two )
    );
wire [7:0] ten_quotint,ten_fractional;
div_8bit    div_8bit_inst (
    .clock ( clk ),
    .denom ( 8'd10),
    .numer ({1'b0,two_byte_temp[10:4]}),
    .quotient ( ten_quotint ),
    .remain ( ten_fractional )
    );
assign temperature = {ten_quotint[3:0],ten_fractional[3:0],one_decimal[3:0],two_decimal[3:0]};

endmodule

然后是温度的数码管显示代码:

module digital_tube_display(
            input clk,
            input rst_n,
            input [15:0] display_num,
            output reg[3:0] dtube_cs_n,//7段数码管位选信号
            output reg[7:0] dtube_data//7段数码管段选信号
           );
//-------------------------------
//参数定义
//数码管显示0~F对应段选输出
parameter    NUM0 = 8'h3f,
            NUM1 = 8'h06,
            NUM2 = 8'h5b,
            NUM3 = 8'h4f,
            NUM4 = 8'h66,
            NUM5 = 8'h6d,
            NUM6 = 8'h7d,
            NUM7 = 8'h07,
            NUM8 = 8'h7f,
            NUM9 = 8'h6f,
            POINT_NUM0 = 8'hbf,
            POINT_NUM1 = 8'h86,
            POINT_NUM2 = 8'hdb,
            POINT_NUM3 = 8'hcf,
            POINT_NUM4 = 8'he6,
            POINT_NUM5 = 8'hed,
            POINT_NUM6 = 8'hfd,
            POINT_NUM7 = 8'h87,
            POINT_NUM8 = 8'hff,
            POINT_NUM9 = 8'hef;
//数码管位选0~3输出
parameter    CSN = 4'B1111,
            CS0 = 4'b1110,
            CS1 = 4'b1101,
            CS2 = 4'b1011,
            CS3 = 4'b0111;
//-----------------------------------
//分时显示数据控制单元
reg[3:0] current_display_num;//当前显示数据
reg[7:0] div_cnt;//分时计数器
always @ (posedge clk or negedge rst_n)
        if(!rst_n)
            div_cnt <= 8'd0;
        else 
            div_cnt <= div_cnt + 1'b1;
        //显示数据
always @ (posedge clk or negedge rst_n)
        if(!rst_n)
            current_display_num <= 4'b0;
        else
            begin
                case(div_cnt)
                    8'hff : current_display_num <= display_num[3:0];
                    8'h3f : current_display_num <= display_num[7:4];
                    8'h7f : current_display_num <= display_num[11:8];
                    8'hbf : current_display_num <= display_num[15:12];
                    default : ;
                endcase
            end
//段选数据译码
always @ (posedge clk or negedge rst_n)
        if(!rst_n)
            dtube_data <= NUM0;
        else if(dtube_cs_n == CS2)
            begin 
                case(current_display_num)   //小数点显示位
                    4'h0 : dtube_data <= POINT_NUM0;
                    4'h1 : dtube_data <= POINT_NUM1;
                    4'h2 : dtube_data <= POINT_NUM2;
                    4'h3 : dtube_data <= POINT_NUM3;
                    4'h4 : dtube_data <= POINT_NUM4;
                    4'h5 : dtube_data <= POINT_NUM5;
                    4'h6 : dtube_data <= POINT_NUM6;
                    4'h7 : dtube_data <= POINT_NUM7;
                    4'h8 : dtube_data <= POINT_NUM8;
                    4'h9 : dtube_data <= POINT_NUM9;
                    default : ;
                endcase
            end
            else if(dtube_cs_n != CS2)
            begin 
                case(current_display_num)
                    4'h0 : dtube_data <= NUM0;
                    4'h1 : dtube_data <= NUM1;
                    4'h2 : dtube_data <= NUM2;
                    4'h3 : dtube_data <= NUM3;
                    4'h4 : dtube_data <= NUM4;
                    4'h5 : dtube_data <= NUM5;
                    4'h6 : dtube_data <= NUM6;
                    4'h7 : dtube_data <= NUM7;
                    4'h8 : dtube_data <= NUM8;
                    4'h9 : dtube_data <= NUM9;
                    default : ;
                endcase
            end
//位选译码
always @ (posedge clk or negedge rst_n)
        if(!rst_n)
            dtube_cs_n <= CSN;
        else
            begin
                case(div_cnt[7:6])
                    2'b00 : dtube_cs_n <= CS0;
                    2'b01 : dtube_cs_n <= CS1;
                    2'b10 : dtube_cs_n <= CS2;
                    2'b11 : dtube_cs_n <= CS3;
                    default : dtube_cs_n <= CSN;
                endcase
            end
endmodule

基于FPGA的DS18B20温度测量以及数码管显示相关推荐

  1. 基于FPGA的 DS18B20多功能温度显示

    基于FPGA的 DS18B20多功能温度显示 实现功能: 1.实时温度显示在数码管上,更新速率1-2s一次 2.按下按键显示最近30s内的最高温和最低温 不包含板子, 3.按下按键可以存储当前温度,最 ...

  2. 74hc164驱动数码管c语言程序,基于51单片机的74HC164驱动数码管显示程序与仿真

    基于51单片机的74HC164驱动数码管显示程序与仿真 基于51单片机的74HC164驱动一位数码管显示程序与仿真 #include #include #define uchar unsigned c ...

  3. 基于51单片机的8位数码管显示的可调时电子时钟

     基于51单片机的8位数码管显示的可调时电子时钟 本人大二本科生,第一次发东西,功能比较简单,代码有点复杂,希望能有大神指正. 基于51单片机的不可调时间的时钟显示,晶振为11.0592MHZ,60H ...

  4. 51单片机DS18B20测温数码管显示例程(Proteus仿真+程序)

    编号:19 51单片机DS18B20测温数码管显示例程 功能描述: 本设计由STM32单片机+DS18B20温度传感器+四段数码管显示模块组成. 1.主控制器是51单片机 2.DS18B20温度传感器 ...

  5. 单片机8位数码管时钟c语言汇编,基于8051单片机和DS12C8878位数码管显示的时钟.docx...

    基于8051单片机和DS12C8878位数码管显示的时钟 #include #include #define sec XBYTE[0xed00]//秒寄存器地址 #define min XBYTE[0 ...

  6. 基于51单片机的温度控制系统数码管显示蜂鸣器报警proteus仿真原理图PCB

    功能: 0.本系统采用STC89C52作为单片机 1.系统实时监测并显示当前温度,并通过四位数码管显示 2.超过设定阈值,蜂鸣器将报警,同时控制相应继电器实现降温或者加热 3.系统具备三个功能按键,可 ...

  7. 【Verilog】基于FPGA的五子棋小游戏(VGA显示、双人对战、胜负判别、附完整代码)

    基于FPGA的五子棋小游戏 有一些说明: 1.本文是基于VGA的显示小游戏,主要为VGA显示的拓展应用: 2.为适应不同显示屏的分辨率,棋盘确定为10X10的黑线白底的方格: 3.下棋主要用棋格颜色变 ...

  8. 基于FPGA的ds18b20温度传感器使用

    文章目录 一.传感器介绍 1.特点 2.内部结构 3.ds18b20管脚 4.ds18b20内部高速暂存存储器 5.ds18b20工作时序 6.ds18b20单线通信 二.FPGA代码实现 1.状态图 ...

  9. DS18B20测量温度数码管显示

    DS18B20温度传感器简介 DS18B20是一种数字温度传感器.它输出的是数字信号,同时具有体积小,硬件资源耗费少,抗干扰能力强,精度高等特点. DS18B20温度传感器特点 1.单线接口:DS18 ...

最新文章

  1. python免费视频百度网盘-Python入门视频百度网盘看这些就够
  2. vue2.0中引入wangEditor2 步骤与坑
  3. 基于动态代码生成技术的动态对象工厂
  4. 玩转Google开源C++单元测试框架Google Test系列(gtest)之八 - 打造自己的单元测试框架
  5. 王盛:QUIC让B站在20%丢包时实现零卡顿
  6. 内推|百度2020春实习-计算机视觉算法研发工程师-北京
  7. 使用devops的团队_DevOps与兼职社区团队兼容吗?
  8. Guacamole 介绍以及架构
  9. salt把返回写入到mysql
  10. 【Oracle】DataGuard中 Switchover 主、备切换
  11. 远程sun服务器,向日葵远程控制(com.oray.sunlogin) - 11.1.0.39347 - 应用 - 酷安
  12. itextpdf字体编码研究
  13. 【业务】5个顶级案例教你实现最牛供应链管理
  14. 动易cms net版本拿shell
  15. sklearn_scaler
  16. 编写一递归函数求斐波纳契数列1,1,2,3,5,8,13,…的前40项。c语言
  17. Versal ACAP AI 引擎入门
  18. Python - yamail - 进阶之路 - Day08
  19. 双鱼座三:舞者与梦想家的一周
  20. ‘tensorflow.python.framework.ops.EagerTensor‘ object has no attribute ‘reshape‘

热门文章

  1. 文件被隐藏了怎么恢复?读完你就知道了
  2. GPON ITU-T G.xxx 标准协议下载
  3. GNU的C++代码书写规范
  4. 今天给在家介绍一篇基于jsp的旅游网站设计与实现
  5. 2018硅谷巨头七大丑闻算总账
  6. passwd出现不完全匹配登陆成功的情况,问题解决如下
  7. CentOS部署ElasticSearch7.6.1集群
  8. Matlab GUI编程技巧(十五):scroll滚动到组件内的位置及ScrollBar动画演示
  9. ioca0中断 pic单片机_PIC单片机
  10. 猫耳FM轮播图模型制作