FPGA驱动DS18B20进行温度测量

FPBGA驱动DS18B20传感器进行温度测量

DS18B20C传感器简介

在这里插入图片描述

使用一路信号线实现主机和从机的双向的一个数据交互。
测温范围-55℃ 到 +125℃,测量范围在-10℃到+85℃的测量范围内,精度可以达到±0.5℃。
温度测量
DS18B20中的温度传感器可完成对温度的测量,它的温度转换精度用户可自定义为9、10、11、12位,精度分别为0.5℃、0.25℃、0.125℃、0.0625℃。
符号标志位(S)表示温度的正负极性:若S=0,则为正数;若S=1,则为负数
在这里插入图片描述
配置寄存器
高速缓存器中第五个字节即为配置寄存器,用户通过改变R1和R0的值来配置DS18B20的分辨率
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

DS18B20实现温度转换

主机控制DS18B20完成温度转换必须经过三个步骤:每一次读写之前都要对DS18B20进行初始化操作,初始化成功之后发送一条ROM命令,最后发送RAM命令,这样才能对DS18B20进行预定的操作。
初始化
单总线上的所有操作都必须以初始化为开始。初始化序列由总线上的主设备发出的复位脉冲以及紧跟着从设备回应的存在脉冲构成。该存在脉冲是让总线主设备知道DS18B20在总线上并准备好运行。
ROM命令
搜索ROM[F0h],读ROM[33h]、匹配ROM[55h]、跳过ROM[CCh]、警报搜索ROM[ECh]
搜索ROM[F0h]命令:当系统上电初始化之后,我们的主设备可以通过这个命令识别该总线上所以的从设备的rom编码,这样可以使得主设备确定总线上从设备的类型以及它的数量。
读ROM[33h]命令:这条命令允许主设备读取我们的DS18B20 ROM编码,只有总线上只存在一个DS18B20传感器,才能够使用这个命令,假如总线上存在多个从设备,我们发送了这条指令,那么这时候所有的从设备都会响应这条指令,那么这时候会引起数据的冲突。
匹配ROM[55h]命令:在主设备发送匹配ROM命令时,后面要接着发送64位的ROM编码,那么这样就使主设备在多点总线上可以定为一支特定的ds18b20,那么只有64位rom序列完全匹配的ds18b20才会做出响应。那么总线上的其他设备都将等待下一个复位脉冲。无论总线上存在单个或者多个器件时,这条命令都可以使用。
跳过ROM[CCh]命令:在使用这条命令时,后面可以不提供64位的rom编码,就可以进行下一步的一个操作,在单点总线时,也就是说我们的总线上只连接了一个从设备,这时候使用这条命令可以节约时间。那么如果总线上不止一个从设备,在跳过rom命令之后,发送读命令,那么所有的从设备将会同时执行温度转换,那么总线上就会发生数据冲突。
警报搜索ROM[ECh]命令:这条命令的操作与跳过ROM命令的操作基本相同但是不同的是,只有温度高于th或者温度低于tl,就是达到警报条件的从设备才会响应这条命令,那么只要不掉电,这个警报状态一直保持,直到温度不在警报范围之内。
RAM命令(功能命令):这些命令可以使得主设备操控从设备进行一系列的一个操作。
温度转换[44h]、写入暂存器[4Eh]、读取高速缓存器[BEh]、复制高速缓存器[48h]、召回EEPROM[B8h]、读取供电模式[B4h]
温度转换[44h]命令:这条命令是单次温度转换,那么温度转换完成之后,转换后的温度数据会寄存在高速缓存器当中的温度传感器,温度的低八位寄存在字节零,温度的高八位寄存在字节一。之后DS18B20会恢复到低功耗的闲置状态,如果总线在该命令之后发出读时序,如果我们的DS18B20正在进行温度转换,就会响应0,如果说完成了温度转换就会响应1.
写入暂存器[4Eh]命令:这条命令会使得我们的主设备像我们的高速缓存器写出三个字节的数据,那么第一个字节写入高速缓存器字节二的位置,写入的是高温报警值;第二个字节的数据写入高速缓存器字节三的位置,写入的是低温报警值;第三个字节的数据写入高速缓存器字节四的位置,写入的是配置寄存器;所有数据的写入都是低位在前,高位在后,复位可以随时终端写入。
读取高速缓存器[BEh]命令:这条命令是读取高速缓存器当中的值,从字节0读到字节8,每个字节的数据从低位开始传输,如果说不想读取这么多数据,在读取过程中可以使用复位来终止读取。
复制高速缓存器[48h]命令:这条命令是将高速缓存器当中的th就是字节二、tl字节三、以及配置寄存器字节四,将这三个字节的数据拷贝到eeprom,如果说主设备在这条命令之后,发送了一个读时序,而我们的ds18b20正在把数据拷贝到eeprom,那么这时候ds18b20会输出一个0,如果拷贝结束,ds18b20输出一个1。
召回EEPROM[B8h]命令:这条命令会将eeprom中存储的三位数据召回到我们的高速缓存器,这个操作上电之后自动执行一次,所以说在上电期间,暂存器中一直存在有效的数据,那么如果在召回命令之后,其中一个读时序,而我们的DS18B20正在进行一个数据的召回,他们就会响应一个0,召回完成响应一个1。
在这里插入图片描述

初始化时序

与DS18B20所有的通信都是由初始化开始的,初始化主设备发出的复位脉冲及从设备响应的存在脉冲组成。在这里插入图片描述
协议定义了多个信号形式有复位脉冲,存在脉冲,写0,写1,读0,读1,存在脉冲是由从设备发出,其他信号都是由主设备控制。
初始化时序解析
首先主设备发出一个480960微秒的低电平脉冲,然后释放总线,变为高电平,然后主设备在480微秒时间内对总线进行一个检测,如果在检测时间内,有低电平出现,就表示总线上有器件做出应答,如果没有低电平出现,一直都是高电平,就说明总线上没有器件做出应答,而从设备上电以后就一直在检测,检测总线上是否出现480960微秒的低电平,如果有,那么总线转为高电平后,等待1660微秒,然后总线会拉低,然后低电平保持时间是60240微秒,这表示从设备做出响应存在脉冲,告诉主机我已经准备好了,可以进行一个数据的交互,如果说没有检测到低电平,就一直在检测等待。

写时序

在这里插入图片描述
当主设备将总线从高电平拉低至低电平时启动写时序 ,所有的写时序它的持续时间最少为60微秒,每个时序的恢复时间为1微秒。如果说要产生写0时序,,主设备将总线拉低,然后保持低电平,低电平保持时间最少为60微秒。如果要实现写1时序,首先将总线拉低,然后释放总线允许总线在写时序开始后15微秒内拉至高电平,当总线拉低之后,从设备在15~65微秒进行一个采样。如果说这时候总线为高电平表示写1,总线为低电平表示写0

读时序在这里插入图片描述

每个读时序最少维持60微秒,读时序的间隔最少为1微秒。首先主设备将总线拉低,表示启动读时序,读时序启动后,总线由从设备控制,ds18b20会向主设备发送0,或者1; 那么从设备将总线拉高表示发送1,总线拉低表示发送0,读时序完成后总线拉高,表示闲置状态,我们的从设备输出数据在启动读数据之后的15微秒内有效,所以主设备必须在启动读时序之后15微秒内释放总线,然后对总线进行采样,采到低电平表示0,采到高电平表示1。

DS18B20一次温度检测流程在这里插入图片描述
状态机变化

在这里插入图片描述

代码编写

控制模块
module driver(
    input                   clk         ,
    input                   rst_n       ,
    input                   dq_in       ,   // 传感器传给控制模块数据
    output                  dq_out      ,   // 控制模块传给传感器数据
    output                  dq_out_en   ,   // 传给传感器数据有效信号
    output[15:0]            t_data      ,   // 将传人控制控制的串行数据进行并行处理
    output                  t_data_vld      // 并行数据转换有效信号
); 
// 定义状态机
parameter IDLE  = 6'b000001,    // 初始状态
          SKIP  = 6'b000010,    // 发送ROM命令
          CONT  = 6'b000100,    // 温度测量命令
          WAIT  = 6'b001000,    // 等待
          RDCMD = 6'b010000,    // 读命令
          RD    = 6'b100000;    // 读数据
// 定义时间参数960us,750ms,65us
parameter max_960us = 10'd960;
parameter max_750ms = 20'd750000;
parameter max_65_us = 7'd65;
// 定义状态机转换命令
wire                         idle2skip  ;
wire                         skip2cont  ;
wire                         skip2rdcmd ;
wire                         cont2wait  ;
wire                         wait2idle  ;
wire                         rdcmd2rd   ;
wire                         rd2idle    ;
// 定义状态机现态,次态
reg[5:0]                    state_c;
reg[5:0]                    state_n;
// 定义标志信号,表示第几次初始化
reg                         flag;
// 定义us计数器
reg[5:0]                    cnt_1us;
wire                        add_cnt_1us;
wire                        end_cnt_1us;
// 定义字节计数器
reg[3:0]                    cnt_byte;
wire                        add_cnt_byte;
wire                        end_cnt_byte;
// 定义960us计数器
reg[9:0]                    cnt_960us;
wire                        add_cnt_960us;
wire                        end_cnt_960us;
// 定义750ms计数器
reg[19:0]                   cnt_750ms;
wire                        add_cnt_750ms;
wire                        end_cnt_750ms;
// 定义65us计数器
reg[6:0]                    cnt_65us;
wire                        add_cnt_65us;
wire                        end_cnt_65us;
// 定义字节计数器是8还是16
reg[4:0]                    max;

// 输出信号
reg                         dq_out_r;
reg                         dq_out_en_r;
reg[15:0]                   t_data_r;
reg                         t_data_vld_r;
// 现态和次态
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        state_c <= IDLE;
    end
    else begin
        state_c <= state_n;
    end
end
// 状态机跳转变化
always @(*) begin
    case (state_c)
        IDLE :begin
            if(idle2skip)begin
                state_n = SKIP;
            end
            else begin
                state_n = IDLE;
            end
        end
        SKIP :begin
            if(skip2cont)begin
                state_n = CONT;
            end
            else if(skip2rdcmd) begin
                state_n = RDCMD;
            end
            else begin
                state_n = SKIP;
            end
        end
        CONT :begin
            if(cont2wait)begin
                state_n = WAIT;
            end
            else begin
                state_n = CONT;
            end
        end
        WAIT :begin
            if(wait2idle)begin
                state_n = IDLE;
            end
            else begin
                state_n = WAIT;
            end
        end
        RDCMD:begin
            if(rdcmd2rd)begin
                state_n = RD;
            end
            else begin
                state_n = RDCMD;
            end
        end
        RD   :begin
            if(rd2idle)begin
                state_n = IDLE;
            end
            else begin
                state_n = RD;
            end
        end
        default: state_n = IDLE;
    endcase
end
// 状态机跳转条件
assign idle2skip    = (state_c == IDLE) && end_cnt_960us;           // 在初始状态下,等待960us
assign skip2cont    = (state_c == SKIP) && end_cnt_byte && (!flag); // 在发送rom跳过命令状态下,发送完8字节指令并且flag信号为低电平
assign skip2rdcmd   = (state_c == SKIP) && end_cnt_byte && flag;    // 在发送rom跳过命令状态下,发送完8字节指令并且flag信号为高电平
assign cont2wait    = (state_c == CONT) && end_cnt_byte;            // 在温度测量命令状态下,发送完8字节数据指令
assign wait2idle    = (state_c == WAIT) && end_cnt_750ms;           // 在等待状态状态下,等待750ms
assign rdcmd2rd     = (state_c == RDCMD) && end_cnt_byte;           // 在读取命令状态下,发送完8字节指令
assign rd2idle      = (state_c == RD) && end_cnt_byte;              // 在读取数据状态下,读取完16字节数据
// 定义标志信号,在发送rom跳过指令状态有效跳温度测量命令或者在发送rom跳过指令状态跳读温度指令状态有效情况下,flag取反
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        flag <= 0;
    end
    else if(skip2cont || skip2rdcmd)begin
        flag <= ~flag;
    end

end
// 1us计数器
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        cnt_1us <= 0;
    end
    else if(add_cnt_1us)begin
        if(end_cnt_1us)begin
            cnt_1us <= 0;
        end
        else begin
            cnt_1us <= cnt_1us + 1;
        end
    end
end
assign add_cnt_1us = 1'b1; // 开始计数条件一直拉高
assign end_cnt_1us = add_cnt_1us && cnt_1us == 50-1;    // 计数到50个周期结束计数
// 960us计数器
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        cnt_960us <= 0;
    end
    else if(add_cnt_960us)begin
        if(end_cnt_960us)begin
            cnt_960us <= 0;
        end
        else begin
            cnt_960us <= cnt_960us + 1;
        end
    end
end
assign add_cnt_960us = end_cnt_1us && (state_c==IDLE);// 在初始状态下,1us计数结束
assign end_cnt_960us = add_cnt_960us && cnt_960us == max_960us-1;// 计数到960us结束计数
// 65us计数器
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        cnt_65us <= 0;
    end
    else if(add_cnt_65us)begin
        if(end_cnt_65us)begin
            cnt_65us <= 0;
        end
        else begin
            cnt_65us <= cnt_65us + 1;
        end
    end
end
assign add_cnt_65us = ((state_c != IDLE) && (state_c != WAIT)) && end_cnt_1us; // 不在初始状态,不在等待状态,1us结束计数
assign end_cnt_65us = add_cnt_65us && cnt_65us == max_65_us-1;  // 计数到65us结束计数
// 定义字节计数器,当在读数据状态下字节计数器计数到16,其他状态下,计数到8
always @(*) begin
    if(state_c == RD)begin
        max = 16;
    end
    else begin
        max = 8;
    end
end
// 字节计数器
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        cnt_byte <= 0;
    end
    else if(add_cnt_byte)begin
        if(end_cnt_byte)begin
            cnt_byte <= 0;
        end
        else begin
            cnt_byte <= cnt_byte + 1;
        end
    end
end
assign add_cnt_byte = end_cnt_65us && ((state_c != IDLE) && (state_c != WAIT));// 65us结束计数,不在初始状态,不在等待状态
assign end_cnt_byte = add_cnt_byte && cnt_byte == max - 1;  // 计数到8,或者16结束计数
// 750ms计数器
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        cnt_750ms <= 0;
    end
    else if(add_cnt_750ms)begin
        if(end_cnt_750ms)begin
            cnt_750ms <= 0;
        end
        else begin
            cnt_750ms <= cnt_750ms + 1;
        end
    end
end
assign add_cnt_750ms = end_cnt_1us && (state_c == WAIT);// 1us计数器结束计数,在等待状态
assign end_cnt_750ms = add_cnt_750ms && cnt_750ms == max_750ms-1; // 计数到750ms结束计数
// 输出数据
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        dq_out_r <= 1;
    end
    else begin
        dq_out_r <= 0;
    end
    
end
assign dq_out = dq_out_r;
// 输出数据使能
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
       dq_out_en_r <= 1'b0; 
    end
    else begin
        case (state_c)
            IDLE  : begin   // 初始状态下,发送480高电平
                if(cnt_960us < 480)begin
                    dq_out_en_r <= 1;
                end
                else begin  // 初始状态下发送480低电平
                    dq_out_en_r <= 0;
                end
            end
            SKIP  : begin
                if(cnt_byte[1])begin
                   if(cnt_65us < 3)begin
                        dq_out_en_r <= 1;
                    end
                    else begin
                        dq_out_en_r <= 0;
                    end 
                end
                else begin
                    if(cnt_65us < 63)begin
                        dq_out_en_r <= 1;
                    end
                    else begin
                        dq_out_en_r <= 0;
                    end
                end
            end
            CONT  : begin // 0100 0100 根据时序发送等待温度测量指令
                if((cnt_byte == 2) || (cnt_byte == 6))begin
                    if(cnt_65us < 3)begin
                        dq_out_en_r <= 1;
                    end
                    else begin
                        dq_out_en_r <= 0;
                    end
                end
                else begin
                    if(cnt_65us < 63)begin
                        dq_out_en_r <= 1;
                    end
                    else begin
                        dq_out_en_r <= 0;
                    end
                end
            end
            WAIT  : begin 
                dq_out_en_r <= 0;
            end
            RDCMD :begin // 1011 1110   根据时序发送读温度指令
                if((cnt_byte == 0)||(cnt_byte==6))begin
                    if(cnt_65us < 63)begin
                        dq_out_en_r <= 1;
                    end
                    else begin
                        dq_out_en_r <= 0;
                    end
                end
                else begin
                    if(cnt_65us < 3)begin
                        dq_out_en_r <= 1;
                    end
                    else begin
                        dq_out_en_r <= 0;
                    end
                end
            end
            RD    :begin    // 根据温度将温度数据读出来
                if(cnt_65us < 3)begin
                    dq_out_en_r <= 1;
                end
                else begin
                    dq_out_en_r <= 0;
                end
            end
            default: dq_out_en_r <= 0;
        endcase
    end
end
assign dq_out_en = dq_out_en_r;
// 将传入的串行数据转成并行数据
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        t_data_r <= 0;
    end
    else if((cnt_65us == 14) && end_cnt_1us)begin
        t_data_r <= {dq_in,t_data_r[15:1]};
    end
end
assign t_data = t_data_r;
// 等待温度数据读取完成之后,输出数据使能拉高
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        t_data_vld_r <= 0;
    end
    else if(end_cnt_byte && (state_c == RD))begin
        t_data_vld_r <= 1;
    end
    else begin
        t_data_vld_r <= 0;
    end
end
assign t_data_vld = t_data_vld_r;
endmodule
数据处理模块
module ctrl (
    input                       clk,
    input                       rst_n,
    input[15:0]                 t_data,    
    input                       t_data_vld,
    output[23:0]                dis_data
);
// 定义输入数据
reg [7:0]                       t_data_r;
// 定义输出数据
reg[23:0]                       dis_data_r;
// 定义显示温度的十位和个位
wire [3:0]                      cnt_ge;
wire [3:0]                      cnt_shi;
// 将输入数据的整数部分保留
always @(posedge clk or negedge rst_n ) begin
    if(!rst_n)begin
        t_data_r <= 0;
    end
    else if(t_data_vld)begin
        t_data_r <= t_data[11:4];
    end
end
// 求出整数部分的十位和个位
assign cnt_shi = t_data_r / 10 ;
assign cnt_ge  = t_data_r % 10 ;
// 将十位和个位拼接到输出数据
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        dis_data_r <= 0;
    end
    else begin
        dis_data_r <= {4'd10,4'd10,4'd10,4'd10,cnt_shi,cnt_ge};
    end
end
assign dis_data = dis_data_r;
endmodule
数码管模块
module seg_driver (
    input                       clk         ,
    input                       rst_n       ,
    input[23:0]                 dis_data      ,
    output[5:0]                 sel         ,
    output[7:0]                 dig         
);

// 定义1ms时间参数
parameter   TIME_1MS = 16'd50000;
// 定义数码管显示0-9的段选信号
parameter   NUM_0 = 8'b1100_0000,
            NUM_1 = 8'b1111_1001,
            NUM_2 = 8'b1010_0100,
            NUM_3 = 8'b1011_0000,
            NUM_4 = 8'b1001_1001,
            NUM_5 = 8'b1001_0010,
            NUM_6 = 8'b1000_0010,
            NUM_7 = 8'b1111_1000,
            NUM_8 = 8'b1000_0000,
            NUM_9 = 8'b1001_0000,
            OFF   = 8'b1111_1111;
// 1ms计数器
reg  [15:0]         cnt_1ms             ;
wire                add_cnt_1ms         ;
wire                end_cnt_1ms         ;
// 位选信号
reg  [5:0]          sel_r               ;
// 段选信号
reg  [7:0]          dig_r               ;
// 定义个位十位的数据
reg  [3:0]          data                ;

//-----------位选切换--------------------
// 1ms计数器
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt_1ms <= 0;
    end
    else if(add_cnt_1ms)begin 
        if(end_cnt_1ms)begin
            cnt_1ms <= 0;
        end
        else begin 
            cnt_1ms <= cnt_1ms + 1;
        end
    end
end
assign add_cnt_1ms = 1'b1;
assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == TIME_1MS - 1;
// 位选信号,初始状态显示最低位,每1ms切换数码管
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        sel_r <= 6'b111_110;
    end
    else if(end_cnt_1ms)begin
        sel_r <= {sel_r[4:0],sel_r[5]};
    end
end
assign sel = sel_r;
//---------------段选--------------------
// 提取输入数据的十位和个位数据,在数码管的最低两位进行显示,其他数码管不显示
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin//规定0-9-->0-9 10-->OFF  14-->E  15-->F
        data <= 10;
    end
    else begin
        case(sel_r)
            6'b111_110:begin data <= dis_data[3 -:4];  end
            6'b111_101:begin data <= dis_data[7 -:4];  end
            6'b111_011:begin data <= 10;end
            6'b110_111:begin data <= 10;end
            6'b101_111:begin data <= 10;end
            6'b011_111:begin data <= 10;end
            default:begin data <= 10; end
        endcase
    end
end
// 将数据进行0-9进行段码变化显示
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        dig_r <= OFF;
    end
    else begin
        case(data)
            0 :dig_r <= {NUM_0};
            1 :dig_r <= {NUM_1};
            2 :dig_r <= {NUM_2};
            3 :dig_r <= {NUM_3};
            4 :dig_r <= {NUM_4};
            5 :dig_r <= {NUM_5};
            6 :dig_r <= {NUM_6};
            7 :dig_r <= {NUM_7};
            8 :dig_r <= {NUM_8};
            9 :dig_r <= {NUM_9};
            10:dig_r <= {OFF  };
            default:dig_r <= {OFF};
        endcase
    end
end
assign dig = dig_r;
endmodule
顶层模块
module top (
    input                   clk     ,
    input                   rst_n   ,
    inout                   dq      ,
    output[5:0]             sel     ,
    output[7:0]             dig
);

wire                        dq_in;
wire                        dq_out;
wire                        dq_out_en;

wire[15:0]                  t_data;
wire                        t_data_vld;
wire[23:0]                  dis_data;
// 定义dq数据线的输入输出
assign dq_in = dq;
assign dq = dq_out_en?dq_out:1'bz;
// 模块例化
driver u_driver(
    /* input                    */.clk         (clk             ),
    /* input                    */.rst_n       (rst_n           ),
    /* input                    */.dq_in       (dq_in           ),
    /* output                   */.dq_out      (dq_out          ),
    /* output                   */.dq_out_en   (dq_out_en       ),
    /* output[15:0]             */.t_data      (t_data          ),
    /* output                   */.t_data_vld  (t_data_vld      )
);
ctrl u_ctrl(
    /* input                        */.clk         (clk         ),
    /* input                        */.rst_n       (rst_n       ),
    /* input[15:0]                  */.t_data      (t_data      ),
    /* input                        */.t_data_vld  (t_data_vld  ),
    /* output[23:0]                 */.dis_data    (dis_data      )
);
seg_driver u_seg_driver(
    /* input                        */.clk         (clk         ),
    /* input                        */.rst_n       (rst_n       ),
    /* input[23:0]                  */.dis_data    (dis_data      ),
    /* output[5:0]                  */.sel         (sel         ),
    /* output[7:0]                  */.dig         (dig         )
); 
endmodule
仿真模块
module seg_driver (
    input                       clk         ,
    input                       rst_n       ,
    input[23:0]                 dis_data      ,
    output[5:0]                 sel         ,
    output[7:0]                 dig         
);

// 定义1ms时间参数
parameter   TIME_1MS = 16'd50000;
// 定义数码管显示0-9的段选信号
parameter   NUM_0 = 8'b1100_0000,
            NUM_1 = 8'b1111_1001,
            NUM_2 = 8'b1010_0100,
            NUM_3 = 8'b1011_0000,
            NUM_4 = 8'b1001_1001,
            NUM_5 = 8'b1001_0010,
            NUM_6 = 8'b1000_0010,
            NUM_7 = 8'b1111_1000,
            NUM_8 = 8'b1000_0000,
            NUM_9 = 8'b1001_0000,
            OFF   = 8'b1111_1111;
// 1ms计数器
reg  [15:0]         cnt_1ms             ;
wire                add_cnt_1ms         ;
wire                end_cnt_1ms         ;
// 位选信号
reg  [5:0]          sel_r               ;
// 段选信号
reg  [7:0]          dig_r               ;
// 定义个位十位的数据
reg  [3:0]          data                ;

//-----------位选切换--------------------
// 1ms计数器
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt_1ms <= 0;
    end
    else if(add_cnt_1ms)begin 
        if(end_cnt_1ms)begin
            cnt_1ms <= 0;
        end
        else begin 
            cnt_1ms <= cnt_1ms + 1;
        end
    end
end
assign add_cnt_1ms = 1'b1;
assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == TIME_1MS - 1;
// 位选信号,初始状态显示最低位,每1ms切换数码管
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        sel_r <= 6'b111_110;
    end
    else if(end_cnt_1ms)begin
        sel_r <= {sel_r[4:0],sel_r[5]};
    end
end
assign sel = sel_r;
//---------------段选--------------------
// 提取输入数据的十位和个位数据,在数码管的最低两位进行显示,其他数码管不显示
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin//规定0-9-->0-9 10-->OFF  14-->E  15-->F
        data <= 10;
    end
    else begin
        case(sel_r)
            6'b111_110:begin data <= dis_data[3 -:4];  end
            6'b111_101:begin data <= dis_data[7 -:4];  end
            6'b111_011:begin data <= 10;end
            6'b110_111:begin data <= 10;end
            6'b101_111:begin data <= 10;end
            6'b011_111:begin data <= 10;end
            default:begin data <= 10; end
        endcase
    end
end
// 将数据进行0-9进行段码变化显示
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        dig_r <= OFF;
    end
    else begin
        case(data)
            0 :dig_r <= {NUM_0};
            1 :dig_r <= {NUM_1};
            2 :dig_r <= {NUM_2};
            3 :dig_r <= {NUM_3};
            4 :dig_r <= {NUM_4};
            5 :dig_r <= {NUM_5};
            6 :dig_r <= {NUM_6};
            7 :dig_r <= {NUM_7};
            8 :dig_r <= {NUM_8};
            9 :dig_r <= {NUM_9};
            10:dig_r <= {OFF  };
            default:dig_r <= {OFF};
        endcase
    end
end
assign dig = dig_r;
endmodule

仿真

使用ModelSim工具仿真
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

上板验证

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
成功测量温度,实验结束。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值