英特尔FPGA实训day9

今天是实训第九天,今天主要是完成了电子表的更加完善的设计。上午设计了闹钟,即到达一定时间后就进行鸣叫,下午进行了自主设计,将电子表设计成可以显示时间,设置时间,设置闹钟时间,并用数码管显示。

收获:

        今天主要的收获,就是对 一些模块更加熟悉,慢慢自己学会了书写与应用,如计时模块等,有了更深的理解,基本上能灵活应用。同时还有一些语法问题,latch的产生。还有就是找到了一些可以自学的资源,即:野火fpga官网的一些文档资源,(相关链接)。这对于后续长期学习,以及查错,纠错提供了新渠道思路。以及对后续学其他东西找资源,有了新启发。

同时通过这么些天对fpga的学习,终于对其能够有所辨识,有所与之前接触的stm32等逐渐区别开。

产生疑惑及解决:

        Q: 我们这个按键,如key[0]按下后,key[0]变成1,后续呢?后续恢复成0,还是仍然为1? 

        A:该问题产生,主要是因为其应用于if判断语句。针对我们这个程序,因为是松开按键的时候会产生一个flag信号,也即key[0]变成1,所以这个是一个瞬间的事,也即 再下一次再面对该if语句的时候,就已经变成0了,也即,其没有存储或持续功能。所以也不能再其内部再嵌套一个用key等相关的判断语句。

        Q:顶层文件中可以写always吗?

        A: 目前理解,应该是不能的,顶层文件只做实例化,所以最好不要出现always用于组合逻辑电路的 写法。

学习杂记,及相关文件设计思路:

在书写电子时钟过程,个人逻辑还是感觉比较清晰。但语法等,还有一些注意点,没能注意到,导致最终没能很好完成任务,其中典型的就是latch的产生。

        latch 的产生典型的三种情况:1. always中if没有else  2. always中case没列举完,且没有default、 2. 输出值给自己赋值 

If else基本结构

if-else 条件语句的这种使用形式中没有出现 else ,这种情况下条件分支语句的执行过程是:如果指定的<条件表达式>成立(也就是这个条件表达式的逻辑值为“ 1”,则执行条件分支语句内给出的语句或语句块,然后退出条件分支语句的执行; 如果<条件表达式>不成立(也就是条件的表达式的逻辑值为“0”“x”“z”),则不执行条件分支语句内给出的语句或语句块,而是直接退出条件语句的执行。这种写法如果在always块中表达组合逻辑时会产生latch,所以不推荐这种写法。

有if  最终一定要有单独的else

If  嵌套写法   

Case语句注意的是,不要出现相同的值

学会层次化设计

今天先简单写在这里。

闹钟的代码实现:

顶层文件:top_sel_led_dynamic

module top_sel_led_dynamic(
    input clk,
    input rst_n,

    output beep,
    output [5:0] sel,
    output [7:0] seg
);

parameter TIME = 26'd19_999;
parameter CNT_SEC = 26'd49_999_999;


parameter   CNT_MAX = 24'd14_999_999;//300ms
parameter   DO  	= 16'd47750		;//1
parameter   RE  	= 16'd42250		;//2
parameter   MI  	= 16'd37900		;//3
parameter   FA  	= 16'd37550		;//4
parameter   SO  	= 16'd31850		;//5
parameter   LA      = 16'd28400		;//6
parameter   XI  	= 16'd25400		;//7
wire flag;

wire flag_reg;
wire sec;
wire temp;

time_count #(.TIME (TIME))u_time_count(//计数数码切换的时间
.clk (clk),
.rst_n (rst_n),

.flag (flag_reg)
);


time_count #(.TIME (CNT_SEC)) u1_time_count(
.clk (clk),
.rst_n (rst_n),

.flag (sec)
);


sel_led_dynamic  u_sel_led_dynamic(//数码管控制模块
.clk (clk),
.rst_n (rst_n),
.flag (flag_reg),
.sec (sec),

.temp (temp),
.sel (sel),
.seg (seg)
);



//实例化音频选择模块
freq_select#(
.CNT_MAX 	(CNT_MAX),
.DO  	  	(DO)     ,
.RE  	  	(RE)     ,
.MI  	  	(MI)     ,
.FA  	  	(FA)     ,
.SO  	  	(SO)     ,
.LA     	(LA)     ,
.XI  	  	(XI)
) u_freq_select(

.clk		(clk)  ,
.rst_n		(rst_n),
		
.flag		(flag)
);
//实例化pwm产生模块
gen_pwm	u_gen_pwm
(
.clk		(clk)  ,
.rst_n		(rst_n),
.flag		(flag) ,
.temp       (temp),
		
.beep		(beep)
);
endmodule

计时模块 time_out

module time_count(
    input clk,
    input rst_n,

    output reg flag
);

parameter TIME = 26'd49_999_999;

reg [25:0] cnt;

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        cnt <= 26'd0;
        flag <= 1'b0;
    end 
    else if(cnt == TIME)begin 
        cnt <= 26'd0;
        flag <= 1'b1;
    end 
    else begin 
        cnt <= cnt + 1'd1;
        flag <= 1'b0;
    end 
end

endmodule 

数码管显示及时间设置:sel_led_dynamic

module sel_led_dynamic(
    input clk,
    input rst_n,
    input flag,
    input sec,

    output reg temp,
    output reg [5:0] sel,
    output reg [7:0] seg
);


reg [3:0] cstate;//当前状态
reg [3:0] nstate;//下一状态

reg [3:0] value;//保存数码要显示的数字

reg [16:0] sec_sum;///记录过去的总秒数

wire [1:0] hour_h;
wire [3:0] hour_l;
wire [2:0] min_h;
wire [3:0] min_l;
wire [2:0] sec_h;
wire [3:0] sec_l;
 
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        sec_sum <= 17'd30000;               //30000s  08:20:00
        temp <= 1'b0;
    end 
    else if(sec_sum == 17'd86399)begin 
        sec_sum <= 17'd0;
        temp <= 1'b0;
    end
    else if(sec)begin
        sec_sum <= sec_sum + 1'd1;
        temp <= 1'b0;
    end
    else if(sec_sum == 17'd30005)begin//闹钟计时达到
        temp <= 1'b1;
    end 
    else begin 
        sec_sum <= sec_sum;
        temp <= 1'b0;
    end 
end



always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        cstate <= 3'd0;
    end
    else begin 
        cstate <= nstate;
    end 
end

always @(*)begin 
     if(!rst_n)begin
       nstate = 3'd0;
     end
     else begin 
        case (cstate)
            3'd0: if(flag)begin
                nstate = 3'd1;
            end
            else begin
                nstate = 3'd0;
            end

            3'd1: if(flag)begin
                nstate = 3'd2;
            end
            else begin
                nstate = 3'd1;
            end

            3'd2: if(flag)begin
                nstate = 3'd3;
            end
            else begin
                nstate = 3'd2;
            end

            3'd3: if(flag)begin
                nstate = 3'd4;
            end
            else begin
                nstate = 3'd3;
            end

            3'd4: if(flag)begin
                nstate = 3'd5;
            end
            else begin
                nstate = 3'd4;
            end

            3'd5: if(flag)begin
                nstate = 3'd0;
            end
            else begin
                nstate = 3'd5;
            end
            default: nstate = 3'd0;
        endcase
     end 
end

assign hour_h = sec_sum / 3600 / 10;
assign hour_l = sec_sum / 3600 % 10;
assign min_h  = sec_sum % 3600 / 60 / 10;
assign min_l  = sec_sum % 3600 / 60 % 10;
assign sec_h  = sec_sum % 60 / 10;
assign sec_l  = sec_sum % 60 % 10;

always @(*)begin 
     if(!rst_n)begin
       sel = 6'b0;
     end
     else begin 
        case (cstate)
            3'd0: begin
                sel = 6'b111_110;
                value = hour_h;
            end 
            3'd1: begin
                sel = 6'b111_101;
                value = hour_l;
            end
            3'd2: begin
                sel = 6'b111_011;
                value = min_h;
            end
            3'd3: begin
                sel = 6'b110_111;
                value = min_l;
            end
            3'd4: begin
                sel = 6'b101_111;
                value = sec_h;
            end
            3'd5: begin
                sel = 6'b011_111;
                value = sec_l;
            end
            default: begin
                sel = 6'b000_000;
                value = 3'd6;
            end
        endcase
     end 
end


always @(*)begin 
     if(!rst_n)begin
       seg = 8'b0;
     end
     else begin 
        case (value)
            4'd0:    seg <= 8'b1100_0000;//匹配到后参考共阳极真值表
	        4'd1:    seg <= 8'b1111_1001;
	        4'd2:    seg <= 8'b1010_0100;
	        4'd3:    seg <= 8'b1011_0000;
	        4'd4:    seg <= 8'b1001_1001;
	        4'd5:    seg <= 8'b1001_0010;
	        4'd6:    seg <= 8'b1000_0010;
	        4'd7:    seg <= 8'b1111_1000;
	        4'd8:    seg <= 8'b1000_0000;
	        4'd9:    seg <= 8'b1001_0000;
			 default :   seg = 8'b00000000;
        endcase
     end 
end
endmodule

pwm波的产生:gen_pwm

module gen_pwm(
    input clk,
    input rst_n,
    input flag,
    input temp,

    output reg beep
);
parameter TIME = 26'd49_999_999;
reg add_cnt;
reg [25:0] cnt;
reg [5:0] cnt_1m;
wire add_cnt_1s;
wire end_cnt_1s;

wire add_cnt_1m;
wire end_cnt_1m;

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        add_cnt <= 1'b0;
    end 
    else if(temp)begin
        add_cnt <= 1'b1;
    end
    else if(end_cnt_1m)begin
        add_cnt <= 1'b0;
    end
    else begin
        add_cnt <= add_cnt;
    end
end

always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt <= 0;
    end 
    else if(add_cnt_1s)begin 
            if(end_cnt_1s)begin 
                cnt <= 0;
            end
            else begin 
                cnt <= cnt + 1;
            end 
    end
   else  begin
       cnt <= cnt;
    end
end 

assign add_cnt_1s = add_cnt;
assign end_cnt_1s = add_cnt_1s && (cnt == TIME);

always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_1m <= 6'd0;
    end 
    else if(add_cnt_1m)begin 
            if(end_cnt_1m)begin 
                cnt_1m <= 6'd0;
            end
            else begin 
                cnt_1m <= cnt_1m + 1'd1;
            end 
    end
   else  begin
       cnt <= cnt;
    end
end 

assign add_cnt_1m = end_cnt_1s;
assign end_cnt_1m = add_cnt_1m && cnt_1m == 59;

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        beep <= 1'b1;
    end 
    else if(add_cnt)begin 
        if(flag)begin 
            beep <= 1'b0;
        end 
        else begin 
            beep <= 1'b1;
        end 
    end 
    else begin 
        beep <= 1'b1;
    end 
end

endmodule

蜂鸣器音乐鸣叫 设置:freq_select

module freq_select
(
	input  wire 	clk  ,//时钟信号
	input  wire 	rst_n,//复位信号
	
	output reg		flag//pwm标志     
	
);
parameter   CNT_MAX = 24'd14_999_999;//300ms
parameter   NUM_FRE = 6'd33			;//34个音符
parameter   DO  	= 16'd47750		;//1
parameter   RE  	= 16'd42250		;//2
parameter   MI  	= 16'd37900		;//3
parameter   FA  	= 16'd37550		;//4
parameter   SO  	= 16'd31850		;//5
parameter   LA      = 16'd28400		;//6
parameter   XI      = 16'd25400		;//7
reg  [23:0]  cnt_delay   ;//300ms计数器
reg  [5:0]	 lut_data    ;//乐谱数据寄存器
reg  [15:0]	 cnt_freq    ;//音符音频计数器
reg  [15:0]	 freq_data   ;//音符数据寄存器
wire [14:0]  duty_data   ;//占空比数据
wire 		 end_note    ;//音符结束标志
wire 		 end_spectrum;//音谱结束标志
//单个音符持续时间计时模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt_delay <= 24'd0;
	end 
	else if(cnt_delay == CNT_MAX)begin
		cnt_delay <= 24'd0;
	end 
	else begin
		cnt_delay <= cnt_delay + 1'd1;
	end 
end 

//音符计时模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt_freq <= 16'd0;
	end 
	else if(end_note)begin
		cnt_freq <= 16'd0;
	end 
	else begin
		cnt_freq <= cnt_freq + 1'd1;
	end 
end 

//音谱计时模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		lut_data <= 6'd0;
	end 
	else if(end_spectrum)begin
		lut_data <= 6'd0;
	end 
	else if(cnt_delay == CNT_MAX)begin
		lut_data <= lut_data + 1'd1;
	end 
	else begin
		lut_data <= lut_data;
	end 
end 

//音符查找表模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		freq_data <= DO;
	end 
	else begin
		case(lut_data)
			6'd0:	freq_data <= DO;
			6'd1:	freq_data <= RE;
			6'd2:	freq_data <= MI;						
			6'd3:	freq_data <= DO;					
			6'd4:	freq_data <= DO;					
			6'd5:	freq_data <= RE;					
			6'd6:	freq_data <= MI;					
			6'd7:	freq_data <= DO;					
			6'd8:	freq_data <= MI;					
			6'd9:	freq_data <= FA;					
			6'd10:	freq_data <= SO;
			6'd11:	freq_data <= MI;
			6'd12:	freq_data <= FA;
			6'd13:	freq_data <= SO;
			6'd14:	freq_data <= SO;
			6'd15:	freq_data <= LA;
			6'd16:	freq_data <= SO;
			6'd17:	freq_data <= FA;
			6'd18:	freq_data <= MI;
			6'd19:	freq_data <= DO;
			6'd20:	freq_data <= SO;
			6'd21:	freq_data <= LA;
			6'd22:	freq_data <= SO;
			6'd23:	freq_data <= FA;
			6'd24:	freq_data <= MI;
			6'd25:	freq_data <= DO;
			6'd26:	freq_data <= RE;
			6'd27:	freq_data <= SO;
			6'd28:	freq_data <= DO;
			6'd29:	freq_data <= DO;
			6'd30:	freq_data <= RE;
			6'd31:	freq_data <= SO;
			6'd32:	freq_data <= DO;
			6'd33:	freq_data <= DO;
			default:freq_data <= DO;
		endcase  
	end         
end  

assign duty_data = freq_data >> 1;//占空比50%

assign end_note = cnt_freq == freq_data;
assign end_spectrum = lut_data == NUM_FRE && cnt_delay == CNT_MAX;
//pwm信号产生模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		flag <= 1'b0;
	end 
	else begin
		flag <= (cnt_freq >= duty_data) ? 1'b1 : 1'b0; 
	end 	 
end         
endmodule                

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值