写在前面
万万没想到秋招春招找工作以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
控制模块文章来源:https://www.toymoban.com/news/detail-501380.html
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
测试文件文章来源地址https://www.toymoban.com/news/detail-501380.html
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
到了这里,关于【FPGA】译码器、计数器及数码管显示的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!