FPGA学习日记

本文详细介绍了FPGA开发流程,包括设计定义、Vivado和Quartus工具的使用、功能仿真、布局布线以及时序分析。此外,还展示了如何用Verilog设计和测试3-8译码器、LED灯控制电路,以及基本的UART串口通信。
摘要由CSDN通过智能技术生成

2024.02.28

FPGA开发流程

  1. 设计定义
  2. 设计输入(编写逻辑)
  3. 分析综合(Vivado、quartus)
  4. 功能仿真(Modelsim)
  5. 布局布线(Vivado、quartus)
  6. 分析性能(时序仿真Modelsim、静态时序分析Vivado、quartus)
  7. 板级调试
  8. OK

Vivado开发流程

  1. 启动Vivado
  2. 创建工程
  3. 添加源文件

MUX2

设计

module mux2(
    a,
    b,
    sel,
    out
    );
    
    input a;
    input b;
    input sel;
    output out;
    
    assign out = (sel==1)?a:b;
        
endmodule

测试

`timescale 1ns / 1ps

module mux2_tb();

   reg s_a;
   reg s_b;
   reg sel;
   wire out;
 //例化
   mux2 mux2_inst0(
     .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;
  end
  
endmodule

仿真

时序仿真

3-8译码器

设计

module decoder_3_8(
    a,
    b,
    c,
    out
    );
    
    input a;
    input b;
    input c;
    output [7:0] out;
    reg [7:0]out;

    
//以always块描述的信号赋值,被赋值对象必须定义为reg类型
    always@(*)begin
        case({a,b,c})
          3'b000: out= 8'b0000_0000;
          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;
        endcase
      end  
//{a,b,c}变成了一个三位的信号,这种操作叫做位拼接
//  always@(*)begin
        case({a,b,c})
          3'd0: out= 8'b0000_0000;
          3'd1: out= 8'b0000_0010;
          3'd2: out= 8'b0000_0100;
          3'd3: out= 8'b0000_1000;
          3'd4: out= 8'b0001_0000;
          3'd5: out= 8'b0010_0000;
          3'd6: out= 8'b0100_0000;
          3'd7: out= 8'b1000_0000;
        endcase
      end //
  
endmodule

测试

`timescale 1ns / 1ps

module decoder_3_8_tb();
    
    reg s_a;
    reg s_b;
    reg s_c;
    wire [7:0]out;

    decoder_3_8 decoder_3_8_inst0(
              .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;
     end
        
endmodule

仿真

2024.03.01

LED灯以1s的频率闪烁

如果时钟频率是100MHz,0.5s对应的计数器值是50,000,000

设计

module led_flash(
    Clk,
    Reset_n,
    Led
    );
    
    input Clk;
    input Reset_n;
    output reg Led;
    
    reg [25:0]counter;
    //<=是非阻塞赋值的意思
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter <= 0;
    else if(counter == 24999999)
        counter <= 0;
    else 
        counter <= counter + 1'd1;
        
     always@(posedge Clk or negedge Reset_n)
     if(!Reset_n)
         Led <= 0;
     else if(counter == 24999999)
         Led <= !Led;

endmodule

测试

`timescale 1ns / 1ps

module led_flash_tb();

    reg Clk;
    reg Reset_n;
    wire Led;
    
    led_flash led_flash_inst0(
          .Clk(Clk),
          .Reset_n(Reset_n),
          .Led(Led)
    );
    
    initial Clk = 1;
    always #10 Clk = !Clk;
    
    initial begin
       Reset_n = 0;
       #201;
       Reset_n = 1;
       #2000000000;
       $stop;
    end

endmodule

仿真

让8个LED灯以每个500μs灯速率循环闪烁(跑马灯)

0.0005s = 0.5ms = 500μs

输入设计

module led_run(
    Clk,
    Reset_n,
    Led
    );
    
    input Clk;
    input Reset_n;
    output reg[7:0] Led;
    
    reg [24:0]counter;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter <= 0;
    else if(counter == 25'd24999)
        counter <= 0;
    else 
        counter <= counter + 1'b1;
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        Led <= 8'b0000_0001;
    else if(counter == 25'd24999)begin
        if(Led == 8'b1000_0000)
            Led <= 8'b0000_0001;
        else
            Led <= Led << 1;
        end
        
endmodule

测试

`timescale 1ns / 1ps

module led_run_tb;
    reg Clk;
    reg Reset_n;
    wire [7:0]Led;
    
    led_run led_run_inst0(
          .Clk(Clk),
          .Reset_n(Reset_n),
          .Led(Led)
    );
    
    initial Clk = 1;
    always #10 Clk = ~Clk;
    
    initial begin
       Reset_n = 0;
       #201;
       Reset_n = 1;
       #40000000;
       $stop;
    end
endmodule

仿真

让 LED 灯按照亮 500μs,灭 500μs的状态循环亮灭

设计

module counter_led_0(
    Clk,
    Reset_n,
    Led
    );
    
    input Clk;
    input Reset_n;
    output reg[7:0] Led;
    
    reg [25:0]counter;
    parameter MCNT = 50000000;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter <= 0;
    else if(counter == 49999999)
        counter <= 0;
    else 
        counter <= counter + 1'b1;
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        Led <= 0;
    else if(counter == 24999999)
        Led <= 1;
    else if(counter == 49999999) 
        Led <= 0;     
           
endmodule

测试

`timescale 1ns / 1ps

module counter_led_0_tb;

    reg Clk;
    reg Reset_n;
    wire Led;
    
    counter_led_0
    #(
         .MCNT(50000)
    )
     counter_led_0_inst0(
          .Clk(Clk),
          .Reset_n(Reset_n),
          .Led(Led)
    );
    
    initial Clk = 1;
    always #10 Clk = !Clk;
    
    initial begin
       Reset_n = 0;
       #201;
       Reset_n = 1;
       #2000000000;
       $stop;
    end

endmodule

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

设计

module counter_led_0(
    Clk,
    Reset_n,
    Led
    );
    
    input Clk;
    input Reset_n;
    output reg[7:0] Led;
    
    reg [25:0]counter;
    parameter MCNT = 50000;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter <= 0;
    else if(counter == MCNT - 1)
        counter <= 0;
    else 
        counter <= counter + 1'b1;
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        Led <= 0;
    else if(counter == MCNT/2 + MCNT/4 - 1)
        Led <= 1;
    else if(counter == MCNT - 1)
        Led <= 0;     
           
endmodule

测试

`timescale 1ns / 1ps

module counter_led_0_tb;

    reg Clk;
    reg Reset_n;
    wire Led;
    
    counter_led_0
    #(
         .MCNT(50000)
    )
     counter_led_0_inst0(
          .Clk(Clk),
          .Reset_n(Reset_n),
          .Led(Led)
    );
    
    initial Clk = 1;
    always #10 Clk = !Clk;
    
    initial begin
       Reset_n = 0;
       #201;
       Reset_n = 1;
       #2000000000;
       $stop;
    end

endmodule

仿真

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

设计

module counter_led_1(
    Clk,
    Reset_n,
    Led
    );
    
    input Clk;
    input Reset_n;
    output reg[7:0] Led;
    
    reg [26:0]counter;
    parameter MCNT = 125000000;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter <= 0;
    else if(counter == MCNT - 1)
        counter <= 0;
    else 
        counter <= counter + 1'b1;
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        Led <= 1;
    else if(counter == MCNT/10 - 1)
        Led <= 0;
    else if(counter == MCNT/10 + MCNT/5 - 1)
        Led <= 1; 
    else if(counter == (MCNT/10 + MCNT/5)*2 - 1)
        Led <= 0;
    else if(counter == MCNT - 1)
        Led <= 1;
           
endmodule

测试

`timescale 1ns / 1ns

module counter_led_1_tb;

    reg Clk;
    reg Reset_n;
    wire Led;
    
    counter_led_1
    #(
         .MCNT(50000)
    )
     counter_led_1_inst0(
          .Clk(Clk),
          .Reset_n(Reset_n),
          .Led(Led)
    );
    
    initial Clk = 1;
    always #10 Clk = !Clk;
    
    initial begin
       Reset_n = 0;
       #201;
       Reset_n = 1;
       #2000000000;
       $stop;
    end

endmodule

仿真

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

设计

module counter_led_2(
    Clk,
    Reset_n,
    Ctrl,
    Led
);
    
    input Clk;
    input Reset_n;
    input [7:0]Ctrl;
    output reg[7:0] Led;
    
    reg [26:0]counter;
    parameter MCNT = 100000000;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter <= 0;
    else if(counter == MCNT -1)
        counter <= 0;
    else 
        counter <= counter + 1'b1;
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        Led <= 0;
    else if(counter == MCNT/8 -1)
        Led <= Ctrl[0];
    else if(counter == MCNT*2/8 -1)
        Led <= Ctrl[1];  
    else if(counter == MCNT*3/8 -1)
        Led <= Ctrl[2];
    else if(counter == MCNT*4/8 -1)
        Led <= Ctrl[3];      
    else if(counter == MCNT*5/8 -1)
        Led <= Ctrl[4];
    else if(counter == MCNT*6/8 -1)
        Led <= Ctrl[5];  
    else if(counter == MCNT*7/8 -1)
        Led <= Ctrl[6];
    else if(counter == MCNT*8/8 -1)
        Led <= Ctrl[7];     
             
endmodule

测试

`timescale 1ns / 1ns

module counter_led_2_tb;

     reg Clk;
     reg Reset_n;
     reg [7:0]Ctrl;
     wire Led;
     
     counter_led_2 
     #(
          .MCNT(100000)
     )
     counter_led_2_inst0(
         .Clk(Clk),
         .Reset_n(Reset_n),
         .Ctrl(Ctrl),
         .Led(Led)
     );
     
     initial Clk =1;
     always #10 Clk = !Clk;
     
     initial begin
         Reset_n = 0;
         Ctrl = 0;
         #201;
         Reset_n =1;
         #2000;
         Ctrl = 8'b1000_0110;
         #2000000000;
         $stop;
     end
        
endmodule

仿真

2024.03.04

串口通信发送

通用异步收发传输器(UART)是一种异步收发传输器,其在数据发送时将并行数据转换成串行数据来传输,在数据接收时将接收到的串行数据转换成并行数据,可以实现全双工传输和接收。

最常见类型:数据位数、波特率大小、奇偶校验类型和停止位数。

最常见的配置是8N1。

按照一个完整的字节包括一位起始位、8 位数据位、一位停止位即总共十位数据来算,

要想完整的实现这十位数据的发送,就需要 11 个波特率时钟脉冲,第 1 个脉冲标记一次传

输的起始,第11 个脉冲标记一次传输的结束,如下所示:

2024.03.07

DDS

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值