FPGA 与单片机的区别
刚接触硬件的同学常问:这货和单片机有啥区别?简单来说,**FPGA(Field Programmable Gate Array)**就像一张白纸,你可以用硬件描述语言(比如 Verilog)在上面'画'出任意数字电路。
单片机是现成的芯片(固定架构),而 FPGA 允许你从底层构建电路。打个比方:单片机是组装好的乐高套装,FPGA 就是一堆零散的积木块,想拼成飞机还是坦克全看你的代码怎么写。这也是它被称为'数字电路橡皮泥'的原因。
开发环境准备
工具安装
去 Xilinx 官网下载 Vivado Design Suite(社区版免费)。建议选 2020.1 之后的版本,对新手更友好。安装时记得勾选"Vivado HL Design Edition"和对应器件支持(比如 Artix-7 系列)。
硬件选择
推荐先用在线仿真器练手,等基础扎实了再入手开发板。常见的入门型号有 Nexys A7、Basys3 或 DE10-Nano(带 ARM 双核)。
工程创建
打开 Vivado → Create Project → 选择 RTL Project → 添加新 Verilog 文件。关键点:器件型号选 xc7a35tcsg324-1,这对应多数入门开发板的芯片。
Verilog 核心语法速览
写 FPGA 代码离不开几个核心概念,不用死记硬背,理解它们的作用更重要:
// 基础结构模板
module my_module(
input wire clk, // 时钟信号
input wire rst_n, // 复位信号(低有效)
output reg led // LED 输出
);
// 组合逻辑用 assign
assign a = b & c;
// 时序逻辑用 always 块
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
led <= 1'b0; // 复位时 LED 灭
else
led <= ~led; // 翻转 LED 状态
end
endmodule
这里有两个重点:
- wire vs reg:线网用于组合逻辑连接,寄存器用于存储状态。
- always 块:这是时序逻辑的核心,通常配合
posedge(上升沿)使用。
实战:LED 流水灯
代码实现
我们要实现一个效果:100MHz 时钟分频后,让 4 个 LED 循环流动。核心在于分频器和移位逻辑。
module led_run(
input clk_100MHz, // 开发板上的 100MHz 时钟
input rst_n, // 复位按键(低电平有效)
output reg [3:0] leds // 4 位 LED 输出
);
// 分频器:100MHz -> 1Hz
reg [26:0] counter;
always @(posedge clk_100MHz or negedge rst_n) begin
if(!rst_n)
counter <= 0;
else
counter <= (counter == 27'd99_999_999) ? 0 : counter + 1;
end
// LED 流水效果
always @(posedge clk_100MHz or negedge rst_n) begin
if(!rst_n)
leds <= 4'b0001; // 初始状态
else if(counter == 27'd99_999_999)
leds <= {leds[2:0], leds[3]}; // 循环左移
end
endmodule
注意这里的分频逻辑:计数器数到 99,999,999 归零,相当于 1 秒一次脉冲。移位操作 {leds[2:0], leds[3]} 实现了循环左移的效果。
仿真测试
在烧录前,务必用 Modelsim 跑一下 Testbench,确认时序无误。
`timescale 1ns / 1ps
module tb_led_run();
reg clk, rst_n;
wire [3:0] leds;
// 实例化被测模块
led_run uut(.clk_100MHz(clk), .rst_n(rst_n), .leds(leds));
// 生成时钟信号
initial begin
clk = 0;
forever #5 clk = ~clk; // 100MHz 周期=10ns
end
// 测试流程
initial begin
rst_n = 0;
#100;
rst_n = 1;
#200000000; // 等待 2 秒(仿真时间)
$stop;
end
endmodule


