描述
使用fpga蜂鸣器连续发出do,re,mi,fa,so,la,xi七个不同的音调,每个音调的持续时间为0.5s。
思路
采用状态机实现音调的转化,当do状态持续了0.5s之后转移到re状态,以此类推...采用0.5s的时间flag信号控制状态机的转变。因为不同的音调有不同的频率,所以在每个时钟周期内需要发出不同频率的方波,采用计数器控制占空比,在每个状态下需要设置不同的频率计数器最大值,采用状态机控制计数器的频率最大值。
细节
设置输入clk,rst,输出beep
内部寄存器cnt_time 计数0.5s时间间隔,标志信号time_flag 每当计数0.5s拉高一个周期,当flag拉高时,状态寄存器状态改变
状态机采用三段式编写
设置内部寄存器cnt_wave,记录不同的频率最大值,设置变量wave_num为不同频率的最大值。
代码
module music
#(parameter time_max = 25'd24999999,
parameter dowave = 17'd95419,
parameter rewave = 17'd85033,
parameter miwave = 17'd75756,
parameter fawave = 17'd71632,
parameter sowave = 17'd63774,
parameter lawave = 17'd56817,
parameter xiwave = 17'd50606
)
(input wire clk,
input wire rst,
output reg beep);
parameter Do = 3'd0,Re = 3'd1,Mi= 3'd2,Fa = 3'd3,So=3'd4,La=3'd5,Xi=3'd6;
reg [24:0] cnt_time ;
reg [2:0] state,next_state;
reg time_flag;
reg [16:0] cnt_wave;
reg [16:0] wave_max;
//产生时钟信号
always@(posedge clk or negedge rst)
begin
if(rst == 1'd0)
cnt_time <= 25'd0;
else if (cnt_time == time_max)
cnt_time <=25'd0;
else
cnt_time <=cnt_time+25'd1;
end
always@(posedge clk or negedge rst)
begin
if(rst == 1'd0)
time_flag <= 1'd0;
else if(cnt_time == (time_max -1))
time_flag <=1'd1;
else
time_flag<=1'd0;
end
//七个音调状态
always@(posedge time_flag or negedge rst)
begin
if(rst == 1'd0)
state <= Do;
else
state <= next_state;
end
always@(*)
begin
if(rst == 1'd0)
next_state = Do;
else
begin
case (state)
Do: next_state = Re;
Re: next_state = Mi;
Mi: next_state = Fa;
Fa: next_state = So;
So: next_state = La;
La: next_state = Xi;
Xi: next_state = Do;
default: next_state=Do;
endcase
end
end
//产生不同的方波
always@(posedge clk or negedge rst)
begin
if(rst == 1'd0)
cnt_wave <= 17'd0;
else if((cnt_wave == wave_max)|| time_flag == 1'd1)
cnt_wave <= 17'd0;
else
cnt_wave <=cnt_wave +17'd1;
end
always@(posedge clk or negedge rst)
begin
if(rst ==1'd0)
beep <=1'd0;
else if(cnt_wave == wave_max)
beep <=~beep;
else
beep <=beep;
end
//选择不同的方波计数值
always@(posedge clk )
begin
case (next_state)
Do: wave_max <= dowave;
Re: wave_max <= rewave;
Mi: wave_max <= miwave;
Fa: wave_max <= fawave;
So: wave_max <= sowave;
La: wave_max <= lawave;
Xi: wave_max <= xiwave;
default: wave_max <= dowave;
endcase
end
endmodule
测试代码:
`timescale 1ns/1ns
`include"music.v"
module top();
reg clk;
reg rst;
wire beep;
initial
begin
rst = 1'b0;
clk = 1'b0;
#15
rst = 1'b1;
end
always #10 clk=~clk;
music
#(.time_max (25'd50),
.dowave (17'd39),
.rewave (17'd29),
.miwave (17'd21),
.fawave (17'd15),
.sowave (17'd10),
.lawave (17'd8),
.xiwave (17'd4))
m1(clk,rst,beep);
endmodule
仿真波形
错误:
状态变化时采用了时序逻辑,应该用组合逻辑,
cnt_time 计数器无法清零,清零条件应改为计数器计数到最大值或者时间等于0.5s时清零,若只有计数器计数到最大值清零,那么只会在第一个频率内有beep波形