0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何通过串口将8路adc采集的数据传输给上位机显示

FPGA技术江湖 来源:FPGA技术江湖 2025-03-14 09:09 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

01概括 前文提供了ad7606的驱动程序,本文通过串口将8路adc采集的数据传输给上位机显示。工程的总体框图如下图所示,ad7606_drive驱动模块采集ad7606八路数据,八个数据处理模块data_dispose把采集的八路数据转换为电压数据,并且转换为BCD编码。uart_byte模块选择对应通道的数据发送给串口发送模块uart_tx,传输给上位机显示。2599c000-0070-11f0-9310-92fbcf53809c.png25a7dbd6-0070-11f0-9310-92fbcf53809c.png图1 工程框图注意本工程ad7606驱动虽然是200Ksps采样率一直在采集数据,但由于uart的传输速率过低,其实并不是采集的所有数据都会通过uart传输给上位机,本工程只能简单采集稳定的电压,做做电压表可以,并不能用来采集波形数据。

驱动模块直接查看前面即可,本文不再赘述。

02程序设计 2.1

数据处理模块

AD7606模块输入电压范围是[-5,+5],本模块功能是将16位adc补码数据转换为电压值,最终转换为BCD码,便于后续传输给上位机显示。如下所示,首先把补码数据转换为15位原码数据,且保存符号位。转换为15位数据ch_data后,对应的模拟电压值为[0,5V],符号位决定电压值的正负。
  always@(posedge clk or negedge rst_n)begin
    r_din_vld <= {r_din_vld[0],din_vld};
 end


  //对应通道数据有效时,把补码数据转换为原码且保留符号位;
  always@(posedge clk or negedge rst_n)begin
   if(~rst_n)begin
      r_ch_data <= 'd0;
      r_ch_sig <= 'd0;
   end
   elseif(din_vld)begin
      r_ch_data <= din[15] ? (~din[14:0] +1) : din[14:0];
      r_ch_sig <= din[15];
   end
 end
电压值y,ad7606采集的15位数据x的转换关系为y=x/(2^15)。因此通过下面的方式转换,为了保留计算精度,电压值ch_voltage为真实值的2^15*1000倍,单位mv。ch_voltage = ch_data * 1000的计算方式采用移位和加法计算。
  //对应通道数据乘以5000,得到真实电压的2^15倍,单位mv
  always@(posedge clk)begin
   if(r_din_vld[0])begin//5/327680.15mv,ADC采集数据乘以0.15得电压,0.15*2^15*1000=5000
      r_ch_voltage <= {r_ch_data,12'd0} + {r_ch_data,9'd0} + {r_ch_data,8'd0} + {r_ch_data,7'd0} + {r_ch_data,3'd0};
    end
  end
舍弃ch_voltage的低15位数据,等效除以2^15,电压值r_voltage计算就是转换结果,单位mv。
 always@(posedge clk)begin
   r_voltage<= r_din_vld[1] ? r_ch_voltage[27:15] : r_voltage;//除以2^15次方,得到mv电压;
   r_voltage_vld<= r_din_vld[1];
   voltage_sig<= r_ch_sig;
 end
最后通过hex2bcd模块把转换后的电压值转换为BCD码,该模块全部采用参数化设计,前面有一篇文章也讲了具体实现原理,有兴趣的可以点击查看。
//--###############################################################################################
//--#
//--# File Name  : data_dispose
//--# Designer  : 数字站
//--# Tool   : Quartus 2018.1
//--# Design Date : 2024.10.10
//--# Description :
//--# Version  : 0.0
//--# Coding scheme : UTF-8(If the Chinese comment of the file is garbled, please do not save it and check whether the file is opened in GBK encoding mode)
//--#
//--###############################################################################################
module data_dispose (
  input         clk        ,//系统时钟信号
  input         rst_n       ,//系统复位信号,低电平有效;


  input    [15:0]   din        ,//输入数据;
  input            din_vld       ,//输入数据有效指示信号,高电平有效;
  output    [15:0]   voltage       ,//输出电压,单位mv
  output reg           voltage_sig ='d0 ,//输出电压的正负,低电平表示正;
  output        voltage_vld     //输出数据有效指示信号,高电平有效;
);
  reg       [1:0]     r_din_vld  ='d0 ;
  reg       [14:0]    r_ch_data      ;//
  reg       [27:0]    r_ch_voltage ='d0 ;
  reg               r_ch_sig   ='d0 ;
  reg       [12:0]    r_voltage  ='d0 ; 
 reg            r_voltage_vld='d0 ;


  always@(posedge clk or negedge rst_n)begin
    r_din_vld<={r_din_vld[0],din_vld};
  end


 //对应通道数据有效时,把补码数据转换为原码且保留符号位;
  always@(posedge clk or negedge rst_n)begin
   if(~rst_n)begin
      r_ch_data<='d0;
      r_ch_sig<='d0;
    end
   elseif(din_vld)begin
      r_ch_data<=din[15]?(~din[14:0]+1) : din[14:0];
      r_ch_sig<=din[15];
    end
  end


 //对应通道数据乘以5000,得到真实电压的2^15倍,单位mv;
  always@(posedge clk)begin
   if(r_din_vld[0])begin//5/32768≈0.15mv,ADC采集数据乘以0.15得电压,0.15*2^15*1000=5000
      r_ch_voltage<={r_ch_data,12'd0}+{r_ch_data,9'd0}+{r_ch_data,8'd0}+{r_ch_data,7'd0}+{r_ch_data,3'd0};
    end
  end


 //产生输出数据;
  always@(posedge clk)begin
    r_voltage<=r_din_vld[1]?r_ch_voltage[27:15] : r_voltage;//除以2^15次方,得到mv电压;
    r_voltage_vld<=r_din_vld[1];
    voltage_sig<=r_ch_sig;
  end


 //调用十六进制转BCD模块,将13位十六进制数据转换成16位BCD码;
  hex2bcd #(
    .IN_DATA_W (13      )//输入数据位宽;
  )
  u_hex2bcd (
    .clk    ( clk      ),//系统时钟;
    .rst_n   ( rst_n     ),//系统复位,低电平有效;
    .din    ( r_voltage   ),//输入二进制数据;
    .din_vld  ( r_voltage_vld ),//输入数据有效指示信号,高电平有效;
    .rdy    (        ),//忙闲指示信号,该信号高电平时才能输入有效数据;
    .dout    ( voltage    ),//输出8421BCD码;
    .dout_vld  ( voltage_vld  )//输出数据有效指示信号,高电平有效;
  );


endmodule
2.2

uart字节发送模块

首先通过存储器保存八路adc转换后的bcd数据,保存的时候还要将数据加48转换为ascii编码,因为0对应的ascii码对应数值为48。
 always@(posedge clk)begin
   if(i_voltage_vld[0])begin
     r_voltage_sig[0] <=  i_voltage_sig[0];//保存通道0的符号位;
     r_voltage_g[0] <= i_voltage0[15:12] +8'd48;//将通道0的个位数据转换为ASCII对应字符;
     r_voltage_s[0] <= i_voltage0[11:8] +8'd48;//将通道0的十分位数据转换为ASCII对应字符;
     r_voltage_b[0] <= i_voltage0[7:4] +8'd48;//将通道0的百分位数据转换为ASCII对应字符;
     r_voltage_q[0] <= i_voltage0[3:0] +8'd48;//将通道0的千分位数据转换为ASCII对应字符;
   end
 end


 always@(posedge clk)begin
   if(i_voltage_vld[1])begin
     r_voltage_sig[1] <=  i_voltage_sig[1];//保存通道1的符号位;
     r_voltage_g[1] <= i_voltage1[15:12] +8'd48;//将通道1的个位数据转换为ASCII对应字符;
     r_voltage_s[1] <= i_voltage1[11:8] +8'd48;//将通道1的十分位数据转换为ASCII对应字符;
     r_voltage_b[1] <= i_voltage1[7:4] +8'd48;//将通道1的百分位数据转换为ASCII对应字符;
     r_voltage_q[1] <= i_voltage1[3:0] +8'd48;//将通道1的千分位数据转换为ASCII对应字符;
   end
 end


 always@(posedge clk)begin
   if(i_voltage_vld[2])begin
     r_voltage_sig[2] <=  i_voltage_sig[2];//保存通道2的符号位;
     r_voltage_g[2] <= i_voltage2[15:12] +8'd48;//将通道2的个位数据转换为ASCII对应字符;
     r_voltage_s[2] <= i_voltage2[11:8] +8'd48;//将通道2的十分位数据转换为ASCII对应字符;
     r_voltage_b[2] <= i_voltage2[7:4] +8'd48;//将通道2的百分位数据转换为ASCII对应字符;
     r_voltage_q[2] <= i_voltage2[3:0] +8'd48;//将通道2的千分位数据转换为ASCII对应字符;
   end
 end


 always@(posedge clk)begin
   if(i_voltage_vld[3])begin
     r_voltage_sig[3] <=  i_voltage_sig[3];//保存通道3的符号位;
     r_voltage_g[3] <= i_voltage3[15:12] +8'd48;//将通道3的个位数据转换为ASCII对应字符;
     r_voltage_s[3] <= i_voltage3[11:8] +8'd48;//将通道3的十分位数据转换为ASCII对应字符;
     r_voltage_b[3] <= i_voltage3[7:4] +8'd48;//将通道3的百分位数据转换为ASCII对应字符;
     r_voltage_q[3] <= i_voltage3[3:0] +8'd48;//将通道3的千分位数据转换为ASCII对应字符;
   end
 end


 always@(posedge clk)begin
   if(i_voltage_vld[4])begin
     r_voltage_sig[4] <=  i_voltage_sig[4];//保存通道4的符号位;
     r_voltage_g[4] <= i_voltage4[15:12] +8'd48;//将通道4的个位数据转换为ASCII对应字符;
     r_voltage_s[4] <= i_voltage4[11:8] +8'd48;//将通道4的十分位数据转换为ASCII对应字符;
     r_voltage_b[4] <= i_voltage4[7:4] +8'd48;//将通道4的百分位数据转换为ASCII对应字符;
     r_voltage_q[4] <= i_voltage4[3:0] +8'd48;//将通道4的千分位数据转换为ASCII对应字符;
   end
 end


 always@(posedge clk)begin
   if(i_voltage_vld[5])begin
     r_voltage_sig[5] <=  i_voltage_sig[5];//保存通道5的符号位;
     r_voltage_g[5] <= i_voltage5[15:12] +8'd48;//将通道5的个位数据转换为ASCII对应字符;
     r_voltage_s[5] <= i_voltage5[11:8] +8'd48;//将通道5的十分位数据转换为ASCII对应字符;
     r_voltage_b[5] <= i_voltage5[7:4] +8'd48;//将通道5的百分位数据转换为ASCII对应字符;
     r_voltage_q[5] <= i_voltage5[3:0] +8'd48;//将通道5的千分位数据转换为ASCII对应字符;
   end
 end


 always@(posedge clk)begin
   if(i_voltage_vld[6])begin
     r_voltage_sig[6] <=  i_voltage_sig[6];//保存通道6的符号位;
     r_voltage_g[6] <= i_voltage6[15:12] +8'd48;//将通道6的个位数据转换为ASCII对应字符;
     r_voltage_s[6] <= i_voltage6[11:8] +8'd48;//将通道6的十分位数据转换为ASCII对应字符;
     r_voltage_b[6] <= i_voltage6[7:4] +8'd48;//将通道6的百分位数据转换为ASCII对应字符;
     r_voltage_q[6] <= i_voltage6[3:0] +8'd48;//将通道6的千分位数据转换为ASCII对应字符;
   end
 end


 always@(posedge clk)begin
   if(i_voltage_vld[7])begin
     r_voltage_sig[7] <=  i_voltage_sig[7];//保存通道7的符号位;
     r_voltage_g[7] <= i_voltage7[15:12] +8'd48;//将通道7的个位数据转换为ASCII对应字符;
     r_voltage_s[7] <= i_voltage7[11:8] +8'd48;//将通道7的十分位数据转换为ASCII对应字符;
     r_voltage_b[7] <= i_voltage7[7:4] +8'd48;//将通道7的百分位数据转换为ASCII对应字符;
     r_voltage_q[7] <= i_voltage7[3:0] +8'd48;//将通道7的千分位数据转换为ASCII对应字符;
   end
 end
上位机显示的格式为:ADX:±3.426V,上位机显示的每个通道的数据需要发送11字节数据,并且后续还要跟两个空格或者回车,因此每个通道需要发送13字节数据。为了便于数据接收端识别数据,当串口发送一个字节数据后,需要暂停一段时间后在发送下字节数据。因此使用一个空闲计数器对空闲时间计数,停留发送2位数据才开始下字节数据传输。
  always@(posedge clkornegedge rst_n)begin
    if(~rst_n)begin//初始值为0;
      r_rdy_cnt<='d0;
    end
    else if(i_uart_tx_rdy)begin
      if(r_end_rdy_cnt)
        r_rdy_cnt <= 'd0;
     else
        r_rdy_cnt<=r_rdy_cnt+'d1;
    end
  end


  always@(posedge clk)begin
    r_end_rdy_cnt <= i_uart_tx_rdy && (r_rdy_cnt == 2*BPS_CNT-2);
  end
通过两个计数器分别记录发送当前通道的第几个数据、发送的数据属于第几个通道。
  always@(posedge clkornegedge rst_n)begin
    if(~rst_n)begin//初始值为0;
      r_byte_cnt<='d0;
    end
    else if(r_end_rdy_cnt)begin
      if(r_byte_cnt == 12)
        r_byte_cnt <= 'd0;
     else
        r_byte_cnt<=r_byte_cnt+'d1;
    end
  end


  //一轮需要传输8个通道的数据到PC端,使用一个8进制计数器对传输数据的通道数计数;
  //当一个通道数据传输结束时加1,计数器采用溢出清零;
  always@(posedge clk or negedge rst_n)begin
    if(~rst_n)begin//初始值为0;
      r_ch_cnt <= 'd0;
   end
   elseif(r_end_rdy_cnt&&(r_byte_cnt==12))begin
      r_ch_cnt<=r_ch_cnt+'d1;
    end
  end
通过译码器转换数据,根据字节计数器的值发送对应的数据,有部分数据根据通道不同发送不同数据。比如通道7数据发送结束后,需要发送回车和换行字符,不需要发送空格字符。
  always@(posedge clk)begin
   if(r_end_rdy_cnt)begin
     case(r_byte_cnt)
       4'd0  : o_uart_txdata <= 8'd65;//发送字符A对应的ASCCI码值;
       4'd1  : o_uart_txdata <= 8'd68;//发送字符D对应的ASCCI码值;
       4'd2  : o_uart_txdata <= r_ch_cnt + 'd49;//发送通道r_ch_cnt对应的ASCCI码值;
       4'd3  : o_uart_txdata <= 8'd58;//发送字符:对应的ASCCI码值;
       //电压的正负值对应的ASCII码,r_voltage_sig为高电平表示对应通道电压为负数。
       4'd4  : o_uart_txdata <= r_voltage_sig[r_ch_cnt] ? 8'd45 :8'd43;
        4'd5  : o_uart_txdata <= r_voltage_g[r_ch_cnt];//发送个位电压对应的ASCCI码值;
       4'd6  : o_uart_txdata <= 8'd46;//发送字符.对应的ASCCI码值;
       4'd7  : o_uart_txdata <= r_voltage_s[r_ch_cnt];//发送十分位对应的ASCCI码值;
        4'd8  : o_uart_txdata <= r_voltage_b[r_ch_cnt];//发送百分位对应的ASCCI码值;
       4'd9  : o_uart_txdata <= r_voltage_q[r_ch_cnt];//发送千分位对应的ASCCI码值;
        4'd10  : o_uart_txdata <= 8'd86 ;//发送字符V对应的ASCCI码值;
        4'd11  : o_uart_txdata <= (&r_ch_cnt) ? 8'd10 : 8'd32;//如果是发送最后一个通道的数据,则发送换行,否则发送空格;
       4'd12  : o_uart_txdata <= (&r_ch_cnt) ? 8'd13 :8'd32;//如果是发送最后一个通道的数据,则发送回车,否则发送空格;
        default : o_uart_txdata <= 8'hff;
      endcase
    end
  end


  always@(posedge clk)begin
    o_uart_txdata_vld <= r_end_rdy_cnt;//生成并行数据有效指示信号;
  end
该模块参考代码如下所示:
//--###############################################################################################
//--#
//--# File Name  : uart_byte
//--# Designer  : 数字站
//--# Tool   : Quartus 2018.1
//--# Design Date : 2024.10.10
//--# Description :
//--# Version  : 0.0
//--# Coding scheme : UTF-8(If the Chinese comment of the file is garbled, please do not save it and check whether the file is opened in GBK encoding mode)
//--#
//--###############################################################################################
module uart_byte#(
  parameter    FLCK  =   50_000_000 ,//系统时钟频率,默认50MHZ;
  parameter    BPS   =   9600    //串口波特率;
)(
  input       clk          ,//系统时钟信号;
  input       rst_n         ,//系统复位信号,低电平有效;


  input   [15:0]   i_voltage0       ,//输入数据;
  input   [15:0]   i_voltage1       ,//输入数据;
  input   [15:0]   i_voltage2       ,//输入数据;
  input   [15:0]   i_voltage3       ,//输入数据;
  input   [15:0]   i_voltage4       ,//输入数据;
  input   [15:0]   i_voltage5       ,//输入数据;
  input   [15:0]   i_voltage6       ,//输入数据;
  input   [15:0]   i_voltage7       ,//输入数据;
  input   [7:0]   i_voltage_sig      ,//各通道数据的正负数据指示信号;
  input   [7:0]   i_voltage_vld      ,//输入数据有效指示信号,高电平有效;
  input            i_uart_tx_rdy      ,//uart发送模块空闲指示信号;
  output reg [7:0]     o_uart_txdata ='d0   ,//需要uart发送的并行数据;
  output reg     o_uart_txdata_vld = 'd0 //需要的发送的并行数据有效指示信号;
);
  localparam BPS_CNT  =   FLCK/BPS        ;//波特率为9600bit/s,当波特率为115200bit/s时,DATA_115200==434
  localparam BPS_CNT_W =   $clog2(2*BPS_CNT-1)   ;//根据BPS_CNT调用函数自动计算计数器bps_cnt位宽;
  reg     [7:0]     r_voltage_sig ='d0   ;
  reg     [BPS_CNT_W-1:0] r_rdy_cnt        ;
  reg             r_end_rdy_cnt      ;
  reg [7 : 0] r_voltage_g   [7 : 0]         ;
  reg [7 : 0] r_voltage_s   [7 : 0]         ;
  reg [7 : 0] r_voltage_b   [7 : 0]         ;
  reg [7 : 0] r_voltage_q   [7 : 0]         ;
  reg [3 : 0]         r_byte_cnt       ;//
  reg [2 : 0]         r_ch_cnt        ;


  /********** 存储数据 *************/
  always@(posedge clk)begin
    if(i_voltage_vld[0])begin
      r_voltage_sig[0] <=  i_voltage_sig[0];//保存通道0的符号位;
      r_voltage_g[0] <= i_voltage0[15 : 12] + 8'd48;//将通道0的个位数据转换为ASCII对应字符;
      r_voltage_s[0] <= i_voltage0[11:8] +8'd48;//将通道0的十分位数据转换为ASCII对应字符;
      r_voltage_b[0] <= i_voltage0[7 : 4] + 8'd48;//将通道0的百分位数据转换为ASCII对应字符;
      r_voltage_q[0]<= i_voltage0[3:0] +8'd48;//将通道0的千分位数据转换为ASCII对应字符;
    end
  end


  always@(posedge clk)begin
    if(i_voltage_vld[1])begin
      r_voltage_sig[1] <=  i_voltage_sig[1];//保存通道1的符号位;
      r_voltage_g[1] <= i_voltage1[15 : 12] + 8'd48;//将通道1的个位数据转换为ASCII对应字符;
      r_voltage_s[1] <= i_voltage1[11:8] +8'd48;//将通道1的十分位数据转换为ASCII对应字符;
      r_voltage_b[1] <= i_voltage1[7 : 4] + 8'd48;//将通道1的百分位数据转换为ASCII对应字符;
      r_voltage_q[1]<= i_voltage1[3:0] +8'd48;//将通道1的千分位数据转换为ASCII对应字符;
    end
  end


  always@(posedge clk)begin
    if(i_voltage_vld[2])begin
      r_voltage_sig[2] <=  i_voltage_sig[2];//保存通道2的符号位;
      r_voltage_g[2] <= i_voltage2[15 : 12] + 8'd48;//将通道2的个位数据转换为ASCII对应字符;
      r_voltage_s[2] <= i_voltage2[11:8] +8'd48;//将通道2的十分位数据转换为ASCII对应字符;
      r_voltage_b[2] <= i_voltage2[7 : 4] + 8'd48;//将通道2的百分位数据转换为ASCII对应字符;
      r_voltage_q[2]<= i_voltage2[3:0] +8'd48;//将通道2的千分位数据转换为ASCII对应字符;
    end
  end


  always@(posedge clk)begin
    if(i_voltage_vld[3])begin
      r_voltage_sig[3] <=  i_voltage_sig[3];//保存通道3的符号位;
      r_voltage_g[3] <= i_voltage3[15 : 12] + 8'd48;//将通道3的个位数据转换为ASCII对应字符;
      r_voltage_s[3] <= i_voltage3[11:8] +8'd48;//将通道3的十分位数据转换为ASCII对应字符;
      r_voltage_b[3] <= i_voltage3[7 : 4] + 8'd48;//将通道3的百分位数据转换为ASCII对应字符;
      r_voltage_q[3]<= i_voltage3[3:0] +8'd48;//将通道3的千分位数据转换为ASCII对应字符;
    end
  end


  always@(posedge clk)begin
    if(i_voltage_vld[4])begin
      r_voltage_sig[4] <=  i_voltage_sig[4];//保存通道4的符号位;
      r_voltage_g[4] <= i_voltage4[15 : 12] + 8'd48;//将通道4的个位数据转换为ASCII对应字符;
      r_voltage_s[4] <= i_voltage4[11:8] +8'd48;//将通道4的十分位数据转换为ASCII对应字符;
      r_voltage_b[4] <= i_voltage4[7 : 4] + 8'd48;//将通道4的百分位数据转换为ASCII对应字符;
      r_voltage_q[4]<= i_voltage4[3:0] +8'd48;//将通道4的千分位数据转换为ASCII对应字符;
    end
  end


  always@(posedge clk)begin
    if(i_voltage_vld[5])begin
      r_voltage_sig[5] <=  i_voltage_sig[5];//保存通道5的符号位;
      r_voltage_g[5] <= i_voltage5[15 : 12] + 8'd48;//将通道5的个位数据转换为ASCII对应字符;
      r_voltage_s[5] <= i_voltage5[11:8] +8'd48;//将通道5的十分位数据转换为ASCII对应字符;
      r_voltage_b[5] <= i_voltage5[7 : 4] + 8'd48;//将通道5的百分位数据转换为ASCII对应字符;
      r_voltage_q[5]<= i_voltage5[3:0] +8'd48;//将通道5的千分位数据转换为ASCII对应字符;
    end
  end


  always@(posedge clk)begin
    if(i_voltage_vld[6])begin
      r_voltage_sig[6] <=  i_voltage_sig[6];//保存通道6的符号位;
      r_voltage_g[6] <= i_voltage6[15 : 12] + 8'd48;//将通道6的个位数据转换为ASCII对应字符;
      r_voltage_s[6] <= i_voltage6[11:8] +8'd48;//将通道6的十分位数据转换为ASCII对应字符;
      r_voltage_b[6] <= i_voltage6[7 : 4] + 8'd48;//将通道6的百分位数据转换为ASCII对应字符;
      r_voltage_q[6]<= i_voltage6[3:0] +8'd48;//将通道6的千分位数据转换为ASCII对应字符;
    end
  end


  always@(posedge clk)begin
    if(i_voltage_vld[7])begin
      r_voltage_sig[7] <=  i_voltage_sig[7];//保存通道7的符号位;
      r_voltage_g[7] <= i_voltage7[15 : 12] + 8'd48;//将通道7的个位数据转换为ASCII对应字符;
      r_voltage_s[7] <= i_voltage7[11:8] +8'd48;//将通道7的十分位数据转换为ASCII对应字符;
      r_voltage_b[7] <= i_voltage7[7 : 4] + 8'd48;//将通道7的百分位数据转换为ASCII对应字符;
      r_voltage_q[7]<= i_voltage7[3:0] +8'd48;//将通道7的千分位数据转换为ASCII对应字符;
    end
  end


  /********* 发送数据 ************/
  //空闲计数器,发送一字节数据后,暂停一段时间在发送下字节数据;
  always@(posedge clk or negedge rst_n)begin
    if(~rst_n)begin//初始值为0;
      r_rdy_cnt <= 'd0;
    end
   elseif(i_uart_tx_rdy)begin
     if(r_end_rdy_cnt)
        r_rdy_cnt <= 'd0;
      else
        r_rdy_cnt <= r_rdy_cnt + 'd1;
    end
  end


  always@(posedge clk)begin
    r_end_rdy_cnt <= i_uart_tx_rdy && (r_rdy_cnt == 2*BPS_CNT-2);
  end


  //每个通道需要发送13字节串口数据到PC端,使用一个13进制计数器对发送数据计数;
  //当下游模块空闲时表示发送完成1字节数据,计数器加1.
  always@(posedge clkornegedge rst_n)begin
   if(~rst_n)begin//初始值为0;
      r_byte_cnt <= 'd0;
    end
    else if(r_end_rdy_cnt)begin
      if(r_byte_cnt == 12)
        r_byte_cnt <= 'd0;
     else
        r_byte_cnt <= r_byte_cnt + 'd1;
    end
  end


  //一轮需要传输8个通道的数据到PC端,使用一个8进制计数器对传输数据的通道数计数;
  //当一个通道数据传输结束时加1,计数器采用溢出清零;
  always@(posedge clk or negedge rst_n)begin
    if(~rst_n)begin//初始值为0;
      r_ch_cnt <= 'd0;
    end
   elseif(r_end_rdy_cnt && (r_byte_cnt ==12))begin
      r_ch_cnt <= r_ch_cnt + 'd1;
    end
  end


  //产生下游uart模块需要发送的并行数据;
  always@(posedge clk)begin
    if(r_end_rdy_cnt)begin
      case(r_byte_cnt)
        4'd0  : o_uart_txdata <= 8'd65;//发送字符A对应的ASCCI码值;
        4'd1  : o_uart_txdata <= 8'd68;//发送字符D对应的ASCCI码值;
        4'd2  : o_uart_txdata <= r_ch_cnt + 'd49;//发送通道r_ch_cnt对应的ASCCI码值;
        4'd3  : o_uart_txdata <= 8'd58;//发送字符:对应的ASCCI码值;
        //电压的正负值对应的ASCII码,r_voltage_sig为高电平表示对应通道电压为负数。
        4'd4  : o_uart_txdata <= r_voltage_sig[r_ch_cnt] ? 8'd45 : 8'd43;
       4'd5  : o_uart_txdata <= r_voltage_g[r_ch_cnt];//发送个位电压对应的ASCCI码值;
        4'd6  : o_uart_txdata <= 8'd46;//发送字符.对应的ASCCI码值;
        4'd7  : o_uart_txdata <= r_voltage_s[r_ch_cnt];//发送十分位对应的ASCCI码值;
       4'd8  : o_uart_txdata <= r_voltage_b[r_ch_cnt];//发送百分位对应的ASCCI码值;
        4'd9  : o_uart_txdata <= r_voltage_q[r_ch_cnt];//发送千分位对应的ASCCI码值;
       4'd10  : o_uart_txdata <= 8'd86 ;//发送字符V对应的ASCCI码值;
       4'd11  : o_uart_txdata <= (&r_ch_cnt) ? 8'd10:8'd32;//如果是发送最后一个通道的数据,则发送换行,否则发送空格;
        4'd12  : o_uart_txdata <= (&r_ch_cnt) ? 8'd13 : 8'd32;//如果是发送最后一个通道的数据,则发送回车,否则发送空格;
        default : o_uart_txdata <= 8'hff;
      endcase
    end
  end


  always@(posedge clk)begin
    o_uart_txdata_vld <= r_end_rdy_cnt;//生成并行数据有效指示信号;
  end


endmodule
uart发送模块依旧使用以前模块,前文详细讲解过uart接收模块全模式设计方式,本文就不再赘述,参考代码如下所示:
//--###############################################################################################
//--#
//--# File Name  : uart_tx
//--# Designer  : 数字站
//--# Tool   : Quartus 2018.1
//--# Design Date : 2024.10.10
//--# Description :
//--# Version  : 0.0
//--# Coding scheme : UTF-8(If the Chinese comment of the file is garbled, please do not save it and check whether the file is opened in GBK encoding mode)
//--#
//--###############################################################################################
module uart_tx#(
  parameter    FLCK  =   50_000_000 ,//系统时钟频率,默认50MHZ;
  parameter    BPS   =   9600    ,//串口波特率;
  parameter    DATA_W =   8     ,//发送数据位数以及输出数据位宽;
  parameter    START_W =   1     ,//1位起始位;
  parameter    CHECK_W =   2'b00    ,//校验位,2'b00代表无校验位,2'b01表示奇校验,2'b10表示偶校验,2'b11按无校验处理。
  parameter    STOP_W =   2'b01    //停止位,2'b01表示1位停止位,2'b10表示2位停止位,2'b11表示1.5位停止位;
)(
  input              clk     ,//系统工作时钟50MHZ
  input              rst_n    ,//系统复位信号,低电平有效


  input      [DATA_W-1:0]  tx_data   ,//数据输入信号。
  input              tx_data_vld ,//数据有效指示信号,高电平有效。


  output reg           uart_tx   ,//uart接口数据输出信号。
  output reg           tx_rdy   //模块忙闲指示信号;
);
  localparam   BPS_CNT  =   FLCK/BPS    ;//波特率为9600bit/s,当波特率为115200bit/s时,DATA_115200==434;
  localparam   BPS_CNT_W =   $clog2(BPS_CNT-1);//根据BPS_CNT调用函数自动计算计数器bps_cnt位宽;
  localparam   DATA_CNT =   START_W + DATA_W + (^CHECK_W) + ((STOP_W==2'b11) ?2: STOP_W);//计数器计数值;
  localparam   DATA_CNT_W=   $clog2(DATA_CNT-1);//根据计数器cnt的值,利用函数自动计算此计数器的位宽;


  reg               flag      ;
  reg               tx_rdy_ff0   ;//
  reg       [DATA_CNT-1:0] tx_data_tmp   ;
  reg       [BPS_CNT_W-1:0] bps_cnt     ;
  reg       [DATA_CNT_W-1:0]data_cnt    ;


  wire              add_bps_cnt   ;
  wire              end_bps_cnt   ;
  wire              end_data_cnt  ;


 /*发送一位数据所需要的时间*/
  always @(posedge clkornegedge rst_n)begin
   if(!rst_n)begin
      bps_cnt <= {{BPS_CNT_W}{1'b0}};
   end
   elseif(add_bps_cnt)begin
     if(end_bps_cnt || end_data_cnt)
        bps_cnt <= {{BPS_CNT_W}{1'b0}};
     else
        bps_cnt <= bps_cnt + {{{BPS_CNT_W-1}{1'b0}},1'b1};
    end
  end


  assign add_bps_cnt = flag;
  assign end_bps_cnt = add_bps_cnt && bps_cnt == BPS_CNT-1;


 /*发送一组数据所用时间*/
  always@(posedge clkornegedge rst_n)begin
   if(rst_n==1'b0)begin//
      data_cnt <= {{DATA_CNT}{1'b0}};
   end
   elseif(end_data_cnt)begin
      data_cnt <= {{DATA_CNT}{1'b0}};
   end
   elseif(end_bps_cnt)begin
      data_cnt <= data_cnt + {{{DATA_CNT-1}{1'b0}},1'b1};
    end
  end


 //根据停止位的不同生成不同的计数器结束条件;
 generate
   if(STOP_W ==2'b11)//1.5位停止位,因为CNT_NUM没有包含起始位,所以要等计数器计数到CNT_NUM时清零;
      assign end_data_cnt = data_cnt == DATA_CNT-1&& add_bps_cnt && bps_cnt == BPS_CNT/2-1;
   else//停止位为1位或者2位;
      assign end_data_cnt = end_bps_cnt && data_cnt == DATA_CNT-1;
  endgenerate


  //这个期间UART在发送数据;
  always@(posedge clkornegedge rst_n)begin
   if(rst_n==1'b0)begin
      flag <= 1'b0;
   end
   elseif(tx_data_vld)begin
      flag <= 1'b1;
   end
   elseif(end_data_cnt)begin
      flag <= 1'b0;
    end
  end


 //UART模块处于忙时期,收到上游模块数据或者正在处理上游模块所发数据;
  always@(*)begin
   if(tx_data_vld || flag)begin
      tx_rdy =1'b0;
    end
   elsebegin
      tx_rdy =1'b1;
    end
  end


  always@(posedge clk)begin
    tx_rdy_ff0 <= tx_rdy;
  end


 //将上游模块所发并行数据转化为串行数据;
 generate
   if(CHECK_W ==2'b01)begin//奇校验;
      always@(posedge clkornegedge rst_n)begin
       if(rst_n==1'b0)begin
          tx_data_tmp <= {{DATA_CNT+1}{1'b1}};
       end
       elseif(tx_rdy_ff0 && tx_data_vld)begin
          tx_data_tmp <= {{{STOP_W}{1'b1}},~(^tx_data),tx_data,{{START_W}{1'b0}}};
       end
      end
    end
   elseif(CHECK_W ==2'b10)begin//偶校验
      always@(posedge clkornegedge rst_n)begin
       if(rst_n==1'b0)begin
          tx_data_tmp <= {{DATA_CNT+1}{1'b1}};
       end
       elseif(tx_rdy_ff0 && tx_data_vld)begin
          tx_data_tmp <= {{{STOP_W}{1'b1}},(^tx_data),tx_data,{{START_W}{1'b0}}};
        end
      end
    end
   elsebegin//无校验
      always@(posedge clkornegedge rst_n)begin
       if(rst_n==1'b0)begin
          tx_data_tmp <= {{DATA_CNT+1}{1'b1}};
       end
       elseif(tx_rdy_ff0 && tx_data_vld)begin
          tx_data_tmp <= {{{STOP_W}{1'b1}},tx_data,{{START_W}{1'b0}}};
        end
      end
    end
  endgenerate


 //将串行数据按9600波特率送出,先发低位;
  always@(posedge clkornegedge rst_n)begin
   if(rst_n==1'b0)begin
      uart_tx <= 1'b1;
   end
   elseif(add_bps_cnt && bps_cnt==0)begin
      uart_tx <= tx_data_tmp[data_cnt];
    end
  end


  endmodule
2.3

顶层模块

顶层模块如下所示,单独列出来是因为代码使用for循环例化了8个通道的数据处理模块。参考代码如下所示:

//--###############################################################################################
//--#
//--# File Name  : top
//--# Designer  :
//--# Tool   : Quartus 2018.1
//--# Design Date : 2024.10.10
//--# Description :
//--# Version  : 0.0
//--# Coding scheme : UTF-8(If the Chinese comment of the file is garbled, please do not save it and check whether the file is opened in GBK encoding mode)
//--#
//--###############################################################################################
module top#(
  parameter    FLCK    = 100_000_000   ,//系统时钟频率,默认50MHZ;
  parameter    BPS     = 115200     ,//串口波特率;
  parameter    UART_DATA_W = 8       ,//发送数据位数以及输出数据位宽;
  parameter    START_W   = 1       ,//1位起始位;
  parameter    CHECK_W   = 2'b00      ,//校验位,2'b00代表无校验位,2'b01表示奇校验,2'b10表示偶校验,2'b11按无校验处理。
  parameter    STOP_W   = 2'b01      //停止位,2'b01表示1位停止位,2'b10表示2位停止位,2'b11表示1.5位停止位;
)(
  input              clk       ,//系统时钟,50MHz;
  input              rst_n      ,//系统复位,低电平有效;


  input              busy      ,//转换完成指示信号,下降沿有效;
  input              frstdata    ,//指示采集到的第一个数据;
  input    [15:0]      adc_din     ,//AD7606所采集到的十六位数据信号;


  input              uart_rx     ,
  output             cs       ,//AD7606片选信号,读数据时拉低;
  output             rd       ,//AD7606读使能信号,读数据时拉低,下降沿时AD7606将数据发送到数据线上,上升沿时可以读出数据;
  output             reset      ,//AD7606复位信号,高电平有效,每次复位至少拉高50ns;
  output   [2:0]       os       ,//AD7606过采样模式信号,默认不使用过采样;
  output             convst     ,//AD7606采样启动信号,无效时高电平,采样计数器完成时拉低两个时钟;
  output             uart_tx     //uart接口数据输出信号。
);
  wire              clk_100m    ;//锁相环输出时钟;
  wire    [15:0]      w_7606_data   ;//AD7606通道采集的补码数据;
  wire    [7:0]       w_7606_data_vld ;//指示AD7606输出的数据来自哪个数据通道;
  wire    [15:0] w_voltage [7:0]     ;//输出电压,单位mv
  wire    [7:0]       w_voltage_sig  ;//输出电压的正负,低电平表示正;
  wire    [7:0]       w_voltage_vld  ;//输出数据有效指示信号,高电平有效;
  wire    [UART_DATA_W-1:0]  w_tx_data    ;//数据输入信号。
  wire              w_tx_data_vld  ;//数据有效指示信号,高电平有效。
  wire              w_tx_rdy    ;//模块忙闲指示信号;


 //例化锁相环
 pllu_pll(
    .areset ( ~rst_n  ),
    .inclk0(clk   ),
    .c0  (clk_100m )
  );


 //例化ad7606驱动模块
  ad7606_drive#(
    .FCLK    ( FLCK       ),//系统时钟频率,单位Hz,默认100MHz;
    .SMAPLE   (200_000      )//AD7606采样频率,单位Hz,默认200KHz;
  )
  u_ad7606_drive (
    .clk    ( clk_100m     ),//系统时钟,100MHz;
    .rst_n   ( rst_n       ),//系统复位,低电平有效;
    .busy    ( busy       ),//转换完成指示信号,下降沿有效;
    .frstdata  ( frstdata     ),//指示采集到的第一个数据;
    .adc_din  ( adc_din      ),//AD7606所采集到的十六位数据信号;
    .cs     ( cs        ),//AD7606片选信号,读数据时拉低;
    .rd     ( rd        ),//AD7606读使能信号,读数据时拉低,下降沿时AD7606将数据发送到数据线上,上升沿时可以读出数据;
    .reset   ( reset       ),//AD7606复位信号,高电平有效,每次复位至少拉高50ns;
    .os     ( os        ),//AD7606过采样模式信号,默认不使用过采样;
    .convst   ( convst      ),//AD7606采样启动信号,无效时高电平,采样计数器完成时拉低两个时钟;
    .data    ( w_7606_data    ),//AD7606采集到的数据.数据均为补码;
    .data_vld  ( w_7606_data_vld  )//指示AD7606输出的数据来自哪个数据通道;
  );


  genvar i;
 //使用for循环例化8个数据处理模块,将ad7606采集的数据转换为bcd码的mv电压;
 generate
   for(i=0; i<8; i=i+1)begin : DATA
      data_disposeu_data_dispose(
        .clk    ( clk_100m     ),//系统时钟信号;
        .rst_n     (rst_n       ),//系统复位信号,低电平有效;
        .din    (w_7606_data   ),//输入数据;
        .din_vld   (w_7606_data_vld[i]),//输入数据有效指示信号,高电平有效;
        .voltage   (w_voltage[i]   ),//输出电压,单位mv
        .voltage_sig  (w_voltage_sig[i] ),//输出电压的正负,低电平表示正;
        .voltage_vld  (w_voltage_vld[i] )//输出数据有效指示信号,高电平有效;
      );
    end
  endgenerate


 //例化数据处理模块
  uart_byte#(
    .FLCK        ( FLCK     ),//系统时钟频率,默认50MHZ;
    .BPS        ( BPS      )//串口波特率;
  )
  u_uart_byte(
    .clk      ( clk_100m   ),//系统时钟信号;
    .rst_n       ( rst_n     ),//系统复位信号,低电平有效;
    .i_voltage0     ( w_voltage[0] ),//输入数据;
    .i_voltage1     ( w_voltage[1] ),//输入数据;
    .i_voltage2     ( w_voltage[2] ),//输入数据;
    .i_voltage3     ( w_voltage[3] ),//输入数据;
    .i_voltage4     ( w_voltage[4] ),//输入数据;
    .i_voltage5     ( w_voltage[5] ),//输入数据;
    .i_voltage6     ( w_voltage[6] ),//输入数据;
    .i_voltage7     ( w_voltage[7] ),//输入数据;
    .i_voltage_sig   ( w_voltage_sig ),//各通道数据的正负数据指示信号;
    .i_voltage_vld   ( w_voltage_vld ),//输入数据有效指示信号,高电平有效;
    .i_uart_tx_rdy   ( w_tx_rdy   ),//uart发送模块空闲指示信号;
    .o_uart_txdata   ( w_tx_data   ),//需要uart发送的并行数据;
    .o_uart_txdata_vld ( w_tx_data_vld )//需要的发送的并行数据有效指示信号;
  );


 //例化串口发送模块;
  uart_tx#(
    .FLCK    ( FLCK     ),//系统时钟频率,默认50MHZ;
    .BPS    ( BPS      ),//串口波特率;
    .DATA_W   ( UART_DATA_W  ),//发送数据位数以及输出数据位宽;
    .START_W  ( START_W    ),//1位起始位;
    .CHECK_W  ( CHECK_W    ),//校验位,2'b00代表无校验位,2'b01表示奇校验,2'b10表示偶校验,2'b11按无校验处理。
    .STOP_W   ( STOP_W    )//停止位,2'b01表示1位停止位,2'b10表示2位停止位,2'b11表示1.5位停止位;
  )
  u_uart_tx (
    .clk    ( clk_100m   ),//系统工作时钟50MHZ
    .rst_n   ( rst_n     ),//系统复位信号,低电平有效
    .tx_data  ( w_tx_data   ),//数据输入信号。
    .tx_data_vld( w_tx_data_vld ),//数据有效指示信号,高电平有效。
    .uart_tx  ( uart_tx    ),//uart接口数据输出信号。
    .tx_rdy   ( w_tx_rdy   )//模块忙闲指示信号;
  );


endmodule
03工程仿真 仿真的数据来源依旧使用前文ad7606驱动模块的测试数据,对应参考代码如下所示。
`timescale1ns/1ns
//--###############################################################################################
//--#
//--# File Name  : test
//--# Designer  : 数字站
//--# Tool   : Quartus 2018.1
//--# Design Date : 2024.11.3
//--# Description :
//--# Version  : 0.0
//--# Coding scheme : GBK(If the Chinese comment of the file is garbled, please do not save it and check whether the file is opened in GBK encoding mode)
//--#
//--###############################################################################################
module test();
  localparam     CYCLE = 20  ;//系统时钟周期,单位ns,默认10ns;
  localparam     RST_TIME= 10  ;//系统复位持续时间,默认10个系统时钟周期;


  reg         clk    = 'd1   ;//系统时钟,100MHz;
  reg         rst_n   = 'd1   ;//系统复位,高电平有效;
  reg         busy    = 'd0   ;//转换完成指示信号,下降沿有效;
  reg         frstdata  = 'd0   ;//指示采集到的第一个数据;
  reg   [15:0]  adc_din  = 'd0   ;//AD7606所采集到的十六位数据信号;


  wire        cs           ;//AD7606片选信号,读数据时拉低;
  wire        rd           ;//AD7606读使能信号,读数据时拉低,下降沿时AD7606将数据发送到数据线上,上升沿时可以读出数据;
  wire        reset          ;//AD7606复位信号,高电平有效,每次复位至少拉高50ns;
  wire  [2:0]   os           ;//AD7606过采样模式信号,默认不使用过采样;
  wire        convst         ;//AD7606采样启动信号,无效时高电平,采样计数器完成时拉低两个时钟;
  wire        uart_tx         ;//uart接口数据输出信号。


 //待测试的模块例化
  top u_top (
    .clk    ( clk    ),//系统时钟,50MHz;
    .rst_n   ( rst_n   ),//系统复位,低电平有效;
    .busy    ( busy   ),//转换完成指示信号,下降沿有效;
    .frstdata  ( frstdata ),//指示采集到的第一个数据;
    .adc_din  ( adc_din  ),//AD7606所采集到的十六位数据信号;
    .cs     ( cs    ),//AD7606片选信号,读数据时拉低;
    .rd     ( rd    ),//AD7606读使能信号,读数据时拉低,下降沿时AD7606将数据发送到数据线上,上升沿时可以读出数据;
    .reset   ( reset   ),//AD7606复位信号,高电平有效,每次复位至少拉高50ns;
    .os     ( os    ),//AD7606过采样模式信号,默认不使用过采样;
    .convst   ( convst  ),//AD7606采样启动信号,无效时高电平,采样计数器完成时拉低两个时钟;
    .uart_tx  ( uart_tx  )//uart接口数据输出信号。
  );


  initial begin
    forever #(CYCLE/2) clk = ~clk;//生成本地时钟50M
  end


 //产生复位信号
  localparamDATA_NUM=400;
  reg [15:0] stimulus[1:DATA_NUM];
  integerPattern;
  initial begin
   $readmemb("waveform_bit.txt",stimulus);//从外部TX文件(waveform_bit.txt)读入数据作为测试激励;
   Pattern=1;
    #1;
    rst_n=1'b0;
    #(CYCLE*RST_TIME);
    rst_n=1'b1;
   repeat(20)@(posedge clk);
   repeat(DATA_NUM)begin
      @(posedge convst);
      busy<=1'b1;
     repeat(30)@(posedge clk);
      busy<=1'b0;
      @(negedge rd);
      adc_din<=stimulus[Pattern];
     Pattern<=Pattern+1;
      @(posedge clk);
    end
   repeat(20)@(posedge clk);//延迟20个时钟周期;
   $stop;
  end


endmodule
采用Quartus 18.1和modelsim联合仿真,打开modelsim仿真界面wave后,先删除该界面自动添加的信号。然后如下图所示,添加我提前设置好的波形文件wave.do。261476c4-0070-11f0-9310-92fbcf53809c.png
图2 添加波形文件对应结果如下所示,相关模块的所有信号已经全部添加且分类。
262e16d8-0070-11f0-9310-92fbcf53809c.png
图3 波形界面之后重新开始仿真,点击run -all即可,仿真文件运行到$stop位置自动停止仿真。 由于TestBench给ad7606八个通道赋值相同数据,因此最终采集的数据如下图所示。2643a0e8-0070-11f0-9310-92fbcf53809c.png
图4 八个通道采集数据通道0的数据处理模块如下图所示,首先采集到的16位补码数据为16’d4107,对应原码为15’d4107,然后计算对应的模拟电压((4107) / (2^15)) * 5V = 0.6266V = 626mv,最终将计算结果转换为BCD码,与下图结果完全一致。265f0374-0070-11f0-9310-92fbcf53809c.png25a7dbd6-0070-11f0-9310-92fbcf53809c.png
图5 数据处理模块仿真而uart_byte模块把八个通道计算结果根据含义保存到对应存储器中,同时根据计数器的值向下游模块传输数据。下图所示,每当上游模块完成一次数据转换,均会将存储器的数据刷新。25a7dbd6-0070-11f0-9310-92fbcf53809c.png2690af64-0070-11f0-9310-92fbcf53809c.png
图6 存储数据传输数据相关的计数器如下所示,uart_tx_rdy为高电平表示uart发送模块处于空闲状态。为了防止uart接收端反应不过来,这里会让空闲状态多持续一段时间,才开始发送下字节数据。使用计数器rdy_cnt来计数这段时间。26b811f8-0070-11f0-9310-92fbcf53809c.png
图7 数据传输时序上图中ch_cnt用来表示当前传输第几个通道的数据,而byte_cnt用来计数当前发送该通道第几字节数据。上图中表示传输通道0第0字节数据为8’d65,对应字符A,然后发送第1字节数据8’d68对应D,之后传输通道对应数值,一般给用户显示都是从1开始的,因此8’d49表示通道1。上述三个数据显示结果为AD1,后续仿真类似,不再赘述。最后就是uart发送模块,如下图所示,发送8’h41(与8’d65相等),先发送低位数据,起始位会占用一位,结果正确。25a7dbd6-0070-11f0-9310-92fbcf53809c.png26e65518-0070-11f0-9310-92fbcf53809c.png
图8 uart发送模块仿真由于工程比较简单,因此仿真这块做得都比较简洁,文末会提供工程,拿到后可以自行仿真。04上板实测 由于手里这块板子的设计问题,导致最终没办法上板,具体问题如下所示。板子上有一个uart的公头,如下所示。25a7dbd6-0070-11f0-9310-92fbcf53809c.png2711da9e-0070-11f0-9310-92fbcf53809c.png
图9 板载uart接口对应原理图如下所示,公头的2脚接的是板子的uart发送引脚。
272a0560-0070-11f0-9310-92fbcf53809c.png
图10 uart原理图下图是淘宝上该接口的线材接口信息,母头线材2脚也是发送引脚?没找到2脚用于接收的母头线材,不知道设计这块板子的工程师是如何想的,黑金自家也没有卖这种线材。2745cba6-0070-11f0-9310-92fbcf53809c.png25a7dbd6-0070-11f0-9310-92fbcf53809c.png
图11 淘宝线材在网上找了一张功能类似的截图,上板后的结果应该与下图一致。277034d6-0070-11f0-9310-92fbcf53809c.png
图12 串口调试助手显示虽然不能使用串口显示数据,但是也可以通过signal tap抓一下实测数据,如果时序没有问题,依旧可以保证工程没有问题。如下图所示,ad7606的八个通道全部悬空,然后下载程序到板子中。2782ee3c-0070-11f0-9310-92fbcf53809c.png
图13 悬空ad7606八个通道输入引脚使用signal tap抓取通道0的数据,如下所示,对应数据为16’d11857,转换为模拟电压为(16’d11857 / (2^15)) * 5V = 1.809V = 1809mv,与抓取的bcd码转换结果一致。25a7dbd6-0070-11f0-9310-92fbcf53809c.png27ba1934-0070-11f0-9310-92fbcf53809c.png
图14 转换时序由于uart每发送一个字节数据中间会间隔很长时间,为了看到依次发送的数据对不对,则需要抓取很多数据,signal tap采用如下设置,只抓取o_uart_tx_vld为高电平的数据,舍弃其余无用数据。25a7dbd6-0070-11f0-9310-92fbcf53809c.png27e22b9a-0070-11f0-9310-92fbcf53809c.png
图15 signal tap设置抓取数据如下所示,65对应的字符A,54对应的是通道6,由此可知第一帧数据为通道6的数据,第二帧为通道7的数据。25a7dbd6-0070-11f0-9310-92fbcf53809c.png28069bb0-0070-11f0-9310-92fbcf53809c.png
图16 抓取发送的uart帧数据与下图译码器部分代码对比,可以验证上图的正确性。
25a7dbd6-0070-11f0-9310-92fbcf53809c.png
282bf536-0070-11f0-9310-92fbcf53809c.png
图17 对应译码最后修改signal tap抓取uart发送模块时序,如下图所示,发送数据为8’h2e,先发送低位数据。2857e15a-0070-11f0-9310-92fbcf53809c.png
图18 抓取uart发送模块时序相关时序验证结束,整体时序是没有问题的,如果换个正常的uart硬件接口可以直接使用。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • adc
    adc
    +关注

    关注

    100

    文章

    7451

    浏览量

    553860
  • 串口
    +关注

    关注

    15

    文章

    1607

    浏览量

    81965
  • 上位机
    +关注

    关注

    27

    文章

    994

    浏览量

    56724

原文标题:fpga通过uart向上位机传输ad7606采集数据

文章出处:【微信号:HXSLH1010101010,微信公众号:FPGA技术江湖】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    信号采集系统中的数据传输显示与处理

    信号采集系统中的数据传输显示与处理
    发表于 05-12 22:25

    基于zigbee网络的数据采集上位系统

    1、本项目可实现对工业、农业数据采集和远程数据传输与监控;2、采用zigbee模块制作节点网络,实现数据的远程传输。3、
    发表于 10-17 23:12

    【OK210申请】无线数据传输模块设计

    和单片的接口电路。(3) 编写控制无线数据传输器件进行数据。目标:(1) 单片系统:通过串口传输
    发表于 07-24 10:39

    【CANNON申请】两块板之间蓝牙数据传输

    申请理由:一直从事单片数据通信,想实现一次蓝牙的数据传输功能。项目描述:两块板实现数据传输。比如,A板采集芯片内部温度,
    发表于 01-19 16:05

    ADC信号采集串口传输的疑问

    用msp430f149采集心电信号,然后通过串口传输给上位。假设设置采样率为200Hz,1s内能采集
    发表于 05-08 12:52

    请问怎么SD卡中存储的数据通过GPRS传输到电脑上显示

    ,认为不能及时的传感器实时采集数据通过GPRS传输给电脑(因为GPRS数据传输所需要的时间大于传感器
    发表于 04-30 02:54

    请问ov2640采集单张照片怎么通过wifi传输给上位

    如题,stm32f1控制ov2640采集单张图片利用wifi发送给上位,wifi是sta透传模式,目前上位接收到的
    发表于 05-09 06:06

    无线数据传输模块的实际应用

    数据传输模块的实际应用一、智能安防安防是物联网的一大应用市场,传统安防对人员的依赖性比较大,非常耗费人力,而智能安防能够通过设备实现智能判断。目前,智能安防最核心的部分在于智能安防系统,该系统中应用无线
    发表于 06-18 04:21

    串口线采集数据,波形图表显示怎么操作?

    我想用labview显示下位的波形。做了一个测试程序。 Stm32做了一个dac输出1k的正弦波,做了一个adc(10khz的速度)来采集这个正弦波,
    发表于 08-30 10:51

    stm32的几种数据传输总结

    引言在一般的项目开发过程中,往往需要两块或以上单片进行通信完成数据传输,例如四旋翼无人机在飞行过程中无线传输数据回到地面站,治疗仪器需要实时
    发表于 08-23 07:32

    如何利用单片上位进行大量的数据传输

    如何利用单片上位进行大量的数据传输呢?传输过程中会遇到哪些问题呢?
    发表于 12-09 06:03

    数据传输速率是什么意思

    数据传输速率是什么意思 数据传输速率是通过信道每秒可传输的数字信息量的量度。数据传输速率也称为吞吐率。
    发表于 03-18 14:45 5164次阅读

    基于单片89c51的浮点型数据串口通信整型的处理和发送

    在做下位通信时往往会用到串口,包括下位数据传输给上位
    发表于 09-05 17:50 6次下载
    基于单片<b class='flag-5'>机</b>89c51的浮点型<b class='flag-5'>数据</b>及<b class='flag-5'>串口</b>通信整型的处理和发送

    如何在单片串口中发送超过8位的数据

    在做下位通信时往往会用到串口,包括下位数据传输给上位
    发表于 04-16 17:28 6次下载
    如何在单片<b class='flag-5'>机</b><b class='flag-5'>串口</b>中发送超过<b class='flag-5'>8</b>位的<b class='flag-5'>数据</b>

    高速数据传输蓝牙双模方案

    高速数据传输透传模式是一种直接传输模式,数据通过蓝牙模块传输,不需要特定命令。 主控制器通过串口
    的头像 发表于 07-26 14:45 1723次阅读
    高速<b class='flag-5'>数据传输</b>蓝牙双模方案