赞
踩
目录
本设计工程文件下载链接(包含注释):https://download.csdn.net/download/qq_33231534/12450178
前两篇将数据采集系统的基本模块详细阐述了一下,下边就开始介绍这几个基本模块互联通信的控制模块,包含按键控制模块和FIFO控制模块。
按键控制模块主要功能为:当按键按下时,控制ADC模数转换tran_num次。
该模块信号端口列表如下表:
信号名称 | 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://blog.csdn.net/qq_33231534 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控制模块功能为:当ADC转换完成后,将数据存入FIFO,同时在往串口发送数据时控制从FIFO读取数据并将12位数据分成两次8位发送到串口。
该模块信号端口列表如下表:
信号名称 | 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://blog.csdn.net/qq_33231534 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控制模块功能为:当接收串口指定的指令时,开始将ROM的正弦数据进行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://blog.csdn.net/qq_33231534 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://blog.csdn.net/qq_33231534 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视图如下图:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。