二进制移频键控(2FSK)
用二进制数字基带信号去控制正弦载波的载频称为二进制移频键控(2FSK)。此时对应于传号与空号的载波频率分别为f1及f2。
频移键控(FSK):
FSK时域波形:
相位不连续的2FSK信号:
相位连续的2FSK信号:
采用top_down设计思想,将正弦波产生器分为三个模块。分别是顶层模块A_sin_gen,子模块B1_addr和子模B2_sin。
图1 设计的总体框图
其中顶层模块主要定义输入输出关系,划分两个子模块的接口,搭建起两个子模块的框架,整个设计要素如图2所示:
图2 顶层模块A_sin_gen的设计要素
子模块B1_addr主要用来产生对ROM的寻址。按照时钟街拍,改变寻址的步进,就可以改变输出正弦波的频率。该模块可以采用简单的向上计数器产生。模块设计要素如图3所示:
图3. 子模块B1_addr的设计要素
子模块B2_sin则主要用LPM_ROM宏模块产生。
一、总体方案设计
图 1 FSK总体设计方案
图1为本次课程设计的总体方案,输入信号为时钟信号CLK和使能信号ENABLE,输出信号为调制信号。
其中输入信号CLK为50MHz的时钟信号,通过PLL锁相环实现分频和倍频,输出三路信号,分别为445MHz、890MHz和2MHz。
输入信号ENABLE分别为PLL锁相环和两个7位计数器提供使能,高电平启动,低电平关机。
正弦波数据存储ROM的地址信号发生器由7位计数器担任,其中ROM的数据长度为128,数据位宽为8,当地址发生器接收到特定时钟信号频率为f ,ROM输出的信号频率为fn=f128 ,为实现输出两路信号分别为6.5MHz和3.5MHz的频率的载波,代入公式求得两路分别输入的时钟信号频率约为445MHz和890MHz。
为了满足码元速率为1MHz的数字信号处理需求,模拟基带信号是由PLL锁相环经过分频得到的2MHz的方波信号。
在二选一数据选择器进行频率选择,根据输入的模拟基带信号的高低电平,在两个独立的正弦载波之间进行切换输出调制信号。
二、系统硬件电路设计
图2 RTL原理图
图2为Verilog语言实现的RTL原理图
三、系统软件设计
3.1主流程图
图3.1 总体流程图
3.2开始
使能信号ENABLE置高电平,启动所有时序。
3.3 频率信号发生器
该部分由三部分构成:分频和倍频器——PLL(锁相环)、ROM地址发生器——7位计数器、正弦波数据存储器——ROM。
锁相环PLL和正弦波数据存储器是调用IP核实现,ROM地址发生器是通过Verilog语言编写的,三部分是通过例化组合成的。
3.3.1锁相环配置
图 3.3.1配置输入时钟
图 3.3.2选择输入使能信号
图3.3.3配置输出时钟1
图3.3.4 配置输出时钟2
图3.3.4配置输出时钟3
图3.3.5生成可例化的.v文件
3.3.2地址发生器(7位计数器)
module addr #(parameter step = 1) //抽样频率
(clk,rst_n,RD_addr);
input clk;
input rst_n;
output[6:0] RD_addr;
reg[6:0] addr;
assign RD_addr = addr;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
addr <= 0;
else addr <= addr + step;
end
endmodule
使用Verilog语言编写实现
图3.3.6地址发生器的RTL图
在输入使能信号enable为高电平时,加法器addr启动,当时钟频率来一个上升沿,就进行一位加1,当计满七位,地址发生器自动清零。地址发生器产生控制ROM波形数据表的地址,输出信号的频率由ROM地址的变化速率决定,变化越快,输出频率越高。由于ROM的容量会受到地址位宽的影响,为防止ROM的容量过大,设定地址发生器的输出位宽为7位。
3.3.3正弦波数据存储器ROM
ROM用于存放波形数据,选取ALTERA中的单端口ROM,单端口ROM只提供一个地址端口和一个读数据端口,数据位宽设为8,数据长度设为128,则数据总位数为8×128=1024。
使用quartus Ⅱ自带的Mif_Maker2010.exe(波形数据生成器)
设定波形全局参数
图3.3.7配置数据长度和位宽
图3.3.8将对应的mif文件导入
图3.3.9生成可例化的.v文件
将地址发生器和正弦波数据存储器ROM组合起来即可构成最简单的DDS(直接数字合成器),根据DDS原理:fOUT=B∆θ2NfCLK ,其中fOUT 为输出信号,fCLK 为输入时钟信号,B∆θ 为频率输入字,2N 为数据长度,N 为加法器的数据位宽。在这设置的地址发生器的输出位宽为7位,而频率输入字(B∆θ )为0,则输出频率fOUT=fCLK2N ,因此,当地址发生器选择7为的加法器时,fOUT=fCLK27 。
3.4二选一数据选择器
module modulation(clk,DDSin,DA_Data1,DA_Data2,DDS_out);//定义模块和端口
input clk;//输入的时钟
input DDSin;//需要调制的信号
input wire [7:0]DA_Data1;//输入的载波=‘0’
input wire [7:0]DA_Data2;//输入的载波=‘1’
output wire[7:0]DDS_out;//输出的调制完成的信号
reg [7:0]DOUT;//模块定义内部寄存器
always @(posedge clk)//每当时钟上升沿时触发
begin
if(DDSin==0)//如果输入的基带信号为0则输出位载波1
DOUT=DA_Data1;
else //如果输入的基带信号为1则输出位载波2
DOUT=DA_Data2;
end
assign DDS_out=DOUT;//
endmodule
图3.4.1二选一数据选择器的RTL图
通过判断模拟基带信号的高低电平,对两个独立的正弦载波之间进行切换,其中clk为选择器的采样频率。
3.5频移键控FSK顶层文件例化
module FSK_2(
input CLK,
input ENABLE,
output wire SIGNAL,
output wire CLK1,
output wire CLK2,
output wire [7:0]DA_Data1,
output wire [7:0]DA_Data2,
output wire [7:0]DDS_OUT
);
MYPLL PLL( // 例化锁相环
.inclk0(CLK),
.pfdena(ENABLE),
.c0(CLK1),
.c1(CLK2),
.c2(SIGNAL)
);
addr #(.step(1))
u1( //例化地址发生器1
.clk(CLK1),
.enable(ENABLE),
.RD_addr(RD_addr1)
);
sin_rom u2( //例化正弦波数据存储ROM1
.clock(CLK1),
.address(RD_addr1),
.q(DA_Data1)
);
addr #(.step(1))
u3( //例化地址发生器2
.clk(CLK2),
.enable(ENABLE),
.RD_addr(RD_addr2)
);
sin_rom u4( //例化正弦波数据存储ROM2
.clock(CLK2),
.address(RD_addr2),
.q(DA_Data2)
);
modulation choose( //例化数据选择器
.clk(CLK1),
.DDSin(SIGNAL),
.DA_Data1(DA_Data1),
.DA_Data2(DA_Data2),
.DDS_out(DDS_OUT)
);
endmodule
图3.5.1 RTL原理图
2FSK(频移键控)原本只有两路输入信号(使能信号ENABLE和输入时钟信号CLK)和一路输出信号(已调信号DDS_OUT),但为了方便后续的signal测试和modelsim仿真,另外引出了5路输出,其中DD_Data1和DD_Data2代表的输出两路不同频率的载波信号;CLK1和CLK2是经过锁相环PLL倍频后,输出的两路更高频率的时钟信号;最后一个SIGNAL——模拟基带信号,为了实现2FSK(频移键控)调整,且码元速率为1MHz的条件,将输入时钟信号CLK经过锁相环PLL分频得到0.5MHz的模拟基带信号SIGNAL,一高电平和一低电平为一周期,分别代表数据比特的“0”和“1”,一高电平或一低电平所占的时间为1000ns,相当于码元速率1MHz。
3.6配置modelsim仿真程序
`timescale 1 ns/ 1 ps
module FSK_2_vlg_tst();
// constants
// general purpose registers
// test vector input registers
reg clk;
reg rst;
// wires
wire [7:0] DA_Data1;
wire [7:0] DA_Data2;
wire [7:0] DDS_out;
wire canshu;
// assign statements (if any)
FSK_2 i1 (
// port map - connection between master ports and signals/registers
.DA_Data1(DA_Data1),
.DA_Data2(DA_Data2),
.DDS_out(DDS_out),
.canshu(canshu),
.clk(clk),
.rst(rst)
);
initial
begin
clk = 0;
rst = 0;
#5 rst = 1;
$display("Running testbench");
end
always #10 clk = ~clk;
endmodule