FPGA-串口通信的接收模块(发送接收模块)

简介: FPGA-串口通信的接收模块(发送接收模块)

接收模块和发送模块类似:

      在接收的过程中为了保证接收数据的准确性对单个时钟波特率进行分频,单个时钟信号下分频16次,进行数据采集保证了数据的准确性,这里的代码思想借鉴了小梅哥的代码的编写思想。

发送接收模块的验证:

这里发送接收的验证是通过PC端进行发送,由开发板先接收到数据,然后进行发送,这里如果要是验证些字符串或者是一些特殊的指令,用状态机或者类似状态机的思想进行设计。

这里只贴出任务要求的接收模块的验证基本任务和代码

任务要求:

由PC端口进行发送指令检测单个字符和字符串

     如果发送I Like FPGA led 全亮,如果错误led闪烁,当发送单个字符时,利用LED灯指示该字符的ASCII码。

串口接收模块:


module uart_rxd(clk,rst_n,bps_set,rxd,data_byte,rxd_finish,uart_state
    );
  input           clk       ;//输入时钟
  input           rst_n     ;//复位信号
  input     [1:0] bps_set   ;//波特率选择
  input           rxd       ;//接收模块
  output    [7:0] data_byte ;//接收数据
  output          rxd_finish;//发送完成标志
  output          uart_state;//串口通信状态
  reg       [7:0] data_byte ;
  reg             rxd_finish;
  reg             uart_state;
  parameter       BPS_4800    =16'd324,
                    BPS_9600    =16'd162,
          BPS_19200   =16'd80 ,
                    BPS_115200  =16'd13 ;
  //消除亚稳态
  reg rxd_s0,rxd_s1;  //同步寄存器
  always@(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
      rxd_s0<=1'b0;
      rxd_s1<=1'b0;
    end
    else begin
      rxd_s0<=rxd;
      rxd_s1<=rxd_s0;
    end
  end
  reg rxd_temp0,rxd_temp1;//数据寄存器
  always@(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
      rxd_temp0<=1'b0;
      rxd_temp1<=1'b0;
    end
    else begin
      rxd_temp0<=rxd_s1;
      rxd_temp1<=rxd_temp0;
    end
  end
  wire rxd_negedge =~rxd_temp0&rxd_temp1;
  reg [15:0] div_cnt;
  reg [15:0] time_div;
  //波特率选择模块
  always@(*)begin
    if(rst_n==1'b0)begin
      time_div=BPS_9600;
    end
    else begin
      case(bps_set)
        2'b00: time_div = BPS_4800;
        2'b01: time_div = BPS_9600;
        2'b10: time_div = BPS_19200;
        2'b11: time_div = BPS_115200;
        default:time_div = BPS_9600;
      endcase
    end
  end
  //波特率计数模块
  always@(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
      div_cnt<=1'b0;
    end
    else if(uart_state==1'b1)begin
      if(div_cnt==time_div)begin
        div_cnt<=1'b0;
      end
      else begin
        div_cnt<=div_cnt+1'b1;
      end
    end
    else begin
      div_cnt<=1'b0;
    end
  end
  //波特率时钟模块
  reg bps_clk;
  always@(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
      bps_clk<=1'b0;
    end
    else if(div_cnt==time_div)begin
      bps_clk<=1'b1;
    end
    else begin
      bps_clk<=1'b0;
    end
  end
  //bps计数模块
  reg [7:0] bps_cnt;
  always@(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
      bps_cnt<=8'd0;
    end
    else if(rxd_finish==1'b1||(bps_cnt==8'd12 && (Start>3'd3)))begin
      bps_cnt<=8'd0;
    end
    else if(bps_clk==1'b1)begin
      bps_cnt<=bps_cnt+1'b1;
    end
    else begin
      bps_cnt<=bps_cnt;
    end
  end
  always@(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
      rxd_finish=1'b0;
    end
    else if(bps_cnt==8'd159)begin
      rxd_finish=1'b1;
    end
    else begin
      rxd_finish=1'b0;
    end
  end
  //数据缓冲区模块
  reg [2:0] r_data_byte[7:0];
  reg [2:0]Start,Stop;
  always@(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
      Start<=3'd0;
      r_data_byte[0]<=3'd0;
      r_data_byte[1]<=3'd0;
      r_data_byte[2]<=3'd0;
      r_data_byte[3]<=3'd0;
      r_data_byte[4]<=3'd0;
      r_data_byte[5]<=3'd0;
      r_data_byte[6]<=3'd0;
      r_data_byte[7]<=3'd0;
      Stop<=3'd0;
    end
    else if(bps_clk==1'b1)begin
      if(bps_cnt==1'b0)begin
        Start<=3'd0;
        r_data_byte[0]<=3'd0;
        r_data_byte[1]<=3'd0;
        r_data_byte[2]<=3'd0;
        r_data_byte[3]<=3'd0;
        r_data_byte[4]<=3'd0;
        r_data_byte[5]<=3'd0;
        r_data_byte[6]<=3'd0;
        r_data_byte[7]<=3'd0;
        Stop<=3'd0;
      end
      if(16'd6<=bps_cnt&&bps_cnt<=16'd12)begin
        Start<=Start+rxd_s1;
      end
      else if(16'd22<=bps_cnt&&bps_cnt<=16'd28)begin
        r_data_byte[0]<=r_data_byte[0]+rxd_s1;
      end
      else if(16'd38<=bps_cnt&&bps_cnt<=16'd44)begin
        r_data_byte[1]<=r_data_byte[1]+rxd_s1;
      end
      else if(16'd54<=bps_cnt&&bps_cnt<=16'd60)begin
        r_data_byte[2]<=r_data_byte[2]+rxd_s1;
      end
      else if(16'd70<=bps_cnt&&bps_cnt<=16'd76)begin
        r_data_byte[3]<=r_data_byte[3]+rxd_s1;
      end
      else if(16'd86<=bps_cnt&&bps_cnt<=16'd92)begin
        r_data_byte[4]<=r_data_byte[4]+rxd_s1;
      end
      else if(16'd102<=bps_cnt&&bps_cnt<=16'd108)begin
        r_data_byte[5]<=r_data_byte[5]+rxd_s1;
      end
      else if(16'd118<=bps_cnt&&bps_cnt<=16'd124)begin
        r_data_byte[6]<=r_data_byte[6]+rxd_s1;
      end
      else if(16'd134<=bps_cnt&&bps_cnt<=16'd140)begin
        r_data_byte[7]<=r_data_byte[7]+rxd_s1;
      end
      else if(16'd150<=bps_cnt&&bps_cnt<=16'd156)begin
        Stop<=Stop+rxd_s1;
      end
    end
    else;
  end
    always@(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
      data_byte<=8'd0;
    end
    else if(bps_cnt==8'd159)begin
      data_byte[0]<=(r_data_byte[0]>3'd3)?1'b1:1'b0;
      data_byte[1]<=(r_data_byte[1]>3'd3)?1'b1:1'b0;
      data_byte[2]<=(r_data_byte[2]>3'd3)?1'b1:1'b0;
      data_byte[3]<=(r_data_byte[3]>3'd3)?1'b1:1'b0;
      data_byte[4]<=(r_data_byte[4]>3'd3)?1'b1:1'b0;
      data_byte[5]<=(r_data_byte[5]>3'd3)?1'b1:1'b0;
      data_byte[6]<=(r_data_byte[6]>3'd3)?1'b1:1'b0;
      data_byte[7]<=(r_data_byte[7]>3'd3)?1'b1:1'b0;
    end
    else begin
      data_byte<=data_byte;
    end
  end
  always@(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
      uart_state<=1'b0;
    end
    else if(rxd_negedge==1'b1)begin
      uart_state<=1'b1;
    end
    else if(rxd_finish==1'b1||(bps_cnt==8'd12 && (Start>3'd3)))begin
      uart_state<=1'b0;
    end
    else begin
      uart_state<=uart_state;
    end
  end
endmodule

字符缓冲模块:


module uart_dat_buf(clk,rst_n,rxd_sel,rxd_finish,rxd_state,data_byte,led
    );
  input           clk       ;//输入时钟
  input           rst_n     ;//复位信号
  input           rxd_sel   ;//指令选择
  input           rxd_finish;//一位数据发送完成标志
  input           rxd_state ;//发送状态标志
  input     [7:0] data_byte ;
  output reg[7:0] led       ;
  parameter       TIME = 25'd2500_0000,
          S0 =4'd0,
          S1 =4'd1,
          S2 =4'd2,
          S3 =4'd3,
          S4 =4'd4,
          S5 =4'd5,
          S6 =4'd6,
          S7 =4'd7,
          S8 =4'd8,
          S9 =4'd9,
          S10=4'd10,
          ERROR =4'd15;
  //数据接收模块
  reg       [7:0] data_byte_temp;
  always@(*)begin
    if(rst_n==1'b0)begin
      data_byte_temp=8'd0;
    end
    else if(rxd_state==1'b1)begin
      data_byte_temp=data_byte;
    end
    else begin
      data_byte_temp=data_byte_temp;
    end
  end
  //状态转换
  reg [3:0] state_c;
  reg [3:0] state_n;
  always@(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
      state_c<=S0;
    end
    else if(rxd_state==1'b1)begin
      state_c<=state_c;
    end
    else begin
      state_c<=state_n;
    end
  end
  //状态判断
  always@(*)begin
    if(rst_n==1'b0)begin
      state_n=S0;
    end
    else if(rxd_sel==1'b0&&rxd_state==1'b1)begin
      case(state_c)
        S0 :
          if(data_byte_temp=="I")begin
            state_n=S1;
          end
          else begin
            state_n=ERROR;
          end
        S1 :
          if(data_byte_temp==" ")begin
            state_n=S2;
          end
          else begin
            state_n=ERROR;
          end
        S2 :
          if(data_byte_temp=="L")begin
            state_n=S3;
          end
          else begin
            state_n=ERROR;
          end
        S3 :
          if(data_byte_temp=="i")begin
            state_n=S4;
          end
          else begin
            state_n=ERROR;
          end
        S4 :
          if(data_byte_temp=="k")begin
            state_n=S5;
          end
          else begin
            state_n=ERROR;
          end
        S5 :
          if(data_byte_temp=="e")begin
            state_n=S6;
          end
          else begin
            state_n=ERROR;
          end
        S6 :
          if(data_byte_temp==" ")begin
            state_n=S7;
          end
          else begin
            state_n=ERROR;
          end
        S7 :
          if(data_byte_temp=="F")begin
            state_n=S8;
          end
          else begin
            state_n=ERROR;
          end
        S8 :
          if(data_byte_temp=="P")begin
            state_n=S9;
          end
          else begin
            state_n=ERROR;
          end
        S9 :
          if(data_byte_temp=="G")begin
            state_n=S10;
          end
          else begin
            state_n=ERROR;
          end
        S10:
          if(data_byte_temp=="A")begin
            state_n=S0;
          end
          else begin
            state_n=ERROR;
          end
        ERROR:if(data_byte_temp=="I")begin
            state_n=S1;
          end
          else begin
            state_n=ERROR;
          end
        default:state_n=S0;
      endcase
    end
    else begin
      state_n=state_n;
    end
  end
  reg [1:0] flag_led;
  //输出模块
  always@(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
      flag_led<=2'd3;
    end
    else if(rxd_sel==1'b1)begin
      flag_led<=2'b10;
    end
    else if(rxd_sel==1'b0)begin
      if(state_c==ERROR)begin
        flag_led<=2'b01;
      end
      else if(state_c==S10)begin
        flag_led<=2'b00;
      end
      else begin
        flag_led<=flag_led;
      end
    end
    else begin
      flag_led<=2'b11;
    end
  end
  //闪烁led设计
  reg  [24:0] cnt;//存放计数器的值
  //数码管特殊状态闪烁计数器模块
  always@(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
      cnt <=25'd0;
    end
    else if(cnt ==TIME-1'b1)begin
      cnt <=1'b0;
    end
    else if(flag_led==2'b01)begin
      cnt <=cnt + 1'b1;
    end
    else begin
      cnt <=25'd0;
    end
  end
  //led灯指示
  always@(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
      led<=8'b1111_1111;
    end
    else if(flag_led==2'b10)begin
      led<=data_byte_temp;
    end
    else if(flag_led==2'b00)begin
      led<=8'b0000_0000;
    end
    else if(flag_led==2'b01)begin
      if(cnt<(TIME/2-1'b1))begin
        led<=8'b1111_1111;
      end
      else begin
        led<=8'b0000_0000;
      end
    end
    else if(flag_led==2'b11)begin
      led<=8'b1111_1111;
    end
    else begin
      led<=led;
    end
  end
endmodule

顶层文件:


module uart_rxd_top(ext_clk_25m,ext_rst_n,uart_rx,led,switch0
    );
  input ext_clk_25m ;//系统时钟
  input ext_rst_n   ;//复位信号
  input uart_rx   ;//串口通信接收
  input switch0   ;//指令切换
  output [7:0]led   ;//led显示
  wire [7:0]data_byte;
  wire uart_state;
  wire rxd_finish;
  uart_rxd u_r1(
  .clk(ext_clk_25m),
  .rst_n(ext_rst_n),
  .bps_set(1), 
  .rxd(uart_rx),
  .data_byte(data_byte),
  .rxd_finish(rxd_finish),
  .uart_state(uart_state)
    );
  uart_dat_buf u_dat1(
  .clk(ext_clk_25m),
  .rst_n(ext_rst_n),
  .rxd_sel(switch0),
  .rxd_finish(rxd_finish),
  .rxd_state(uart_state),
  .data_byte(data_byte),
  .led(led)
    );
endmodule
目录
相关文章
|
数据采集 算法 测试技术
【硬件测试】基于FPGA的1024QAM基带通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍了基于FPGA的1024QAM基带通信系统的硬件测试版本,包含testbench、高斯信道模块和误码率统计模块。系统新增ila在线数据采集和vio在线SNR设置模块,支持不同SNR条件下的性能测试。1024QAM调制将10比特映射到复平面上的1024个星座点之一,实现高效数据传输。硬件测试结果表明,在SNR=32dB和40dB时,系统表现出良好的性能。Verilog核心程序展示了各模块的连接与功能实现。
376 7
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的MSK调制解调系统系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文基于FPGA实现MSK调制解调系统,采用Verilog开发,包含同步模块、高斯信道模拟、误码率统计等功能。相比仿真版本,新增ILA数据采集与VIO在线SNR设置模块。通过硬件测试验证,展示不同SNR(如10dB和16dB)下的性能表现。研究聚焦软件无线电领域,优化算法复杂度以适应硬件限制,利用MSK恒定包络、相位连续等特性提升频谱效率。核心代码实现信号生成、调制解调、滤波及误码统计,提供完整的硬件设计与分析方案。
513 19
|
数据采集 移动开发 算法
【硬件测试】基于FPGA的QPSK调制+软解调系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文基于FPGA实现QPSK调制与软解调系统,包含Testbench、高斯信道、误码率统计模块,并支持不同SNR设置。硬件版本新增ILA在线数据采集和VIO在线SNR设置功能,提供无水印完整代码及测试结果。通过VIO分别设置SNR为6dB和12dB,验证系统性能。配套操作视频便于用户快速上手。 理论部分详细解析QPSK调制原理及其软解调实现过程,涵盖信号采样、相位估计、判决与解调等关键步骤。软解调通过概率估计(如最大似然法)提高抗噪能力,核心公式为*d = d_hat / P(d_hat|r[n])*,需考虑噪声对信号点分布的影响。 附Verilog核心程序代码及注释,助力理解与开发。
429 5
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的4ASK调制解调通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍了基于FPGA的4ASK调制解调系统的硬件测试版本,该系统包括testbench、高斯信道模块和误码率统计模块,并新增了ILA在线数据采集和VIO在线SNR设置功能。通过VIO设置不同SNR(如15dB和25dB),实现了对系统性能的实时监测与调整。4ASK是一种通过改变载波幅度表示数据的数字调制方式,适用于多种通信场景。FPGA平台的高效性和灵活性使其成为构建高性能通信系统的理想选择。
377 17
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的16QAM调制+软解调系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文基于之前开发的16QAM调制与软解调系统,增加了硬件测试功能。该系统包含FPGA实现的16QAM调制、软解调、高斯信道、误码率统计模块,并新增了ILA在线数据采集和VIO在线SNR设置模块。通过硬件测试,验证了不同SNR条件下的系统性能。16QAM软解调通过比较接收信号采样值与16个调制点的距离,选择最近的调制点来恢复原始数据。核心Verilog代码实现了整个系统的功能,包括SNR设置、信号处理及误码率统计。硬件测试结果表明系统在不同SNR下表现良好,详细操作步骤可参考配套视频。
358 13
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的4FSK调制解调通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文基于之前的文章《基于FPGA的4FSK调制解调系统》,增加了ILA在线数据采集模块和VIO在线SNR设置模块,实现了硬件测试版本。通过VIO设置不同SNR(如10dB和20dB),并展示了ILA采集的数据结果。四频移键控(4FSK)是一种数字调制方法,利用四个不同频率传输二进制数据,具有较高的频带利用率和抗干扰性能。输入的二进制数据分为两组,每组两个比特,对应四个频率f1、f2、f3、f4,分别代表二进制组合00、01、10、11。调制过程中选择相应频率输出,并进行幅度调制以增强抗干扰能力。接收端通过带通滤波器提取信号并还原为原始二进制数据。
362 7
|
数据采集 算法 数据处理
【硬件测试】基于FPGA的256QAM基带通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍了基于FPGA的256QAM基带通信系统的硬件测试版本,包含testbench、高斯信道模块和误码率统计模块。系统新增ila在线数据采集和vio在线SNR设置模块,支持不同信噪比(如30dB和40dB)的仿真测试,并提供配套操作视频。256QAM调制方案每个符号携带8比特信息,通过复数值星座图映射实现高效传输。Verilog代码展示了核心模块设计,包括SNR设置、数据处理和ILA测试分析,确保系统在实际硬件环境中的稳定性和性能。
349 2
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的16QAM基带通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍了基于FPGA的16QAM基带通信系统硬件测试版本。该系统在仿真基础上增加了ILA在线数据采集和VIO在线SNR设置模块,支持不同信噪比(如15dB、25dB)的测试。16QAM是一种正交幅度调制方式,通过两路4ASK信号叠加实现,每个符号包含4比特信息。系统采用正交调幅法生成16QAM信号,并通过DAC转换为模拟信号。解调时使用正交相干解调,经低通滤波器恢复电平信号。开发板内完成发射与接收,无需定时同步模块。代码可移植至其他开发板,具体步骤见配套文档。
321 2
|
数据采集 算法 测试技术
【硬件测试】基于FPGA的2ASK调制解调系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍基于FPGA的2ASK调制解调系统,涵盖仿真效果、理论知识、Verilog核心程序及开发板使用说明。系统包含testbench、高斯信道模块和误码率统计模块,支持不同SNR设置。硬件测试版本增加了ILA在线数据采集和VIO在线SNR设置功能。2ASK调制通过改变载波振幅传输二进制信号,FPGA实现包括系统设计、Verilog编码、仿真测试和硬件部署。详细操作步骤见配套视频,代码适用于多种开发板,提供移植方法。
340 1
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的64QAM基带通信系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍了基于FPGA的64QAM基带通信系统的硬件测试版本,包含testbench、高斯信道模块和误码率统计模块。系统新增ila在线数据采集模块和vio在线SNR设置模块,支持不同SNR条件下的仿真与测试。通过设置SNR为25dB和30dB进行测试,验证了系统的可行性和性能。此外,本文详细阐述了64QAM调制解调的工作原理,包括信号生成、调制、解调及误码率测试等环节,并提供了Verilog核心程序代码。
288 0

热门文章

最新文章