发布时间 : 星期一 文章Verilog实现FSK解调更新完毕开始阅读
Verilog实现FSK解调
FSK(Frequency-shift keying)频移键控是利用载波的频率变化来传递数字信息。它是利用基带数字信号离散取值特点去键控载波频率以传递信息的一种数字调制技术。FSK解调就是将频率信号转换成数字信号,完成频率-幅度转换的过程。本文介绍利用Verilog硬件描述语言实现调制电路。
一、原理分析
2FSK信号是用载波频率的变化来表征被传信息的状态的,被解调波的频率随二进制序列0、1状态而变化。如图1,当输入信号频率高时,输出信号为1;当输入信号频率低时,输出信号为0。
图1 调制输入信号与输出信号
二、信号要求与指标
在FSK解调时,需要给输入信号的频率划分高频率段和低频率段,来区分解调后二进制状态1或0。为了简便起见,本文给出的输入信号为方波信号,这里取每12个clk时钟信号后为一个采样点,每次采样时如果输入信号的上升沿数大于等于3,输出信号即为1;反之,输出信号即为0。
三、Verilog设计方案
通过对clk上升沿和cin上升沿计数,cnt为clk计数器,而count为cin的计数器,当cnt==11时,查看count的值,如果大于等于3,那么此时检测到的就是高频率输入信号,所以此时cout输出高电平1,否则输出低电平0。这样就完成了频率-幅度转换,把高频率和低频率利用幅度上区分开来,恢复了数字信号。
四、Verilog代码
实现FSK解调的代码如下(有代码注释): //解调模块
module fsk(cin,clk,start,cout); input cin,clk,start;
output cout; reg cout;
reg[3:0]cnt; //对clk计数 reg[2:0]count; //对cin计数 reg ec; //同步计数 initial ec=1'b0; initial cnt=4'b0; initial count=3'b0; initial cout<=0;
always@(posedge clk or posedge start) //对clk计数 begin
if(start) //开启信号 begin
cnt<=0; ec<=1'b1; end else begin
if(cnt==11) //每12个clk周期后有一个采样点 begin cnt<=0;
ec<=1'b1; //采样点状态 end else begin
cnt<=cnt+1; //clk计数 ec<=1'b0; end end end
always@(posedge cin or posedge ec) //对cin计数 begin
if(ec)
count<=0; //采样后计数清零 else
count<=count+1; //cin计数 end
always@(count or cnt) begin
if(cnt==11)
cout<=(count>=3)?1:0; //采样点时频率高为1频率低为0 end
endmodule
五、逻辑仿真
利用Modelsim对代码进行仿真。测试信号为一个低频高频交替变化的方波信号,首先编写测试代码如下: //测试模块
`timescale 1ns/1ns
`include \module fsktest; reg cin,clk,start; wire cout;
initial //产生时钟信号 begin clk=1; forever
#10 clk=~clk; end
initial //产生开启信号 begin start=1; #5 start=0; end
initial //产生cin测试信号 begin cin=0; repeat(8) begin repeat(12) #20 cin=~cin; repeat(4)
#60 cin=~cin; end end
fsk fsk1(.cin(cin),.clk(clk),.start(start),.cout(cout)); endmodule
利用工具Modelsim编译,解调模块和测试模块均没有错误,编译成功。如图2。
图2 编译
接下来进行仿真,给出start、cin、cout信号随clk信号变化的波形图,如图
3。
图3 仿真波形图
从波形图上可以看出,当测试信号频率高时,经解调后的输出信号为1;当测试信号频率低时,经解调后的输出信号为0。但是会有一个采样周期的延迟,就是说解调后信号比输入信号慢一个采样周期。但总的来说,本文介绍的利用Verilog硬件描述语言编写的FSK解调电路基本完成的对FSK的解调。
六、综合
对仿真完的解调模块进行综合,利用工具Design Compiler。综合后电路图如图4。
图4 综合后电路图
综合后生成逻辑网表如下: module fsk ( cin, clk, start, cout ); input cin, clk, start; output cout;
wire N9, N10, N11, N15, N16, N18, N19, n7, n8, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20, n21; wire [3:0] cnt; wire [2:0] count;
LD1 cout_reg ( .D(N15), .G(N16), .Q(cout) );
FD2 \\count_reg[0] ( .D(n13), .CP(cin), .CD(n8), .Q(count[0]), .QN(n13) ); FD2 \\count_reg[1] ( .D(N18), .CP(cin), .CD(n8), .Q(count[1]), .QN(n16) ); FD2 \\count_reg[2] ( .D(N19), .CP(cin), .CD(n8), .Q(count[2]) );
FD2 \\cnt_reg[0] ( .D(n11), .CP(clk), .CD(n7), .Q(cnt[0]), .QN(n11) );