【FPGA入门教程】(六)时序逻辑电路设计
用always@(posedge clk)描述
时序逻辑电路的基础——计数器(在每个时钟的上升沿递增1)
例1.四位计数器(同步使能、异步复位)
// Module Name: counter_4bit
// Description: 4bit异步复位同步使能二进制计数器module counter_4bit(input clk, //系统时钟信号input rst, //系统复位按键input en, //计数器使能端output reg [3:0]q //计数器计数值输出);//同步使能,异步复位always@(posedge clk,posedge rst)if(rst)q <= 0;else if(en)q <= q + 1'b1; //计数器加一
endmodule
testbench测试代码如下:
`timescale 1ns / 1ps
//
// Module Name: counter_4bit_tb
// Description: 4bit计数器模块测试文件
//
`define clk_period 20 //宏定义时钟周期
module counter_4bit_tb();reg clk; //用于产生时钟信号reg rst; //用于产生复位信号reg en; //用于产生使能信号wire [3:0]q; //计数器计数值输出//例化测试模块counter_4bit counter_4bit_test(.clk(clk), //系统时钟信号.rst(rst), //系统复位按键.en(en), //计数器使能端.q(q) //计数器计数值输出);//开始测试//生成时钟信号initial clk = 1;always #(`clk_period/2) clk = ~clk; //clk每5ns翻转一次,产生100M时钟信号initial beginrst = 1; en = 0;#(`clk_period * 5 + 1 ); rst = 0;#(`clk_period * 5);en = 1;#(`clk_period *20); //因为4bit计数16个clk就清零,所以延时20个时钟周期$stop;end
endmodule
测试结果如下:
综合的电路图如下:
计数器是我们设计的第一个时序逻辑电路,也是最基本、最重要的时序逻辑电路,由图中可以看到一个计数器由加法器和D触发器组成;
特别要注意的一点,在用verilog描述计数寄存器加一的时候,我们没有先写一个加法器,然后例化调用,而是直接采用 q <= q + 1'b1这样描述加法器,这点在综合出的电路图也可以看出,加法器不再是门电路的组合,而是用一个圆圈替代,这时,数字逻辑设计的思想就又抽象了一层,不再是门电路的组合,而是这些具有逻辑功能的小方块的组合,所以,抽象的思想在数字逻辑设计中至关重要;
在编写testbench仿真测试的时候,我们也不再像测试组合逻辑电路那样利用穷举法测试功能,而是利用时钟测试,比如测试4bit的加法器,一要测试它能不能在每个时钟沿加一,而要测试它计满时可不可以自动清零;所以,在测试时序逻辑电路的时候要准确把握clk时钟信号;
注:计数器只是基本电路,比如分频器、定时器、巴克码序列发生器在计数器基本电路上设计即可;
例2.基本分频操作——分频器(闪烁灯:LED以1hz的频率闪烁)
分频器是计数器的一大应用,在FPGA中没有像C语言中delay()这样的延时,那如何延时呢?可以通过分频器,将系统100M的高速时钟信号经过分频器,变为1hz的输出信号,这样,LED就会按1s的周期闪烁;
1hz的时钟信号是每500ms翻转1次,而在100M的时钟下,1个clk是10ns,所以应该每计数 500_000_000/10 = 50_000_000 次输出信号翻转,就产生了1hz的信号;50_000_000大概估算需要一个26位的寄存器;又因为计数器是从0开始计数的,所以最大计数值应该为49_999_999,设计如下:
`timescale 1ns / 1ps
//
// Create Date: 2018/05/22 20:32:26
// Module Name: flashled
// Description: 产生一个时钟信号,让LED灯按1hz的频率闪烁
////`define SIMULATION /*** 仿真时保留,板级验证时注释 ***/
module flashled(input clk, //时钟信号输入input rst, //复位信号输入input en, //使能信号输入output [15:0]led //led信号输出);`ifdef SIMULATION //仿真情况下parameter CNT_MAX = 26'd49;`else //板级验证情况下parameter CNT_MAX = 26'd49_999_999;`endif reg [25:0]cnt; //最大计数值49_999_999reg [15:0]led_clk; //输出驱动led的1hz信号//计数器功能描述always@(posedge clk,posedge rst)if(rst)cnt <= 0;else if(en)beginif(cnt == CNT_MAX)cnt <= 0;elsecnt <= cnt + 1'b1;end//产生1hz信号always@(posedge clk,posedge rst)if(rst)led_clk <= 0;else if(cnt == CNT_MAX)led_clk <= ~led_clk; //每计满50_000_000个时钟周期(500ms),输出信号翻转一下elseled_clk <= led_clk;//经1hz信号输出到ledassign led = led_clk;endmodule
testbench测试文件如下:
`timescale 1ns / 1ps
//
// Module Name: flashled_tb
// Description: flashled模块测试文件
//
`define clk_period 10 //100M时钟信号
module flashled_tb();reg clk; //用于产生时钟信号reg rst; //用于产生复位信号reg en; //用于产生使能信号wire [15:0]led; //观察led输出//例化测试模块flashled flashled_test(.clk(clk), //时钟信号输入.rst(rst), //复位信号输入.en(en), //使能信号输入.led(led) //led信号输出);//产生时钟信号initial clk = 1;always #(`clk_period/2) clk = ~clk;//开始测试initial beginrst = 1; //复位;en = 0;#(`clk_period * 5);rst = 0;#(`clk_period * 5); en = 1; //使能#(`clk_period * 50 * 5 ); //仿真情况下计数器每计50次翻转,所以应该延时50 * 5个时钟周次观察翻转情况$stop; endendmodule
测试结果如下:
综合电路图如下:
在编写testbench测试分频器模块时,由于计数器计数值为49_999_999 ,所以花费长时间,因为只需要测试功能,看模块计到设定值后会不会翻转信号,所以这样就是在浪费时间;
为了加快仿真速度,可以在仿真时将最大值改为49,这样就非常快,为了方便,可以在verilog中使用条件编译:
`ifdef SIMULATION //仿真情况下parameter CNT_MAX = 26'd49;`else //板级验证情况下parameter CNT_MAX = 26'd49_999_999;`endif
例3.基本移位操作——verilog位操作(流水灯:16个LED循环左移)
//1.取某一位直接操作wire [2:0]m;assign m = out[5:3];//2.循环移位(移位寄存器)reg [7:0] shift_a;always@(posedge clk)shift_a <= {shifta[0],shift[7:1]};reg [7:0] shift_a;wire data;always@(posedge clk)shift_a <= {data,shift[7:1]};reg [7:0] shift_a;wire data;always@(posedge clk)shift_a <= {shift[7:1],data};//3、拼接wire [3:0]x;wire [3:0]y;wire [7:0]z;wire [31:0]n;assign z = {x,y};assign n = {x,7{x}};
verilog设计代码如下(计数器部分和分频器相同):
//移位寄存器功能描述always@(posedge clk,posedge rst)if(rst)led_temp <= 26'h0001;else if(cnt == CNT_MAX)led_temp <= {led_temp[14:0],led_temp[15]}; //循环左移elseled_temp <= led_temp;//输出到ledassign led = led_temp;
testbench仿真测试文件和分频器相同;
测试结果如下:
综合出的电路图如下:
例4.BCD计数器
计数器是二进制的,但我们所熟悉的是十进制,所以4bit BCD计数器相当于十进制的计数器:从0计到9,然后进位,清零,设计图如下:
BCD计数器常常应用在数码管显示中,比如要要是1234,在单片机中通常会用C语言中的除法和取余提取每一位送到数码管显示,但是在数字逻辑电路中,除法器很耗费资源且效率不高,所以不采用除法,那如何进行显示呢?这个时候就可以将1234转换为对应的BCD码:0001_0010_0011_0100;这样只需要每次送入一个4bitBCD码就可以显示(如果以1ms的频率刷新,就是数码管动态扫描显示,也是下一个例子);
verilog代码:
Module Name: BCDcounter
// Description: BCD计数器
//
module BCDcounter(input clk, //时钟信号输入input rst, //复位信号输入input cin, //进位信号输入output cout, //进位信号输出output [3:0]q //4bitBCD码输出 );reg [3:0]cnt; //计数器最大值为9,所以需要4bit计数器 //BCD计数器计数功能描述always@(posedge clk,posedge rst)if(rst)cnt <= 0;else if(cin)beginif(cnt == 4'd9)cnt <= 0;elsecnt <= cnt + 1'b1;endassign cout = cin && (cnt == 4'd9); /** 此处不能使用时序逻辑,需要在计满9的时候同步输出cout信号,然后在下次清零是cout恢复为0 **/assign q = cnt; //BCD计数值输出endmodule
testbench测试文件如下:
`timescale 1ns / 1ps
//
// Module Name: BCDcounter_tb
// Description: BCDcounter模块测试文件
//
`define clk_period 10 //100M时钟信号
module BCDcounter_tb();reg clk; //时钟信号输入reg rst; //复位信号输入reg cin; //进位信号输入wire cout; //进位信号输出wire [3:0]q; //4bitBCD码输出 //例化测试模块BCDcounter BCDcounter_test(.clk(clk), //时钟信号输入.rst(rst), //复位信号输入.cin(cin), //进位信号输入.cout(cout), //进位信号输出.q(q) //4bitBCD码输出 );//产生100M时钟信号initial clk = 1;always #(`clk_period/2) clk = ~clk;//开始测试initial beginrst = 1; //复位cin = 0; //无进位#(`clk_period * 2);rst = 0; #(`clk_period * 2);cin = 1; //产生进位,计数器开始计数#(`clk_period * 15); //1个clk计一次数,总共计10次,所以延时15个clk观察波形$stop;endendmodule
测试结果如下:
综合电路图如下:
至此一个4bitBCDcounter就设计完成了,一般使用时,都是通过级联实现多位BCD计数器,比如四个BCD计数器级联起来最大值为9999,可以很方便的应用在数码管动态显示上;
verilog代码如下:
`timescale 1ns / 1ps
//
// Module Name: BCDcounter_top
// Description: 4个4bit计数器进行级联,实现计数最大值为9999
//module BCDcounter_top(input clk, //时钟信号输入input rst, //复位信号输入input cin, //进位信号输入output cout, //进位信号输出output [15:0]q //BCD码输出);wire cout0,cout1,cout2; //4个BCD计数器级联之间连接线wire [3:0]q0,q1,q2,q3; //每个BCD计数器的输出assign q = {q3,q2,q1,q0}; //拼接成16位输出//例化4个BCD计数器BCDcounter BCDcounter0(.clk(clk), //时钟信号输入.rst(rst), //复位信号输入.cin(cin), //进位信号输入.cout(cout0), //进位信号输出.q(q0) //4bitBCD码输出 );BCDcounter BCDcounter1(.clk(clk), //时钟信号输入.rst(rst), //复位信号输入.cin(cout0), //进位信号输入.cout(cout1), //进位信号输出.q(q1) //4bitBCD码输出 );BCDcounter BCDcounter2(.clk(clk), //时钟信号输入.rst(rst), //复位信号输入.cin(cout1), //进位信号输入.cout(cout2), //进位信号输出.q(q2) //4bitBCD码输出 );BCDcounter BCDcounter3(.clk(clk), //时钟信号输入.rst(rst), //复位信号输入.cin(cout2), //进位信号输入.cout(cout), //进位信号输出.q(q3) //4bitBCD码输出 );
endmodule
testbench测试文件与之前一样,但是需要增大延时时长,因为要计数到9999;
测试结果如下:
综合电路图如下:
例5.数码管动态扫描显示
设计图如上图,在数码管静态显示的基础上只需要添加一个分频器,将系统时钟分频为1ms的时钟信号,然后每1ms同时改变段选和位选,刷新显示,这就是数码管动态显示的原理;位选信号已经由2-4译码器控制,只有输入2位选择信号,所以还需一个四选一数据选择器,和2-4译码器共享一个选择信号sel,这样只需要改变sel的值就可以了;
verilog代码如下(这是顶层文件,还需要之前):
`timescale 1ns / 1ps
//
// Module Name: Dynamic_seg_display
// Description: 4位数码管动态扫描显示
//
`define SIMULATION /*** 仿真时保留,板级验证时注释 ***/
module Dynamic_seg_display(input clk, //时钟信号input rst, //复位信号input [15:0]data_display, //16位待显示数据显示(4个BCD码)output [6:0]segments, //数码管段码output [3:0]wei_sel //数码管位码);`ifdef SIMULATION //仿真情况下 parameter CNT_MAX = 26'd49;`else //板级验证情况下parameter CNT_MAX = 26'd99_999;`endif reg [22:0]cnt; //最大计数值4_999_999,需要23位计数器reg [1:0]wei; //选择哪一位显示wire [3:0]data_display_temp; //显示信号传输//计数器功能描述always@(posedge clk,posedge rst)if(rst)cnt <= 0;else if(cnt == CNT_MAX)cnt <= 0;elsecnt <= cnt + 1'b1;//控制数码管动态扫描显示(每隔1ms加一,刷新段选和位选)always@(posedge clk,posedge rst)if(rst)wei <= 2'b00;else if(cnt == CNT_MAX)wei <= wei + 1'b1; //每计满100_000个时钟周期(1ms),位选加一,切换下一位elsewei <= wei;//例化四选一多路器,选择输入哪一位显示段码信号mux4 mux4_1(.sel(wei),.data_in(data_display),.data_out(data_display_temp) );//例化数码管译码模块seg_display seg_display0(.data_display(data_display_temp), //数码管待显示数据.wei(wei), //选择哪一位显示.segments(segments), //数码管段码.wei_sel(wei_sel) //数码管位码);endmodule//四选一多路器
module mux4(input [1:0]sel,input [15:0]data_in,output reg [3:0]data_out );always@(*)case(sel)//对应位4'h0: data_out = data_in[3:0];4'h1: data_out = data_in[7:4];4'h2: data_out = data_in[11:8];4'h3: data_out = data_in[15:12];default: data_out = 4'bz;endcase
endmodule
testbench测试代码如下:
`timescale 1ns / 1psModule Name: Dynamic_seg_display_tb
// Description: 数码管动态扫描显示控制模块测试文件
//
`define clk_period 10 //100M时钟信号module Dynamic_seg_display_tb();reg clk; //时钟信号reg rst; //复位信号reg [15:0]data_display; //16位待显示数据显示(4个BCD码)wire [6:0]segments; //数码管段码wire [3:0]wei_sel; //数码管位码//例化测试模块Dynamic_seg_display Dynamic_seg_display_test(.clk(clk), //时钟信号.rst(rst), //复位信号.data_display(data_display), //16位待显示数据显示(4个BCD码).segments(segments), //数码管段码.wei_sel(wei_sel) //数码管位码);//产生100M时钟信号initial clk = 1;always #(`clk_period/2) clk = ~clk;//开始测试initial beginrst = 1;data_display = 16'h4321; //数码管上显示"1234"#(`clk_period * 2);rst = 0;#(`clk_period * 50 * 5); //计50次数刷新一下,观察5次$stop;end
endmodule
测试结果如下:
综合后的电路图如图:
注:
将上一例中四个级联BCD计数器的16bit输出和该例中数码管动态扫描控制模块的16bit输入接起来,控制BCD计数的频率为1hz,就形成一个简易计时器,从0000一直计到9999;
verilog代码如下(这是顶层文件,底层模块调用之前的数码管动态扫描模块和4个级联BCD计数器模块):
`timescale 1ns / 1ps
//
// Module Name: easyclock
// Description: 简易数字钟:按1hz的频率从0000-9999显示
//
//`define SIMULATION /*** 仿真时保留,板级验证时注释 ***/
module easyclock(input clk, //时钟信号输入input rst, //复位信号输入output [6:0]segments, //数码管段码output [3:0]wei_sel //数码管位码);`ifdef SIMULATION //仿真情况下parameter CNT_MAX = 26'd49;`else //板级验证情况下parameter CNT_MAX = 26'd49_999_999;`endif reg clk_1hz; //1hz时钟信号reg [25:0]cnt; //计数器计数寄存起(用于分频器)wire [15:0]data_display; //待显示数据//计数器always@(posedge clk,posedge rst)if(rst)cnt <= 0;else if(cnt == CNT_MAX)cnt <= 0;elsecnt <= cnt + 1'b1;//产生1hz信号always@(posedge clk,posedge rst)if(rst)clk_1hz <= 0;else if(cnt == CNT_MAX)clk_1hz <= ~clk_1hz; //每计满50_000_000个时钟周期(500ms),输出信号翻转一下elseclk_1hz <= clk_1hz;//例化4个BCD计数器BCDcounter_top BCDcounter_top0(.clk(clk_1hz), /** 因为BCD需要按1hz计数,所以需要一个1hz时钟信号 **/.rst(rst), //复位信号输入.cin(1'b1), //进位信号输入.cout(), //进位信号输出.q(data_display) //BCD码输出);//例化数码管动态扫描显示控制模块Dynamic_seg_display Dynamic_seg_display0(.clk(clk), //时钟信号.rst(rst), //复位信号.data_display(data_display), //16位待显示数据显示(4个BCD码).segments(segments), //数码管段码.wei_sel(wei_sel) //数码管位码);endmodule
综合电路图如下:
例6.74HC595驱动
在上一例中讲述了数码管动态扫描的设计,但是仅仅是4位数码管显示,就占用了8+4个IO,如果是8段8位数码管,就会占用16个IO,造成IO浪费,所以可以采用74HC595串转并芯片两片级联,只采用3个IO完成8段8位数码管的显示;
verilog描述如下:
//
//module: 74HC595驱动模块
//description: 将输入的16位数据串行输出到74HC595
//
module HC595drive(input clk, //50M系统时钟input rst, //低电平复位input [7:0]seg, //8bit段选信号input [7:0]sel, //8bit位选信号output reg DIO, //74HC595数据引脚output reg SHCP, //74HC595移位脉冲引脚output reg STCP //74HC595输出脉冲引脚);reg clk_595;reg [1:0]divid_cnt;reg [4:0]count;//产生74HC595工作时钟12.5Malways@(posedge clk,negedge rst)if(!rst)begindivid_cnt <= 0;clk_595 <= 0;endelse if(divid_cnt == 2'd3)beginclk_595 <= 1;divid_cnt <= 0;endelse begindivid_cnt <= divid_cnt + 1'b1;clk_595 <= 0;end//对74HC595工作时钟clk_595计数always@(posedge clk,negedge rst)if(!rst)count <= 0;else if(clk_595 == 1)begin //一共串行发送16bit数据if(count == 5'd31)count <= 0;else count <= count + 1'b1;endelsecount <= count; //count清零//功能描述always@(posedge clk,negedge rst)if(!rst)beginDIO <= 0;SHCP <= 0;STCP <= 0;endelse case(count)5'd0: begin DIO <= seg[7]; SHCP <= 0; STCP <= 1; end //HEX_DP,输出5'd1: begin SHCP <= 1; STCP <= 0; end //移位5'd2: begin DIO <= seg[6]; SHCP <= 0; STCP <= 0; end //HEX_G5'd3: begin SHCP <= 1; end 5'd4: begin DIO <= seg[5]; SHCP <= 0; end //HEX_F5'd5: begin SHCP <= 1; end 5'd6: begin DIO <= seg[4]; SHCP <= 0; end //HEX_E5'd7: begin SHCP <= 1; end 5'd8: begin DIO <= seg[3]; SHCP <= 0; end //HEX_D5'd9: begin SHCP <= 1; end 5'd10: begin DIO <= seg[2]; SHCP <= 0; end //HEX_C5'd11: begin SHCP <= 1; end 5'd12: begin DIO <= seg[1]; SHCP <= 0; end //HEX_B5'd13: begin SHCP <= 1; end 5'd14: begin DIO <= seg[0]; SHCP <= 0; end //HEX_A5'd15: begin SHCP <= 1; end 5'd16: begin DIO <= sel[7]; SHCP <= 0; end //第7位5'd17: begin SHCP <= 1; end 5'd18: begin DIO <= sel[6]; SHCP <= 0; end //第6位5'd19: begin SHCP <= 1; end 5'd20: begin DIO <= sel[5]; SHCP <= 0; end //第5位5'd21: begin SHCP <= 1; end 5'd22: begin DIO <= sel[4]; SHCP <= 0; end //第4位5'd23: begin SHCP <= 1; end 5'd24: begin DIO <= sel[3]; SHCP <= 0; end //第3位5'd25: begin SHCP <= 1; end 5'd26: begin DIO <= sel[2]; SHCP <= 0; end //第2位5'd27: begin SHCP <= 1; end 5'd28: begin DIO <= sel[1]; SHCP <= 0; end //第1位5'd29: begin SHCP <= 1; end 5'd30: begin DIO <= sel[0]; SHCP <= 0; end //第0位5'd31: begin SHCP <= 1; end endcase
endmodule
testbench如下:
`timescale 1ns/1ps
//
//module: 74HC595驱动测试模块
//
`define clk_period 20 //50M系统时钟module HC595drive_tb();reg clk; //50M系统时钟reg rst; //低电平复位reg [7:0]seg; //8bit段选信号reg [7:0]sel; //8bit位选信号wire DIO; //74HC595数据引脚wire SHCP; //74HC595移位脉冲引脚wire STCP; //74HC595输出脉冲引脚//例化测试模块HC595drive HC595drive_test(.clk(clk), .rst(rst), .seg(seg), .sel(sel), .DIO(DIO), .SHCP(SHCP), .STCP(STCP) );//产生50M时钟信号initial clk = 1;always #(`clk_period / 2) clk = ~clk;//开始测试initial beginrst = 0; //复位seg = 8'hc0; //显示数字"1" sel = 8'ha5; //10100101#(`clk_period * 5); rst = 1;#(`clk_period * 32 * 4); //传送16位需要32个clk,clk又被进行4分频#(`clk_period * 10);$stop;end
endmodule
测试结果如下:
例7.定时器
玩过单片机的小伙伴都很熟悉,单片机的基本外设就是定时器,定时器的核心也是计数器,设定工作方式(单次计数和循环计数)和定时值后,就开始计数,计满之后产生计数慢标志信号,提示设定的定时时间到达;
所以,如果要用计数器来设计一个定时器,需要实现的功能有:
1、定时时间参数通过一个端口输入,调节该值可以修改定时时间;
2、设置一个计数模式控制信号,当该信号为1时为循环定时模式,当该信号为0时为单次定时模式;
3、设置一个计数启动信号,在循环定时模式下,该信号为高电平使能计时,为低电平则停止计时;当单次计数模式下,该信号的一个单基准时钟周期的脉冲使能一次定时;
4、输出计数器定时计数值,该值用于产生特定占空比的方波;
设计图如下:
verilog代码如下:
module timer(input clk, //50M时钟信号input rst, //低电平复位input [31:0]timer_value, //定时值input mode, //定时器模式选择input en, //定时器使能控制端output [31:0]cnt_value, //定时器计数值实时输出output full_flag //定时器计满输出标志位
);reg [31:0]cnt; //32bit计数器reg oneshot; //在单次定时模式中,使能端一个脉冲就启动,但是计数器需要en保持为1才会计数,所以需要另外一个单次使能信号,当外部一个脉冲时,它会变为1,保持至定时结束;//功能描述assign full_flag = (cnt == timer_value)?1'b1:1'b0; //输出计满标志位assign cnt_value = cnt; //实时输出计数值always@(posedge clk,negedge rst)if(!rst)cnt <= 0;else if(mode)begin //mode = 1,循环定时模式if(en && cnt < timer_value) cnt <= cnt +1'b1; //使能状态下且计数值未满,加一elsecnt <= 0; //其余情况下cnt清零endelse begin //mode = 0,单次定时模式if(oneshot)cnt <= cnt + 1'b1;elsecnt <= 0;end//利用外部一个脉冲产生oneshot信号供定时器单次定时模式下使用//功能:当外部en产生一个高脉冲时,它会变为1,保持至定时结束;always@(posedge clk,negedge rst)if(!rst)oneshot <= 0;else if(en)oneshot <= 1'b1;else if(cnt >= timer_value) //计满清零oneshot <= 0;
endmodule
testbench测试文件如下:
`timescale 1ns/1ps
`define clk_period 20module timer_tb();reg clk; //50M时钟信号reg rst; //低电平复位reg [31:0]timer_value; //定时值reg mode; //定时器模式选择reg en; //定时器使能控制端wire [31:0]cnt_value; //定时器计数值实时输出wire full_flag; //定时器计满输出标志位//例化测试模块timer timer_test(.clk(clk), //50M时钟信号.rst(rst), //低电平复位.timer_value(timer_value), //定时值.mode(mode), //定时器模式选择.en(en), //定时器使能控制端.cnt_value(cnt_value), //定时器计数值实时输出.full_flag(full_flag) //定时器计满输出标志位
);//产生50M时钟信号initial clk = 1;always #(`clk_period / 2) clk = ~clk;//开始测试initial beginrst = 0; //系统复位mode = 0; //首先测试模式0,单次计数模式en = 0; //未使能timer_value = 32'd10; //定时器计数值为10#(`clk_period * 2);rst = 1;#(`clk_period * 2);en = 1; //产生一个高脉冲,使能定时器#(`clk_period * 2);en = 0;#(`clk_period * 15); //系统计数10个clk会输出计满flag,在延时观察5个clk观察定时器是否停止mode = 1; //开始测试定时器模式1,循环计数模式#(`clk_period);en = 1; //使能定时器#(`clk_period * 10 * 5); //系统计数10个clk会输出计满flag,一共观察5次flagen = 0; //停止使能#(`clk_period * 10); //等待10个clk,观察定时器是否已停止工作$stop; //停止测试end
endmodule
测试结果如下:
单次计数模式测试:
循环计数模式测试:
综合电路图如下:
定时器至此就设计结束,定时器有很多应用,比如产生PWM驱动无源蜂鸣器,驱动直流电机调速,驱动舵机,驱动步进电机,驱动RGBLED变色,总之利用定时器可以很方便产生可变PWM,利用好PWM也是很深的学问,如有兴趣自行深入;
【FPGA入门教程】(六)时序逻辑电路设计相关推荐
- 零基础学FPGA(五):时序逻辑电路设计之计数器(附有呼吸灯实验、简单组合逻辑设计介绍)
目录 日常·唠嗑 前言 一.认清逻辑设计 二.时序逻辑电路设计 三.扩展:呼吸灯实验 日常·唠嗑 第一次建立<零基础学FPGA>专栏,是在2021年2月2日,已经过去了一年了,目前只更新了 ...
- 实验二 组合逻辑电路设计;实验三 时序逻辑电路设计
文章目录 实验二 组合逻辑电路设计实验报告 实验三 时序逻辑电路设计实验报告 实验二 组合逻辑电路设计实验报告 一.实验目的 1.加深理解组合逻辑电路的工作原理. 2.掌握组合逻辑电路的设计方法. 3 ...
- 异步时序逻辑电路设计方法(统一使用上升沿触发的触发器)
在异步时序逻辑电路设计部分停留了好些时候, 思维一度陷入混乱, 但最终还是坚持了下来, 并找到了一种设计异步时序逻辑电路的方法. 这里肯定会有很多朋友问道, 既然已经掌握了同步时序逻辑电路的设计方法, ...
- R语言七天入门教程六:文件相关操作
R语言七天入门教程六:文件相关操作 一.文件的读写 R 语言作为统计学编程语言,常常需要处理大量数据,而这些数据通常会从文件中进行读取,因此文件读写在R语言中是非常重要的操作.在R语言中,用到最多的文 ...
- 双 JK 触发器 74LS112 逻辑功能。真值表_时序逻辑电路设计(一):同步计数器...
时序逻辑电路设计(一):同步计数器 时序电路的考察主要涉及分析与设计两个部分, 上文介绍了时序逻辑电路的一些分析方法,重点介绍了同步时序电路分析的步骤与注意事项.本文就时序逻辑电路设计的相关问题进行讨 ...
- matlab 与非门 simulink,基于MATLAB的时序逻辑电路设计与仿真
<基于MATLAB的时序逻辑电路设计与仿真>由会员分享,可在线阅读,更多相关<基于MATLAB的时序逻辑电路设计与仿真(19页珍藏版)>请在人人文库网上搜索. 1.成绩 MAT ...
- 用python做自我介绍_用python做个自我介绍(python入门教程)_逻辑教育
原标题:用python做个自我介绍(python入门教程)_逻辑教育 本文涉及的python基础语法为:数据类型等 数字类型 1. 字符串的拼接 我们在上一章中已经简单介绍了一下字符串的创建方式,这里 ...
- 【MATLAB Image Processing Toolbox 入门教程六】“导入、导出和转换”之“图像类型转换Ⅰ——在不同图像类型之间转换”
[MATLAB Image Processing Toolbox 入门教程六] 1 gray2ind函数 2 ind2gray函数 3 mat2gray函数 4 rgb2gray函数 5 rgb2in ...
- 时序逻辑电路设计实例
时序逻辑电路设计实例: [例1]触发器设计实例 module dff( q, data, clk);output q;input data, clk;reg q;always @( posedge c ...
- 无废话ExtJs 入门教程六[按钮:Button]
无废话ExtJs 入门教程六[按钮:Button] extjs技术交流,欢迎加群(201926085) 继上一节内容,我们在表单里加了个两个按钮"提交"与重置.如下所示代码区的第6 ...
最新文章
- 函数调用时栈的相关变化
- java练气期(1)----java高级(JDBC)
- golang 远程传输文件
- 软件工程2017第二次作业
- javascript开发后端程序的神器nodejs
- MySQL error 1477_mysql_error.md
- linux vim 高亮查找,vim技巧:用列表形式显示所有搜索到的内容,去掉搜索内容的高亮...
- express利用nodemailer发送邮件(163邮箱)
- [webpack-cli] Unable to load ‘@webpack-cli/serve‘ command
- 系统500报警 php_Zabbix3.4 部署、监测及邮件报警
- FontAwesome-网站ui设计中一套非常棒的icon
- MongoDB | Mysql亿级别---数据生成及高效率导入
- serialize java_java serialize 浅谈
- Linux系统版本大全
- 学计算机用微软笔记本可以吗,当我用上二合一电脑的时候我还是个学生
- 迅歌KTV服务器各型号,十大ktv必点歌曲排行榜 ktv点唱率最高的十首歌榜单公布...
- axure9实用操作设置鼠标单击交互事件为什么没响应
- iMac重装系统的问题:无法与恢复服务器取得联系/将安装器信息下载到目标卷宗失败
- github、npm、Stack Overflow...... 一键加速 【支持多平台】
- 腾讯地图只显示某一区域,覆盖图,marker自定义图标和文本标注
热门文章
- 十年阿里P6大牛谈外包!
- i5-1135g7是标压还是低压 i5 1135g7是集成显卡么
- 10G至40G互连方案-40G QSFP+ PSM4单模光模块
- UltraEdit 多词搜索
- 服务器存储的作用和用途,存储服务器有四大作用你都清楚吗?
- linux中如何查看文件上下文,linux通过grep根据关键字查找日志文件上下文
- 项目实战 |根据找到的variants的结果生成突变矩阵
- 【读点论文】A ConvNet for the 2020s,结合swin transformer的结构设计和训练技巧调整resnet网络,在类似的FLOPs和参数量取得更好一点的效果
- 当前计算机三档配置,剑灵五档配置要求 电脑配置推荐
- # 前端初学html+css+js+bootstrap4+jquery部分后的简单响应式静态网页编写(漫威主题个人博客)