基于FPGA的数据采集系统(三)终

目录

八、按键控制模块

九、FIFO控制模块

十、DAC控制模块

十一、系统整合


本设计工程文件下载链接(包含注释):https://download.csdn.net/download/qq_33231534/12450178  


前两篇将数据采集系统的基本模块详细阐述了一下,下边就开始介绍这几个基本模块互联通信的控制模块,包含按键控制模块和FIFO控制模块。

八、按键控制模块

按键控制模块主要功能为:当按键按下时,控制ADC模数转换tran_num次。

该模块信号端口列表如下表:

表8.1 按键控制模块端口信号列表
信号名称 I/O 位数 功能描述
clk I 1 系统时钟50MHz
rst_n I 1 系统复位
key_flag I 1 按键有效信号
tran_num I 7 转换次数
adc_done I 1 ADC一次转换完成标志
adc_en O 1 ADC转换使能标志

该模块代码为:key_ctrl.v

//-------------------------------------------------------------------
//https://mp.csdn.net/console/article PHF的CSDN   
//File name:           key_ctrl.v
//Last modified Date:  2020/5/23
//Last Version:        
//Descriptions:        按键控制模块:按键按下,控制ADC转换tran_num次
//-------------------------------------------------------------------

module key_ctrl(
    input                   clk         , //系统时钟50MHz
    input                   rst_n       , //系统复位
    input                   key_flag    , //按键有效信号
    input   [ 6: 0]         tran_num    , //转换次数
    input                   adc_done    , //ADC一次转换完成标志
    output  reg             adc_en        //ADC转换使能标志      
);

reg   [  6: 0]         cnt          ; //计数器,计数ADC转换次数
reg                    add_flag     ; //计数器加1标志
wire                   add_cnt      ; //加一条件
wire                   end_cnt      ; //结束条件

//按键按下,add_flag为1,开始计数
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        add_flag <= 0;
    end
    else if(key_flag) begin
        add_flag <= 1;
    end
    else if(end_cnt)begin
        add_flag <= 0;
    end
end

//计数器,ADC使能一次,计数器加1
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt <= 0;
    end
    else if(add_cnt)begin
        if(end_cnt)
            cnt <= 0;
        else
            cnt <= cnt + 1'b1;
    end
end

assign add_cnt = add_flag==1 && adc_en;       
assign end_cnt = add_cnt && cnt== tran_num-1;   

//adc_en输出控制
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        adc_en <= 0;
    end
    else if(key_flag || (add_flag && adc_done)) begin
        adc_en <= 1;
    end
    else begin
        adc_en <= 0;
    end
end
endmodule

该部分由于比较简单,不给仿真波形图。


九、FIFO控制模块

FIFO控制模块功能为:当ADC转换完成后,将数据存入FIFO,同时在往串口发送数据时控制从FIFO读取数据并将12位数据分成两次8位发送到串口。

该模块信号端口列表如下表:

表9.1:FIFO控制模块信号端口列表
信号名称 I/O 位数 功能描述
clk I 1 系统时钟50MHz
rst_n I 1 系统复位
empty I 1 fifo数据空信号
tx_done I 1 串口数据发送完成标志
q I 12 从fifo读出的数据
adc_done I 1 ADC转换完成一次标志
adc_data_out I 12 ADC转换完成的12位数据
rdreq O 1 fifo读使能
send_en O 1 串口发送使能
data_byte O 8 输出发送的数据
wrreq O 1 FIFO写使能,在ADC转换结束后置1
data_to_fifo O 12 ADC转换完成的数据存入FIFO

FIFO控制模块代码为:fifo_ctrl.v

//-------------------------------------------------------------------
//https://mp.csdn.net/console/article PHF的CSDN   
//File name:           fifo_ctrl.v
//Last modified Date:  2020/5/23
//Last Version:        
//Descriptions:        FIFO控制模块:当ADC转换完成后,将数据存入FIFO,
//                     同时在往串口发送数据时控制从FIFO读取数据并将12位
//                     数据分成两次8位发送到串口
//-------------------------------------------------------------------

module fifo_ctrl(
    input                   clk         , //系统时钟50MHz
    input                   rst_n       , //系统复位
    input                   empty       , //fifo数据空信号
    input                   tx_done     , //串口数据发送完成标志
    input   [ 11: 0]        q           , //从fifo读出的数据
    input                   adc_done    , //ADC转换完成一次标志
    input   [ 11: 0]        adc_data_out, //ADC转换完成的12位数据

    output reg              rdreq       , //fifo读使能
    output reg              send_en     , //串口发送使能
    output reg [7:0]        data_byte   , //输出发送的数据
    output reg              wrreq       , //FIFO写使能,在ADC转换结束后置1
    output reg [11:0]       data_to_fifo  //ADC转换完成的数据存入FIFO
);

parameter IDLE      = 3'b000     ; //空闲状态
parameter DATA_R    = 3'b001     ; //当fifo数据不为空时,读取fifo数据
parameter DATA_S    = 3'b010     ; //将fifo的12位数据发送出去
parameter SEND_1    = 3'b011     ; //发送前4位数据
parameter SEND_2    = 3'b100     ; //发送后8位数据

reg   [  2: 0]         state_c      ; //状态改变
reg   [  2: 0]         state_n      ; //现在状态

//状态机
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        state_c <= IDLE;
    end
    else begin
        state_c <= state_n;
    end
end

//状态改变条件
always  @(*)begin
    case(state_c)
        IDLE:begin
                if(empty==0)
                    state_n = DATA_R;
                else
                    state_n = state_c;
             end
        DATA_R:state_n = DATA_S;
        DATA_S:state_n = SEND_1;
        SEND_1:begin
                  if(tx_done)
                      state_n = SEND_2;
                  else
                      state_n = state_c;
               end
        SEND_2:begin
                  if(tx_done)
                      state_n = IDLE;
                  else
                      state_n = state_c;
               end                  
    endcase
end

//各个状态下rdreq和send_en输出的结果
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        rdreq <= 0;
        send_en <= 0;
    end
    else begin
        case(state_c)
            IDLE:  begin
                       if(empty==0)
                           rdreq <= 1;
                       else
                           rdreq <= 0;
                   end
            DATA_R:begin rdreq <= 0; end
            DATA_S:begin send_en <= 1; data_byte <= {4'd0,q[11:8]}; end
            SEND_1:begin 
                       send_en <= 0; 
                       if(tx_done)begin
                           send_en <= 1;
                           data_byte <= q[7:0];
                       end
                   end
            SEND_2:begin send_en <= 0; end                
        endcase
    end
end

//ADC转换完成后将数据存入FIFO
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        data_to_fifo <= 0;
    end
    else if(adc_done) begin
        data_to_fifo <= adc_data_out;
    end
end

//ADC转换完成写使能打开
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        wrreq <= 0;
    end
    else if(adc_done) begin
        wrreq <= 1;
    end
    else begin
        wrreq <= 0;
    end
end

endmodule

仿真测试如下:


十、DAC控制模块

DAC控制模块功能为:当接收串口指定的指令时,开始将ROM的正弦数据进行DAC转换。

该模块信号端口列表如下表:

表10.1:DAC控制模块信号端口列表
信号名称 I/O 位数 功能描述
clk I 1 系统时钟50MHz
rst_n I 1 系统复位
data_rx I 8 从串口接收到的指令
rx_done I 1 1字节串口数据接收完成标志
dac_done I 1 DAC转换完成标志
addr O 12 ROM的地址线
dac_en O 1 DAC转换使能标志

DAC控制模块代码为:dac_ctrl.v

//-------------------------------------------------------------------
//https://mp.csdn.net/console/article PHF的CSDN   
//File name:           dac_ctrl.v 
//Last modified Date:  2020/5/23
//Last Version:        
//Descriptions:        DAC控制模块:当接收串口指定的指令时,
//                     开始将ROM的正弦数据进行DAC转换
//-------------------------------------------------------------------

module dac_ctrl(
    input                   clk         ,//系统时钟50MHz
    input                   rst_n       ,//系统复位
    input   [ 7: 0]         data_rx     ,//从串口接收到的指令
    input                   rx_done     ,//1字节串口数据接收完成标志
    input                   dac_done    ,//DAC转换完成标志
    output  reg [11:0]      addr        ,//ROM的地址线
    output  reg             dac_en       //DAC转换使能标志
);

//控制地址线自加1
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        addr <= 0;
    end
    else if(dac_en) begin
        addr <= addr + 1'b1;
    end
end

//DAC转换使能标志
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        dac_en <= 0;
    end
    else if(rx_done || dac_done) begin
        dac_en <= 1;
    end
    else begin
        dac_en <= 0;
    end
end

endmodule

该模块较为简单,不做仿真调试。


十一、系统整合

在完成所有模块设计并仿真测试后,对整个系统模块进行整合,新建一个顶层吧文件,将各个模块例化连接起来。

其代码如下:data_collection_top.v

//-------------------------------------------------------------------
//https://mp.csdn.net/console/article PHF的CSDN   
//File name:           
//Last modified Date:  
//Last Version:        
//Descriptions:        
//-------------------------------------------------------------------

module data_collection_top(
    input                   clk         ,//系统时钟50MHz
    input                   rst_n       ,//系统复位
    input                   rs232_tx    ,//串口向FPGA发送数据
    input                   adc_data_din,//adc数据输出到FPGA
    input                   key_in      ,//按键输入

    output wire             dac_din     ,//dac串行数据接口控制和数据输出
    output wire             dac_sclk    ,//dac串行数据接口时钟信号
    output wire             dac_cs      ,//dac串行数据接口使能信号
    output wire             adc_din     ,//ADC控制信号,通道控制选取
    output wire             adc_sclk    ,//ADC串行数据接口时钟信号
    output wire             adc_cs      ,//ADC串行数据接口使能信号
    output wire             rs232_rx     //串口接收FPGA数据

);

wire  [  7: 0]         data_rx      ;
wire                   rx_done      ;
wire                   dac_en       ;
wire  [ 11: 0]         addr         ;
wire                   dac_done     ;
wire  [ 11: 0]         data_rom     ;
wire                   empty        ;
wire                   adc_en       ;
wire                   key_flag     ;
wire                   adc_done     ;
wire                   tx_done      ;
wire                   rdreq        ;
wire                   send_en      ;
wire  [  7: 0]         data_byte    ;
wire                   wrreq        ;
wire  [ 11: 0]         data_to_fifo ;
wire  [ 11: 0]         adc_data_out ;
wire  [ 11: 0]         fifo_data_out;

//串口接收模块
UART_Byte_Rx u_UART_Byte_Rx(
    .clk       (clk)        ,
    .rst_n     (rst_n)      ,
    .rs232_tx  (rs232_tx)   ,
    .baud_set  (3'd1)       ,

    .data_byte (data_rx)    ,
    .rx_done   (rx_done)      
);

//DAC控制模块
dac_ctrl u_dac_ctrl(
    .clk       (clk)        ,
    .rst_n     (rst_n)      ,
    .data_rx   (data_rx)    ,
    .rx_done   (rx_done)    ,
    .dac_done  (dac_done)   ,

    .addr      (addr)       ,
    .dac_en    (dac_en) 
);

//ROM模块
single_port_rom
#(.DATA_WIDTH(12), .ADDR_WIDTH(12))
u_single_port_rom(
	.addr   (addr)  ,
	.clk    (clk)   ,

	.q      (data_rom)  
);

//DAC驱动模块
dac_driver1 u_dac_driver(
    .clk        (clk)               ,
    .rst_n      (rst_n)             ,
    .dac_data_in({4'b1100,data_rom}),
    .dac_en     (dac_en)            ,

    .din        (dac_din)           ,
    .dac_sclk   (dac_sclk)          ,
    .cs         (dac_cs)            ,
    .dac_down   (dac_done)          ,
    .dac_state  ()                    
);

//ADC驱动模块
adc_driver u_adc_driver(
    .clk       (clk)            ,//系统时钟50MHz
    .rst_n     (rst_n)          ,//复位
    .channel   (3'd0)           ,//通道选择
    .adc_en    (adc_en)         ,//使能单次转换,该信号为周期有效高脉冲使能一次转换
    .dout      (adc_data_din)   ,//ADC转换结果,由ADC输给FPGA

    .din       (adc_din)        ,//ADC控制信号,通道控制选择
    .adc_sclk  (adc_sclk)       ,//ADC串行数据接口时钟信号
    .cs        (adc_cs)         ,//ADC串行数据接口使能信号
    .data_out  (adc_data_out)   ,//ADC转换结果
    .adc_done  (adc_done)       ,//转换完成信号,完成后输出一个周期高脉冲
    .adc_state ()                //ADC工作状态:0为空闲状态,1为转换状态      
);

//按键控制模块
key_ctrl u_key_ctrl(
    .clk       (clk)        ,
    .rst_n     (rst_n)      ,
    .key_flag  (key_flag)   , //按键信号
    .tran_num  (7'd100)     , //转换次数
    .adc_done  (adc_done)   ,    

    .adc_en    (adc_en)             
);

//按键消抖模块
key_filter u_key_filter(
    .clk       (clk)        ,
    .rst_n     (rst_n)      ,
    .key_in    (key_in)     ,

    .key_flag  (key_flag)   ,
    .key_state ()           
);

//FIFO控制模块
fifo_ctrl u_fifo_ctrl(
    .clk         (clk)         , //系统时钟50MHz
    .rst_n       (rst_n)       , //系统复位
    .empty       (empty)       , //fifo数据空信号
    .tx_done     (tx_done)     , //串口数据发送完成标志
    .q           (fifo_data_out)            , //从fifo读出的数据
    .adc_done    (adc_done)    ,
    .adc_data_out(adc_data_out),

    .rdreq       (rdreq)        , //fifo读使能
    .send_en     (send_en)      , //串口发送使能
    .data_byte   (data_byte)    ,  //输出发送的数据
    .wrreq       (wrreq)        ,
    .data_to_fifo(data_to_fifo) 
);

//同步FIFO模块
sync_fifo 
#(.WIDTH        (12)    ,      //缓存的数据宽度
  .DEPTH        (100)   ,      //缓存的数据深度
  .MAX_DEPTH_BIT(7))           //可设置的最大深度位数7,即最大深度为2^7-1
u_sync_fifo
(
    .clk     (clk)          , //系统时钟
    .rst_n   (rst_n)        , //系统复位
    .wrreq   (wrreq)        , //写使能
    .data    (data_to_fifo) , //写数据
    .rdreq   (rdreq)        , //读使能

    .q       (fifo_data_out)            , //读数据
    .empty   (empty)        , //空信号
    .full    ()             , //满信号
    .half    ()             , //半满信号
    .usedw   ()               //fifo中剩余数据个数    
);

//串口发送模块
Uart_Byte_Tx u_Uart_Byte_Tx(
    .clk       (clk)        ,
    .rst_n     (rst_n)      ,
    .send_en   (send_en)    ,
    .data_byte (data_byte)  ,
    .baud_set  (3'd1)       ,

    .rs232_tx  (rs232_rx)   ,
    .tx_done   (tx_done)    ,
    .uart_state()                  
);

endmodule

在quartus prime17.1软件上进行分析与综合后,按照电路连接进行管脚分配,如图:

全编译后,将sof文件下载到板子上,将DAC的A输出口与ADC的1通道口用杜邦线相连,完成电路连接。然后打开串口助手,采用16进制发送和接收显示,先向串口发送控制DA转换的指令(这里设置为ff),这样DAC按照ROM里正弦信号进行转换输出模拟的正弦信号。然后再按下按键,控制ADC转换100次,输出到串口显示在PC上。

其串口的放松与接收图如下图:

其中每16位数据表示一个ADC转换结果,例如第一个数据06 1C,前四位都是为0,为了串口发送数据方便这样设置的,实际ADC采样结果为0x61C。

总体RTL视图如下图:

 

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读