当前位置:   article > 正文

基于FPGA的数据采集系统设计总结(dds和ad)_fpga 的频率采集模块

fpga 的频率采集模块

  1. 通过dds(rom)和ad(可能电路其他模块传输给ad的模拟数据转换为数字数据)接收数据,dds数据进行调频调相操作,ad数据直接输出,
  2. 通过按键进行通道选择ad或者dds数据,
  3. 利用uart串口将控制调频调相指令输入,输出控制uart接收信号和ad,dds采样使能信号(主要是控制设置波特率不同产生的采样率)
  4. 最后fifo和uart输出按键模块最后产生的数据

总共分为四个模块:
1.数据源采集模块
    1.ad数据采集模块:tl549_interface(本模块主要从TL549中读取信号采样的数据)
           该模块使用adTL549协议进行ad数据传输,其中所需的接口:ad部分接口:cs,sdi,scl、人机控制采样信号:ad_en、
           采样传输到下一个模块的数据信号和数据有效信号:ad_data,flag_ad_data。
    (其中需要注意代码写法:序列机的0状态空闲,计数器可以用输入的人机交互信号进行控制,71+(25*0 )上升沿scl置1,数据由高位先输入,
                     数据有效位在最后一个数据生成时非阻塞生成一个时钟周期的信号)
    2.dds数据采集模块:dds(本模块完成频率可调,相位可调的dds)
**           module  dds
**(
**        //模块工作相关信号
**        input            clk_50mhz,//默认DDS原始参考采样时钟为50mhz
**        input            rst_n,//系统复位
**        
**        
**        //与dds信号相关信号
**        output    [7:0]    dds_data,//输出PCM编码,默认8位
**        output            flag_dds_data,
**        
**        
**        //人机交互相关信号
**        input    [31:0]fword,//调频因子
**        input    [10:0]pword, //相位地址偏移
**        input          dds_en
**);
**
**//调频程序实现,精度N=32,原始信号一个周期采样点数为2^32
**reg  [31:0] rom_addr_vir;
**always  @(posedge  clk_50mhz   or  negedge rst_n)
**        if(~rst_n)
**                rom_addr_vir[31:0]  <=  32'd0;
**        else  
**                rom_addr_vir[31:0]  <= rom_addr_vir[31:0]  +  fword[31:0];
**//由于FPGA内部的存储资源有限,不能够存放N=32的采样的所有采样数据,因此我们从2^32个点钟等间隔抽取2048个点
**reg   [10:0] rom_addr;
**always  @(posedge  clk_50mhz   or negedge rst_n)
**        if(~rst_n)
**            rom_addr  <=  11'd0;
**        else  
**            rom_addr  <=  rom_addr_vir[31:21]  +    pword[10:0];  
**
**assign  flag_dds_data   =  dds_en;
**
**
**rom    rom_inst (
**    .address ( rom_addr ),
**    .clock ( clk_50mhz ),
**    .q ( dds_data )
**    );
**
**endmodule 
            1.在判断时,频率和相位的加减在RTL写法下是相同的(都是相加)频率对应的数据位宽[31:0],相位对应的位宽[10:0]
            2.数据有效位输出    assign  flag_dds_data   =  dds_en;(rom中的地址一直在加,当有效信号来临时,数据输出再进行地址循环相加,数据循环输出,dds产生波形,相当于产生的波形起始位时随机的,就当有效信号来临时数据输出,有效信号结束,产生波形截止)

2.数据通道选择模块
       1.独立按键消抖模块:key_dec(本模块主要对独立按键消抖)
    两种方式:第一种状态机计数,计10ms停止(相当于从1-0中间间隔10ms,0持续10ms)
                     第二种用计数,三个寄存器相与打拍操作(简洁)(相当于从1-0中间间隔36ms,0持续到检测按键置1状态,置1)
    //本模块主要对独立按键消抖
**module  key_dec
**(
**        //模块工作相关信号
**        input             clk_50mhz,
**        input            rst_n,
**        
**        //与独立按键相关信号
**        input            key,//原始按键检测电平输入
**        output            flag_key//消除抖动后的电平输出
**
**);
**//本程序通过每次间隔默认12ms对原始按键检测电平进行采样,连续采样3次
**reg  sap_en;//定义采样使能,使能之间间隔12ms
**reg   [19:0]cnt;
**always  @(posedge clk_50mhz    or   negedge  rst_n )
**        if(~rst_n)begin
**                cnt  <=20'd0;
**                sap_en  <=  1'b0;end
**        else  if(cnt ==  (20'd600000-1'b1))begin
**                cnt  <=20'd0;
**                sap_en  <=  1'b1;end
**        else  begin
**                cnt   <=   cnt  +1'b1;
**                sap_en  <= 1'b0;end
**
**reg key1,kye2,key3;
**always  @(posedge clk_50mhz   or  negedge  rst_n)
**        if(~rst_n)begin
**            key1  <= 1'b1;
**            kye2  <= 1'b1;
**            key3  <=1'b1;end    
**        else if(sap_en)begin
**                key1  <= key;
**                kye2  <= key1;
**                key3  <= kye2;
**        end
**assign  flag_key  =  ~(  (~key1)   &   (~kye2)   &  (~key3)  ) ;
**endmodule 

       2.按键通道选择模块:ch_sel(按键信号边沿检测,选择通道)
    首先进行边沿检测,再进行通道0.1选择,取反操作,数据=输入ad数据or输入dds数据。

3.命令参数解析控制模块
             通过uart接收解析包中(解析包中需要控制定义相关寄存器的地址标号,使用uart进行串口调试时,需要进行输入)需要控制输入数据的数据信号,
             将数据通过解析产生总线(使能,数据,数据有效),通过总线产生控制uart时钟,通过总线产生控制调频调相的数据
             
       1.uart接收数据模块:uart_receive(本模块通过uart接收数据)

    ****通过使能信号clk_r控制传输速率,不用自己写15倍时钟。(相当于在所需要使用变化时钟模块的所有always下,先使用此信号进行判断条件)

**//奇偶校验模块
**always  @(posedge clk_50mhz  or  negedge rst_n  )
**        if(~rst_n)                    
**                flag_rvdata  <=1'b0;
****        else if(clk_r   &&    (cnt==(14+(15*8) +7)      )) begin
**                        //odd(奇校验) eve(偶校验)  mark(填充1) space(填充0)
**                                                      (奇偶校验位判断时,首先在数据传输之前确定奇校验还是偶校验,若此模块开始为偶校验1,此时判断数据中1的个数,若为偶数,则对应偶校验,条件则成立输出)(偶校验数据中1的个数为偶数,校验位为1,奇校验反之)
**                     if( rvdata[0]^rvdata[1]^rvdata[2]^rvdata[3]^rvdata[4]^rvdata[5]^rvdata[6]^rvdata[7]^ rx )
**                                flag_rvdata  <=1'b1;
**                     else 
**                                flag_rvdata  <=1'b0;end
**        else 
**                flag_rvdata  <=1'b0;
       2.将数据包的内容进行解析,将数据传输到数据总线:pk_conv(本模块将软件发送的包数据进行解析,然后通过系统总线数据转发)

    ****wr_en使能信号:相当于在一个包数据接收完成时,使能信号拉高,此时数据线和数据有效线的值为当前包的数据值,
                                                       直接运用到需要使能信号进行控制,数据直接赋值的条件下。(一个使能对应一个16位数据,如果该数据32位,则定义中间寄存器暂存)

**//wr_en总线使能信号生成
**always  @(posedge clk_50mhz   or negedge rst_n )
**        if(~rst_n)            
**            bus_wr         <=1'b0;
**        else  if(  (state == PK_TAIL)  && (rvdata  ==  8'h66 ) && flag_rvdata  )//检查完是否接收一个完整的包
**                        bus_wr         <=1'b1;
**        else     
**                        bus_wr       <=1'b0;
       
       3.通过寄存器配置,控制uart接收或者发送解析包中控制用数据:uart_band_ctl(本模块主要是通过寄存器配置,控制uart接收或者发送是速率)

**//本模块主要是通过寄存器配置,控制uart接收或者发送是速率
**module uart_band_ctl
**(
**       //模块工作相关信号
**       input               clk_50mhz,
**       input            rst_n,
**       
**       //接收寄存器配置信号相关信号
**       input            bus_wr,
**       input    [7:0]    bus_addr,
**       input    [15:0]    bus_data,
**       
**       
**       //与uart速率控制相关信号
**       output    reg        clk_r,//本地控制uart接收
**       output    reg        clk_t //本地控制uart发送
**);
**reg   [2:0]uart_band_sel;
**always  @(posedge  clk_50mhz   or  negedge rst_n)
**        if(~rst_n)
**            uart_band_sel  <=  3'd0;
**        else  if(bus_wr  &&   (bus_addr[7:0]==3'd7))
**            uart_band_sel  <=  bus_data[2:0];
**
**parameter       FSYS_CLK         =   26'd50_000_000                    ;
**parameter    BAND_1152000    =  (FSYS_CLK/26'd115200     )         ,
**             BAND_57600         =  (FSYS_CLK/26'd57600     )         ,
**             BAND_56000         =  (FSYS_CLK/26'd56000     )         , 
**             BAND_38400         =  (FSYS_CLK/26'd38400     )         , 
**             BAND_28800         =  (FSYS_CLK/26'd28800     )         ,
**             BAND_19200         =  (FSYS_CLK/26'd19200     )         ,
**             BAND_14400         =  (FSYS_CLK/26'd14400     )         ,
**             BAND_9600         =  (FSYS_CLK/26'd9600      )         ;             
**
**//uart发送默认采用速率等效的时钟信号控制发送
**reg   [11:0]cnt_t,cnt_t_max;
**always  @(posedge   clk_50mhz   or  negedge rst_n)
**        if(~rst_n)begin
**            clk_t  <= 1'b0;
**            cnt_t  <=  12'd0;end
**        else  if(cnt_t ==  cnt_t_max  )begin
**            clk_t  <= ~clk_t;
**            cnt_t  <=  12'd0;end
**        else 
**            cnt_t  <=  cnt_t + 1'b1;
**always  @(posedge   clk_50mhz   or  negedge rst_n)
**        if(~rst_n)
**                cnt_t_max  <= 12'd0;
**        else  case(uart_band_sel[2:0])
**                0  :cnt_t_max  <=   ((BAND_1152000/2'd2)-1'b1);
**                1  :cnt_t_max  <=   ((BAND_57600/2'd2)-1'b1);
**                2  :cnt_t_max  <=   ((BAND_56000/2'd2)-1'b1);
**                3  :cnt_t_max  <=   ((BAND_38400/2'd2)-1'b1);
**                4  :cnt_t_max  <=   ((BAND_28800/2'd2)-1'b1);
**                5  :cnt_t_max  <=   ((BAND_19200/2'd2)-1'b1);
**                6  :cnt_t_max  <=   ((BAND_14400/2'd2)-1'b1);
**                7  :cnt_t_max  <=   ((BAND_9600/2'd2)-1'b1);
**                default:cnt_t_max <= cnt_t_max;
**        endcase
**
**//接收默认采样速率等效时钟的15倍使能信号作为控制接收
**reg [8:0] cnt_r,cnt_r_max;
**always  @(posedge  clk_50mhz  or negedge rst_n)
**        if(~rst_n)begin
**            clk_r  <=1'b0;
**            cnt_r  <=9'd0;end
**        else  if(cnt_r ==  cnt_r_max)begin
**            clk_r  <= 1'b1;
**            cnt_r  <=9'd0;end
**        else  begin
**            clk_r  <=1'b0;
**            cnt_r  <=  cnt_r  +1'b1;end
**always @(posedge  clk_50mhz   or negedge rst_n)
**       if(~rst_n)
**            cnt_r_max  <=  9'd0;
**       else  case(uart_band_sel[2:0])
**                0:cnt_r_max   <=  ((BAND_1152000/4'd15)-1'b1);
**                1:cnt_r_max   <=  ((BAND_57600/4'd15)-1'b1);
**                2:cnt_r_max   <=  ((BAND_56000/4'd15)-1'b1);
**                3:cnt_r_max   <=  ((BAND_38400/4'd15)-1'b1);
**                4:cnt_r_max   <=  ((BAND_28800/4'd15)-1'b1);
**                5:cnt_r_max   <=  ((BAND_19200/4'd15)-1'b1);
**                6:cnt_r_max   <=  ((BAND_14400/4'd15)-1'b1);
**                7:cnt_r_max   <=  ((BAND_9600/4'd15)-1'b1);
**                default:cnt_r_max <= cnt_r_max;
**        endcase
**endmodule

       4.通过数据采集系统进行数据采集:data_sap_ctl(本模块通过寄存器控制数据采集系统数据采集控制)

    ****为了逻辑严谨:在控制fword时,需要将数据低[7:0]存入中间变量,再和高[15:8]数据结合起来。
    调频,调相初始值不能为0或者小数,复位置1。
    ad和dds采样率控制时,定义计数器和采样数据最大值,最大值由总线数据输出,比较计数器计数值=采样数据最大值,输出使能信号

**//本模块通过寄存器控制数据采集系统数据采集控制
**module  data_sap_ctl
**(
**        //模块工作相关信号
**        input            clk_50mhz,
**        input            rst_n,
**                
**        //寄存器参数接收相关信号
**        input            bus_wr,
**        input    [7:0]    bus_addr,
**        input    [15:0]  bus_data,
**                
**        //与信号采集相关的控制信号
**        output reg[31:0]fword,//控制DDS调频
**        output reg[10:0]pword,//控制DDS调相
**        output            ad_en,//控制TL549采样率
**        output            dds_en//控制DDS采样率
**);
**//DDS调频控制
**reg  [15:0]fword_l16;
**always  @(posedge  clk_50mhz   or  negedge rst_n)
**        if(~rst_n)begin
**                fword_l16     <= 16'd0;
**                fword          <= 31'd1000;end
**        else  if(bus_wr  )
**                case(bus_addr[7:0] )
**                        0:fword_l16[15:00]  <=   bus_data[15:0];
**                        1:fword[31:00]  <=   {bus_data[15:0],fword_l16[15:0]};
**                        default:fword<= fword;
**                endcase
**//DDS调相
**always  @(posedge  clk_50mhz   or  negedge rst_n)
**        if(~rst_n)
**                pword  <= 11'd0;
**        else  if(bus_wr  &&  bus_addr[7:0]==8'd2)
**                pword  <=bus_data[10:0] ;
**                
**//ad采样率控制
**reg   [31:0]cnt_ad_sap, ad_sap_max;
**always  @(posedge  clk_50mhz   or  negedge rst_n)
**        if(~rst_n)
**            cnt_ad_sap  <= 32'd0;
**        else  if(cnt_ad_sap  ==  ad_sap_max  )
**            cnt_ad_sap  <= 32'd0;
**        else 
**            cnt_ad_sap  <=  cnt_ad_sap  +1'b1;
**assign  ad_en = (cnt_ad_sap  ==  ad_sap_max  )?1'b1:1'b0;
**
**
**always  @(posedge  clk_50mhz   or  negedge rst_n)
**        if(~rst_n)    
**                ad_sap_max  <=  32'd5300;
**        else  if(bus_wr )
**                case(bus_addr[7:0])
**                        3:ad_sap_max[15:00]  <= bus_data[15:0];
**                        4:ad_sap_max[31:16]  <= bus_data[15:0];
**                        default:ad_sap_max <= ad_sap_max;
**                endcase
**    
**//DDS采样率控制
**reg  [31:0]cnt_dds_sap,dds_sap_max;
**always  @(posedge  clk_50mhz  or negedge rst_n)
**        if(~rst_n)
**            cnt_dds_sap  <=  32'd0;
**        else  if(cnt_dds_sap  == dds_sap_max )
**            cnt_dds_sap  <=  32'd0;
**        else 
**            cnt_dds_sap <= cnt_dds_sap+1'b1;
**assign dds_en  =      (cnt_dds_sap  == dds_sap_max )?1'b1:1'b0;
**always  @(posedge  clk_50mhz  or negedge rst_n)
**        if(~rst_n)
**                dds_sap_max  <= 32'd5300;
**        else  if(bus_wr)
**                case(bus_addr[7:0])
**                        5:dds_sap_max[15:00]<= bus_data[15:0];
**                        6:dds_sap_max[31:16]<= bus_data[15:0];
**                        default:dds_sap_max <= dds_sap_max;
**                endcase
**endmodule 


4.采集数据传输:
       1.读取fifo数据,通过uart发送:uart_trans(本模块主要读取FIFO的数据,通过uart发送)

**//读使能在fifo不空和计数条件下开始读数据
**reg [3:0]cnt;
**always  @(posedge  Clk_t  or  negedge rst_n)
**        if(~rst_n)
**            cnt   <= 4'd0;
**        else  case(cnt)
**                4'd00:  if(~empty)cnt <=  cnt+1'b1;
**                4'd11:    cnt   <= 4'd0;
**                default:cnt <=  cnt+1'b1;
**        endcase
**//Fifo读数据程序
**assign  rd_clk  =  Clk_t;
**assign  rd_en   =  ((cnt==4'd0) && (~empty) )?1'b1:1'b0;
 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/470040
推荐阅读
相关标签
  

闽ICP备14008679号