Xilinx FPGA:vivado实现串口的接收端

补充一些串口里用到的数值的相关知识点

接收端串口时序图:

程序设计:

Matlab 复制代码
`timescale 1ns / 1ps
/串口接收端    串行转并行
module uart_rx(
    input                  sys_clk ,
    input                  rst_n    ,
    input                  rx_data   ,  //输入串行数据
    output    reg[7:0]     uart_data , // 输出并行数据
    output    reg          rx_done     //数据传输完成结束信号      

    );
    
    parameter         SYSCLK =   50_000_000  ;
    parameter         Baud   =   115200      ;
    parameter         COUNT  =   SYSCLK/Baud ;//434   传输1比特所需要的时钟周期
    parameter         MID    =   COUNT/2     ;
    
    ///产生开始信号(检测下降沿-----二级寄存)
    reg           rx_reg1     ;
    reg           rx_reg2     ;
    
    wire          start_flag    ;  开始信号
    reg           rx_flag       ;
    reg    [3:0]   cnt_bit      ;///0~9
    reg    [9:0]   cnt          ;///434
    reg    [7:0]   data_reg     ;
    
    always@(posedge sys_clk)
          if(!rst_n)begin
          rx_reg1 <= 1 ;  //处于空闲位  数据线上无数据
          rx_reg2 <= 1 ;  //处于空闲位  数据线上无数据
          end
          else
              begin
                  rx_reg1 <= rx_data  ;
                  rx_reg2 <= rx_reg1  ;
              end
     assign start_flag = ~rx_reg1 & rx_reg2  ;  
     //rx_flag
     always@(posedge sys_clk )
           if(!rst_n)
              rx_flag <= 0 ;
           else if (start_flag)
              rx_flag <= 1 ;
           else if ( cnt_bit == 9 && cnt == MID -1 )
              rx_flag <= 0 ;
           else
              rx_flag <= rx_flag ;
   cnt 434  
     always@(posedge sys_clk )
           if(!rst_n)
              cnt <= 0;
           else if ( rx_flag == 1 )begin
                if ( cnt == COUNT -1) ///一定要减一,如果不减一,实际会计到435次,反算回去波特率就不是115200了
                    cnt <= 0;
                else
                    cnt <= cnt +1 ;
           end
           else
               cnt <= 0 ;
   
   /计数器
      always@(posedge sys_clk )
           if(!rst_n)
              cnt_bit <= 0 ;
           else if ( rx_flag )begin
                if ( cnt == COUNT -1)begin
                    if(cnt_bit == 9)
                    cnt_bit <= 0 ;
                    else
                    cnt_bit <= cnt_bit +1 ;
                    end
                else
                cnt_bit <= cnt_bit     ;
                end
           else
           cnt_bit <= 0 ;
           
    [7:0]uart_data
    /*
    cnt_bit = 0 起始位
    cnt_bit = 1-8 数据位
    cnt_bit = 9 停止位
    但是  [7:0]uart_data   没有uart[8]
    所以
    if ( cnt == MID -1 && cnt_bit > 0 && cnt_bit < 9 )
         uart_data[cnt_bit -1] <= rx_data ;
    */
//    always@(posedge sys_clk )
//          if(!rst_n)
//          uart_data <= 0 ;
//          else if ( rx_flag )begin
//                if ( cnt == MID -1 && cnt_bit > 0 && cnt_bit < 9 )
//                uart_data[cnt_bit -1] <= rx_data ; //这里uart_data是不断随着cnt_bit变化的,只有在第九位的时候才有正确的最终值
//                else
//                uart_data <= uart_data ;
//          end
//          else
//          uart_data <= 0 ;
    因为这里要让uart_data只在rx_done的时候有值,所以定义一个中间寄存器data_reg
     always@(posedge sys_clk )
          if(!rst_n)
          data_reg <= 0 ;
          else if ( rx_flag )begin
                if ( cnt == MID -1 && cnt_bit > 0 && cnt_bit < 9 )
                data_reg[cnt_bit -1] <= rx_data ; //这里uart_data是不断随着cnt_bit变化的,只有在第九位的时候才有正确的最终值
                else
                data_reg <= data_reg ;
          end
          else
          data_reg <= 0 ;
//  其他赋值方法1
//      always@(posedge sys_clk )
//          if(!rst_n)
//             uart_data <= 0;
//          else if (cnt == MID -1)begin
//             case(cnt_bit)
//             0:  uart_data  <= 0  ;
//             1:  uart_data [0] <= rx_data  ;
//             2:  uart_data [1] <= rx_data  ;
//             3:  uart_data [2] <= rx_data  ;
//             4:  uart_data [3] <= rx_data  ;
//             5:  uart_data [4] <= rx_data  ;
//             6:  uart_data [5] <= rx_data  ;
//             7:  uart_data [6] <= rx_data  ;
//             8:  uart_data [7] <= rx_data  ;
//             9:  uart_data  <= uart_data  ;  ///停止位的时候数据传完,保持
//             endcase
//             end
//           else
//             uart_data  <= uart_data  ;
   
//   其他赋值方法2
//    always@(posedge sys_clk )
//          if(!rst_n)
//          uart_data <= 0 ;
//          else if (cnt == MID -1 && cnt_bit > 0 && cnt_bit < 9)
//               uart_data <= {rx_data,uart_data[7:1]} ;
//          else
//               uart_data <= uart_data ;
          
   给uart_data赋值
     always@(posedge sys_clk )
          if(!rst_n)     
             uart_data <= 0 ;   
          else if (rx_flag)begin
               if (cnt_bit == 9 && cnt == MID/4 -1)
               uart_data <= data_reg ;
               else
               uart_data <= uart_data ;
          end
          else
          uart_data <= uart_data ; 可以保持到下一个数据到来
          uart_data <= 0 ;  只保持在rx_done处于高电平的时候
  /rx_done
     always@(posedge sys_clk )
          if(!rst_n)           
            rx_done <= 0 ;
          else if (rx_flag)begin
               if ( cnt_bit == 9 && cnt == MID/2 -1)
                   rx_done <= 1 ;
               else
                   rx_done <= 0 ;       
          end
          else
            rx_done <= 0 ;  
      
endmodule

仿真程序

Matlab 复制代码
`timescale 1ns / 1ps
module test_bench(  );

    reg                  sys_clk    ;
    reg                  rst_n      ;
    reg                  rx_data    ;  //输入串行数据
    wire[7:0]            uart_data  ; // 输出并行数据
    wire                 rx_done    ;//数据传输完成结束信号      

    parameter         SYSCLK =   50_000_000  ;
    parameter         Baud   =   115200      ;
    parameter         COUNT  =   SYSCLK/Baud ;//434   传输1比特所需要的时钟周期
    parameter         MID    =   COUNT/2     ;
    
initial
      begin
           sys_clk = 0 ;
           rst_n   = 0 ;
           #10
           rst_n   = 1 ;
      end
  always #1 sys_clk = ~sys_clk ; //2ns
  
  initial
        begin
            uart_out (8'h34);
            uart_out (8'hef);
            uart_out (8'h98);
            uart_out (8'h70);
            uart_out (8'h14);
        end
  
  
  //任务函数
  task     uart_out   ;
     input      [7:0]    DATA   ;
         begin
              rx_data = 1 ;///空闲位初始
              #20 
              rx_data = 0 ;///起始位
               ///传输1bit的计时次数*1周期时间=总时间
               #(COUNT*2)  rx_data = DATA[0] ;///数据位第一位
               #(COUNT*2)  rx_data = DATA[1] ;///数据位第二位
               #(COUNT*2)  rx_data = DATA[2] ;
               #(COUNT*2)  rx_data = DATA[3] ;
               #(COUNT*2)  rx_data = DATA[4] ;
               #(COUNT*2)  rx_data = DATA[5] ;
               #(COUNT*2)  rx_data = DATA[6] ;
               #(COUNT*2)  rx_data = DATA[7] ;
               #(COUNT*2)  rx_data = 1       ;
               #(COUNT*2)                    ;//停止位也需要时间
         end
  
  
  
  endtask



 
 uart_rx  uart_rx1(
          .    sys_clk    (sys_clk  )   ,
          .    rst_n      (rst_n    )   ,
          .    rx_data    (rx_data  )   ,  //输入串行数据
          .    uart_data  (uart_data)   ,  // 输出并行数据
          .    rx_done    (rx_done  )      //数据传输完成结束信号      

    );
endmodule

仿真波形

相关推荐
apple_ttt3 小时前
SystemVerilog学习——虚拟接口(Virtual Interface)
fpga开发·fpga·systemverilog·uvm
学习路上_write13 小时前
FPGA/Verilog,Quartus环境下if-else语句和case语句RT视图对比/学习记录
单片机·嵌入式硬件·qt·学习·fpga开发·github·硬件工程
jjjxxxhhh12314 小时前
FPGA,使用场景,相比于单片机的优势
单片机·嵌入式硬件·fpga开发
诚实可靠小郎君952719 小时前
FPGA高速设计之Aurora64B/66B的应用与不足的修正
fpga开发·aurora·高速通信
百锦再19 小时前
基于Zynq FPGA对雷龙SD NAND的测试
fpga开发
∑狸猫不是猫1 天前
HDLBIts习题(4):边沿检测、分频计数器、多位BCD计数器
fpga开发
黑旋风大李逵2 天前
FPGA使用Verilog实现CAN通信
fpga开发·can通信·sja1000t·fpga实现can通信
hi942 天前
PYNQ 框架 - 中断(INTR)驱动
嵌入式硬件·fpga开发·zynq·pynq
transfer_ICer3 天前
Vscode搭建verilog开发环境
vscode·fpga开发·编辑器
沐欣工作室_lvyiyi3 天前
汽车牌照识别系统的设计与仿真(论文+源码)
人工智能·单片机·fpga开发·汽车·单片机毕业设计·matlab车牌识别