野火FPGA入门(5):控制LED灯

文章目录

    • 第17讲:触摸按键控制LED灯
    • 第18讲:流水灯
    • 第19讲:呼吸灯
    • 第20讲:状态机
    • 第21讲:无源蜂鸣器驱动实验

第17讲:触摸按键控制LED灯

触摸按键可分为四大类:电阻式、电容式、红外感应式、表面声波式

电容式触摸按键主要由按键IC部分和电容部分构成;按键IC用于将电容的变化转换为电信号;电容部分指的是由电容极板、地、隔离区等组成触摸按键的电容环境。
野火FPGA入门(5):控制LED灯_第1张图片

模块绘制
野火FPGA入门(5):控制LED灯_第2张图片
波形图绘制:按键未按下时保持高电平,按键按下保持低电平;按下时间与低电平保持时间相同,松开按键返回高电平
使用按键下降沿控制灯的点亮和熄灭
野火FPGA入门(5):控制LED灯_第3张图片

touch_ctrl_led.v

`timescale  1ns/1ns

module  touch_ctrl_led
(
    input   wire    sys_clk     ,   //系统时钟,频率50MHz
    input   wire    sys_rst_n   ,   //复位信号,低电平有效
    input   wire    touch_key   ,   //触摸按键信号

    output  reg     led             //led输出信号
);

//wire  define
wire    touch_flag    ;   //触摸使能信号

//reg   define
reg touch_key_dly1  ;   //touch_key延迟一个时钟信号
reg touch_key_dly2  ;   //touch_key延迟两个时钟信号

//对touch_key信号延迟两个时钟周期用来产生触摸按键信号
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        begin
            touch_key_dly1  <=  1'b1;
            touch_key_dly2  <=  1'b1;
        end
    else
        begin
            touch_key_dly1  <=  touch_key;
            touch_key_dly2  <=  touch_key_dly1;
        end

//根据触摸按键信号的下降沿判断触摸了触摸按键
assign  touch_flag    =   ((touch_key_dly1 == 1'b0) && (touch_key_dly2 == 1'b1));

//根据触摸使能信号控制led状态
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        led <=  1'b1;
    else    if(touch_flag == 1'b1)
        led <=  ~led;
    else  
        led <=  led;
        
endmodule
`timescale  1ns/1ns

module  tb_touch_ctrl_led();

//wire  define
wire    led         ;

//reg   define
reg     sys_clk     ;
reg     sys_rst_n   ;
reg     touch_key   ;

//sys_clk,sys_rst_n初始赋值,模拟触摸按键信号值
initial
    begin
        sys_clk       =   1'b1 ;
        sys_rst_n    <=   1'b0 ;
        touch_key    <=   1'b1 ;
        #20
        sys_rst_n    <=   1'b1 ;
        #200
        touch_key    <=   1'b0 ;
        #2000
        touch_key    <=   1'b1 ;
        #1000
        touch_key    <=   1'b0 ;
        #3000
        touch_key    <=   1'b1 ;
    end

//clk:产生时钟
always  #10 sys_clk = ~sys_clk ;

//------------- touch_ctrl_led_inst -------------
touch_ctrl_led    touch_ctrl_led_inst
(
    .sys_clk    (sys_clk    ),  //系统时钟,频率50MHz
    .sys_rst_n  (sys_rst_n  ),  //复位信号,低电平有效
    .touch_key  (touch_key  ),  //触摸按键信号

    .led        (led        )   //led输出信号
);

endmodule



第18讲:流水灯

模块设计
野火FPGA入门(5):控制LED灯_第4张图片
波形绘制:0.5秒转换一个灯
野火FPGA入门(5):控制LED灯_第5张图片

water_led.v

`timescale  1ns/1ns

module  water_led
#(
    parameter CNT_MAX = 25'd24_999_999
)
(
    input   wire            sys_clk     ,   //系统时钟50Mh
    input   wire            sys_rst_n   ,  //全局复位

    output  wire    [3:0]   led_out        //输出控制led灯

);

//reg   define
reg     [24:0]  cnt         ;
reg             cnt_flag    ;
reg     [3:0]   led_out_reg ;

//cnt:计数器计数500ms
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt <= 25'b0;
    else    if(cnt == CNT_MAX)
        cnt <= 25'b0;
    else
        cnt <= cnt + 1'b1;

//cnt_flag:计数器计数满500ms标志信号
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_flag <= 1'b0;
    else    if(cnt == CNT_MAX - 1)
        cnt_flag <= 1'b1;
    else
        cnt_flag <= 1'b0;

//led_out_reg:led循环流水
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        led_out_reg <=  4'b0001;
    else    if(led_out_reg == 4'b1000 && cnt_flag == 1'b1)
        led_out_reg <=  4'b0001;
    else    if(cnt_flag == 1'b1)
        led_out_reg <=  led_out_reg << 1'b1; //左移

assign  led_out = ~led_out_reg;

endmodule

tb_water_led.v

`timescale  1ns/1ns

module  tb_water_led();

//wire  define
wire    [3:0]   led_out     ;

//reg   define
reg             sys_clk     ;
reg             sys_rst_n   ;

//初始化系统时钟、全局复位
initial begin
    sys_clk    = 1'b1;
    sys_rst_n <= 1'b0;
    #20
    sys_rst_n <= 1'b1;
end

//sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50Mhz
always #10 sys_clk = ~sys_clk;

//-------------------- water_led_inst --------------------
water_led   
#(
    .CNT_MAX    (25'd24)
)
water_led_inst
(
    .sys_clk    (sys_clk    ),  //input          sys_clk
    .sys_rst_n  (sys_rst_n  ),  //input          sys_rst_n
                    
    .led_out    (led_out    )   //output  [3:0]  led_out
);

endmodule



第19讲:呼吸灯

LED灯低电平点亮,高电平熄灭。

模块设计
野火FPGA入门(5):控制LED灯_第6张图片
波形图绘制
野火FPGA入门(5):控制LED灯_第7张图片
野火FPGA入门(5):控制LED灯_第8张图片

breath_led.v

`timescale  1ns/1ns

module  breath_led
#(
    parameter CNT_1US_MAX = 6'd49   ,
    parameter CNT_1MS_MAX = 10'd999 ,
    parameter CNT_1S_MAX  = 10'd999
)
(
    input   wire    sys_clk     ,   //系统时钟50Mhz
    input   wire    sys_rst_n   ,   //全局复位

    output  reg     led_out         //输出信号,控制led灯
);

//reg define
reg [5:0]   cnt_1us     ;
reg [9:0]   cnt_1ms     ;
reg [9:0]   cnt_1s      ;
reg         cnt_1s_en   ;  //方便点亮到熄灭,熄灭到点亮的取反

//cnt_1us:1us计数器
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1us <= 6'b0;
    else    if(cnt_1us == CNT_1US_MAX)
        cnt_1us <= 6'b0;
    else
        cnt_1us <= cnt_1us + 1'b1;

//cnt_1ms:1ms计数器
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1ms <= 10'b0;
    else    if(cnt_1ms == CNT_1MS_MAX && cnt_1us == CNT_1US_MAX)
        cnt_1ms <= 10'b0;
    else    if(cnt_1us == CNT_1US_MAX)
        cnt_1ms <= cnt_1ms + 1'b1;
    else   
        cnt_1ms <= cnt_1ms;
        
//cnt_1s:1s计数器
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1s <= 10'b0;
    else    if(cnt_1s == CNT_1S_MAX && cnt_1ms == CNT_1MS_MAX && cnt_1us == CNT_1US_MAX)
        cnt_1s <= 10'b0;
    else    if(cnt_1ms == CNT_1MS_MAX && cnt_1us == CNT_1US_MAX)
        cnt_1s <= cnt_1s + 1'b1;
    else 
        cnt_1s <= cnt_1s;
        
//cnt_1s_en:1s计数器使能信号
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1s_en <= 1'b0;
    else    if(cnt_1s == CNT_1S_MAX && cnt_1ms == CNT_1MS_MAX  && cnt_1us == CNT_1US_MAX)
        cnt_1s_en <= ~cnt_1s_en;
    else   
        cnt_1s_en <= cnt_1s_en;
        
//led_out:输出信号连接到外部的led灯
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        led_out <= 1'b1;
    else    if((cnt_1s_en == 1'b0 && cnt_1ms <= cnt_1s) || (cnt_1s_en == 1'b1 && cnt_1ms > cnt_1s))
        led_out <= 1'b0;
    else
        led_out <= 1'b1;

endmodule

tb_breath_led.v

`timescale  1ns/1ns

module  tb_breath_led();

//wire  define
wire    led_out     ;

//reg   define
reg     sys_clk     ;
reg     sys_rst_n   ;

//初始化系统时钟、全局复位
initial begin
    sys_clk    = 1'b1;
    sys_rst_n <= 1'b0;
    #20
    sys_rst_n <= 1'b1;
end

//sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50Mhz
always #10 sys_clk = ~sys_clk;

//-------------------- breath_led_inst --------------------
breath_led
#(
    .CNT_1US_MAX(6'd4   ),
    .CNT_1MS_MAX(10'd9  ),
    .CNT_1S_MAX (10'd9  )
)
breath_led_inst
(
    .sys_clk    (sys_clk    ),  //input     sys_clk
    .sys_rst_n  (sys_rst_n  ),  //input     sys_rst_n

    .led_out    (led_out    )   //output    led_out
);

endmodule



第20讲:状态机

野火FPGA入门(5):控制LED灯_第9张图片

例:简单状态机
模块设计
野火FPGA入门(5):控制LED灯_第10张图片

输入:投入1元硬币
输出:出可乐,不出可乐
状态:投入0元,投入1元,投入2元,投入3元

状态分析
野火FPGA入门(5):控制LED灯_第11张图片
波形图绘制
野火FPGA入门(5):控制LED灯_第12张图片
simple_fsm.v

`timescale  1ns/1ns

module  simple_fsm
(
    input   wire    sys_clk     ,   //系统时钟50MHz
    input   wire    sys_rst_n   ,   //全局复位
    input   wire    pi_money    ,   //投币方式可以为:不投币(0)、投1元(1)

    output  reg     po_cola         //po_cola为1时出可乐,po_cola为0时不出可乐
);

//parameter define
//只有三种状态,使用独热码
parameter   IDLE = 3'b001;
parameter   ONE  = 3'b010;
parameter   TWO  = 3'b100;

//reg   define
reg     [2:0]   state;

//第一段状态机,描述当前状态state如何根据输入跳转到下一状态
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        state <= IDLE;  //任何情况下只要按复位就回到初始状态
    else    case(state)
                IDLE    :   if(pi_money == 1'b1)//判断输入情况
                                state <= ONE;
                            else
                                state <= IDLE;

                ONE     :   if(pi_money == 1'b1)
                                state <= TWO;
                            else
                                state <= ONE;

                TWO     :   if(pi_money == 1'b1)
                                state <= IDLE;
                            else
                                state <= TWO;
                //如果状态机跳转到编码的状态之外也回到初始状态
                default :       state <= IDLE;
            endcase

//第二段状态机,描述当前状态state和输入pi_money如何影响po_cola输出
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        po_cola <= 1'b0;
    else    if((state == TWO) && (pi_money == 1'b1))
        po_cola <= 1'b1;
    else
        po_cola <= 1'b0;

endmodule

野火FPGA入门(5):控制LED灯_第13张图片
野火FPGA入门(5):控制LED灯_第14张图片

tb_simple_fsm.v

`timescale  1ns/1ns

module  tb_simple_fsm();

//reg define
reg     sys_clk;
reg     sys_rst_n;
reg     pi_money;

//wire  define
wire    po_cola;

//初始化系统时钟、全局复位
initial begin
    sys_clk    = 1'b1;
    sys_rst_n <= 1'b0;
    #20
    sys_rst_n <= 1'b1;
end

//sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50MHz
always  #10 sys_clk = ~sys_clk;

//pi_money:产生输入随机数,模拟投币1元的情况
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pi_money <= 1'b0;
    else
        pi_money <= {$random} % 2;  //取模求余数,产生非负随机数0、1

//------------------------------------------------------------
//将RTL模块中的内部信号引入到Testbench模块中进行观察
wire [2:0] state = simple_fsm_inst.state;

initial begin
    $timeformat(-9, 0, "ns", 6);
    $monitor("@time %t: pi_money=%b state=%b po_cola=%b", $time, pi_money, state, po_cola);
end
//------------------------------------------------------------

//------------------------simple_fsm_inst------------------------
simple_fsm  simple_fsm_inst(
    .sys_clk    (sys_clk    ),  //input     sys_clk
    .sys_rst_n  (sys_rst_n  ),  //input     sys_rst_n
    .pi_money   (pi_money   ),  //input     pi_money

    .po_cola    (po_cola    )   //output    po_cola
);

endmodule



例:复杂状态机
模块设计
野火FPGA入门(5):控制LED灯_第15张图片

输入:0.5、1
输出:不出可乐/不找零、出可乐/不找零、出可乐/找零
状态:0、0.5、1、1.5、2、2.5、3

状态转移图
野火FPGA入门(5):控制LED灯_第16张图片
波形图绘制
野火FPGA入门(5):控制LED灯_第17张图片

complex_fsm.v

`timescale  1ns/1ns

module  complex_fsm
(
    input   wire    sys_clk         ,   //系统时钟50MHz
    input   wire    sys_rst_n       ,   //全局复位
    input   wire    pi_money_one    ,   //投币1元
    input   wire    pi_money_half   ,   //投币0.5元
                    
    output  reg     po_money        ,   //po_money为1时表示找零
                                        //po_money为0时表示不找零
    output  reg     po_cola             //po_cola为1时出可乐
                                        //po_cola为0时不出可乐
);

//parameter define
//只有五种状态,使用独热码
parameter   IDLE     = 5'b00001;
parameter   HALF     = 5'b00010;
parameter   ONE      = 5'b00100;
parameter   ONE_HALF = 5'b01000;
parameter   TWO      = 5'b10000;

//reg   define
reg     [4:0]   state;

//wire  define
wire    [1:0]   pi_money;

//pi_money:为了减少变量的个数,我们用位拼接把输入的两个1bit信号拼接成1个2bit信号
//投币方式可以为:不投币(00)、投0.5元(01)、投1元(10),每次只投一个币
assign pi_money = {pi_money_one, pi_money_half};

//第一段状态机,描述当前状态state如何根据输入跳转到下一状态
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        state <= IDLE;  //任何情况下只要按复位就回到初始状态
    else	case(state)
                IDLE    : if(pi_money == 2'b01)   //判断一种输入情况
                              state <= HALF;
                          else    if(pi_money == 2'b10)//判断另一种输入情况
                              state <= ONE;
                          else
                              state <= IDLE;
    
                HALF    : if(pi_money == 2'b01)
                              state <= ONE;
                          else    if(pi_money == 2'b10)
                              state <= ONE_HALF;
                          else
                              state <= HALF;
    
                ONE     : if(pi_money == 2'b01)
                              state <= ONE_HALF;
                          else    if(pi_money == 2'b10)
                              state <= TWO;
                          else
                              state <= ONE;
    
                ONE_HALF: if(pi_money == 2'b01)
                              state <= TWO;
                          else    if(pi_money == 2'b10)
                              state <= IDLE;
                          else
                              state <= ONE_HALF;
    
                TWO     : if((pi_money == 2'b01) || (pi_money == 2'b10))
                              state <= IDLE;
                          else
                              state <= TWO;
        //如果状态机跳转到编码的状态之外也回到初始状态
                default :       state <= IDLE;
            endcase

//第二段状态机,描述当前状态state和输入pi_money如何影响po_cola输出
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        po_cola <= 1'b0;
    else if((state==TWO && pi_money==2'b01) || (state==TWO && pi_money==2'b10) || (state==ONE_HALF && pi_money==2'b10))
        po_cola <= 1'b1;
    else
        po_cola <= 1'b0;

//第二段状态机,描述当前状态state和输入pi_money如何影响po_money输出
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n ==	1'b0)
        po_money <= 1'b0;
    else if((state == TWO) && (pi_money == 2'b10))  //只有一种情况需要找零
        po_money <= 1'b1;
    else
        po_money <= 1'b0;

endmodule

野火FPGA入门(5):控制LED灯_第18张图片
tb_complex_fsm.v

`timescale  1ns/1ns
module  tb_complex_fsm();

//reg   define
reg         sys_clk;
reg         sys_rst_n;
reg         pi_money_one;
reg         pi_money_half;
reg         random_data_gen;

//wire  define
wire        po_cola;
wire        po_money;

//初始化系统时钟、全局复位
initial begin
    sys_clk    = 1'b1;
    sys_rst_n <= 1'b0;
    #20
    sys_rst_n <= 1'b1;
end

//sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50MHz
always  #10 sys_clk = ~sys_clk;

//random_data_gen:产生非负随机数0、1
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        random_data_gen <= 1'b0;
    else
        random_data_gen <= {$random} % 2;

//pi_money_one:模拟投入1元的情况
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pi_money_one <= 1'b0;
    else
        pi_money_one <= random_data_gen;

//pi_money_half:模拟投入0.5元的情况
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pi_money_half <= 1'b0;
    else
    //取反是因为一次只能投一个币,即pi_money_one和pi_money_half不能同时为1
        pi_money_half <= ~random_data_gen;

//------------------------------------------------------------
//将RTL模块中的内部信号引入到Testbench模块中进行观察
wire    [4:0]   state    = complex_fsm_inst.state;
wire    [1:0]   pi_money = complex_fsm_inst.pi_money;

initial begin
    $timeformat(-9, 0, "ns", 6);
    $monitor("@time %t: pi_money_one=%b pi_money_half=%b pi_money=%b state=%b po_cola=%b po_money=%b", $time, pi_money_one, pi_money_half, pi_money, state, po_cola, po_money);
end
//------------------------------------------------------------

//------------------------complex_fsm_inst------------------------
complex_fsm complex_fsm_inst(
    .sys_clk        (sys_clk        ),  //input     sys_clk
    .sys_rst_n      (sys_rst_n      ),  //input     sys_rst_n
    .pi_money_one   (pi_money_one   ),  //input     pi_money_one
    .pi_money_half  (pi_money_half  ),  //input     pi_money_half
                    
    .po_cola        (po_cola        ),  //output    po_money
    .po_money       (po_money       )   //output    po_cola
);  

endmodule



第21讲:无源蜂鸣器驱动实验

蜂鸣器按其结构可分为电磁式蜂鸣器和压电式蜂鸣器两种类型;蜂鸣器按其是否带有信号源又分为有源蜂鸣器和无源蜂鸣器
有源蜂鸣器的内部装有集成电路,不需要音频驱动电路,只需要接通直流电压就能直接发出声响;而无源蜂鸣器只有外加音频驱动信号才能发出声响。

无源蜂鸣器与有源蜂鸣器不同,因其内部不带震荡源,所以其无法像有源蜂鸣器那样直接用直流信号驱动,这里需要使用PWM方法才能驱动其发生。
输入不同频率和占空比的PWM方法发出的声音是不同的,其中频率对音频有影响,占空比对音量大小有影响。

野火FPGA入门(5):控制LED灯_第19张图片

模块设计
野火FPGA入门(5):控制LED灯_第20张图片
波形图绘制
野火FPGA入门(5):控制LED灯_第21张图片
beep.v

`timescale  1ns/1ns
module  beep
#(
    parameter   TIME_500MS =   25'd24999999,   //0.5s计数值
    parameter   DO  =   18'd190839 ,   //"哆"音调分频计数值(频率262)
    parameter   RE  =   18'd170067 ,   //"来"音调分频计数值(频率294)
    parameter   MI  =   18'd151514 ,   //"咪"音调分频计数值(频率330)
    parameter   FA  =   18'd143265 ,   //"发"音调分频计数值(频率349)
    parameter   SO  =   18'd127550 ,   //"梭"音调分频计数值(频率392)
    parameter   LA  =   18'd113635 ,   //"拉"音调分频计数值(频率440)
    parameter   XI  =   18'd101214     //"西"音调分频计数值(频率494)
)
(
    input   wire        sys_clk     ,   //系统时钟,频率50MHz
    input   wire        sys_rst_n   ,   //系统复位,低有效

    output  reg         beep            //输出蜂鸣器控制信号
);

//reg   define
reg     [24:0]  cnt         ;   //0.5s计数器
reg     [17:0]  freq_cnt    ;   //音调计数器
reg     [2:0]   cnt_500ms   ;   //0.5s个数计数
reg     [17:0]  freq_data   ;   //音调分频计数值

//wire  define
wire    [16:0]  duty_data   ;   //占空比计数值

//cnt:0.5s循环计数器
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt <=  25'd0;
    else    if(cnt == TIME_500MS )
        cnt <=   25'd0;
    else
        cnt <=  cnt +   1'b1;

//cnt_500ms:对500ms个数进行计数,每个音阶鸣叫时间0.5s,7个音节一循环
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_500ms   <=  3'd0;
    else    if(cnt == TIME_500MS && cnt_500ms ==  6)
        cnt_500ms   <=  3'd0;
    else    if(cnt == TIME_500MS)
        cnt_500ms   <=  cnt_500ms + 1'b1;
    else   
        cnt_500ms   <=  cnt_500ms;   //时序逻辑中可以不写,组合逻辑一定要写

//freq_cnt:当计数到音阶计数值或跳转到下一音阶时,开始重新计数
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        freq_cnt    <=  18'd0;
    else    if(freq_cnt == freq_data || cnt == TIME_500MS)
        freq_cnt    <=  18'd0;
    else
        freq_cnt    <=  freq_cnt +  1'b1;    
            
//不同时间鸣叫不同的音阶
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        freq_data   <=  DO;
    else    case(cnt_500ms)
        0:  freq_data   <=   DO;
        1:  freq_data   <=   RE;
        2:  freq_data   <=   MI;
        3:  freq_data   <=   FA;
        4:  freq_data   <=   SO;
        5:  freq_data   <=   LA;
        6:  freq_data   <=   XI;
        default:  freq_data   <=   DO;
    endcase

//设置50%占空比:音阶分频计数值的一半即为占空比的高电平数
assign  duty_data   =   freq_data   >>    1'b1;

//beep:输出蜂鸣器波形
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        beep    <=  1'b0;
    else    if(freq_cnt >= duty_data)
        beep    <=  1'b1;
    else
        beep    <=  1'b0;

endmodule

tb_beep.v

`timescale  1ns/1ns
module  tb_beep();

//reg   define
reg     sys_clk     ;   //时钟
reg     sys_rst_n   ;   //复位

//对时钟,复位信号赋初值
initial
    begin
        sys_clk     =   1'b1;
        sys_rst_n   <=  1'b0;
        #100
        sys_rst_n   <=  1'b1;
    end

//产生时钟信号
always #10 sys_clk =   ~sys_clk;

beep
#(
    .TIME_500MS(25'd24999),   //0.5s计数值
    .DO        (18'd190  ),   //"哆"音调分频计数值(频率262)
    .RE        (18'd170  ),   //"来"音调分频计数值(频率294)
    .MI        (18'd151  ),   //"咪"音调分频计数值(频率330)
    .FA        (18'd143  ),   //"发"音调分频计数值(频率349)
    .SO        (18'd127  ),   //"梭"音调分频计数值(频率392)
    .LA        (18'd113  ),   //"拉"音调分频计数值(频率440)
    .XI        (18'd101  )    //"西"音调分频计数值(频率494)
)
beep_inst
(
    .sys_clk     (sys_clk   ),   //系统时钟,频率50MHz
    .sys_rst_n   (sys_rst_n ),   //系统复位,低有效

    .beep        (beep      )    //输出蜂鸣器控制信号
);

endmodule

你可能感兴趣的:(FPGA,fpga开发)