FPGA开发入门:盘古1K按键控制LED实验详解

📅 2026/7/17 6:41:29 👁️ 阅读次数 📝 编程学习
FPGA开发入门:盘古1K按键控制LED实验详解

1. 盘古1K开发板按键控制LED实验概述

盘古1K开发板作为国产FPGA学习的热门平台,其板载资源设计充分考虑了初学者的实操需求。本次实验聚焦最基础的GPIO控制场景——通过按键控制LED灯状态变化,这是嵌入式开发入门的"Hello World"级实验,但其中蕴含着硬件设计的关键思维模式。

开发板上的LED和按键通常采用共阳极或共阴极设计。根据紫光同创PGC系列开发套件的设计惯例,盘古1K很可能采用共阳极连接(LED阳极通过限流电阻接VCC,阴极接IO口)。这意味着当IO口输出低电平时LED点亮,高电平时熄灭。按键则通常采用上拉设计,未按下时IO口检测到高电平,按下时通过接地变为低电平。

注意:实际操作前务必查阅开发板原理图确认具体电路设计,错误的电平假设会导致实验失败。部分开发板可能设计有防反接保护电路,这会影响IO口的驱动能力计算。

2. 实验环境搭建与工程创建

2.1 开发工具链准备

使用Pango Design Suite(PDS)进行开发,这是紫光同创官方推出的FPGA开发环境。建议安装最新稳定版本(当前为PDS 2022.1),安装时需注意:

  • 选择完整安装以获取所有器件支持
  • 安装USB驱动以保证开发板识别
  • 配置License文件(社区版有功能限制)

2.2 新建工程关键步骤

  1. 创建新工程时选择正确的器件型号:PGC1KG-LPG100
  2. 设置顶层模块名为key_led_ctrl
  3. 添加约束文件时选择"Create File Later",后续需手动编写IO约束
// 示例:顶层模块框架代码 module key_led_ctrl( input wire clk, // 系统时钟 input wire rst_n, // 复位信号(低有效) input wire key_in, // 按键输入 output reg led_out // LED输出 ); // 功能代码将在此添加 endmodule

3. 硬件电路设计与信号处理

3.1 按键消抖实现方案

机械按键存在5-10ms的抖动现象,必须进行消抖处理。推荐两种实现方式:

方案一:硬件消抖

按键 -- 10k上拉电阻 --+-- 100nF电容 -- GND | IO口

成本低但占用PCB面积,适合固定电路设计。

方案二:软件消抖(推荐)采用状态机实现,Verilog代码示例:

localparam DEBOUNCE_CNT = 20'd500000; // 10ms@50MHz always @(posedge clk or negedge rst_n) begin if(!rst_n) begin key_stable <= 1'b1; key_cnt <= 20'd0; end else begin if(key_raw != key_stable) begin key_cnt <= key_cnt + 1; if(key_cnt == DEBOUNCE_CNT) begin key_stable <= key_raw; key_cnt <= 20'd0; end end else begin key_cnt <= 20'd0; end end end

3.2 LED驱动电路设计

典型LED驱动参数计算:

  • 红色LED正向压降:≈2V
  • 工作电流:5-10mA
  • 限流电阻计算:(VCC - Vf)/I = (3.3V-2V)/0.01A = 130Ω

实测技巧:使用万用表测量实际LED压降,不同颜色LED的Vf差异较大。蓝色/白色LED通常需要3V以上驱动电压。

4. Verilog代码实现与优化

4.1 基础功能实现

实现按键按下时LED亮,松开时灭:

always @(posedge clk or negedge rst_n) begin if(!rst_n) led_out <= 1'b1; // 初始熄灭 else led_out <= ~key_stable; // 按键低有效,LED低电平点亮 end

4.2 状态切换进阶实现

增加状态切换功能(按一次亮,再按一次灭):

reg led_state; always @(posedge clk or negedge rst_n) begin if(!rst_n) begin led_state <= 1'b0; led_out <= 1'b1; end else if(key_stable_fall) begin // 检测按键下降沿 led_state <= ~led_state; led_out <= ~led_state; end end

4.3 边缘检测技巧

可靠的状态切换需要精确的边缘检测:

reg [1:0] key_sync; always @(posedge clk) key_sync <= {key_sync[0], key_stable}; wire key_stable_rise = (key_sync == 2'b01); wire key_stable_fall = (key_sync == 2'b10);

5. 约束文件编写与下载验证

5.1 IO约束文件示例

创建.pdc约束文件,根据原理图分配管脚:

# 系统时钟 50MHz set_pin_assignment { clk } { LOCATION = R7; IOSTANDARD = LVCMOS33; } # 复位按键(开发板已带上拉) set_pin_assignment { rst_n } { LOCATION = T7; IOSTANDARD = LVCMOS33; PULLTYPE = PULLUP; } # 用户按键K1 set_pin_assignment { key_in } { LOCATION = M5; IOSTANDARD = LVCMOS33; PULLTYPE = PULLUP; } # LED D1 set_pin_assignment { led_out } { LOCATION = E5; IOSTANDARD = LVCMOS33; DRIVESTRENGTH = 8; }

5.2 下载调试常见问题

  1. 编程器无法识别

    • 检查USB驱动安装
    • 尝试更换USB线(需支持数据传输)
    • 确认开发板供电正常(电源指示灯亮)
  2. LED不响应按键

    • 用示波器检查按键信号是否到达FPGA管脚
    • 验证约束文件中的管脚编号是否正确
    • 检查代码中信号名是否与约束文件一致
  3. LED亮度异常

    • 测量LED两端电压确认驱动能力
    • 检查约束文件中DRIVESTRENGTH设置
    • 确认没有多个输出信号短路到同一LED

6. 扩展实验与进阶思考

6.1 多按键组合控制

实现两个按键控制LED的不同模式:

  • K1:切换开关状态
  • K2:长按调节亮度(PWM控制)

PWM生成代码片段:

reg [7:0] pwm_cnt; reg [7:0] duty_cycle; always @(posedge clk) pwm_cnt <= pwm_cnt + 1; always @(posedge clk) begin if(key2_pressed_long) begin if(duty_cycle < 8'd255) duty_cycle <= duty_cycle + 1; end end assign led_out = (pwm_cnt < duty_cycle) ? 1'b0 : 1'b1;

6.2 状态机设计优化

使用Moore型状态机实现复杂控制逻辑:

typedef enum logic [1:0] { LED_OFF, LED_ON, LED_BLINK_SLOW, LED_BLINK_FAST } led_state_t; led_state_t current_state, next_state; // 状态转移逻辑 always @(posedge clk) begin case(current_state) LED_OFF: if(key_press) next_state = LED_ON; LED_ON: if(key_press) next_state = LED_BLINK_SLOW; // ...其他状态转移 endcase end

6.3 时序约束分析

添加时序约束保证可靠性:

create_clock -name clk -period 20 [get_ports clk] set_input_delay -clock clk 2 [get_ports key_in] set_output_delay -clock clk 1 [get_ports led_out]

在完成基础实验后,可以尝试将工程移植到其他兼容开发板(如粤嵌GEC6818),注意不同平台的时钟频率、IO电压等参数差异。实际项目中,这种按键LED控制逻辑可扩展为设备状态指示、用户输入检测等实用功能。