当前位置:   article > 正文

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

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

目录

八、按键控制模块

九、FIFO控制模块

十、DAC控制模块

十一、系统整合


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


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

八、按键控制模块

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

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

表8.1 按键控制模块端口信号列表
信号名称I/O位数功能描述
clkI1系统时钟50MHz
rst_nI1系统复位
key_flagI1按键有效信号
tran_numI7转换次数
adc_doneI1ADC一次转换完成标志
adc_enO1ADC转换使能标志

该模块代码为:key_ctrl.v

  1. //-------------------------------------------------------------------
  2. //https://blog.csdn.net/qq_33231534 PHF的CSDN
  3. //File name: key_ctrl.v
  4. //Last modified Date: 2020/5/23
  5. //Last Version:
  6. //Descriptions: 按键控制模块:按键按下,控制ADC转换tran_num次
  7. //-------------------------------------------------------------------
  8. module key_ctrl(
  9. input clk , //系统时钟50MHz
  10. input rst_n , //系统复位
  11. input key_flag , //按键有效信号
  12. input [ 6: 0] tran_num , //转换次数
  13. input adc_done , //ADC一次转换完成标志
  14. output reg adc_en //ADC转换使能标志
  15. );
  16. reg [ 6: 0] cnt ; //计数器,计数ADC转换次数
  17. reg add_flag ; //计数器加1标志
  18. wire add_cnt ; //加一条件
  19. wire end_cnt ; //结束条件
  20. //按键按下,add_flag为1,开始计数
  21. always @(posedge clk or negedge rst_n)begin
  22. if(rst_n==1'b0)begin
  23. add_flag <= 0;
  24. end
  25. else if(key_flag) begin
  26. add_flag <= 1;
  27. end
  28. else if(end_cnt)begin
  29. add_flag <= 0;
  30. end
  31. end
  32. //计数器,ADC使能一次,计数器加1
  33. always @(posedge clk or negedge rst_n)begin
  34. if(!rst_n)begin
  35. cnt <= 0;
  36. end
  37. else if(add_cnt)begin
  38. if(end_cnt)
  39. cnt <= 0;
  40. else
  41. cnt <= cnt + 1'b1;
  42. end
  43. end
  44. assign add_cnt = add_flag==1 && adc_en;
  45. assign end_cnt = add_cnt && cnt== tran_num-1;
  46. //adc_en输出控制
  47. always @(posedge clk or negedge rst_n)begin
  48. if(rst_n==1'b0)begin
  49. adc_en <= 0;
  50. end
  51. else if(key_flag || (add_flag && adc_done)) begin
  52. adc_en <= 1;
  53. end
  54. else begin
  55. adc_en <= 0;
  56. end
  57. end
  58. endmodule

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


九、FIFO控制模块

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

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

表9.1:FIFO控制模块信号端口列表
信号名称I/O位数功能描述
clkI1系统时钟50MHz
rst_nI1系统复位
emptyI1fifo数据空信号
tx_doneI1串口数据发送完成标志
qI12从fifo读出的数据
adc_doneI1ADC转换完成一次标志
adc_data_outI12ADC转换完成的12位数据
rdreqO1fifo读使能
send_enO1串口发送使能
data_byteO8输出发送的数据
wrreqO1FIFO写使能,在ADC转换结束后置1
data_to_fifoO12ADC转换完成的数据存入FIFO

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

  1. //-------------------------------------------------------------------
  2. //https://blog.csdn.net/qq_33231534 PHF的CSDN
  3. //File name: fifo_ctrl.v
  4. //Last modified Date: 2020/5/23
  5. //Last Version:
  6. //Descriptions: FIFO控制模块:当ADC转换完成后,将数据存入FIFO,
  7. // 同时在往串口发送数据时控制从FIFO读取数据并将12
  8. // 数据分成两次8位发送到串口
  9. //-------------------------------------------------------------------
  10. module fifo_ctrl(
  11. input clk , //系统时钟50MHz
  12. input rst_n , //系统复位
  13. input empty , //fifo数据空信号
  14. input tx_done , //串口数据发送完成标志
  15. input [ 11: 0] q , //从fifo读出的数据
  16. input adc_done , //ADC转换完成一次标志
  17. input [ 11: 0] adc_data_out, //ADC转换完成的12位数据
  18. output reg rdreq , //fifo读使能
  19. output reg send_en , //串口发送使能
  20. output reg [7:0] data_byte , //输出发送的数据
  21. output reg wrreq , //FIFO写使能,在ADC转换结束后置1
  22. output reg [11:0] data_to_fifo //ADC转换完成的数据存入FIFO
  23. );
  24. parameter IDLE = 3'b000 ; //空闲状态
  25. parameter DATA_R = 3'b001 ; //当fifo数据不为空时,读取fifo数据
  26. parameter DATA_S = 3'b010 ; //将fifo的12位数据发送出去
  27. parameter SEND_1 = 3'b011 ; //发送前4位数据
  28. parameter SEND_2 = 3'b100 ; //发送后8位数据
  29. reg [ 2: 0] state_c ; //状态改变
  30. reg [ 2: 0] state_n ; //现在状态
  31. //状态机
  32. always @(posedge clk or negedge rst_n)begin
  33. if(rst_n==1'b0)begin
  34. state_c <= IDLE;
  35. end
  36. else begin
  37. state_c <= state_n;
  38. end
  39. end
  40. //状态改变条件
  41. always @(*)begin
  42. case(state_c)
  43. IDLE:begin
  44. if(empty==0)
  45. state_n = DATA_R;
  46. else
  47. state_n = state_c;
  48. end
  49. DATA_R:state_n = DATA_S;
  50. DATA_S:state_n = SEND_1;
  51. SEND_1:begin
  52. if(tx_done)
  53. state_n = SEND_2;
  54. else
  55. state_n = state_c;
  56. end
  57. SEND_2:begin
  58. if(tx_done)
  59. state_n = IDLE;
  60. else
  61. state_n = state_c;
  62. end
  63. endcase
  64. end
  65. //各个状态下rdreq和send_en输出的结果
  66. always @(posedge clk or negedge rst_n)begin
  67. if(rst_n==1'b0)begin
  68. rdreq <= 0;
  69. send_en <= 0;
  70. end
  71. else begin
  72. case(state_c)
  73. IDLE: begin
  74. if(empty==0)
  75. rdreq <= 1;
  76. else
  77. rdreq <= 0;
  78. end
  79. DATA_R:begin rdreq <= 0; end
  80. DATA_S:begin send_en <= 1; data_byte <= {4'd0,q[11:8]}; end
  81. SEND_1:begin
  82. send_en <= 0;
  83. if(tx_done)begin
  84. send_en <= 1;
  85. data_byte <= q[7:0];
  86. end
  87. end
  88. SEND_2:begin send_en <= 0; end
  89. endcase
  90. end
  91. end
  92. //ADC转换完成后将数据存入FIFO
  93. always @(posedge clk or negedge rst_n)begin
  94. if(rst_n==1'b0)begin
  95. data_to_fifo <= 0;
  96. end
  97. else if(adc_done) begin
  98. data_to_fifo <= adc_data_out;
  99. end
  100. end
  101. //ADC转换完成写使能打开
  102. always @(posedge clk or negedge rst_n)begin
  103. if(rst_n==1'b0)begin
  104. wrreq <= 0;
  105. end
  106. else if(adc_done) begin
  107. wrreq <= 1;
  108. end
  109. else begin
  110. wrreq <= 0;
  111. end
  112. end
  113. endmodule

仿真测试如下:


十、DAC控制模块

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

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

表10.1:DAC控制模块信号端口列表
信号名称I/O位数功能描述
clkI1系统时钟50MHz
rst_nI1系统复位
data_rxI8从串口接收到的指令
rx_doneI11字节串口数据接收完成标志
dac_doneI1DAC转换完成标志
addrO12ROM的地址线
dac_enO1DAC转换使能标志

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

  1. //-------------------------------------------------------------------
  2. //https://blog.csdn.net/qq_33231534 PHF的CSDN
  3. //File name: dac_ctrl.v
  4. //Last modified Date: 2020/5/23
  5. //Last Version:
  6. //Descriptions: DAC控制模块:当接收串口指定的指令时,
  7. // 开始将ROM的正弦数据进行DAC转换
  8. //-------------------------------------------------------------------
  9. module dac_ctrl(
  10. input clk ,//系统时钟50MHz
  11. input rst_n ,//系统复位
  12. input [ 7: 0] data_rx ,//从串口接收到的指令
  13. input rx_done ,//1字节串口数据接收完成标志
  14. input dac_done ,//DAC转换完成标志
  15. output reg [11:0] addr ,//ROM的地址线
  16. output reg dac_en //DAC转换使能标志
  17. );
  18. //控制地址线自加1
  19. always @(posedge clk or negedge rst_n)begin
  20. if(rst_n==1'b0)begin
  21. addr <= 0;
  22. end
  23. else if(dac_en) begin
  24. addr <= addr + 1'b1;
  25. end
  26. end
  27. //DAC转换使能标志
  28. always @(posedge clk or negedge rst_n)begin
  29. if(rst_n==1'b0)begin
  30. dac_en <= 0;
  31. end
  32. else if(rx_done || dac_done) begin
  33. dac_en <= 1;
  34. end
  35. else begin
  36. dac_en <= 0;
  37. end
  38. end
  39. endmodule

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


十一、系统整合

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

其代码如下:data_collection_top.v

  1. //-------------------------------------------------------------------
  2. //https://blog.csdn.net/qq_33231534 PHF的CSDN
  3. //File name:
  4. //Last modified Date:
  5. //Last Version:
  6. //Descriptions:
  7. //-------------------------------------------------------------------
  8. module data_collection_top(
  9. input clk ,//系统时钟50MHz
  10. input rst_n ,//系统复位
  11. input rs232_tx ,//串口向FPGA发送数据
  12. input adc_data_din,//adc数据输出到FPGA
  13. input key_in ,//按键输入
  14. output wire dac_din ,//dac串行数据接口控制和数据输出
  15. output wire dac_sclk ,//dac串行数据接口时钟信号
  16. output wire dac_cs ,//dac串行数据接口使能信号
  17. output wire adc_din ,//ADC控制信号,通道控制选取
  18. output wire adc_sclk ,//ADC串行数据接口时钟信号
  19. output wire adc_cs ,//ADC串行数据接口使能信号
  20. output wire rs232_rx //串口接收FPGA数据
  21. );
  22. wire [ 7: 0] data_rx ;
  23. wire rx_done ;
  24. wire dac_en ;
  25. wire [ 11: 0] addr ;
  26. wire dac_done ;
  27. wire [ 11: 0] data_rom ;
  28. wire empty ;
  29. wire adc_en ;
  30. wire key_flag ;
  31. wire adc_done ;
  32. wire tx_done ;
  33. wire rdreq ;
  34. wire send_en ;
  35. wire [ 7: 0] data_byte ;
  36. wire wrreq ;
  37. wire [ 11: 0] data_to_fifo ;
  38. wire [ 11: 0] adc_data_out ;
  39. wire [ 11: 0] fifo_data_out;
  40. //串口接收模块
  41. UART_Byte_Rx u_UART_Byte_Rx(
  42. .clk (clk) ,
  43. .rst_n (rst_n) ,
  44. .rs232_tx (rs232_tx) ,
  45. .baud_set (3'd1) ,
  46. .data_byte (data_rx) ,
  47. .rx_done (rx_done)
  48. );
  49. //DAC控制模块
  50. dac_ctrl u_dac_ctrl(
  51. .clk (clk) ,
  52. .rst_n (rst_n) ,
  53. .data_rx (data_rx) ,
  54. .rx_done (rx_done) ,
  55. .dac_done (dac_done) ,
  56. .addr (addr) ,
  57. .dac_en (dac_en)
  58. );
  59. //ROM模块
  60. single_port_rom
  61. #(.DATA_WIDTH(12), .ADDR_WIDTH(12))
  62. u_single_port_rom(
  63. .addr (addr) ,
  64. .clk (clk) ,
  65. .q (data_rom)
  66. );
  67. //DAC驱动模块
  68. dac_driver1 u_dac_driver(
  69. .clk (clk) ,
  70. .rst_n (rst_n) ,
  71. .dac_data_in({4'b1100,data_rom}),
  72. .dac_en (dac_en) ,
  73. .din (dac_din) ,
  74. .dac_sclk (dac_sclk) ,
  75. .cs (dac_cs) ,
  76. .dac_down (dac_done) ,
  77. .dac_state ()
  78. );
  79. //ADC驱动模块
  80. adc_driver u_adc_driver(
  81. .clk (clk) ,//系统时钟50MHz
  82. .rst_n (rst_n) ,//复位
  83. .channel (3'd0) ,//通道选择
  84. .adc_en (adc_en) ,//使能单次转换,该信号为周期有效高脉冲使能一次转换
  85. .dout (adc_data_din) ,//ADC转换结果,由ADC输给FPGA
  86. .din (adc_din) ,//ADC控制信号,通道控制选择
  87. .adc_sclk (adc_sclk) ,//ADC串行数据接口时钟信号
  88. .cs (adc_cs) ,//ADC串行数据接口使能信号
  89. .data_out (adc_data_out) ,//ADC转换结果
  90. .adc_done (adc_done) ,//转换完成信号,完成后输出一个周期高脉冲
  91. .adc_state () //ADC工作状态:0为空闲状态,1为转换状态
  92. );
  93. //按键控制模块
  94. key_ctrl u_key_ctrl(
  95. .clk (clk) ,
  96. .rst_n (rst_n) ,
  97. .key_flag (key_flag) , //按键信号
  98. .tran_num (7'd100) , //转换次数
  99. .adc_done (adc_done) ,
  100. .adc_en (adc_en)
  101. );
  102. //按键消抖模块
  103. key_filter u_key_filter(
  104. .clk (clk) ,
  105. .rst_n (rst_n) ,
  106. .key_in (key_in) ,
  107. .key_flag (key_flag) ,
  108. .key_state ()
  109. );
  110. //FIFO控制模块
  111. fifo_ctrl u_fifo_ctrl(
  112. .clk (clk) , //系统时钟50MHz
  113. .rst_n (rst_n) , //系统复位
  114. .empty (empty) , //fifo数据空信号
  115. .tx_done (tx_done) , //串口数据发送完成标志
  116. .q (fifo_data_out) , //从fifo读出的数据
  117. .adc_done (adc_done) ,
  118. .adc_data_out(adc_data_out),
  119. .rdreq (rdreq) , //fifo读使能
  120. .send_en (send_en) , //串口发送使能
  121. .data_byte (data_byte) , //输出发送的数据
  122. .wrreq (wrreq) ,
  123. .data_to_fifo(data_to_fifo)
  124. );
  125. //同步FIFO模块
  126. sync_fifo
  127. #(.WIDTH (12) , //缓存的数据宽度
  128. .DEPTH (100) , //缓存的数据深度
  129. .MAX_DEPTH_BIT(7)) //可设置的最大深度位数7,即最大深度为2^7-1
  130. u_sync_fifo
  131. (
  132. .clk (clk) , //系统时钟
  133. .rst_n (rst_n) , //系统复位
  134. .wrreq (wrreq) , //写使能
  135. .data (data_to_fifo) , //写数据
  136. .rdreq (rdreq) , //读使能
  137. .q (fifo_data_out) , //读数据
  138. .empty (empty) , //空信号
  139. .full () , //满信号
  140. .half () , //半满信号
  141. .usedw () //fifo中剩余数据个数
  142. );
  143. //串口发送模块
  144. Uart_Byte_Tx u_Uart_Byte_Tx(
  145. .clk (clk) ,
  146. .rst_n (rst_n) ,
  147. .send_en (send_en) ,
  148. .data_byte (data_byte) ,
  149. .baud_set (3'd1) ,
  150. .rs232_tx (rs232_rx) ,
  151. .tx_done (tx_done) ,
  152. .uart_state()
  153. );
  154. 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视图如下图:

 

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

闽ICP备14008679号