Verilog实现的2FSK调制/解调器

文章目录

  • 前言
  • 一、调制解调概念
  • 1.2FSK原理
  • 二、硬件设计
  • 1.调制器设计思路
  • 2.解调器设计思路
  • 三、代码
  • 1.顶层
  • 2.F1载波发生模块
  • 3.F2载波发生模块
  • 4.频率计模块
  • 5.测试文件
  • 四、仿真结果

  • 前言

      在某些具体情况下,如通过电话线传输信息时,由于在电话线上只能传输模拟信号,因此需要将数字信号转换为模拟信号,进而将转换后的模拟信号进行传输。数据接收端对模拟信号进行采样,量化,编码后,还原出数字信号。
      在上述过程中,数据发送端将数字信号转换为模拟信号的过程叫做调制,数据接收端将模拟信号转为数字信号的过程叫做解调。

    一、调制解调概念

      数字信号调制的方法有很多,根据不同原理,有2FSK(二进制频率调制)、2PSK(二进制相移键控)、2ASK(二进制振幅键控)等等。但不管哪种方法,都建立了一种二进制信息与模拟信息之间的关系,当然不同的调制方法其对频带的利用率也有所不同。
      本篇主要进行基于2FSK的二进制信号调制的实验。

    1.2FSK原理

      2FSK是通过所要传输的数字信息控制载波的频率。如图1.0所示,现有两种不同频率的载波f1与f2,在数据发送端对输入信号进行调制时,根据当前所需要发送的数据Din,选择不同的载波,可以定义为 当 din=0b时,dout端口输出载波f1,当din=1b时,dout端口输出载波f2,则在dout端口输出的波形可以如图1.1中所示
                   图1.0 2FSK硬件原理简图

                   图1.1 2FSK波形图

      上述为调制部分,解调部分其实就是调制部分的逆过程,通过接收模拟信号,然后转换为数字量,进而计算信号的频率,然后对应还原基带信号。

    二、硬件设计

    1.调制器设计思路

      根据其原理,在设计调制器时,需要一个产生载波的模块,该模块需要能够产生两个不同频率的sin波形;其次需要一个移位寄存器作为数据的发送缓冲区;其大致结构如图2.0所示。

                   图2.0 2FSK调制器结构
      这里需要注意的是,为了保证每个传输数据都能有一个完整周期的载波表示,移位寄存器的时钟分频应当是载波f1与f2分频的整数倍乘积。

    2.解调器设计思路

      解调器实际上是一个频率计,频率计实时计算输入信号的频率,在通过一个频率的阈值比较器,判断输出的数字信号为1或0。
      这里由于考虑到模拟信号在传输过程中可能引入的干扰信号,为了不使通信出错,所以在频率计输入前再增加一个施密特触发器。其结构如图2.1所示。

                   图2.1 2FSK解调器结构
      施密特触发器将输入模拟信号转换为边沿脉冲信号,然后通过频率计计算频率,最终转换为数字信号输出。

    三、代码

    1.顶层

    module        FSK_2#(
        parameter integer CLOCK_DIV = 80
    )(
        input                fsk_clk,
        input                de_fsk_clk,//解调时钟
        input                fsk_en,
        input                fsk_rst,
        
        input      [7:0]         din,
        input      [7:0]       dqvld,//数据有效信号
        output                    do,
        output                   deo,
        output     [7:0]        dout,
        output     [15:0]      fre_o,
        output reg         send_qvld,//发送完成信号
        output reg             sbusy //繁忙标志位
        );
        
        localparam IDLE0 = 4'd0;
        localparam IDLE1 = 4'd1;
        localparam SEND = 4'd2;
        localparam FINISH = 4'd3;
        
        wire [7:0] f1_out;
        wire [7:0] f2_out;
        reg  [7:0] send_buff;//发送数据缓冲区
        
        reg [15:0] div_cnt;
        wire        send_clk;//数据发送时钟
        assign send_clk = div_cnt < ((CLOCK_DIV>>1)-1) ? 1'b1:1'b0;
        //分频
        always@(posedge fsk_clk,posedge fsk_rst)
        begin
            if(fsk_rst)
            begin
                div_cnt <= 16'd0;
            end
            else
            begin
                if(fsk_en)
                begin
                    if(div_cnt != CLOCK_DIV-1)
                        div_cnt <= div_cnt + 16'd1;
                    else
                        div_cnt <= 16'd0;
                end
                else
                begin  div_cnt <= div_cnt;end
            end
        end
        
        //数据发送状态机
         reg  [3:0] send_state;//发送数据缓冲区
         reg [3:0] bit_cnt;
         assign do = send_buff[0];
         assign dout = do ? f1_out:f2_out;
         always @ (posedge send_clk,posedge fsk_rst)
         begin
            if(fsk_rst)
            begin
                send_buff <= 8'd0;
                send_state <= 8'd0;
                send_qvld <= 1'b0;
                sbusy <= 1'b0;
                bit_cnt <= 4'd0;
            end
            else
            begin
                if(fsk_en)
                begin
                    case(send_state)
                        IDLE0:begin//空闲
                             sbusy <= 1'b0;
                              bit_cnt <= 4'd0;
                             if(dqvld)
                             begin
                                 send_buff <= din;
                                 send_state <= IDLE1;
                             end
                             else
                             begin
                                 send_state <= IDLE0;
                             end
                        end
                        IDLE1:begin//等待qvld撤销
                            sbusy <= 1'b1;
                            if(dqvld)
                             begin
                                 send_state <= IDLE1;
                             end
                             else
                             begin
                                 send_state <= SEND;
                             end
                        end
                        SEND:begin
                               if(bit_cnt != 4'd8)
                               begin    
                                    send_buff <= send_buff >> 1;
                                    bit_cnt <= bit_cnt + 4'd1;
                               end
                               else
                               begin send_state <= FINISH; end
                        end
                        FINISH:begin
                            send_qvld <= 1'b1;
                            send_state <= IDLE0;
                        end
                    endcase
                end
                else
                begin send_buff<=send_buff;send_state<=send_state; bit_cnt <= bit_cnt;send_qvld <= 1'b0;  end
            end
         end
        
        F1 F1_inist0(
        .  f1_clk(fsk_clk),
        .   f1_en(fsk_en),
        .  f1_rst(fsk_rst),
        .    dout(f1_out)
        );
        
        F2 F2_inist0(
        .  f2_clk(fsk_clk),
        .   f2_en(fsk_en),
        .  f2_rst(fsk_rst),
        .    dout(f2_out)
        );
        
        assign deo = fre_o >= 34? 1'b1:1'b0;
        cymo #(
            .SCH_thread0(130)
        )cymo_inist0(
           . cy_clk(de_fsk_clk),
           .    din(dout),
           .  cy_en(fsk_en),
           . cy_rst(fsk_rst),
           .  fre_o(fre_o)
        );
        
    endmodule
    
    

      在顶层模块中除了例化了f1与f2两个载波的发生模块和频率计模块外,还通过两个always块实现了移位寄存器和FSK的状态控制。
      在信号接口中,do为调制器需要调制的基带信号,deo为最终的解调信号。

    2.F1载波发生模块

    //10点采样sin波形
    module F1(
        input             f1_clk,
        input              f1_en,
        input             f1_rst,
        output reg [7:0]    dout
        );
        
        parameter integer sin0 = 128;
        parameter integer sin1 = 203;
        parameter integer sin2 = 250;
        parameter integer sin3 = 250;
        parameter integer sin4 = 203;
        parameter integer sin5 = 128;
        parameter integer sin6 = 52;
        parameter integer sin7 = 6;
        parameter integer sin8 = 6;
        parameter integer sin9 = 52;
        
        reg [3:0] f1_state;
        
        always @ (posedge f1_clk,posedge f1_rst)
        begin
            if(f1_rst)
            begin
                f1_state <= 4'd0;
            end
            else
            begin
                if(f1_en)
                begin
                    if(f1_state != 4'd9)
                    begin
                        f1_state <= f1_state+4'd1;
                    end
                    else
                    begin  f1_state <= 4'd0; end
                end
                else
                begin
                    f1_state <= f1_state;
                end
            end
        end
        
        always @ (posedge f1_clk,posedge f1_rst)
        begin
            if(f1_rst)
            begin
                f1_state <= 4'd0;
                dout <= sin0;
            end
            else
            begin
                if(f1_en)
                begin
                    case(f1_state)
                        4'd0:begin dout <= sin0; end    
                        4'd1:begin dout <= sin1; end  
                        4'd2:begin dout <= sin2; end
                        4'd3:begin dout <= sin3; end
                        4'd4:begin dout <= sin4; end    
                        4'd5:begin dout <= sin5; end 
                        4'd6:begin dout <= sin6; end
                        4'd7:begin dout <= sin7; end
                        4'd8:begin dout <= sin8; end
                        4'd9:begin dout <= sin9; end
                        default:begin dout<=sin0; end
                    endcase
                end
                else
                begin dout<=dout; end
            end
        end    
        
    endmodule
    
    

      载波可以通过cordic IP核计算发出,这里为了方便,选择了查表法。f1载波是10点采样的sin波形。

    3.F2载波发生模块

    //8点采样sin波形
    module F2(
        input             f2_clk,
        input              f2_en,
        input             f2_rst,
        output reg [7:0]    dout
        );
        
        parameter integer sin0 = 128;
        parameter integer sin1 = 218;
        parameter integer sin2 = 255;
        parameter integer sin3 = 218;
        parameter integer sin4 = 128;
        parameter integer sin5 = 37;
        parameter integer sin6 = 0;
        parameter integer sin7 = 37;
        
        reg [3:0] f2_state;
        
        always @ (posedge f2_clk,posedge f2_rst)
        begin
            if(f2_rst)
            begin
                f2_state <= 4'd0;
            end
            else
            begin
                if(f2_en)
                begin
                    if(f2_state != 4'd7)
                    begin
                        f2_state <= f2_state+4'd1;
                    end
                    else
                    begin  f2_state <= 4'd0; end
                end
                else
                begin
                    f2_state <= f2_state;
                end
            end
        end
        
        always @ (posedge f2_clk,posedge f2_rst)
        begin
            if(f2_rst)
            begin
                f2_state <= 4'd0;
                dout <= sin0;
            end
            else
            begin
                if(f2_en)
                begin
                    case(f2_state)
                        4'd0:begin dout <= sin0; end    
                        4'd1:begin dout <= sin1; end  
                        4'd2:begin dout <= sin2; end
                        4'd3:begin dout <= sin3; end
                        4'd4:begin dout <= sin4; end    
                        4'd5:begin dout <= sin5; end 
                        4'd6:begin dout <= sin6; end
                        4'd7:begin dout <= sin7; end
                        default:begin dout<=sin0; end
                    endcase
                end
                else
                begin dout<=dout; end
            end
        end    
        
    endmodule
    
    

      f2同样采用查表法,是8点采样的sin波形。
      假设现在f1与f2模块的输入时钟为10Mhz,则不难得出,f1频率为10Mhz/10 = 1Mhz ,f2频率为 10Mhz/8 = 1.125Mhz。

    4.频率计模块

    module cymo#(
        parameter integer SCH_thread0 = 150
    )(
            input            cy_clk,
            input         [7:0] din,
            input             cy_en,
            input             cy_rst,
            output reg [15:0]  fre_o
        );
        
        localparam  SCH_thread1 = (SCH_thread0<<1)/3;
        
        reg [3:0] cy_state;
        reg [15:0] cy_cnt;
        always@(posedge cy_clk,posedge cy_rst)
        begin
            if(cy_rst)
            begin
                cy_cnt<=16'd0;
                cy_state <= 4'd0;
            end
            else
            begin
                if(cy_en)
                begin
                    case(cy_state)
                        4'd0:begin
                            if(din>=SCH_thread0)
                            begin
                                 cy_state<=cy_state+4'd1;cy_cnt<=32'd0;//大于开始计时
                            end
                            else
                            begin
                                cy_state<=cy_state;
                            end
                        end
                        4'd1:begin
                            cy_cnt<=cy_cnt+32'd1;//定时器加
                            if(din<=SCH_thread1)
                                 cy_state<=cy_state+4'd1;//大于开始计时
                            else
                                cy_state<=cy_state;
                        end
                        4'd2:begin
                            if(din>=SCH_thread0)
                            begin
                                 cy_state<=4'd0;//大于开始计时
                                 fre_o<=cy_cnt;
                            end
                            else
                                 cy_cnt<=cy_cnt+32'd1;//定时器加
                        end
                    endcase
                end
                else
                begin
                    cy_state <= cy_state;
                    cy_cnt <= 16'd0;
                end
            end
        end
        
    endmodule
    
    

      在频率计模块中,SCH_thread0为施密特触发器的阈值1,阈值2为SCH_thread0的三分之一。

    5.测试文件

    `timescale 1ps / 1ps
    
    module FSK_tb(
    
        );
        reg clk;
        reg en;
        reg rst;
        reg de_fsk_clk;
        wire[7:0]dout;
        wire[15:0]fre_o;
        wire deo;
        
        reg      [7:0]         din;
        reg                  dqvld;//数据有效信号
        wire                    do;
        wire             send_qvld;//发送完成信号
        wire                 sbusy;//繁忙标志位
        
        integer i;
        
        initial begin
            en = 0;
            rst = 0;
            #2 rst = 1;
            #2 rst = 0;
            en = 1;
            i = 0;
           #4 din = 8'b1011_0110;
            while(i<50)
            begin
                while(sbusy == 1)
                begin
                #1 dqvld = 1'b0;
                end    
                dqvld = 1'b1;
                while(sbusy == 0)
                begin
                    #1 dqvld = 1'b1;
                end
                dqvld = 1'b0;
                din = din + 1;
                i = i + 1;
            end
        end
        
        initial begin
            de_fsk_clk = 0;
            forever begin
                #1 de_fsk_clk = ~de_fsk_clk;
            end
        end
        
        initial begin
            clk = 0;
            forever begin
                #4 clk = ~clk;
            end
        end
        
    
       FSK_2#(
       . CLOCK_DIV (80)
    )FSK_2_inist0(
        .                fsk_clk(clk),
        .              de_fsk_clk(de_fsk_clk),
        .                fsk_en(en),
        .                fsk_rst(rst),
        
        .                  din(din),
        .                dqvld(dqvld),//数据有效信号
        .        do(       do),
        .       deo(deo),
        .    fre_o(fre_o),
        .      dout(     dout),
        . send_qvld(send_qvld),//发送完成信号
        .     sbusy(    sbusy) //繁忙标志位
        );
    endmodule
    
    

    四、仿真结果

    din为输入的需要发送的8位数据,dout为调制器发出的模拟波形,fre_o为频率计输出的计数值,do为转换为串行数据流的基带信号,deo为解调器解调后的数据。
    基本实现了2FSK调制解调器的功能。
                   图4.1 模拟波形转换图

    在图4.1中由于两个载波采样点数比较相近,频率相近,所以其波形比较相似,大家也可以通过增加采样点数的方式,改变其频率。

    物联沃分享整理
    物联沃-IOTWORD物联网 » Verilog实现的2FSK调制/解调器

    发表回复