FPGA学习 | 例子合集

小梅哥Xilinx FPGA教程 课程例题整理
课程视频 : https://www.bilibili.com/video/BV1va411c7Dz?p=1&vd_source=371c3c83b450d1d337bdf87db2243dc5
课程资料:http://www.corecourse.cn/forum.php?mod=viewthread&tid=28730&extra=page=1



一、二选一选择器

2.源代码 mux2.v

`timescale 1ns/1ps

//1ns 是步进 1ps是精度

module mux2(
		a,
		b,
		sel,
		out
	);
	input a;
	input b;
	input c;
	
	output out;
	
	assign out = sel?a:b; //sel为1时,out = a ,否则为 b

endmodule

2.激励信号 mux2_tb.v

`timescale 1ns /1ns

module mux2_td();

    reg s_a;
    reg s_b;
    reg sel;
    wire out;

   mux2 mux2_tb( //模块名 例化标签名(缺少标签名仿真会报错)
    .a(s_a), //连线自定义
    .b(s_b),
    .sel(sel),
    .out(out)
    ); 
    
    initial begin
        s_a=0;s_b=0;sel=0;
        #200;
        s_a=0;s_b=0;sel=1;
        #200;
        s_a=0;s_b=1;sel=0;
        #200;
        s_a=0;s_b=1;sel=1;        
        #200;
        s_a=1;s_b=0;sel=0;
        #200;
        s_a=1;s_b=0;sel=1;
        #200;
        s_a=1;s_b=1;sel=0;       
        #200;
        s_a=1;s_b=1;sel=1;
        #200;
        
        $stop;//仿真终止
                  
    end

endmodule

3.仿真图
在这里插入图片描述

二、三八译码器

1.源代码 decoder_3_8.v

`timescale 1ns / 1ns

module decoder_3_8(
    a,
    b,
    c,
    out
    );

    input a;
    input b;
    input c;
    output reg [7:0]out; //always块中赋值的信号必须定义为reg型

    always@(*)
        case({a,b,c}) //{}位拼接符
            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 : out=8'b0000_0000; //默认项 以免情况没有罗列全出现锁存器
        endcase
endmodule

2.激励信号 decoder_3_8_tb.v

`timescale 1ns / 1ns

module decoder_3_8_tb();

    reg s_a;
    reg s_b;
    reg s_c;
    wire [7:0]out;

    decoder_3_8 decoder_3_8(
        .a(s_a),
        .b(s_b),
        .c(s_c),
        .out(out)
        );
        
    initial begin
        s_a = 0; s_b = 0; s_c = 0;
        #200;
        s_a = 0; s_b = 0; s_c = 1;
        #200;        
        s_a = 0; s_b = 1; s_c = 0;
        #200;    
        s_a = 0; s_b = 1; s_c = 1;
        #200;
        s_a = 1; s_b = 0; s_c = 0;
        #200;
        s_a = 1; s_b = 0; s_c = 1;
        #200;        
        s_a = 1; s_b = 1; s_c = 0;
        #200;    
        s_a = 1; s_b = 1; s_c = 1;
        #200;
        
        $stop;           
    end
  
endmodule

3.仿真图

在这里插入图片描述

三、LED亮灭

1.源代码 LED_flash.v

`timescale 1ns / 1ns

module LED_flash(
    CLK,
    Reset,
    LED
    );
    
    input CLK;
    input Reset;
    
    output reg LED;
    
    reg [24:0] counter; //未定义位数则变为1位且一直为初值0
    
    always@(posedge CLK or negedge Reset) //时钟上升沿与复位下降沿
        if (!Reset)
            counter <= 0; //非阻塞赋值
        else if (counter == 24999999) //计数器计数时要减1 ,默认数字是十进制
        //50HZ晶振两个上升沿间是20ns,5s就是500ms/20ns = 25_000_000次 
            counter <= 0;
        else
            counter <= counter + 1'b1;
            //b 二进制
            //d 十进制
            //h 十六进制    
            
    always@(posedge CLK or negedge Reset) //一般将计数与LED状态分开写,方便调试
        if (!Reset)
            LED <= 0;
        else if (counter == 24999999)
            LED <= !LED;     
endmodule

2.激励信号 LED_flash_tb.v

`timescale 1ns / 1ns

module LED_flash_tb();
    
    reg CLK;
    reg Reset;
    
    wire LED;
    
    LED_flash LED_flash(
        .CLK(CLK),
        .Reset(Reset),
        .LED(LED)
        );
     
    //50HZ时钟激励信号    
    initial CLK = 1;
    always #10 CLK = ~CLK;
    
    initial begin
        Reset = 0;   //仿真复位结果
        #201; //201避开时钟上升沿,方便观察
        Reset = 1;   //仿真正常结果,给出几个周期的时间
        #2000000000;
        $stop;
    end  
    
endmodule

3.仿真图

在这里插入图片描述

三、流水灯

1.源代码 LED_run.v

`timescale 1ns / 1ns

module LED_run(
    CLK,
    Reset,
    LED
    );
    
    input CLK;
    input Reset;
    
//方法一 
//    output reg [7:0] LED;
//    reg [24:0] counter;   
//    always@(posedge CLK or negedge Reset)
//    if (!Reset)
//        counter <= 0;
//    else if(counter == 24999)
//        counter <= 0;
//    else
//        counter <= counter + 1'b1;
   
//    always@(posedge CLK or negedge Reset)
//    if (!Reset)
//        LED <= 8'b0000_0001;
//    else if(counter == 24999)
//            begin
//                if(LED == 8'b1000_0000)
//                    LED <= 8'b0000_0001;
//                else
//                     LED <= LED << 1;   //右移位运算(用0填补空位)
//            end 
//    else
//       LED <= LED;
 //

//方法二/使用三八译码器例化模块/    
    
    output [7:0] LED; 
    //注意:调用的子模块,底层output已经定义过reg型,此处LED不能再次定义!!仿真会出错
	//将decoder_3_8.V的程序复制到工程中
   
    reg [24:0] counter;  //时间计数器
    reg [2:0] counter2;  //流水灯选择器
    
    always@(posedge CLK or negedge Reset)
    if (!Reset)
        counter <= 0;
    else if(counter == 24999)
        counter <= 0;
    else
        counter <= counter + 1'b1;
          
    always@(posedge CLK or negedge Reset)
    if (!Reset)
        counter2 <= 0;
    else if(counter == 24999)
    	counter2 <= counter2 +1'b1;
    
    decoder_3_8 decoder_3_8( 
        .a(counter2[2]),		//{a,b,c}对应{counter2[2],counter2[1],counter2[0]}
        .b(counter2[1]),
        .c(counter2[0]),
        .out(LED)				//三八译码器中已定义过out连线类型为reg
        );          
   
endmodule

2.激励信号 LED_run_tb.v

`timescale 1ns / 1ns

module LED_run_tb();

    reg CLK;
    reg Reset;
    wire [7:0] LED;

    LED_run LED_run(
    .CLK(CLK),
    .Reset(Reset),
    .LED(LED)
    );

    initial CLK = 1;
    always #10 CLK = !CLK;
    
    initial begin
        Reset = 0;
        #201;
        Reset = 1;
        #40000;          
    end

endmodule

3.仿真图

在这里插入图片描述

四、让4个LED以不同频率亮灭(将变量参数化)

1.源代码

(1)子模块 LED_flash.v

`timescale 1ns / 1ps

module LED_flash(
    CLK,
    Reset,
    LED
    );
    
    input CLK;
    input Reset;
    
    output reg LED;
    
    reg [24:0] counter;
    
    parameter MCNT = 2499; //参数化
    
    always@(posedge CLK or negedge Reset)
        if (!Reset)
            counter <= 0;
        else if (counter == MCNT)
            counter <= 0;
        else
            counter <= counter + 1'b1;    
            
    always@(posedge CLK or negedge Reset)
        if (!Reset)
            LED <= 0;
        else if (counter == MCNT)
            LED <= !LED;     
endmodule

(2)主程序 LED_run4.v

//用LED_Flash.v模块例化

`timescale 1ns / 1ns

module LED_run4(
    CLK,
    Reset,
    LED
    );
    
    input CLK;
    input Reset;
    
    output [3:0] LED;

	//1s 是25_000_000 - 1 = 24_999_999
	//0.1s 是 25_000_00 - 1 =  24_999_99
    //0.2s 是 50_000_00 - 1 =  49_999_99
    
    //给4个LED灯做4次例化,并修改时间参数
    
    LED_flash LED_flash_0(   //模块名 例化标签名
        .CLK(CLK),
        .Reset(Reset),
        .LED(LED[0])
        );
    defparam LED_flash_0.MCNT = 24999;  //修改例化模块中的参数,注意是用引用标签名(方法一)
   
    LED_flash LED_flash_1(
        .CLK(CLK),
        .Reset(Reset),
        .LED(LED[1])
        );
    defparam LED_flash_1.MCNT = 49999; 
    
    LED_flash 
    #( .MCNT(74999)  //修改例化模块中的参数(方法二)
    )
    LED_flash_2(
        .CLK(CLK),
        .Reset(Reset),
        .LED(LED[2])
        );
    
    LED_flash 
    #( .MCNT(99999)
        )
    LED_flash_3(
        .CLK(CLK),
        .Reset(Reset),
        .LED(LED[3])
        );
                   
endmodule

2.激励信号 LED_run4_tb.v

`timescale 1ns / 1ns

module LED_run4_tb();
    
    reg CLK;
    reg Reset;
    
    wire [3:0]LED;
    
    LED_run4 LED_run4(   //激励信号例化 主程序的模块名
        .CLK(CLK),
        .Reset(Reset),
        .LED(LED)
        );
        
    initial CLK = 1;
    always #10 CLK = ~CLK;
    
    initial begin
        Reset = 0;   
        #201;
        Reset = 1;   
        #2000000000;
    end
    
endmodule

五、从计数器到可控线性序列机———LED 实验进化六部曲

(为后续串口通信做基础准备)

1.让LED灯按照亮0.25秒,灭0.75秒的状态循环亮灭
2. 让LED灯按照亮0.25秒,灭0.5秒、亮0.75秒,灭1秒的状态循环亮灭
3. 让LED 灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。以0.25秒为一个变化周期,8个变化状态为一个循环
4. 让LED灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。8个变化状态为 一个循环,每个变化状态的时间值可以根据不同的应用场景选择
5.让多个LED 灯按照设置的模式各自在一个变化循环内独立亮灭变化
6.每隔10ms,让 LED灯的一个8状态循环执行一次(每个状态的变化时间值小一点,方便测试,比如设置为10us)

1:让LED灯按照灭0.25秒,亮0.75秒的状态循环亮灭。

1.源代码 counter_LED_1.v

`timescale 1ns / 1ns

module counter_LED(
    CLK,
    Reset,
    LED
    );
    
    input CLK;
    input Reset;
    
    output reg LED;
    
    reg [26:0] counter; 

	parameter MCNT = 12500000; //0.25s的计数器     1s/4/20ns=12500000
    
    always@(posedge CLK or negedge Reset) 
        if (!Reset)
            counter <= 0; 
        else if (counter == MCNT*4 - 1)//定义一个1s的总时钟 
            counter <= 0;
        else
            counter <= counter + 1'b1;
            
    always@(posedge CLK or negedge Reset) //一般将计数与LED状态分开写,方便调试
        if (!Reset)
            LED <= 0;
        else if (counter == MCNT - 1)//0.25s时LED为1
            LED <= 1;
        else if (counter == MCNT*4 - 1)//0.25s+0.75s时LED为0
            LED <= 0;  
endmodule

2.激励信号 counter_LED_1_tb.v

`timescale 1ns / 1ns

module counter_LED_tb();
    
    reg CLK;
    reg Reset;
    
    wire LED;
    
        counter_LED 
    #(
        .MCNT (12500) //缩短仿真时间
    )
    counter_LED(
        .CLK(CLK),
        .Reset(Reset),
        .LED(LED)
        );
  
    initial CLK = 1;
    always #10 CLK = ~CLK;
    
    initial begin
        Reset = 0;   
        #201; 
        Reset = 1;   
        #2000000000;
    end  
    
endmodule

3.仿真图

在这里插入图片描述

2:让LED灯按照亮0.25秒,灭0.5秒,亮0.75秒,灭1秒的状态循环亮灭。

1.源代码 counter_LED_2.v

`timescale 1ns / 1ns

module counter_LED_2(
    CLK,
    Reset,
    LED
    );
    
    input CLK;
    input Reset;
    output reg LED;
    
    reg [23:0] counter;
    
    parameter MCNT = 12500000; //0.25s
    
    always@(posedge CLK or negedge Reset)
    if(!Reset)
        counter <= 0;
    else if(counter == MCNT*10 - 1)//1s
        counter <= 0;
    else
        counter <= counter +1'b1;
    
    always@(posedge CLK or negedge Reset)
    if(!Reset)
        LED <= 0;
    else if(counter == MCNT - 1)//0.25s
        LED <= 0;
    else if(counter == MCNT*3 -1)//0.25+0.5
        LED <= 1;
    else if(counter == MCNT*6 -1)//0.25+0.5+0.75
        LED <= 0;
    else if(counter == MCNT*10 -1)//0.25+0.5+0.75+1
        LED <= 1;
endmodule


2.激励信号 counter_LED_2_tb.v

`timescale 1ns / 1ps

module counter_LED_2_tb(  );

    reg CLK;
    reg Reset;
    
    wire LED;
    
        counter_LED_2
    #(
        .MCNT (12500) //缩短仿真时间
    )
    counter_LED_2(
        .CLK(CLK),
        .Reset(Reset),
        .LED(LED)
        );
  
    initial CLK = 1;
    always #10 CLK = ~CLK;
    
    initial begin
        Reset = 0;   
        #201; 
        Reset = 1;   
        #2000000000;
    end 
    
endmodule

3.仿真图
在这里插入图片描述

3:让LED灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。以0.25秒为一个变化周期, 8个变化状态为一个循环。

分析:2秒为一个循环周期;有指定亮灭的端口输入。

1.源代码 counter_LED_3.v

`timescale 1ns / 1ns

module counter_LED_3(
    CLK,
    Reset,
    Ctrl, //指定亮灭的输入信号
    LED
    );
    
    input CLK;
    input Reset;
    input [7:0] Ctrl;
    
    output reg LED;
    
    reg [26:0] counter; 

	parameter MCNT = 12500000; //0.25s
    
    always@(posedge CLK or negedge Reset) 
        if (!Reset)
            counter <= 0; 
        else if (counter == MCNT*8 - 1)//定义一个2s的总时钟 
            counter <= 0;
        else
            counter <= counter + 1'b1;
            
//else if 语句          
//    always@(posedge CLK or negedge Reset) 
//		 if (!Reset)
//		     LED <= 0;
//		 else if (counter == MCNT - 1)
//		     LED <= Ctrl[0];
//		 else if (counter == MCNT*2 - 1)
//		     LED <= Ctrl[1];  
//		 else if (counter == MCNT*3 - 1)
//		     LED <= Ctrl[2]; 
//		 else if (counter == MCNT*4 - 1)
//		     LED <= Ctrl[3]; 
//		 else if (counter == MCNT*5 - 1)
//		     LED <= Ctrl[4];  
//		 else if (counter == MCNT*6 - 1)
//		     LED <= Ctrl[5]; 
//		 else if (counter == MCNT*7 - 1)
//		     LED <= Ctrl[6]; 
//		 else if (counter == MCNT*8 - 1)
//		     LED <= Ctrl[7]; 


//case语句
    always@(posedge CLK or negedge Reset) 
		 if (!Reset)
		     LED <= 0;
		 else case(counter)
		      MCNT * 1 - 1: LED <= Ctrl[0];
		      MCNT * 2 - 1: LED <= Ctrl[1];
		      MCNT * 3 - 1: LED <= Ctrl[2];
		      MCNT * 4 - 1: LED <= Ctrl[3];
		      MCNT * 5 - 1: LED <= Ctrl[4];
		      MCNT * 6 - 1: LED <= Ctrl[5];
		      MCNT * 7 - 1: LED <= Ctrl[6];
		      MCNT * 8 - 1: LED <= Ctrl[7];
		      default : LED <= LED;
		 endcase
		 
endmodule

2.激励信号 counter_LED_3_tb.v


`timescale 1ns / 1ns

module counter_LED_td();
    
    reg CLK;
    reg Reset;
    reg [7:0]Ctrl;
    
    wire LED;
    
    counter_LED_3 
    #(
        .MCNT (12500) //减少仿真时间
    )
    counter_LED_3(
        .CLK(CLK),
        .Reset(Reset),
        .Ctrl(Ctrl),
        .LED(LED)
        );
       
    initial CLK = 1;
    always #10 CLK = ~CLK;
    
    initial begin
        Reset = 0;
        Ctrl = 0;   
        #201; 
        Reset = 1;
        #2000
        Ctrl = 8'b1000_0110;  //自定义 LED将根据Ctrl的变化而变化                     
        #20000000;
        Ctrl = 8'b1100_1110;                        
        #20000000;
        $stop;
    end  
    
endmodule

3.仿真图

在这里插入图片描述

4:让LED灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。8个变化状态为一个循环,每个变化状态的时间值可以根据不同的应用场景选择。

分析:循环周期时长自定义;有指定亮灭的端口输入。

1.源代码 counter_LED_4.v

`timescale 1ns / 1ps

module counter_LED_4(
    CLK,
    Reset,    
    Ctrl,
    Time,
    LED    
    );
    input CLK;
    input Reset;
    
    input [7:0] Ctrl;
    input [31:0] Time;
    
    output reg LED;
    
    reg [31:0] counter;
    reg [2:0] counter2;
    
    always@(posedge CLK or negedge Reset) 
        if (!Reset)
            counter <= 0; 
        else if (counter == Time - 1)//定义一个Time变化周期 ,一拍是几秒
            counter <= 0;
        else
            counter <= counter + 1'b1;    

    always@(posedge CLK or negedge Reset) 
        if (!Reset)
            counter2 <= 0; 
        else if (counter == Time - 1) //满一拍计数加1,三位满7(111)自动循环
            counter2 <= counter2 + 1'b1;
    
    always@(posedge CLK or negedge Reset) 
		 if (!Reset)
		     LED <= 0;
		 else case(counter2)
		      0: LED <= Ctrl[0];
		      1: LED <= Ctrl[1];
		      2: LED <= Ctrl[2];
		      3: LED <= Ctrl[3];
		      4: LED <= Ctrl[4];
		      5: LED <= Ctrl[5];
		      6: LED <= Ctrl[6];
		      7: LED <= Ctrl[7];
		      default : LED <= LED;
		 endcase
    
endmodule

2.激励信号 counter_LED_4_tb.v

`timescale 1ns / 1ps

module counter_LED_4_tb(    );

    reg CLK;
    reg Reset;
    reg [7:0] Ctrl;
    reg [31:0] Time;
    
    wire LED;
    
    counter_LED_4 counter_LED_4(
        .CLK(CLK),
        .Reset(Reset),    
        .Ctrl(Ctrl),
        .Time(Time),
        .LED(LED)
    );
    
    
    initial CLK = 1;
    always #10 CLK = ~CLK;
    
    initial begin
        Reset = 0; 
        Ctrl = 0;
        Time = 0;
        #201
        Reset = 1;
        #2000
        Time = 12500; //自定义
        Ctrl = 8'b1000_0110;  //自定义                 
        #20000000;
        Ctrl = 8'b1100_1110;                        
        #20000000;
        $stop;
    end


endmodule


3.仿真图

在这里插入图片描述

5:让多个LED 灯按照设置的模式各自在一个变化循环内独立亮灭变化。

分析:时间不变,同时控制多个输出信号.

1.源代码 counter_LED_5.v

`timescale 1ns / 1ns

module counter_LED_5(
    CLK,
    Reset,
    CtrlA,
    CtrlB,
    Time, //定义一个时间单位
    LED
    );
    
    input CLK;
    input Reset;
    input [7:0] CtrlA,CtrlB;
    input [31:0] Time;
        
    output reg [1:0] LED;
    
    reg [31:0] counter; 
    reg [2:0] counter2;  //第二个计数器,8个时间单位一个周期
   
    always@(posedge CLK or negedge Reset) 
        if (!Reset)
            counter <= 0; 
        else if (counter == Time - 1) 
            counter <= 0;
        else
            counter <= counter + 1'b1;
  
    always@(posedge CLK or negedge Reset) 
        if (!Reset)
            counter2 <= 0; 
        else if (counter == Time - 1) 
            counter2 <= counter2 + 1'b1;  
  
    always@(posedge CLK or negedge Reset) 
		 if (!Reset)
		     LED <= 0;
		 else case(counter2)
		      0: begin
		      	 LED[0] <= CtrlA[0];
		      	 LED[1] <= CtrlB[0];
		      	 end
		      1: begin
		      	 LED[0] <= CtrlA[1];
		      	 LED[1] <= CtrlB[1];
		      	 end
		      2: begin
		      	 LED[0] <= CtrlA[2];
		      	 LED[1] <= CtrlB[2];
		      	 end
		      3: begin
		      	 LED[0] <= CtrlA[3];
		      	 LED[1] <= CtrlB[3];
		      	 end
		      4: begin
		      	 LED[0] <= CtrlA[4];
		      	 LED[1] <= CtrlB[4];
		      	 end
		      5: begin
		      	 LED[0] <= CtrlA[5];
		      	 LED[1] <= CtrlB[5];
		      	 end
		      6: begin
		      	 LED[0] <= CtrlA[6];
		      	 LED[1] <= CtrlB[6];
		      	 end
		      7: begin
		      	 LED[0] <= CtrlA[7];
		      	 LED[1] <= CtrlB[7];
		      	 end
		      default : LED <= LED;
		 endcase

endmodule

2.激励信号 counter_LED_5_tb.v

`timescale 1ns / 1ns

module counter_LED_td();
    
    reg CLK;
    reg Reset;
    reg [7:0]CtrlA;
    reg [7:0]CtrlB;
    reg [31:0]Time;
    
    wire [1:0] LED;
    
    counter_LED_5 counter_LED_5(
        .CLK(CLK),
        .Reset(Reset),
        .CtrlA(CtrlA),
        .CtrlB(CtrlB),
        .Time(Time),
        .LED(LED)
        );
       
    initial CLK = 1;
    always #10 CLK = ~CLK;
    
    initial begin
        Reset = 0;
        CtrlA = 0;
        CtrlB = 0;
        Time = 0;   
        #201; 
        Reset = 1;
        #2000
        Time = 12500; 
        CtrlA = 8'b1000_0110;  //自定义  
        CtrlB = 8'b1001_0110;  //自定义                
        #20000000;
        CtrlA = 8'b1100_1110;
        CtrlB = 8'b1010_0110;  //自定义 
        #20000000;
        $stop;
    end  
    
endmodule

3.仿真图

在这里插入图片描述

6:每隔10ms,让 LED灯的一个8状态循环执行一次(每个状态的变化时间值小一点,方便测试, 比如设置为10us)。

分析: 以10ms为一个周期,8个状态为一组,8个状态结束后停止,直到下一个周期开始时进入下一个8个状态循环。


在这里插入图片描述

1.源代码 counter_LED_6.v

`timescale 1ns / 1ns

module counter_LED_6(
    CLK,
    Reset,
    Ctrl,
    Time,
    LED
    );
    
    input CLK;
    input Reset;
    input [31:0] Time;
    input [7:0] Ctrl;
    
    output reg LED;
    
    reg [18:0] counter0; //10ms 的计数器,500 000
    
    reg [31:0] counter1; //EN为1 时计数器
    
    reg [2:0] counter2; //8个Time的计数器
   
    reg EN;
    
    //10ms的周期计数器
    always@(posedge CLK or negedge Reset) 
        if (!Reset)
            counter0 <= 0; 
        else if (counter0 == 500_000 - 1) //10ms
            counter0 <= 0;
        else
            counter0 <= counter0 + 1'b1;
            
    //EN状态 ,10msEN变高,8拍结束EN变低     
    always@(posedge CLK or negedge Reset) 
        if (!Reset)
            EN <= 0; 
        else if (counter0 == 0) 
            EN <= 1;
        else if ((counter2 == 7) && (counter1 == Time - 1))
        //状态持续时间结束后才复位,若没有(counter == Time - 1),两个周期后EN就置0,导致最后一位数据无法保持 
            EN <= 0;

    //EN为1时的计数器
    always@(posedge CLK or negedge Reset) 
        if (!Reset)
            counter1 <= 0; 
        else if (EN) begin
            if (counter1 == Time - 1)
                counter1 <= 0;
            else
                counter1 <= counter1 + 1'b1;//在EN有效期内,循环计数
            end
        else 
            counter1 <= 0;
     
     //EN为1时的拍子计数器,数8拍
    always@(posedge CLK or negedge Reset) 
        if (!Reset)
            counter2 <= 0; 
        else if (EN) begin
            if (counter1 == Time - 1)
                counter2 <= counter2 + 1'b1;//在EN有效期内,循环数拍
            end
        else 
            counter2 <= 0;
     
     //控制LED
     always@(posedge CLK or negedge Reset) 
		 if (!Reset)
		     LED <= 0;
		 else case(counter2)
		      0: LED <= Ctrl[0];
		      1: LED <= Ctrl[1];
		      2: LED <= Ctrl[2];
		      3: LED <= Ctrl[3];
		      4: LED <= Ctrl[4];
		      5: LED <= Ctrl[5];
		      6: LED <= Ctrl[6];
		      7: LED <= Ctrl[7];
		      default : LED <= LED;
		 endcase 

endmodule

2.激励信号 counter_LED_6_tb.v

`timescale 1ns / 1ps

module counter_LED_6_tb(    );

    reg CLK;
    reg Reset;
    reg [7:0] Ctrl;
    reg [31:0] Time;
    
    wire LED;
    
    counter_LED_6 counter_LED_6(
        .CLK(CLK),
        .Reset(Reset),    
        .Ctrl(Ctrl),
        .Time(Time),
        .LED(LED)
    );
    
    
    initial CLK = 1;
    always #10 CLK = ~CLK;
    
    initial begin
        Reset = 0; 
        Ctrl = 0;
        Time = 0;
        #201
        Reset = 1;
        #2000
        Time = 50_000; //自定义
        Ctrl = 8'b1000_0110;  //自定义                 
        #20000000;
        Ctrl = 8'b1100_1110;                        
        #20000000;
        $stop;
    end


endmodule


3.仿真图

在这里插入图片描述

六、阻塞赋值与非阻塞赋值

上文中出现过的赋值语句,如:

always(*)
	case({s,b,c})
		3'b000 : out = 8'b0000_0001;  //不是阻塞赋值,也不是非阻塞赋值,因为不是时序逻辑
always(posedge CLK)
	counter <= counter + 1'b;   //非阻塞赋值

注意:阻塞赋值与非阻塞赋值仅在时序逻辑中才存在

七、串口(UART)发送实验

1、串口通信模块设计的目的是用来发送数据的,因此需要一个数据输入端口(Ctrl)
2、串口通信,支持不同的波特率,所以需要有一个比特率设置端口(Time)
3、串口通信的本质就是将8位的并行数据通过一根信号线,在不同的时刻传输并行数据的不同位,通过多个时刻,最终将8位并行数据全部传出(LED)
4、串口通信以1位的低电平标志串行传输的开始,待8位数据传输完成之后,再以1位的高电平标志传输的结束
5、控制信号,控制并转串模块什么时刻开始工作,什么时候数据发送完成?需要有一个发送开始信号,以及一个发送完成信号(EN)

附:波特率计算

在这里插入图片描述

附:计数发送节拍

在这里插入图片描述

1:发送数据(不成熟版本)

1.源代码 .v

`timescale 1ns / 1ns

module uart_byte_tx(
    Clk,
    Reset_n,
    Data,
    Send_en,
    Baud_set,
    uart_tx,
    Tx_done
);

    input Clk;
    input Reset_n;
    input [7:0]Data;
    input Send_en;
    input [2:0]Baud_set;
    output reg uart_tx;
    output reg Tx_done;
    
    //波特率计数器计算================================
    
    // Baud_set = 0  波特率 = 9600;
    // Baud_set = 1  波特率 = 19200;
    // Baud_set = 2  波特率 = 38400;
    // Baud_set = 3  波特率 = 57600;
    // Baud_set = 4  波特率 = 112500;
    
    //1s = 1_000_000_000ns    50MHz两个上升沿之间是1_000_000_000ns/50_000_000 = 20ns
    //1_000_000_000/9600/20 = bps_DR = 5208 (数拍子要-1)
    
    reg [17:0]bps_DR;
    always@(*)
        case(Baud_set)
            0: bps_DR = 1000000000/9600/20;
            1: bps_DR = 1000000000/19200/20;
            2: bps_DR = 1000000000/38400/20;
            3: bps_DR = 1000000000/57600/20;
            4: bps_DR = 1000000000/115200/20;
            default:bps_DR = 1000000000/9600/20;
        endcase
            
    reg [17:0]div_cnt; //分频得到基本时钟,每个数据位需要保持的时间(bps_DR的计数器)
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        div_cnt <= 0;        
    else if(Send_en)
        begin
            if(div_cnt == bps_DR - 1)
                div_cnt <= 0;
            else
                div_cnt <= div_cnt +1'b1; 
        end
    else
        div_cnt <= 0;
    
    reg [3:0]bps_cnt; //满一拍,为一位,发送一次数据一共要11拍(11拍的计数器)
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        bps_cnt <= 0;
    else if(Send_en)
        begin
            if(div_cnt == bps_DR - 1)
                begin
                    if(bps_cnt == 11)
                       bps_cnt <= 0;
                   else
                        bps_cnt <= bps_cnt +1'b1; 
                end   
        end
    else
        bps_cnt <= 0;
    
    //发送Tx数据和Tx_done信号
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        begin
            uart_tx <= 1'b1;
            Tx_done <= 1'b0;
        end    
    else
        begin
            case(bps_cnt)
                0: begin uart_tx <= 0;Tx_done <= 1'b0; end
                1: uart_tx <= Data[0];
                2: uart_tx <= Data[1];
                3: uart_tx <= Data[2];
                4: uart_tx <= Data[3];
                5: uart_tx <= Data[4];
                6: uart_tx <= Data[5];
                7: uart_tx <= Data[6];
                8: uart_tx <= Data[7];
                9: uart_tx <= 1;
                10:begin uart_tx <= 1; Tx_done <= 1'b1; end
                default:uart_tx <= 1;
            endcase
        end
    
endmodule

2.激励信号 tb.v

`timescale 1ns / 1ns

module uart_byte_tx_tb;
    
    reg Clk;
    reg Reset_n;
    reg [7:0] Data;
    reg Send_en;
    reg [2:0] Baud_set;
    wire uart_tx;
    wire Tx_done;
    
        
    uart_byte_tx uart_byte_tx(
        .Clk(Clk),
        .Reset_n(Reset_n),
        .Data(Data),
        .Send_en(Send_en),
        .Baud_set(Baud_set),
        .uart_tx(uart_tx),
        .Tx_done(Tx_done)
    );
    
    //50MHz激励信号
    initial Clk = 1;
    always #10 Clk = ~Clk;
    
    
    //
    initial
        begin
        //复位状态
        Reset_n = 0;
        Data = 0;
        Send_en = 0;
        Baud_set = 4;//波特率设置为115200
        #201;
        
        //运行状态
        Reset_n = 1;
        #100;
        Data = 8'h57;
        Send_en = 1'b1;
        #20;
        @(posedge Tx_done);//死循环等待Tx_done为1后进入下一步
        Send_en = 0;
        #20000;
        Data = 8'h75;
        Send_en = 1;
        #20;
        @(posedge Tx_done);//死循环等待Tx_done为1后进入下一步
        Send_en = 0;
        #20000;
        $stop;
        end
        
endmodule

3.仿真图
在这里插入图片描述

八、

1.源代码 .v

`timescale 1ns / 1ns




2.激励信号 tb.v

`timescale 1ns / 1ns



3.仿真图

总结

以上就是本文要讲的内容。

1.源代码

在这里插入代码片

2.激励文件

在这里插入代码片
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值