【FPGA】译码器、计数器及数码管显示

写在前面
万万没想到秋招春招找工作以C++为主、FPGA为辅,最后去了FPGA岗位
也算是不忘初心,回归了从研一就开始学的FPGA老本行
但之前学FPGA的时候并没有养成写笔记的习惯,导致后面有些东西都比较模糊,因此打算从今天开始从头来过,把之前基础知识和新学到的FPGA相关内容记录下来,记录我的FPGA之路!

这是某本书上的第一章节,感觉写的还是挺不错的,大概看了一下让我回想起很多知识,个人感觉比较适合学习了Verilog语法和数电之后上板的同学

1. 原理介绍

1.1 数码管

数码管按段分可分为七段数码管八段数码管,区别就是八段数码管多了个小数点
在这里插入图片描述
常见的数码管有两种:共阴数码管共阳数码管
共阴数码管就是高电平亮,低电平灭;共阳数码管就是低电平亮,高电平灭。

1.2 译码器

七段数码管译码器的结构图如下,4个输入变量能够组合成十六进制数字0-F,那么相应的输出就可以通过七个输出变量,表示成数字,从而达到译码的效果。
在这里插入图片描述
这里译码器有两种写法,一种比较复杂,就是通过对应的真值表或者卡诺图写出h的逻辑表达式,写起来比较繁琐,就直接放代码,通过逻辑门(assign赋值语句)实现译码器

assign h[6] = (~b[3] & ~b[2] & ~b[1]) | (~b[3] & b[2] & b[1] & b[0]) | (b[3] & b[2] & ~b[1] & ~b[0]);
assign h[5] = (~b[3] & ~b[2] & ~b[0]) | (~b[3] & ~b[2] & b[1]) | (~b[3] & b[1] & ~b[0]) |(b[3] & b[2] & ~b[1] & b[0]);
assign h[4] = (~b[3] & b[0]) | (~b[3] & b[2] & ~b[1]) | (b[3] & ~b[2] & ~b[1] & b[0]);
assign h[3] = (~b[2] & ~b[1] & b[0]) | (~b[3] & b[2] & ~b[1] & ~b[0]) | (b[2] & b[1] & b[0] ) | (b[3] & ~b[2] &b[1] & ~b[0]);
assign h[2] = (~b[3] & ~b[2] & b[1] & ~b[0]) | (b[3] & b[2] & ~b[1] & ~b[0]) | (b[3] & b[2] & b[1]);
assign h[1] = (~b[3] & b[2] & ~b[1] & b[0]) | (& b[2] & b[1] & ~b[0]) | (b[3] & b[2] & ~b[0]) | (b[3] & b[1] & b[0]);
assign h[0] = (~b[3] & ~b[2] & ~b[1] & b[0]) | (~b[3] & b[2] & ~b[1] & ~b[0]) | (b[3] & b[2] & ~b[1] & b[0] | b[3] & ~b[2] & b[1] & b[0]);

当然,这样不仅要推导,写起来就很麻烦
所以还可以用case条件语句实现

case (b)
    4`b0000: h = 7`b1000000;
    4`b0001: h = 7`b1111001;
    4`b0010: h = 7`b0100100;
    4`b0011: h = 7`b0110000;
    4`b0100: h = 7`b0011001;
    4`b0101: h = 7`b0010010;
    4`b0110: h = 7`b0000010;
    4`b0111: h = 7`b1111000;
    4`b1000: h = 7`b0000000;
    4`b1001: h = 7`b0011000;
    4`b1010: h = 7`b0001000;
    4`b1011: h = 7`b0000011;
    4`b1100: h = 7`b1000110;
    4`b1101: h = 7`b0100001;
    4`b1110: h = 7`b1000110;
    4`b1111: h = 7`b1001110;
endcase

1.3 D触发器

D触发器的特性方程Qn+1 = D,Qn+1为次态,D为输入信号,都是数电上的东西,Verliog HDL代码为:

module dff(
    input clk,
    intpu d,
    output reg q
);

always @(posedge clk)
    q <= d;
endmudle;

而通常会用到复位信号来设定电路的起始值或者做清楚动作,因此D触发器根据复位的不同分为两种:异步复位D触发器和同步复位D触发器

异步复位D触发器:
“异步”指的是和工作时钟不同步的意思,即寄存器的复位不关心时钟的有效沿来不来,只要检测到复位信号有效,就立即执行复位操作。

module DFF_async_rst(
    input clk,
    input rst_n,
    intpu d,
    output reg q
);

always @(posedge clk,negedge rst_n)
    if(~rst_n)            //复位信号rst_n的优先级比时钟信号clk高
        q <= 1'b0;
    else
        q <= d;
endmudle;

同步复位D触发器
“同步”是和工作时钟同步的意思,即复位信号只有在时钟的有效沿到来时,才能有效,否则无法完成复位任务。

module DFF_async_rst(
    input clk,
    input rst_n,
    intpu d,
    output reg q
);

always @(posedge clk)     //always语句只有一个触发条件
    if(~rst_n)            //复位信号rst_n需要在clk的上升沿触发下才能起作用
                          //当rst_n=0,并且clk上升沿到来时,Q才会被清零
        q <= 1'b0;
    else
        q <= d;
endmudle;

1.4 寄存器

寄存器是数字系统中用来存储二进制数据的逻辑部件。1个触发器可以存储一位二进制数据,存储n位二进制数据的寄存器需要用n个触发器组成。

当然,上述说法是表现在硬件上,在代码方便只是定义了输入输出的位宽:

module reg4bits(
    input clk,
    input rst_n,
    input en;
    intpu [3:0] d,
    output reg [3:0] q
);

always @(posedge clk,negedge rst_n)
    if(~rst_n)         
        q <= 4'b0000;
    else if(en)             //增加了使能端
        q <= d;
    else                    
        q <= q;
endmudle;

1.5 计数器

计数器不仅可以用于对脉冲进行计数,还可用于分频、定时、产生节拍脉冲以及其他时序信号。

同步二进制加(减)计数器

module counter_up(
    input        clk,
    input        rst_n,
    input        en,
    output  reg [3:0] q
);

always @(posedge clk or negedge rst_n)
begin
    if(~rst_n)
        q <= 4'b0000;             //复位,计数清零
    else if(en)                   //计数器使能,开始计数
        q <= q + 1'b1;            //加计数
      //q <= q - 1'b1;            //减计数,原理都是一样的
    else                          //计数器未使能,计数器保持不变
        q <= q;
end
endmodule

模m计数器
计数器运行时总是从某个起始状态开始,以此经过所有不重复的状态后完成一次循环。把一次循环所包含的状态数称为计数器的模,用M表示。

module counter_m #(
    parameter n = 4
    parameter m = 16
)(
    input             clk,
    input             rst_n;
    input             en;
    output reg [3:0]  cnt;           //计数器计数值
    output            carry_out;     //计数器进位输出
);

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)              //复位,计数值清零
        cnt <= 4'b0000;
    else if(en)             //计数器使能端,开始计数
    begin             
        if (cnt == m-1)     //计数值达到m-1,计数值清零
            cnt <= 4'b0000;
        else
            cnt <= cnt + 1'b1;
    end
    else 
        cnt <= cnt;
end
assign carry_out = (cnt == m-1);   //计数值达到m-1,计数器进位输出1
endmodule

1.6 数码管显示

前面说了那么多,都是为了将其结合起来,原理也比较简单,就直接放上代码了

译码器decod7seg

module decod7seg (
    input       [3:0]   hex,
    output  reg [6:0]   display
);

always @ (hex)
    case (hex)
        4'h0: display = 7'b1000000;
        4'h1: display = 7'b1111001;
        4'h2: display = 7'b0100100;
        4'h3: display = 7'b0110000;
        4'h4: display = 7'b0011001;
        4'h5: display = 7'b0010010;
        4'h6: display = 7'b0000010;
        4'h7: display = 7'b1111000;
        4'h8: display = 7'b0000000;
        4'h9: display = 7'b0011000;
        4'hA: display = 7'b0001000;
        4'hB: display = 7'b0000011;
        4'hC: display = 7'b1000110;
        4'hD: display = 7'b0100001;
        4'hE: display = 7'b0000110;
        4'hF: display = 7'b0001110;
    endcase

endmodule

计数器

module counter_up_down (
    input               clk,
    input               rst_n,
    input               up_down,
    output  reg [3:0]   q
);
    
always @(posedge clk or negedge rst_n)
begin
    if (~rst_n)
        q <= 4'b0000;
    else if (up_down)
        q <= q + 1'b1;
    else
        q <= q - 1'b1;
end
    
endmodule

控制模块

module display_controller (
    input           clk,
    input           rst_n,
    input           up_down,
    output  [6:0]   hex0_out
);

wire [3:0] q;

counter_up_down counter_up_down_inst (
    .clk        (clk),
    .rst_n      (rst_n),
    .up_down    (up_down),
    .q          (q)
);
    
decod7seg decod7seg_inst (
    .hex        (q),
    .display    (hex0_out)
);
    
endmodule

测试文件

module display_controller_tb (
    input           clk,
    input           rst_n,
    input           up_down,
    output  [6:0]   hex0_out
);

wire [3:0] q;

counter_up_down counter_up_down_inst (
    .clk        (clk),
    .rst_n      (rst_n),
    .up_down    (up_down),
    .q          (q)
);
    
decod7seg decod7seg_inst (
    .hex        (q),
    .display    (hex0_out)
);
    
endmodule

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值