其他分享
首页 > 其他分享> > FPGA学习---数电及verilog知识补充

FPGA学习---数电及verilog知识补充

作者:互联网

数电及verilog知识补充

在做前面的练习的时候深深感到了基础知识的不足,有必要好好补充一下

1数据选择器

八选一数据选择器

通过对3位地址线的控制,是8为二进制数据只有一路送到输出上。因为8个中只能有一个到达,因此叫数据选择器。

8选1数据选择器数据选择器的典型应用:

采用8选1数据选择器74LS151可实现任意三输入变量的组合逻辑函数。作出函数F的功能表,将函数F功能表与8选1数据选择器的功能表相比较,可知:

1、将输入变量C、B、A作为8选1数据选择器的地址码A2、A1、A0。

2、使8选1数据选择器的各数据输入D0~D7分别与函数F的输出值一一相对应。

img

即:A2A1A0=CBA,D0=D7=0,D1=D2=D3=D4=D5=D6=1。

则8选1数据选择器的输出Q便实现了函数。

img

采用具有n个地址端的数据选择实现n变量的逻辑函数时, 应将函数的输入变量加到数据选择器的地址端(A),选择器的数据输入端(D)按次序以函数F输出值来赋值。

2 逻辑函数

M1表示的是A+B+C’,M2表示的是A+B’+C,M5表示的是A’+B+C’,M7表示的是A’+B’+C’;(M是大写,是最大项)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

3function使用

1.函数的定义

函数通过关键词 function 和 endfunction 定义,不允许输出端口声明(包括输出和双向端口) ,但可以有多个输入端口。函数定义的语法如下:
function [range] function_id;
input_declaration
other_declarations
procedural_statement
endfunction

其中,function 语句标志着函数定义结构的开始;[range]参数指定函数返回值的类型或位宽,是一个可选项,若没有指定,默认缺省值为 1 比特的寄存器数据;function_id 为所定义函数的名称,对函数的调用也是通过函数名完成的,并在函数结构体内部代表一个内部变量,函数调用的返回值就是通过函数名变量传递给调用语句;input_declaration 用于对寒暑各个输入端口的位宽和类型进行说明,在函数定义中至少要有一个输入端口;endfunction为函数结构体结束标志。

注意
**(1)函数定义只能在模块中完成,不能出现在过程块中;

(2)函数至少要有一个输入端口;不能包含输出端口和双向端口;
(3) 在函数结构中, 不能使用任何形式的时间控制语句 (#、 wait 等) , 也不能使用 disable中止语句;
(4)函数定义结构体中不能出现过程块语句(always 语句) ;
(5)函数内部可以调用函数,但不能调用任务。**

2 调用

和任务一样,函数也是在被调用时才被执行的,调用函数的语句形式如下:
func_id(expr1, expr2, …, exprN)
其中,func_id 是要调用的函数名,expr1, expr2, …exprN是传递给函数的输入参数列表,该输入参数列表的顺序必须与函数定义时声明其输入的顺序相同

4 三位二进制减法计数器

在这里插入图片描述

5 四位寄存器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6 D触发器

普通的电路,以及常规的逻辑门都有一个共性,那就是输出直接依赖于输入,当输入消失的时候,输入也跟着不存在了。触发器不同,当它触发的时候,输出会发生变化。但是,当输入撤销之后,输出依然能够维持。
在这里插入图片描述
在这里插入图片描述

7 同步清零和异步清零

“异步”输入信号和时钟信号无关,是指输入信号变为有效状态,器件的状态就改变;

“同步”输入信号和时钟信号有关,实际上输入信号和时钟信号进行了与运算或者与非运算,输入信号和时钟信号的运算结果是有效的,器件的状态才会改变。

8 同步置数和异步置数

异步置数:与时钟脉冲CP没有任何关系,只要异步置数控制端出现置数信号,并行数据便立刻被置入。

同步置数:输入端获得置数信号后,只是为置数创造了条件,还需要再输入一个计数脉冲CP,计数器才能将预置数置入。

9 模n计数器

通常的做法是将计数器加1,再将结果除以n(n为最大值),余数为结果。这种计数器用途很广,如循环队列。

counter = (counter + 1)%n;

相比来讲,使用比较的方法来实现的话效率会更高:

counter = counter + 1;

if( counter >= n )

{counter = 0;}

10 分频器

一个数字系统中往往需要多种频率的时钟脉冲作为驱动源,这样就需要对FPGA的系统时钟(频率较高)进行分频。比如在进行流水灯、数码管动态扫描设计时不能直接使用系统时钟(太快而肉眼无法识别),或者需要进行通信时,由于通信速度不能太高(由不同的标准限定),这样就需要对系统时钟分频以得到较低频率的时钟。

分频器主要分为偶数分频、奇数分频、半整数分频和小数分频

在对时钟要求不是很严格的FPGA系统中,分频通常都是通过计数器的循环计数来实现的。

分类

偶数分频(2N)

偶数分频最为简单,很容易用模为N的计数器实现50%占空比的时钟信号,即每次计数满N(计到N-1)时输出时钟信号翻转。

奇数分频(2N+1)

使用模为2N+1的计数器,让输出时钟在X-1(X在0到2N-1之间)和2N时各翻转一次,则可得到奇数分频器,但是占空比并不是50%(应为 X/(2N+1))。

得到占空比为50%的奇数分频器的基本思想是:将得到的上升沿触发计数的奇数分频输出信号CLK1,和得到的下降沿触发计数的相同(时钟翻转值相同)奇数分频输出信号CLK2,

最后将CLK1和CLK2相或之后输出,就可以得到占空比为50%的奇数分频器。原理图如下:

分频器的作用是什么 半整数分频器原理图分析

用Quartus II 得到的占空比为50%的9分频时钟输出信号outclk如下:

分频器的作用是什么 半整数分频器原理图分析

半整数分频(N-0.5)

基本设计思想为:首先进行模N的计数,计数到N-1时输出时钟翻转;而且在计数返回到0时,输出时钟再次翻转。

所以,只要使计数值N-1保持半个时钟周期,即可实现N-0.5分频时钟。那么如何保持半个时钟周期呢?

因为计数器是上升沿触发计数,如果在计数值=N-1时把计数器的触发时钟翻转,则时钟的下降沿就变成了上升沿。即计数值=N-1时,时钟马上翻转,

则计数值保持半个时钟周期后,会遇到上升沿而使计数值归0. 然后计数器以翻转了的时钟继续计数,在产生N-0.5个分频周期后,时钟再次翻转。

2.5分频的时序示意图如下:

分频器的作用是什么 半整数分频器原理图分析

怎样才能够使计数器的触发时钟在N-1时翻转呢? 由半整数分频器的原理图可知,将输出时钟二分频后和输入时钟相异或就可使触发时钟翻转。

半整数分频器原理图如下:

分频器的作用是什么 半整数分频器原理图分析

用Quartus II 实现的2.5分频时序图如下:

分频器的作用是什么 半整数分频器原理图分析

由通用分频器电路组成图可以看到,半整数分频器是由整数分频器加上二分频和异或门而构成的。

那么,如果使用元件例化的思想就可以得到通用的分频(即可选择整数分频和半整数分频)。

如果想要得到任意分频,则可以参考CrazyBingo 的 利用DDS原理的 教你什么才是真正的任意分频。

说人话版本

分频器还是比较简单的,一般的思路是:每数几个时钟就输出一个时钟。最简单的当数二分频器了,每当时钟上升沿(或下降沿)就把输出翻转一下。

module divider2(clk_in, clk_out);

input clk_in;
output clk_out;

reg clk_out;

initial clk_out <= 1'b0;

always@(posedge clk_in) clk_out <= ~clk_out;

endmodule

如果是6分频则是一个周期=6个clk周期,

reg[1:0] count

always @(posedge clk)
    begin
     if(count==2'b10)
      count<=2'b0;
      clk_3<=~clk_6;
     else
      count<=count+2'b1;

说人话进阶版本

1. 偶数分频器
// 偶数分频器示例,20分频即N=10,占空比50%
 
module Fre_div_even(
 
	input clk,
	input rst_n,
	input [3:0] N, // N = 分频倍数/2
	output reg clk_out
 
    );
 
 
reg [3:0] cnt;
 
 
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        cnt <= 4'b0;
        clk_out <= 1'b0;
    end
    else
    begin
        if(cnt == N-1)
        begin
            clk_out <= ~clk_out;
            cnt <= 4'b0;
        end
        else
        begin
            cnt <= cnt + 4'b1;
        end
    end
end
 
endmodule
2. 奇数分频器
// 奇数分频器示例,5分频即N=5,占空比50%
 
module Fre_div_odd(
    input clk,
    input rst_n,
	input [3:0] N,  // N分频
    output clk_out
    );
 
reg clk_n;
reg clk_p;
reg [3:0] cnt_p;
reg [3:0] cnt_n;
 
 
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        clk_p <= 1'b0;
        cnt_p <= 4'b0;
    end
    else
    begin
        if(cnt_p == N-1)
        begin
            clk_p <= ~clk_p;
            cnt_p <= 4'b0;
        end
        else if(cnt_p == (N-1)/2)
        begin
            clk_p <= ~clk_p;
            cnt_p <= cnt_p + 1;
        end
        else
        begin
            cnt_p <= cnt_p + 1;
            clk_p <= clk_p;
        end
    end
end
 
always @(negedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        clk_n <= 1'b0;
        cnt_n <= 4'b0;
    end
    else
    begin
        if(cnt_n == N-1)
        begin
            clk_n <= ~clk_n;
            cnt_n <= 4'b0;
        end
        else if(cnt_n == (N-1)/2)
        begin
            clk_n <= ~clk_n;
            cnt_n <= cnt_n + 1;
        end
        else
        begin
            cnt_n <= cnt_n + 1;
            clk_p <= clk_p;
        end
    end
end
 
assign clk_out = clk_n | clk_p;
 
 
endmodule
3.半分频器

img

// 半分频器示例,以2.5分频为例,即N=2
 
module Fre_div_half(
    input clk,
    input rst_n,
	input [3:0] N,  // 即实现N+0.5分频
    output clk_out
    );
	 
 
wire clk_div_odd;
wire clk_rev;
 
/*  按照上文的实现方法搭建奇数分频
    N_odd = 2 * N + 1             
    具体实现省略                  
    奇数分频后得到clk_div_odd     */
Fre_div_odd Fre_div_odd(
    .clk(clk),
    .rst_n(rst_n),
	.N(2*N+1),
    .clk_out(clk_div_odd)
    );	
 
	
assign clk_rev = clk_div_odd ? ~clk : clk;
 
reg [3:0] cnt_rev;
reg clk_rev_div; 
 
always @(posedge clk_rev or negedge rst_n)
begin
    if(!rst_n)
    begin
        clk_rev_div <= 0;
        cnt_rev <= 0;
    end
    else
    begin
		if(cnt_rev == N/2)
		begin
            clk_rev_div <= ~clk_rev_div;
			cnt_rev <= cnt_rev + 1;
		end
        else if(cnt_rev == N)
        begin
            cnt_rev <= 0;
        end
        else
        begin
            cnt_rev <= cnt_rev + 1;
            clk_rev_div <= clk_rev_div;
        end
    end
end
 
assign clk_out = clk_div_odd ^ clk_rev_div;
 
 
endmodule

B站老师

2的次方分频

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

16就是16最高位

2偶数分频

在这里插入图片描述

六分频

在这里插入图片描述

十分频

在这里插入图片描述
在这里插入图片描述

自己写的并验证了的

偶数倍分频
六分频
module test(clk,rst_n,out_clk);
	input clk,rst_n;
	output reg out_clk;
	reg [1:0]cnt;
	
	always@(posedge clk or negedge rst_n)
	if(rst_n==1'b0)begin
	cnt<=1'b0;
	out_clk<=1'b0;end
	else if(cnt==2'b10)begin
	cnt<=1'b0;
	out_clk<=~out_clk;end
	else 
	cnt<=cnt+1'b1;


endmodule
	
`timescale 1ns/1ns
`define clock_period 20
	module test_tb;
	
	reg clk,rst_n;
	wire out_clk;
	
test	test1(clk,rst_n,out_clk);

initial clk=1'b0;
always #(`clock_period/2)clk=~clk;

initial begin
rst_n=1'b0;
#100
rst_n=1'b1;
#2000
$stop;
end

endmodule

在这里插入图片描述

标签:分频,分频器,FPGA,数电及,clk,函数,---,rst,时钟
来源: https://blog.csdn.net/qq_45638430/article/details/113921032