当前位置:   article > 正文

FPGA基础自学流程_fpga入门教程

fpga入门教程

目录

一、Quartus II与 Modelsim 软件安装与破解

二、完成基础电路仿真

1、组合逻辑电路

(1)、基本的与或非门电路仿真与基本的加减乘除仿真

(2)、半加器和全加器

(3)、编码器 和 译码器

(5)、数据选择器(二选一)

2、时序逻辑电路

 (1)、寄存器 和 移位寄存器

(2)、计数器(十进制 / 二十四进制 / 六十进制)

(3)、分频器(二分频 / 十分频)

3、状态机


一、Quartus II与 Modelsim 软件安装与破解

(备注:如果芯片是EP2XXX那么对应编程使用Cyclone II或以下版本,该版本只在Quartus13.0及以下版本支持使用,而EP4XXX及以上可适用Quartus13.0及以上版本。)

Quartus13.0安装包链接:

http://链接:https://pan.baidu.com/s/1TvCEyduApTvVlgcFJO9h_g    提取码:6666.

Quartus13.0安装教程链接:

https://blog.csdn.net/pang9998/article/details/83447190

Quartus18.0安装包及教程链接:

https://mp.weixin.qq.com/s/m1sFpNMR79V0Mk81axJ22Q

二、完成基础电路仿真

1、组合逻辑电路

(1)、基本的与或非门电路仿真与基本的加减乘除仿真

电路原件图(加减乘除不在其中):

代码:

  1. //与门
  2. module door(
  3. input in1,
  4. input in2,
  5. output out
  6. );
  7. //连续赋值(逻辑描述)
  8. assign out = in1 & in2;
  9. //位置调用(结构描述)
  10. // and (out, in1, in2);
  11. endmodule
  12. //或门
  13. module door(
  14. input in1,
  15. input in2,
  16. output out
  17. );
  18. //连续赋值(逻辑描述)
  19. assign out = in1 | in2;
  20. //位置调用(结构描述)
  21. // or (out, in1, in2);
  22. endmodule
  23. //非门
  24. module door(
  25. input in,
  26. output out
  27. );
  28. //连续赋值(逻辑描述)
  29. assign out = ~ in;
  30. //位置调用(结构描述)
  31. // not (out, in1);
  32. endmodule
  33. //除此之外还有“nor”异或 “xnor”同或
  34. //加减乘除
  35. module door(
  36. input in1,
  37. input in2,
  38. output out
  39. );
  40. assign out = in1 + in2; //1+1=0,1+0=1
  41. assign out = in1 - in2; //0-1=1,1-1=0
  42. assign out = in1 * in2; //0*1=0,1*1=1
  43. assign out = in1 / in2; //1/1=1,当in1=1,in2=0和in1=0,in2=0时出现1/2
  44. endmodule

(2)、半加器和全加器

设计思路参考链接:

https://wuzhikai.blog.csdn.net/article/details/124116237

  • 半加器

半加器是一种将两个一位二进制相加,并对应输出“结果”和“进位”的加法器运算电路。

主代码:

  1. //半加器
  2. module add(
  3. input in1, //加数1
  4. input in2, //加数2
  5. output sum, //两个数的加和
  6. output cout //加数和的进位
  7. );
  8. //第一种方式
  9. assign sum = in1 ^ in2;
  10. assign cout = in1 & in2;
  11. //第二种方式
  12. assign {cout, sum} = in1 + in2;
  13. endmodule

Testbench仿真代码:

  1. `timescale 1ns/1ns
  2. module sim_add();
  3. //输入reg定义
  4. reg in1, in2;
  5. //输出wire定义
  6. wire cout, sum;
  7. //给初始信号
  8. initial begin
  9. in1<=1'b0;
  10. in2<=1'b0;
  11. end
  12. //↓写成令每10ns,产生一次随机输入
  13. always #10 in1<= {$random} %2; //每10个时钟周期产生1个随机数
  14. always #10 in2<= {$random} %2;
  15. //创建模块
  16. add adder(
  17. .in1(in1),
  18. .in2(in2),
  19. .sum(sum),
  20. .cout(cout)
  21. );
  22. endmodule

其仿真电路图(从左到右分别是第一种和第二种):

 ModelSim仿真波形:

全加器是一种可以对两个一位二进制数据进行相加,并输出“结果”、“进位”和“低位进位”的一种器件。

主代码:

  1. module add(
  2. input in1, //加数1
  3. input in2, //加数2
  4. input cin, //低位向高位的进位
  5. output sum, //两个数的加和
  6. output cout //加数和的进位
  7. );
  8. assign {cout, sum} = in1 + in2 + cin;
  9. endmodule

Testbench仿真代码:

  1. `timescale 1ns/1ns
  2. module sim_add();
  3. //输入reg定义
  4. reg in1, in2, cin;
  5. //输出wire定义
  6. wire cout, sum;
  7. //给初始信号
  8. initial begin
  9. in1<=1'b0;
  10. in2<=1'b0;
  11. cin<=1'b0;
  12. end
  13. //↓写成令每10ns,产生一次随机输入
  14. always #10 in1<= {$random} %2; //每10个时钟周期产生1个随机数
  15. always #10 in2<= {$random} %2;
  16. always #10 cin<= {$random} %2;
  17. //创建模块
  18. add adder(
  19. .in1(in1),
  20. .in2(in2),
  21. .cin(cin),
  22. .sum(sum),
  23. .cout(cout)
  24. );
  25. endmodule

仿真电路图:

ModelSim仿真波形:

 

(3)、编码器 和 译码器

  • 编码器

编码器是一种可以将少位输入信号转换为特定多位编码的器件。

8-3编码器设计参考链接:

https://blog.csdn.net/Ding_ding_fly/article/details/54882615?ops_request_misc=&request_id=&biz_id=102&utm_term=8-3%E7%BC%96%E7%A0%81%E5%99%A8&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-54882615.142^v47^pc_rank_34_1,201^v3^control_2&spm=1018.2226.3001.4187

主代码:

  1. //8-3编码器
  2. module encode_decode(
  3. input [7:0]in,
  4. output reg [2:0]out
  5. );
  6. always @(*) begin
  7. case (in)
  8. 8'b00000001: out = 3'b000;
  9. 8'b00000010: out = 3'b001;
  10. 8'b00000100: out = 3'b010;
  11. 8'b00001000: out = 3'b011;
  12. 8'b00010000: out = 3'b100;
  13. 8'b00100000: out = 3'b101;
  14. 8'b01000000: out = 3'b110;
  15. 8'b10000000: out = 3'b111;
  16. endcase
  17. end
  18. endmodule

Testbench仿真代码:

  1. `timescale 1ns/1ns
  2. module sim_encode_decode();
  3. //输入reg定义
  4. reg [7:0]in;
  5. //输出wire定义
  6. wire [2:0]out;
  7. //给初始信号
  8. initial begin
  9. in[0] = 1;in[1] = 0;in[2] = 0;in[3] = 0;
  10. in[4] = 0;in[5] = 0;in[6] = 0;in[7] = 0;
  11. #100;
  12. in= in << 1;
  13. #100;
  14. in= in << 1;
  15. #100;
  16. in= in << 1;
  17. end
  18. //创建模块
  19. encode_decode encode(
  20. .in(in[7:0]),
  21. .out(out[2:0])
  22. );
  23. endmodule

仿真电路图(部分展示):

ModelSim仿真波形:

  • 译码器(包含3-8译码器和数码管译码器)

译码器是一种可以将少位输入信号转换为特定多位编码的器件。

设计参考链接:

https://blog.csdn.net/quanqueen/article/details/113094663

>3-8译码器主代码:

  1. //3-8译码器
  2. module encode_decode(
  3. input [2:0]in,
  4. output reg [7:0]out
  5. );
  6. always @(*) begin
  7. case (in)
  8. 3'b000: out = 8'b00000001;
  9. 3'b001: out = 8'b00000010;
  10. 3'b010: out = 8'b00000100;
  11. 3'b011: out = 8'b00001000;
  12. 3'b100: out = 8'b00010000;
  13. 3'b101: out = 8'b00100000;
  14. 3'b110: out = 8'b01000000;
  15. 3'b111: out = 8'b10000000;
  16. endcase
  17. end
  18. endmodule

Testbench仿真代码:

  1. `timescale 1ns/1ns
  2. module sim_encode_decode();
  3. //输入reg定义
  4. reg [2:0]in;
  5. //输出wire定义
  6. wire [7:0]out;
  7. //给初始信号
  8. initial in<=3'b0;
  9. //↓写成令每10ns,产生一次随机输入
  10. always #10 in<= {$random} %2;
  11. //创建模块
  12. encode_decode decode(
  13. .in(in[2:0]),
  14. .out(out[7:0])
  15. );
  16. endmodule

仿真电路图:

ModelSim仿真波形:

数码管译码器

数码管译码器是一种转门对于数码管显示的译码器。

设计参考链接:

https://blog.csdn.net/weixin_63090979/article/details/121106854

>数码管译码器主代码:

  1. //数码管编码器(共阳极)
  2. module ni_tub_dec(
  3. input [3:0]in,
  4. output reg [7:0]out
  5. );
  6. always @(*) begin
  7. case (in)
  8. 4'b0000: out = 8'b1100_0000;
  9. 4'b0001: out = 8'b1111_1001;
  10. 4'b0010: out = 8'b1010_0100;
  11. 4'b0011: out = 8'b1011_0000;
  12. 4'b0100: out = 8'b1001_1001;
  13. 4'b0101: out = 8'b1000_0010;
  14. 4'b0110: out = 8'b1100_0000;
  15. 4'b0111: out = 8'b1111_1000;
  16. 4'b1000: out = 8'b1000_0000;
  17. 4'b1001: out = 8'b1001_0000;
  18. endcase
  19. end
  20. endmodule

Testbench仿真代码:

  1. `timescale 1ns/1ns
  2. module sim_ni_tub_dec();
  3. //输入reg定义
  4. reg [3:0]in;
  5. //输出wire定义
  6. wire [7:0]out;
  7. //给初始信号
  8. initial begin
  9. in = 4'd0;
  10. #100;
  11. in = 4'd1;
  12. #100;
  13. in = 4'd2;
  14. #100;
  15. in = 4'd3;
  16. #100;
  17. in = 4'd4;
  18. #100;
  19. in = 4'd5;
  20. #100;
  21. in = 4'd6;
  22. #100;
  23. in = 4'd7;
  24. #100;
  25. in = 4'd8;
  26. #100;
  27. in = 4'd9;
  28. #100;
  29. $stop;
  30. end
  31. //创建模块
  32. ni_tub_dec decode(
  33. .in(in[3:0]),
  34. .out(out[7:0])
  35. );
  36. endmodule

仿真电路图:

ModelSim仿真波形:

(5)、数据选择器(二选一)

数据选择器是一种根据选择位输出的相应信号的器件。

设计参考链接:

https://blog.csdn.net/hyhop150/article/details/51222711

主代码:

  1. //二选一数据选择器
  2. module dat_sel(
  3. input in1,
  4. input in2,
  5. input sel,
  6. output out
  7. );
  8. assign out = sel? in1:in2 ;
  9. endmodule

Testbench仿真代码:

  1. `timescale 1ns/1ns
  2. module sim_dat_sel();
  3. //输入reg定义
  4. reg in1, in2, sel;
  5. //输出wire定义
  6. wire out;
  7. //给初始信号
  8. initial begin
  9. in1 <= 0;in2 <= 1;sel <= 0;
  10. #100
  11. in1 <= 1;in2 <= 0;sel <= 0;
  12. #100
  13. in1 <= 0;in2 <= 1;sel <= 1;
  14. #100
  15. in1 <= 1;in2 <= 0;sel <= 1;
  16. #100
  17. $stop;
  18. end
  19. //创建模块
  20. dat_sel selector(
  21. .in1(in1),
  22. .in2(in2),
  23. .sel(sel),
  24. .out(out)
  25. );
  26. endmodule

仿真电路图:

ModelSim仿真波形:

2、时序逻辑电路

 (1)、寄存器 和 移位寄存器

  • 寄存器

由时钟边沿触发的一种用于寄存数据的器件。

 寄存器设计参考链接:

https://blog.csdn.net/cjx_csdn/article/details/105203494

主代码:

  1. //基本寄存器
  2. module rag_srag(
  3. input in,
  4. input clk,
  5. output reg out
  6. );
  7. always @(posedge clk) begin
  8. out = in;
  9. end
  10. endmodule

Testbench仿真代码:

  1. //基本寄存器
  2. `timescale 1ns/1ns
  3. module sim_rag_srag();
  4. //输入reg定义
  5. reg clk, in;
  6. //输出wire定义
  7. wire out;
  8. //给初始信号
  9. initial begin
  10. in <= 0;clk <= 1;
  11. #50
  12. in <= 1;clk <= 1;
  13. #50
  14. in <= 0;clk <= 0;
  15. #50
  16. in <= 1;clk <= 0;
  17. #50
  18. $stop;
  19. end
  20. //创建模块
  21. rag_srag rag(
  22. .in(in),
  23. .clk(clk),
  24. .out(out)
  25. );
  26. endmodule

仿真电路图:

ModelSim仿真波形:

  • 移位寄存器

由时钟边沿触发,且会将寄存数据左移右移的一种寄存器。

设计参考链接:

https://reborn.blog.csdn.net/article/details/80377919

主代码:

  1. //移位寄存器(右)
  2. module rag_srag(
  3. input clk,
  4. input [15:0]in,
  5. output reg [15:0]out
  6. );
  7. always @(posedge clk) begin
  8. out = {in[0], in[15:1]};
  9. end
  10. endmodule

Testbench仿真代码:

  1. //移位寄存器(16位)
  2. `timescale 1ns/1ns
  3. module sim_rag_srag();
  4. //输入reg定义
  5. reg clk;
  6. reg [15:0]in;
  7. //输出wire定义
  8. wire [15:0]out;
  9. always #50 clk = ~clk;
  10. //给初始信号
  11. initial begin
  12. in =16'b0;clk = 1;
  13. #50
  14. in =16'b0000_0000_0000_0001;
  15. #50
  16. in =16'b1100_0000_0000_0011;
  17. #50
  18. in =16'b0011_0000_0000_1111;
  19. #50
  20. in =16'b0011_0000_0011_1111;
  21. #50
  22. in =16'b0011_0110_0000_1000;
  23. #50
  24. $stop;
  25. end
  26. //创建模块
  27. rag_srag srag(
  28. .in(in[15:0]),
  29. .clk(clk),
  30. .out(out[15:0])
  31. );
  32. endmodule

仿真电路图:

ModelSim仿真波形:

(2)、计数器(十进制 / 二十四进制 / 六十进制)

主要通过时钟的边沿信号触发计数的一种器件。

设计参考链接:

https://blog.csdn.net/weixin_43758368/article/details/101517017

主代码:

  1. //计数器(四位十进制)
  2. //无输入,内定一个寄存器进行时钟上升沿计数,最后通过输出反映出来
  3. module counter(
  4. input clk,rst, //时钟,复位
  5. output [3:0]out
  6. );
  7. reg [3:0]q;
  8. assign out = q;
  9. always @(posedge clk)
  10. begin
  11. if(rst==0)
  12. q = 0;
  13. else if(q>=4'd9)
  14. q = 0;
  15. else
  16. q = q + 1;
  17. end
  18. endmodule
  19. //计数器(五位二十四进制)
  20. module counter(
  21. input clk,rst, //时钟,复位
  22. output [4:0]out
  23. );
  24. reg [4:0]q;
  25. assign out = q;
  26. always @(posedge clk)
  27. begin
  28. if(rst==0)
  29. q = 0;
  30. else if(q>=5'd24)
  31. q = 0;
  32. else
  33. q = q + 1;
  34. end
  35. endmodule
  36. //计数器(五位二十四进制)
  37. module counter(
  38. input clk,rst, //时钟,复位
  39. output [5:0]out
  40. );
  41. reg [5:0]q;
  42. assign out = q;
  43. always @(posedge clk)
  44. begin
  45. if(rst==0)
  46. q = 0;
  47. else if(q>=6'd60)
  48. q = 0;
  49. else
  50. q = q + 1;
  51. end
  52. endmodule

Testbench仿真代码:

  1. //计数器(十进制)
  2. `timescale 1ns/1ns
  3. module sim_counter();
  4. //十进制定义
  5. reg clk, rst;
  6. wire [3:0]out;
  7. //二十四进制定义
  8. reg clk, rst;
  9. wire [4:0]out;
  10. //六十进制定义
  11. reg clk, rst;
  12. wire [5:0]out;
  13. always #5 clk <= ~clk;
  14. //给初始信号
  15. initial begin
  16. clk <= 0;rst <= 0;
  17. #10;
  18. rst <= 1;
  19. end
  20. //十进制模块
  21. counter coun10(
  22. .rst(rst),
  23. .clk(clk),
  24. .out(out[3:0])
  25. );
  26. //二十四进制模块
  27. counter coun24(
  28. .rst(rst),
  29. .clk(clk),
  30. .out(out[4:0])
  31. );
  32. //六十进制模块
  33. counter coun60(
  34. .rst(rst),
  35. .clk(clk),
  36. .out(out[5:0])
  37. );
  38. endmodule

仿真电路图:

(十进制)

(二十四进制)

(六十进制)

 ModelSim仿真波形(例六十进制):

(3)、分频器(二分频 / 十分频)

用于通过原有的高时钟频率信号,生成低时钟频率信号的器件。

设计参考链接:

https://blog.csdn.net/supenman_mwg/article/details/7654141

主代码(二分频 / 十分频):

  1. //二分频
  2. //使用复位仿照时钟由边沿改变输出信号,配合着原本的时钟,这就形成了二分的频率
  3. module fre_div(
  4. input clk,rst, //时钟,复位
  5. output out_clk
  6. );
  7. reg q;
  8. assign out_clk = q;
  9. always @(posedge clk, posedge rst)
  10. begin
  11. if(rst==1)
  12. q = 0;
  13. else
  14. q = ~q;
  15. end
  16. endmodule
  17. //十分频
  18. //需要定义一个计数器,计五个二分频
  19. module fre_div(
  20. input clk,rst, //时钟,复位
  21. output out_clk
  22. );
  23. parameter N = 5;
  24. reg [N-1:0]cnt; //计数器
  25. reg q;
  26. assign out_clk = q;
  27. always @(posedge clk, posedge rst) begin
  28. if(rst==1) begin
  29. q <= 0;
  30. cnt <= 0;
  31. end
  32. else begin
  33. if(cnt>=N-1)begin
  34. q <= ~q;
  35. cnt <= 0;
  36. end
  37. else begin
  38. cnt <= cnt + 1;
  39. end
  40. end
  41. end
  42. endmodule

Testbench仿真代码:

  1. //二分频/十分频
  2. `timescale 1ns/1ns
  3. module sim_fre_div();
  4. reg clk, rst;
  5. wire out_clk;
  6. always #20 clk <= ~clk;
  7. //给初始信号
  8. initial begin
  9. clk=0;rst=1;
  10. #24 rst =0;
  11. end
  12. fre_div divider2(
  13. .rst(rst),
  14. .clk(clk),
  15. .out_clk(out_clk)
  16. );
  17. endmodule

仿真电路图:

(二分频)

(十分频)

ModelSim仿真波形:

(二分频)

(十分频)

3、状态机

状态机,全称是有限状态机,是一种在有限个状态之间按一定规律转换的时序电路,可以认为是组合逻辑和时序逻辑的一种组合。
➢ Mealy状态机:组合逻辑的输出不仅取决于当前状态,还取决于输入状态。
➢ Moore状态机:组合逻辑的输出只取决于当前状态。
 

 状态机设计参考链接:

https://wuzhikai.blog.csdn.net/article/details/119421783

主代码:

  1. /**********<三段式状态机>*************/
  2. //特点:在二段的基础上,再次细分,将输出的状态分离,形成划分明确的状态机
  3. //------"摩尔型"-----//
  4. //三段米勒型写法,同上段与摩尔的关系写法一样
  5. module sta_mac(
  6. input clk, //时钟信号
  7. input rst, //复位信号(低电平有效)
  8. input money, //投币信号(高电平有效)
  9. output reg cola //可乐信号(高电平为出可乐)
  10. );
  11. //独热码定义(状态参数)
  12. localparam Init = 4'b0001,
  13. One_cin = 4'b0010,
  14. Two_cin = 4'b0100,
  15. There_cin= 4'b1000;
  16. reg [3:0] curr_sta; //现态
  17. reg [3:0] next_sta; //次态(相当于一个中间传递数据的寄存器)
  18. //***第一段:同步时序"状态转移"
  19. always @(posedge clk, negedge rst) begin
  20. if(!rst)
  21. curr_sta <= Init; //回到初始
  22. else
  23. curr_sta <= next_sta; //向现态传递次态数据
  24. end
  25. //***第二段:组合逻辑状态"转移条件"
  26. always @(*) begin
  27. case (curr_sta) // 依据现态情况转移状态
  28. Init: begin //初始状态
  29. if(money)
  30. next_sta <= One_cin;
  31. else
  32. next_sta <= Init;
  33. end
  34. One_cin: begin //一个硬币状态
  35. if(money)
  36. next_sta <= Two_cin;
  37. else
  38. next_sta <= One_cin;
  39. end
  40. Two_cin: begin //二个硬币状态
  41. if(money)
  42. next_sta <= There_cin;
  43. else
  44. next_sta <= Two_cin;
  45. end
  46. There_cin: begin //三个硬币状态
  47. if(money)
  48. next_sta <= One_cin;
  49. else
  50. next_sta <= Init;
  51. end
  52. default: begin //其他情况,同初始状态
  53. if(money)
  54. next_sta <= One_cin;
  55. else
  56. next_sta <= Init;
  57. end
  58. endcase
  59. end
  60. //***第三段:各个"状态对应的输出情况"
  61. always @(posedge clk, negedge rst) begin
  62. if(!rst)
  63. cola <= 1'b0;
  64. else
  65. case (curr_sta)
  66. Init: cola <= 1'b0;
  67. One_cin: cola <= 1'b0;
  68. Two_cin: cola <= 1'b0;
  69. There_cin: cola <= 1'b1;
  70. default: cola <= 1'b0;
  71. endcase
  72. end
  73. endmodule

Testbench仿真代码:

  1. //状态机仿真代码
  2. `timescale 1ns/1ns
  3. module sim_sta_mac();
  4. reg clk; //时钟信号
  5. reg rst; //复位信号
  6. reg money; //投币信号
  7. wire cola; //可乐信号
  8. //建立模块
  9. sta_mac machin_1duan(
  10. .money(money),
  11. .rst(rst),
  12. .clk(clk),
  13. .cola(cola)
  14. );
  15. //给初始信号
  16. initial begin
  17. clk = 1'b0; //初始时钟为0
  18. rst <= 1'b0; //初始复位
  19. money <= 1'b0; //投币初始化为0
  20. #5
  21. rst <= 1'b1; //拉高复位,系统进入工作状态
  22. #25
  23. money <= 1'b1; //拉高投币信号(投币)
  24. #40
  25. money <= 1'b0; //拉低投币信号(不投币)
  26. #20
  27. money <= 1'b1; //拉高投币信号(投币)
  28. #80
  29. money <= 1'b0; //拉低投币信号(不投币)
  30. end
  31. //给时钟信号
  32. always #10 clk <= ~clk;
  33. //状态名称查看器(看不了)
  34. /*reg [71:0] state_name;
  35. always @(*) begin
  36. case (machin_1duan.state)
  37. 4'b0001: state_name = "Init";
  38. 4'b0010: state_name = "One_cin";
  39. 4'b0100: state_name = "Two_cin";
  40. 4'b1000: state_name = "There_cin";
  41. default: state_name = "Init";
  42. endcase
  43. end*/
  44. endmodule

状态图:

仿真电路图:

ModelSim仿真波形:

四、最后一步,也就是上FPGA板做仿真实验

上板实验进阶可以于B站搜索:野火FPGA

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/903175
推荐阅读
相关标签
  

闽ICP备14008679号