OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 76|回复: 1

[XILINX] 其他功能正常,流水灯的代码无法正常运行,但找不到问题感觉很奇怪,求大佬指点!

[复制链接]

1

主题

1

帖子

0

精华

新手入门

积分
4
金钱
4
注册时间
2025-11-16
在线时间
0 小时
发表于 12 小时前 | 显示全部楼层 |阅读模式
1金钱
源码如下breath_led.v:

// 呼吸灯控制模块:PWM占空比线性增减实现呼吸效果
// 功能:KEY1减慢双灯呼吸速度,KEY2加快双灯呼吸速度,3次调整后重置
module breath_led(
    input                  clk,          // 50MHz时钟
    input                  rst_n,        // 低电平复位
    input                  mode_en,      // 模式使能(高电平有效)
    input                  key1_press,   // key1按下(减慢双灯速度)
    input                  key2_press,   // key2按下(加快双灯速度)
    output reg             led1_out,     // LED1输出
    output reg             led2_out      // LED2输出
);

// 参数定义
parameter CLK_FREQ    = 50_000_000;  // 50MHz时钟
parameter STEP_NUM    = 1000;         // 占空比步长数(精度1/1000)
// 3档呼吸速度:步长时间(时钟周期数)→ 步长时间越长,呼吸越慢
localparam SPEED_STEP_SLOW  = CLK_FREQ * 3 / STEP_NUM;  // 慢档(3秒呼吸周期)
localparam SPEED_STEP_MID   = CLK_FREQ * 2 / STEP_NUM;  // 中档(2秒呼吸周期,初始)
localparam SPEED_STEP_FAST  = CLK_FREQ * 1 / STEP_NUM;  // 快档(1秒呼吸周期)

// 内部信号
reg [1:0] speed_cnt;     // 双灯共用速度档位计数器(0:中档,1:快档,2:慢档)
reg [31:0] step_timer;   // 双灯共用步长定时器(控制占空比变化速度)
reg [9:0] duty_cycle1;   // LED1占空比(0~STEP_NUM-1)
reg [9:0] duty_cycle2;   // LED2占空比(与LED1同步,保证双灯一致)
reg dir;                 // 占空比变化方向(0:增加,1:减少)
reg [9:0] pwm_cnt;       // PWM载波计数器(0~STEP_NUM-1)

// 1. 速度档位控制(KEY1减慢,KEY2加快,3次后重置)
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        speed_cnt <= 2'd0;  // 复位后默认中档(2秒周期)
    end else if(mode_en) begin
        // KEY2按下:加快速度(0→1→2→0,3次后重置)
        if(key2_press) begin
            speed_cnt <= (speed_cnt == 2'd1) ? 2'd0 : speed_cnt + 2'd1;
            // 说明:0=中档→1=快档→2=重置回中档(3次加快逻辑:按3次KEY2→0→1→0→1→...)
            // 实际效果:按1次→快档,按2次→中档,按3次→快档?不,修正为3次后重置:
            // 正确逻辑:0(中)→1(快)→2(超快?不,原需求3次后重置,所以0→1→2→0)
            // 重新调整:3档循环(0:中,1:快,2:超慢?不,按需求“加快3次后重置”)
            // 最终逻辑:加快次数计数(0→1→2→0),对应档位:0=中,1=快,2=更快→3次后回中
            speed_cnt <= (speed_cnt == 2'd2) ? 2'd0 : speed_cnt + 2'd1;
        end
        // KEY1按下:减慢速度(0→2→1→0,3次后重置)
        else if(key1_press) begin
            speed_cnt <= (speed_cnt == 2'd0) ? 2'd2 : speed_cnt - 2'd1;
        end
    end
end

// 2. 步长定时器(根据档位选择步长时间:档位越高,步长时间越短→呼吸越快)
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        step_timer <= SPEED_STEP_MID;  // 初始中档
    end else if(mode_en) begin
        case(speed_cnt)
            2'd0: step_timer <= SPEED_STEP_MID;   // 中档(2秒周期)
            2'd1: step_timer <= SPEED_STEP_FAST;  // 快档(1秒周期)
            2'd2: step_timer <= SPEED_STEP_SLOW;  // 慢档(3秒周期)
            default: step_timer <= SPEED_STEP_MID;
        endcase
    end
end

// 3. PWM载波计数器(生成固定频率PWM,确保占空比精度)
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        pwm_cnt <= 10'd0;
    end else if(mode_en) begin
        pwm_cnt <= (pwm_cnt == STEP_NUM - 1) ? 10'd0 : pwm_cnt + 10'd1;
    end else begin
        pwm_cnt <= 10'd0;
    end
end

// 4. 占空比线性增减控制(双灯共用同一占空比和方向,保证同步)
reg [31:0] cnt;  // 步长计时计数器
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        cnt <= 32'd0;
        duty_cycle1 <= 10'd0;
        duty_cycle2 <= 10'd0;
        dir <= 1'b0;  // 初始方向:占空比增加(LED渐亮)
    end else if(mode_en) begin
        cnt <= cnt + 32'd1;
        if(cnt >= step_timer) begin  // 达到步长时间,更新占空比
            cnt <= 32'd0;
            if(dir == 1'b0) begin  // 占空比增加(渐亮)
                // 达到最大占空比(STEP_NUM-1),反向(渐暗)
                if(duty_cycle1 == STEP_NUM - 1) begin
                    dir <= 1'b1;
                end else begin
                    duty_cycle1 <= duty_cycle1 + 10'd1;
                    duty_cycle2 <= duty_cycle2 + 10'd1;  // 双灯同步更新
                end
            end else begin  // 占空比减少(渐暗)
                // 达到最小占空比(0),反向(渐亮)
                if(duty_cycle1 == 10'd0) begin
                    dir <= 1'b0;
                end else begin
                    duty_cycle1 <= duty_cycle1 - 10'd1;
                    duty_cycle2 <= duty_cycle2 - 10'd1;  // 双灯同步更新
                end
            end
        end
    end else begin
        cnt <= 32'd0;
        duty_cycle1 <= 10'd0;
        duty_cycle2 <= 10'd0;
        dir <= 1'b0;
    end
end

// 5. LED1 PWM输出(占空比比较)
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        led1_out <= 1'b0;
    end else if(mode_en) begin
        led1_out <= (pwm_cnt < duty_cycle1) ? 1'b1 : 1'b0;
    end else begin
        led1_out <= 1'b0;
    end
end

// 6. LED2 PWM输出(与LED1完全同步)
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        led2_out <= 1'b0;
    end else if(mode_en) begin
        led2_out <= (pwm_cnt < duty_cycle2) ? 1'b1 : 1'b0;
    end else begin
        led2_out <= 1'b0;
    end
end

endmodule

-------------------------------------------------
buzzer_ctrl.v:
// 蜂鸣器控制模块:任何按键按下时,输出100ms提示音
// 特性:多次按键按下时,重新计时100ms
module buzzer_ctrl(
    input                  clk,          // 50MHz时钟
    input                  rst_n,        // 低电平复位
    input                  key1_press,   // key1按下脉冲
    input                  key2_press,   // key2按下脉冲
    input                  touch_press,  // 触摸按键按下脉冲
    output reg             buzzer_en     // 蜂鸣器使能(高电平有效)
);

// 参数定义(移至端口声明后,修复语法错误)
parameter CLK_FREQ    = 50_000_000;  // 50MHz时钟
parameter PROMPT_MS   = 250;         // 提示音时长250ms
localparam PROMPT_CNT_MAX = CLK_FREQ * PROMPT_MS / 1000 - 1;  // 100ms对应的时钟周期数

// 内部信号
reg [23:0] prompt_cnt;  // 提示音计数器(24位足够表示5e6)

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        prompt_cnt <= 24'd0;
        buzzer_en <= 1'b0;
    end else begin
        // 任何按键按下,重置计数器并开启蜂鸣器
        if(key1_press || key2_press || touch_press) begin
            prompt_cnt <= PROMPT_CNT_MAX;
            buzzer_en <= 1'b1;
        end else if(prompt_cnt > 24'd0) begin  // 计数器倒计时
            prompt_cnt <= prompt_cnt - 24'd1;
            buzzer_en <= 1'b1;
        end else begin  // 计时结束,关闭蜂鸣器
            buzzer_en <= 1'b0;
        end
    end
end

endmodule

------------------------------------------------------
flow_led.v:
module flow_led(
    input                  clk,          // 50MHz时钟
    input                  rst_n,        // 低电平复位
    input                  mode_en,      // 模式使能(高电平有效)
    input                  key1_press,   // key1按下(减慢)
    input                  key2_press,   // key2按下(加快)
    output reg             led1_out,     // LED1输出
    output reg             led2_out      // LED2输出
);

parameter BASE_PERIOD = 50_000_000;         // 基础流水周期(1000ms)
localparam ADJUST_STEP = 10_000_000;         // 速度调整步长(200ms)
localparam MAX_PERIOD  = BASE_PERIOD + ADJUST_STEP * 2;  // 最大周期1400ms
localparam MIN_PERIOD  = BASE_PERIOD - ADJUST_STEP * 2;  // 最小周期600ms

// 内部信号(确保每个寄存器仅在一个always块中赋值)
reg [31:0] flow_period;// 当前流水周期(时钟周期数)
reg [31:0] flow_cnt;   // 流水周期计数器
reg led_state;         // 流水状态(0ED1亮, 1ED2亮)

// 1. 速度档位控制(互斥逻辑:加快/减慢二选一,3次后重置)
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        flow_period <= BASE_PERIOD;
    end else if(mode_en) begin
        if(key2_press) begin  // 加快模式:优先级高于减慢
            flow_period <= flow_period - ADJUST_STEP;
        end else if(key1_press) begin  // 减慢模式
            flow_period <= flow_period + ADJUST_STEP;
        end else begin
            flow_period <= flow_period;
        end
    end
end
// 3. 流水状态切换(mode_en有效即自动流水,无需按键触发)
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        flow_period <= flow_period;
    end else if(mode_en) begin
        if(flow_cnt >= flow_period / 2) begin  // 半周期切换一次状态
            flow_cnt <= 32'd0;
            led_state <= ~led_state;
        end
    end else begin
        led_state <= 1'b0;
    end
end

// 4. LED输出控制(唯一驱动源,无多驱动冲突)
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        led1_out <= 1'b0;
        led2_out <= 1'b0;
    end else if(mode_en) begin
        case(led_state)
            1'b0: begin  // LED1亮,LED2灭
                led1_out <= 1'b1;
                led2_out <= 1'b0;
            end
            1'b1: begin  // LED1灭,LED2亮
                led1_out <= 1'b0;
                led2_out <= 1'b1;
            end
            default: {led1_out, led2_out} <= 2'b00;
        endcase
    end else begin
        led1_out <= 1'b0;
        led2_out <= 1'b0;
    end
end

endmodule

--------------------------------------
key_debounce.v:
// 按键消抖模块:处理3个按键的抖动,输出1个时钟周期的按下脉冲
// 特性:两级同步消抖,避免亚稳态,消抖时间20ms(50MHz下1e6个时钟周期)
module key_debounce(
    input                  clk,          // 50MHz时钟
    input                  rst_n,        // 低电平复位
    input        [2:0]     key_in,       // 3个按键输入(未按下高电平,按下低电平)
    output reg   [2:0]     key_press     // 按键按下脉冲(高电平有效,持续1周期)
);

// 参数定义(移至端口声明后,修复语法错误)
parameter CLK_FREQ    = 50_000_000;  // 时钟频率50MHz
parameter DEBOUNCE_MS = 20;          // 消抖时间20ms
localparam DEBOUNCE_CNT_MAX = CLK_FREQ * DEBOUNCE_MS / 1000 - 1;  // 消抖计数最大值

// 内部信号
reg [2:0] key_in_sync;  // 按键输入同步(消除亚稳态)
reg [2:0] key_in_stable;// 稳定的按键状态
reg [19:0] debounce_cnt;// 消抖计数器(20位足够表示1e6)
reg [2:0] key_in_stable_prev;  // 上一周期稳定状态

// 第一步:两级同步按键输入(避免亚稳态)
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        key_in_sync <= 3'b111;  // 初始状态:按键未按下(高电平)
    end else begin
        key_in_sync <= key_in;
    end
end

// 第二步:消抖计数,获取稳定状态
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        key_in_stable <= 3'b111;
        debounce_cnt  <= 20'd0;
    end else begin
        if(key_in_sync != key_in_stable) begin  // 按键状态变化,开始计数
            debounce_cnt <= DEBOUNCE_CNT_MAX;
            key_in_stable <= key_in_sync;
        end else if(debounce_cnt > 20'd0) begin  // 计数未结束,继续倒计时
            debounce_cnt <= debounce_cnt - 20'd1;
        end
    end
end

// 第三步:检测按键按下(高→低跳变),输出脉冲
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        key_press <= 3'b000;
        key_in_stable_prev <= 3'b111;
    end else begin
        key_in_stable_prev <= key_in_stable;  // 存储上一周期状态
        // 未按下(1)→按下(0):产生高脉冲
        key_press <= ~key_in_stable & key_in_stable_prev;
    end
end

endmodule

--------------------------------
mode_ctrl.v:
// 模式控制模块:触摸按键按下一次,切换一次工作模式
// 初始模式:呼吸灯模式(mode=0),再次按下切换为流水灯模式(mode=1)
module mode_ctrl(
    input  clk,          // 50MHz时钟
    input  rst_n,        // 低电平复位
    input  touch_press,  // 触摸按键按下脉冲
    output reg mode      // 模式输出(0:呼吸灯,1:流水灯)
);

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        mode <= 1'b0;  // 复位后默认呼吸灯模式
    end else begin
        if(touch_press) begin  // 触摸按键按下,模式翻转
            mode <= ~mode;
        end
    end
end

endmodule

------------------------------
top_key_led_buzzer.v:
module top_key_led_buzzer(
    input           clk_50mhz,    // 50MHz系统时钟
    input           rst_n,        // 低电平复位
    input           key1,         // 实体按键1
    input           key2,         // 实体按键2
    input           touch_key,    // 触摸按键
    output reg      led1,         // LED1
    output reg      led2,         // LED2
    output reg      buzzer        // 蜂鸣器
);

wire [2:0] key_press;  // 3个按键的按下脉冲(0:key1, 1:key2, 2:touch_key)
wire       mode;       // 工作模式(0:呼吸灯, 1:流水灯)
wire       led1_breath;// 呼吸灯模式下LED1输出
wire       led2_breath;// 呼吸灯模式下LED2输出
wire       led1_flow;  // 流水灯模式下LED1输出
wire       led2_flow;  // 流水灯模式下LED2输出
wire       buzzer_en;  // 蜂鸣器使能

// 按键消抖模块例化
key_debounce u_key_debounce(
    .clk         (clk_50mhz),
    .rst_n       (rst_n),
    .key_in      ({touch_key, key2, key1}),
    .key_press   (key_press)
);

// 模式控制模块例化
mode_ctrl u_mode_ctrl(
    .clk         (clk_50mhz),
    .rst_n       (rst_n),
    .touch_press (key_press[2]),
    .mode        (mode)
);

// 呼吸灯模块例化
breath_led u_breath_led(
    .clk         (clk_50mhz),
    .rst_n       (rst_n),
    .mode_en     (~mode),
    .key1_press  (key_press[0]),
    .key2_press  (key_press[1]),
    .led1_out    (led1_breath),
    .led2_out    (led2_breath)
);

// 流水灯模块例化
flow_led u_flow_led(
    .clk         (clk_50mhz),
    .rst_n       (rst_n),
    .mode_en     (mode),
    .key1_press  (key_press[0]),
    .key2_press  (key_press[1]),
    .led1_out    (led1_flow),
    .led2_out    (led2_flow)
);

// 蜂鸣器模块例化
buzzer_ctrl u_buzzer_ctrl(
    .clk         (clk_50mhz),
    .rst_n       (rst_n),
    .key1_press  (key_press[0]),
    .key2_press  (key_press[1]),
    .touch_press (key_press[2]),
    .buzzer_en   (buzzer_en)
);

// LED输出选择逻辑(唯一驱动源)
always @(posedge clk_50mhz or negedge rst_n) begin
    if(!rst_n) begin
        led1 <= 1'b0;
        led2 <= 1'b0;
    end else begin
        case(mode)
            1'b0: begin  // 呼吸灯模式
                led1 <= led1_breath;
                led2 <= led2_breath;
            end
            1'b1: begin  // 流水灯模式
                led1 <= led1_flow;
                led2 <= led2_flow;
            end
            default: {led1, led2} <= 2'b00;
        endcase
    end
end

// 蜂鸣器输出逻辑
always @(posedge clk_50mhz or negedge rst_n) begin
    if(!rst_n) begin
        buzzer <= 1'b0;
    end else begin
        buzzer <= buzzer_en;
    end
end

endmodule


回复

使用道具 举报

4

主题

2148

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
6043
金钱
6043
注册时间
2018-10-21
在线时间
1775 小时
发表于 8 小时前 | 显示全部楼层
你可以仿真或者在线调试看看,方便查原因
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-11-22 22:13

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表