当前位置: 首页 > article >正文

数字电路基础

组合逻辑——多路选择器:

多路选择器MUX(multiplexer)是一个多输入、单输出的组合逻辑电路,一个N输入的多路选择器就是一个N路的数字开关,可以根据通道选择控制信号的不同,从N个输入中选取一个输出到公共的输出端。多路选择器也是FPGA内部的一个基本资源,主要用于内部信号的选通。简单的多路选择器还可以通过级联生成更大的多路选择器。这里介绍一个四选一的多路选择器。

verilog代码:

module mux4_1(
input              in1 ,//输入四个信号
input              in2 ,
input              in3 ,
input              in4 ,
input        [1:0] sel ,//输入条件信号
output  reg        out  //输出信号

);

always@(*)begin
  case(sel)
    2'b00:out <= in1;
	2'b01:out <= in2;
	2'b10:out <= in3;
	2'b11:out <= in4;
	default:;
  endcase
end

endmodule

tb代码:

`timescale 1ns / 1ps

module tb_test();
reg       in1 ;
reg       in2 ;
reg       in3 ;
reg       in4 ;
reg [1:0] sel ;
wire      out ;

initial begin
in1 = 0;
in2 = 1;
in3 = 1;
in4 = 0;
sel = 2'b00;
#100
sel = 2'b10;
#100
sel = 2'b11;
#100
sel = 2'b01;

end

mux4_1 u_mux4_1(
.   in1  (in1),//输入四个信号
.   in2  (in2),
.   in3  (in3),
.   in4  (in4),
.   sel  (sel),//输入条件信号
.   out  (out) //输出信号

);

endmodule

在仿真中我们分别给四个输入信号赋初值,每次间隔100ns更改sel的值

仿真结果:

由仿真结果可以出,四个输入信号成功赋初值,每当sel发生改变时,out输出的值也在发生改变。自此多路选择器成功实现。


组合逻辑——译码器:

译码器是一种多输入多输出的组合逻辑电路,译码是编码的逆过程,同时去掉比特流在传播过程中混入的噪声。利用译码表把文字译成一组组数码或用译码表将代表某一项信息的一系列信号译成文字的过程称之为译码。在数码管等部分需要使用,这里将介绍其中一种——38译码器。

verilog代码:

module yima3_8(
input            A    ,//输入三个数据信号
input            B    ,//
input            C    ,//
output reg [7:0] out   //输出译码后的8位二进制数

);
wire [2:0] sel;//定义一个3位的信号

assign sel = {A,B,C};//通过拼接的方式将输入的三个数据组成在一起 000 001 010等

always@(*)begin
  case(sel)
    3'b000:out <= 8'b0000_0001;
	3'b001:out <= 8'b0000_0010;
	3'b010:out <= 8'b0000_0100;
	3'b011:out <= 8'b0000_1000;
	3'b100:out <= 8'b0001_0000;
	3'b101:out <= 8'b0010_0000;
	3'b110:out <= 8'b0100_0000;
	3'b111:out <= 8'b1000_0000;
	default:;
endcase
end

endmodule

tb代码:

`timescale 1ns / 1ps

module tb_test();
reg A ;
reg B ;
reg C ;
wire [7:0] out;

initial begin
A = 0;B = 0;C = 0;
#100
A = 0;B = 0;C = 1;
#100
A = 0;B = 1;C = 0;
#100
A = 0;B = 1;C = 1;
#100
A = 1;B = 0;C = 0;
#100
A = 1;B = 0;C = 1;
#100
A = 1;B = 1;C = 0;
#100
A = 1;B = 1;C = 1;

end

yima3_8 u_yima3_8(
.    A    (A  ),
.    B    (B  ),
.    C    (C  ),
.    out  (out)
);

endmodule

在仿真代码中每间隔100ns给A、B、C三个输入信号赋不同的值

仿真结果:

由于这里是组合逻辑,因此在仿真代码中并没有加入时钟,根据仿真结果可以看到每相隔100ns,A、B、C数据跳变一次,同时输出的8位数据也在跳变。那么译码器就编写成功,感兴趣的可以去尝试一下其它多路输入输出。


边沿检测电路:

在实际设计中,通常需要观测信号是否发生跳变,这里通常需要有一个边沿检测电路,它也是一种非常典型的电路设计。一般可分为上边沿检测、下边沿检测、双边沿检测电路。

verilog代码:

module edge_test(
  input  wire clk       ,//时钟
  input  wire rst_n     ,//复位
  input       a         ,//输入待检测信号
  output      a_posedge ,//输出上边沿检测
  output      a_negedge ,//输出下边沿检测
  output      a_edge     //输出双沿检测
  
);

reg a_dly ;//将待检测信号寄存打一拍

always @(posedge clk or negedge rst_n)begin
  if(!rst_n)
    a_dly <= 0;
  else
    a_dly <= a;

end


assign    a_posedge = a & ~a_dly;//待检测信号与上打拍后取反信号
assign    a_negedge = ~a & a_dly;//取反待检测信号与上打拍后信号
assign    a_edge    = a ^ a_dly ;//待检测信号异或打拍后信号


endmodule

tb代码:

`timescale 1ns / 1ps

module tb_test();
reg   clk       ;  
reg   rst_n     ;  
reg   a         ;  
wire  a_posedg  ;
wire  a_negedg  ;
wire  a_edge    ;

initial begin
clk   = 0;
rst_n = 0;
a     = 0;

#101 rst_n = 1;
#20  a     = 1;
#100 a     = 0;

end

always #10 clk = ~clk;

edge_test u_edge_test(
  .   clk        (clk      ),//时钟
  .   rst_n      (rst_n    ),//复位
  .   a          (a        ),//输入待检测信号
  .   a_posedge  (a_posedge),//输出上边沿检测
  .   a_negedge  (a_negedge),//输出下边沿检测
  .   a_edge     (a_edge   ) //输出双沿检测
  
);

endmodule

仿真结果:

由仿真结果可以看到,在经过101ns后复位拉高,再经过20ns后信号a到来,a_dly打一拍后在下一个时钟周期拉高。经过100ns后a信号拉低,a_dly信号也随之拉低。

上升沿:粉色信号线

下降沿:紫色信号线

双边沿检测:黄色信号线


分频电路:

在开发过程中,通常会遇到对时钟进行分频或倍频,一般情况下使用的是PLL(锁相环),但由于其特性,可能在某些特定环境下无法实现分频,这时候就可以使用verilog代码来设计分频电路。

偶分频:

这里设计一个四分配电路为例,实现方法就是套用公式n/2-1,得到cnt计数为1,每次cnt加到1,清零时钟翻转

verilog代码:

module divider_4(
input   wire clk     ,//输入系统时钟
input   wire rst_n   ,//输入复位信号
output  reg  out_clk  //输出分频后时钟

);

reg [1:0] cnt;//用于分频计数

always @(posedge clk or negedge rst_n)begin
   if(!rst_n)
    cnt <= 0;
   else if(cnt == 1)
    cnt <= 0;
   else
    cnt <= cnt + 1;
end

always @(posedge clk or negedge rst_n)begin
   if(!rst_n)
    out_clk <= 0;
   else if(cnt == 1)
    out_clk <= ~out_clk;
   else
    out_clk <= out_clk;
end

endmodule

tb代码:

`timescale 1ns / 1ps

module tb_test();
reg   clk       ;  
reg   rst_n     ;  
wire  out_clk   ;

initial begin
clk   = 0;
rst_n = 0;


#101 rst_n = 1;

end

always #10 clk = ~clk;

divider_4 u_divider_4(
.   clk      (clk    ),//输入系统时钟
.   rst_n    (rst_n  ),//输入复位信号
.   out_clk  (out_clk) //输出分频后时钟

);

endmodule

仿真结果:

由上图可以看出,粉色是分频后的时钟,分频后的一个完整的时钟周期相当于分频前的四个时钟周期,根据cnt计数进行翻转。

奇分频:

这里设计一个7分频电路,将会存在两个delay,第一个是n-1为6,第二个是n-/2为3,同时一个检测上升沿,一个检测下降沿,最后再将两者用或门输出。

verilog代码:

module divider_7(
input  wire clk     ,//时钟
input  wire rst_n   ,//复位
output      out_clk  //分频后时钟

);


parameter delay  = 6    ;//定义分频次数 N-1

reg [2:0] cnt     ;//分频计数
reg       out_clk1;//上升沿
reg       out_clk2;//下降沿

always @(posedge clk or negedge rst_n)begin
   if(!rst_n)
    cnt <= 0;
   else if(cnt == delay)//计数器等于6清零
    cnt <= 0;
   else
    cnt <= cnt + 1;
end
	
always @(posedge clk or negedge rst_n)begin//检测上升沿
   if(!rst_n)
    out_clk1 <= 0;
   else if(cnt == 3 || cnt == 6)
    out_clk1 <= ~out_clk1;
   else
    out_clk1 <= out_clk1;
end

always @(negedge clk or negedge rst_n)begin//检测下降沿
   if(!rst_n)
    out_clk2 <= 0;
   else if(cnt == 3 || cnt == 6)
    out_clk2 <= ~out_clk2;
   else
    out_clk2 <= out_clk2;
end

assign out_clk = out_clk1 || out_clk2;//用或门将两者合并输出

endmodule

tb仿真:

`timescale 1ns / 1ps

module tb_test();
reg   clk       ;  
reg   rst_n     ;  
wire  out_clk   ;

initial begin
clk   = 0;
rst_n = 0;


#101 rst_n = 1;

end

always #10 clk = ~clk;

divider_7 u_divider_7(
.   clk      (clk    ),//时钟
.   rst_n    (rst_n  ),//复位
.   out_clk  (out_clk) //分频后时钟

);

endmodule

仿真结果:

由上图可以看出,黄色的线是最终合并输出的7分频后时钟,它由7个原本的时钟构成。

总结:

以上是一些常见的FPGA数字电路基础设计,感兴趣的可以去尝试一下。有错误的地方希望能够指出,谢谢!


http://www.kler.cn/a/599601.html

相关文章:

  • jupyter 操作相关内容
  • ADB介绍
  • VL开源模型实现文本生成图片
  • 计算图(Computation Graph)
  • 在VMware17中安装使用Ubuntu虚拟机
  • 四.ffmpeg对yuv数据进行h264编码
  • 基于SpringBoot的名著阅读网站
  • 神奇的FlexBox弹性布局
  • 【docker】安装SQLServer
  • 数学概念学习
  • 分布式中间件:基于 Redis 实现分布式锁
  • 51单片机程序变量作用域问题
  • NSSRound(持续更新)
  • 测试工程 常用Python库
  • 数据库的左连接,右连接,全外连接,自连接,内连接的区别
  • IS-IS原理与配置
  • 苹果iPhone 16e销量表现糟糕 难以拯救市场
  • 嵌入式八股RTOS与Linux---进程间的通信与同步篇
  • Select多路转接
  • 【机器学习】什么是线性回归?