差不多三天的时间都在弄这个抢答器,总算今天把它弄好了,这FPGA中还是得学会建模,学划分模块,对于这一块感觉自己还差那么点,不能很好地考虑好大局,然后细化到每一个模块,因为一个好的顶层模块,可以让子模块的程序更加简洁,否则子模块看起来很复杂,程序写起来也很费劲。好吧,下面来看程序。
//程序实现的功能:三路抢答器,当刚上电时,数码管开始倒计时40s;蜂鸣器响一下,四个LED灯闪烁一段时间; //期间如果有键盘按下,蜂鸣器响一下,四个LED灯闪烁一段时间,而数码管显示相应的按键值; //如果40S计时到后,没按键按下,蜂鸣器响一下,四个LED灯闪烁一段时间,数码管又从新开始计时; module qiang_da_qi //顶层模块; ( sysclk, rst_n, key, buzzer, led_out, smg_sel, smg_data ); input sysclk; //系统时钟50MHZ; input rst_n; //复位信号,低电平有效; input[2:0] key; //3个键盘 output buzzer; //蜂鸣器 output[3:0] led_out; //LED灯 output[1:0] smg_sel; //数码管片选; output[6:0] smg_data; //数码管段选; parameter div_clk_num1=32'h17_D783F; //1s分频系数; parameter div_clk_num2=32'hEE6_B27F; //10s分频系数; reg [2:0] key_reg; // 键盘检测; always @(posedge sysclk or negedge rst_n) begin if(!rst_n) key_reg<=3'b111; else if(key!=3'b111) key_reg<=key; else if(key_reg!=3'b111) key_reg<=key_reg; else key_reg<=key_reg; end reg [3:0] key_num; always @ (*) begin case(key_reg) 3'b110 : key_num=4'h1; 3'b101 : key_num=4'h2; 3'b011 : key_num=4'h3; default: key_num=4'h0; endcase end //--------------------------------------------------// reg lock; wire [3:0] sec_h; wire [3:0] sec_l; always @(posedge sysclk or negedge rst_n) begin if(!rst_n) lock<=1'h0; else if((key_reg==3'h7)&&(!sec_h)&&(!sec_l)) //当没有键盘按下且两个数码管显示都为0时; lock<=1'h1; else lock<=lock; end reg [3:0] smg_l; always @(posedge sysclk or negedge rst_n) begin if(!rst_n) smg_l<=4'h0; else if(key_reg!=3'h7) smg_l<=key_num; else smg_l<=sec_l; end reg [3:0] smg_h; always @(posedge sysclk or negedge rst_n) begin if(!rst_n) smg_h<=4'h0; else if(key_reg!=3'h7) smg_h<=4'h0; else smg_h<=sec_h; end //---------------------------------------------------------// 蜂鸣器和LED灯控制; reg [31:0] lig_buz_time; reg lig_buz_en; always @(posedge sysclk or negedge rst_n) begin if(!rst_n) lig_buz_time<=32'h0; else if(lig_buz_time==32'h17_D7840) lig_buz_time<=32'h0; else if(lig_buz_en) lig_buz_time<=lig_buz_time+32'h1; else lig_buz_time<=lig_buz_time; end always @(posedge sysclk or negedge rst_n) begin if(!rst_n) lig_buz_en<=1'h1; else if(lig_buz_time==32'h17_D7840) //lig_buz_en维持高电平的时间; lig_buz_en<=1'h0; else if((!rst_n)||(lock)||((key_reg==3'h7)&&(key!=3'h7))) lig_buz_en<=1'h1; else lig_buz_en<=lig_buz_en; end //-----------------------------------------------------//蜂鸣器模块; fmq fmq ( .sysclk(sysclk), .rst_n(rst_n), .buzzer_en(lig_buz_en), .buzzer(buzzer) ); //----------------------------------------------------// LED灯模块; led led ( .sysclk(sysclk), .rst_n(rst_n), .light_en(lig_buz_en), .led_out(led_out) ); //---------------------------------------------------//1s 计数模块; count counter_1s ( .sysclk(sysclk), .rst_n(rst_n), .cnt_max_num(4'h9), .div_clk_num(div_clk_num1), .data_out(sec_l) ); count counter_10s //10s 计数模块; ( .sysclk(sysclk), .rst_n(rst_n), .cnt_max_num(4'h3), .div_clk_num(div_clk_num2), .data_out(sec_h) ); smg smg ( .sysclk(sysclk), .rst_n(rst_n), .data_0(smg_l), .data_1(smg_h), .smg_sel(smg_sel), .smg_data(smg_data) ); endmodule
//计数模块; module count ( sysclk, rst_n, cnt_max_num, div_clk_num, data_out ); input sysclk; input rst_n; input[3:0] cnt_max_num; input[31:0] div_clk_num; output[3:0] data_out; wire sysclk; wire rst_n; wire[3:0] cnt_max_num; wire[31:0] div_clk_num; wire[3:0] data_out; //-------------------------------------------------------// reg [31:0] num; always @ (posedge sysclk or negedge rst_n) begin if(!rst_n) num<=32'h0; else if(num==div_clk_num) num<=32'h0; else num<=num+32'h1; end //----------------------------------------------------------------// reg clk_div; reg clk_div_n; always @(posedge sysclk or negedge rst_n) begin if(!rst_n) clk_div<=1'h0; else clk_div<=clk_div_n; end always @ (*) begin if(num==div_clk_num) clk_div_n<=~clk_div; else clk_div_n<=clk_div; end //----------------------------------------------------------------// reg[3:0] data_out_r; always @( posedge sysclk or negedge rst_n) begin if(!rst_n) data_out_r<=cnt_max_num; else if((data_out_r==4'h0)&&(clk_div)&&(!clk_div_n)) data_out_r<=cnt_max_num ; else if((clk_div)&&(!clk_div_n)) data_out_r<=data_out_r-4'h1; else data_out_r<= data_out_r; end assign data_out=data_out_r; endmodule
//蜂鸣器模块; module fmq ( sysclk, rst_n, buzzer_en, buzzer ); input sysclk; //50MHZ; input rst_n; input buzzer_en; output buzzer; //500HZ; wire sysclk; wire rst_n; wire buzzer_en; reg buzzer; reg [23:0] div_cnt; always @ (posedge sysclk or negedge rst_n) begin if(!rst_n) div_cnt<=24'h0; else if(div_cnt==24'hC350) div_cnt<=24'h0; else div_cnt<=div_cnt+24'h1; end always @ (posedge sysclk or negedge rst_n) begin if(!rst_n) buzzer<=1'h0; else if((buzzer_en)&&(div_cnt==24'hC350)) buzzer<=~buzzer; else buzzer<=buzzer; end endmodule
//LED灯模块; module led ( sysclk, rst_n, light_en, led_out ); input sysclk; input rst_n; input light_en; output[3:0] led_out; wire sysclk; wire rst_n; wire light_en; wire[3:0] led_out; //----------------------------------------------------// reg [23:0] led_cnt; always @ (posedge sysclk or negedge rst_n) begin if(!rst_n) led_cnt<=24'h0; else if(led_cnt==24'h33_12D0) led_cnt<=24'h0; else led_cnt<=led_cnt+24'h1; end reg [3:0] led_out_r; always @ (posedge sysclk or negedge rst_n) begin if(!rst_n) led_out_r<=4'b1111; else if((light_en)&&(led_cnt==24'h33_12D0)) led_out_r<=~led_out_r; else if(light_en) led_out_r<=led_out_r; else led_out_r<=4'b1111; end assign led_out=led_out_r; endmodule
//数码管模块; module smg ( sysclk, rst_n, data_0, data_1, smg_sel, smg_data ); input sysclk; input rst_n; input[3:0] data_0; input[3:0] data_1; output[1:0] smg_sel; output[6:0] smg_data; wire sysclk; wire rst_n; wire[3:0] data_0; wire[3:0] data_1; reg[1:0] smg_sel; reg[6:0] smg_data; //-----------------------------------------------------------// reg[23:0] cnt; always @ (posedge sysclk or negedge rst_n) begin if(!rst_n) cnt<=24'h0; else if(cnt==24'h3_D090) cnt<= 24'h0; else cnt<=cnt+24'h1; end //------------------------------------------------------------// reg smg_sel_num; //数码管片选寄存器; always @(posedge sysclk or negedge rst_n) begin if(!rst_n) smg_sel_num<=1'h0; else if(cnt==24'h3_D090) smg_sel_num<=smg_sel_num+1'h1; else smg_sel_num<=smg_sel_num; end always @(*) begin case(smg_sel_num) 1'h0 : smg_sel=2'b01; 1'h1 : smg_sel=2'b10; default: smg_sel=2'b00; endcase end //-------------------------------------------------------------// reg[3:0] smg_data_num; //数码管段选寄存器; always @ (*) begin case(smg_sel_num) 1'h0 : smg_data_num=data_0; 1'h1 : smg_data_num=data_1; default: smg_data_num=4'h0; endcase end always @ (*) begin case(smg_data_num) 4'h0: smg_data[6:0]=7'b100_0000; 4'h1: smg_data[6:0]=7'b111_1001; 4'h2: smg_data[6:0]=7'b010_0100; 4'h3: smg_data[6:0]=7'b011_0000; 4'h4: smg_data[6:0]=7'b001_1001; 4'h5: smg_data[6:0]=7'b001_0010; 4'h6: smg_data[6:0]=7'b000_0010; 4'h7: smg_data[6:0]=7'b111_1000; 4'h8: smg_data[6:0]=7'b000_0000; 4'h9: smg_data[6:0]=7'b001_0000; default:smg_data[6:0]=7'b111_1111; endcase end endmodule