module freq_select( input sys_clk , input sys_rst_n , input [1: 0] dev_id , input [3: 0] opcode , input [3: 0] data , output pwm ); parameter MAX = 24'd15_000_000;//300ms最大数 parameter TWO_TIGER = 6'd34, SKY_CITY = 6'd64;//音符个数 parameter DO = 16'd47750,//1 RE = 16'd42550,//2 MI = 16'd37900,//3 FA = 16'd37550,//4 SO = 16'd31850,//5 LA = 16'd28400,//6 XI = 16'd25400;//7 reg start_flag; reg [23: 0] cnt_300 ; wire add_cnt_300; wire end_cnt_300; reg [5: 0] cnt_note; wire add_cnt_note; wire end_cnt_note; reg [15: 0] cnt_freq; wire add_cnt_freq; wire end_cnt_freq; reg [5: 0] note ; wire [15: 0] duty ;//占空比 reg [15: 0] X; always @(posedge sys_clk or negedge sys_rst_n)begin if(!sys_rst_n)begin start_flag <= 1'b0; end else if(dev_id == 2'd1 && opcode == 4'b0010)begin start_flag <= 1'b1; end else if(dev_id == 2'd1 && opcode == 4'b0001)begin start_flag <= 1'b0; end else begin start_flag <= start_flag; end end //300ms计数器设计 always @(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n)begin cnt_300 <= 24'd0; end else if(add_cnt_300)begin if(end_cnt_300)begin cnt_300 <= 24'd0; end else begin cnt_300 <= cnt_300 + 1'd1; end end else if(dev_id == 2'd1 && opcode == 4'b0001)begin cnt_300 <= 24'd0; end else begin cnt_300 <= cnt_300; end end assign add_cnt_300 = start_flag; assign end_cnt_300 = add_cnt_300 && (cnt_300 == MAX - 1'd1);//要么计数完成,要么重新开始指令有效 //34个音符计数器设计 always @(posedge sys_clk or negedge sys_rst_n)begin if(!sys_rst_n)begin cnt_note <= 6'd0; end else if(add_cnt_note)begin if(end_cnt_note)begin cnt_note <= 6'd0; end else begin cnt_note <= cnt_note + 1'd1; end end else if(dev_id == 2'd1 && opcode == 4'b0001)begin cnt_note <= 6'd0; end else begin cnt_note <= cnt_note; end end assign add_cnt_note = end_cnt_300; assign end_cnt_note = add_cnt_note && (cnt_note == note - 1'd1); //每个音符频率计数器 always @(posedge sys_clk or negedge sys_rst_n)begin if(!sys_rst_n)begin cnt_freq <= 16'd0; end else if(add_cnt_freq)begin if(end_cnt_freq)begin cnt_freq <= 16'd0; end else begin cnt_freq <= cnt_freq + 1'd1; end end else if(dev_id == 2'd1 && opcode == 4'b0001)begin cnt_freq <= 16'd0; end else begin cnt_freq <= cnt_freq; end end assign add_cnt_freq = start_flag; assign end_cnt_freq = add_cnt_freq && (cnt_freq == X - 1); //查找表 always @(*)begin case(data) 4'b0001: note = TWO_TIGER; 4'b0010: note = SKY_CITY; endcase end always @(*)begin case(cnt_note) 6'd0 : X = DO;//1 6'd1 : X = RE;//2 6'd2 : X = MI;//3 6'd3 : X = DO;//1 6'd4 : X = DO;//1 6'd5 : X = RE;//2 6'd6 : X = MI;//3 6'd7 : X = DO;//1 6'd8 : X = MI;//3 6'd9 : X = FA;//4 6'd10 : X = SO;//5 6'd11 : X = MI;//3 6'd12 : X = FA;//4 6'd13 : X = SO;//5 6'd14 : X = SO;//5 6'd15 : X = LA;//6 6'd16 : X = SO;//5 6'd17 : X = FA;//4 6'd18 : X = MI;//3 6'd19 : X = DO;//1 6'd20 : X = SO;//5 6'd21 : X = LA;//6 6'd22 : X = SO;//5 6'd23 : X = FA;//4 6'd24 : X = MI;//3 6'd25 : X = DO;//1 6'd26 : X = RE;//2 6'd27 : X = SO;//5 6'd28 : X = DO;//1 6'd29 : X = DO;//1 6'd30 : X = RE;//2 6'd31 : X = SO;//5 6'd32 : X = DO;//1 6'd33 : X = DO;//1 default: X = DO;//1 endcase end assign duty = X >> 1;//占空比是1/2 assign pwm = (cnt_freq >= duty) ? 1'b0: 1'b1; endmodule