Xilinx FPGA:vivado利用单端RAM/串口传输数据实现自定义私有协议

一、项目要求

       实现自定义私有协议,如:pc端产生数据:02    56    38  ,“02”代表要发送数据的个数,“56”“38”需要写进RAM中。当按键信号到来时,将“56”“38”读出返回给PC端。

二、信号流向图

三、状态转换图

四、程序设计:

按键消抖模块:

`timescale 1ns / 1ps
module key_debounce(
   input              sys_clk ,
   input              rst_n   ,
   input              key     ,
   output             key_flag 
    );
    parameter        delay = 100;//_000_0 ; //10ms
    reg[25:0]         cnt               ;
    
    always@(posedge sys_clk )
         if(!rst_n)
            cnt <= 0 ;
         else if ( key == 0 )begin
              if ( cnt == delay - 1 )
                   cnt <= cnt ;
              else
                   cnt <= cnt +1 ;
         end
         else
         cnt <= 0 ;
    
    assign  key_flag = ( cnt == delay - 2 )?1:0 ;







endmodule

接收端模块:

`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;
    parameter               MID    = COUNT/2    ;
    
    ///start_flag
    reg             rx_reg1 ;
    reg             rx_reg2 ;
    wire            start_flag ;
    
    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
    reg               rx_flag  ;
    reg[4:0]          cnt_bit  ;
    reg[9:0]          cnt      ;
    
    always@(posedge sys_clk )
         if(!rst_n)
            rx_flag <= 0 ;
         else if ( start_flag == 1 )
            rx_flag <= 1 ;
         else if ( cnt_bit == 10 && cnt == MID - 1 )
            rx_flag <= 0 ;
         else
            rx_flag <= rx_flag ;
    
    cnt
    always@(posedge sys_clk )
         if(!rst_n)
            cnt <= 0 ;
         else if ( rx_flag == 1 )begin
              if ( cnt == COUNT - 1 )
                   cnt <= 0 ;
              else
                   cnt <= cnt +1 ;
         end
         else
         cnt <= 0 ;
  
  cnt_bit
    always@(posedge sys_clk )
         if(!rst_n)
            cnt_bit <= 0 ;
         else if ( rx_flag == 1 )begin
              if ( cnt == COUNT - 1 )begin
                  if( cnt_bit == 10 )
                      cnt_bit <= 0 ;
                  else
                      cnt_bit <= cnt_bit +1 ;
              end
              else
              cnt_bit <= cnt_bit ;
         end
         else
         cnt_bit <= 0 ;
         
         
            
  
  ///data_reg                         
     reg[8:0]         data_reg  ;  //data_reg:01234567 [8]
     always@(posedge sys_clk )     //cnt_bit:[0]12345678[9][10]
          if(!rst_n)
             data_reg <= 0 ;
          else if ( rx_flag == 1 )begin
               if ( cnt_bit > 0 && cnt_bit < 10 && cnt == MID - 1)
                    data_reg[cnt_bit - 1 ] <= rx_data  ;
               else
                    data_reg <= data_reg  ;
          end
          else
          data_reg <= 0 ;
 
 check
   reg                  check   ;
   always@(posedge sys_clk )
        if(!rst_n)
           check <= 0 ;
        else if ( rx_flag == 1 )begin
             if ( cnt_bit == 10 )
                 check <= ^data_reg  ;
             else
                 check <= 0 ;
        end
        else
        check <= 0 ;
 
 uart_data
 parameter            MODE_CHECK = 0 ;
 
    always@(posedge sys_clk )
         if(!rst_n)
            uart_data <= 0 ;
         else if ( rx_flag == 1 )begin
              if ( cnt_bit == 10 && cnt == 10 && check == MODE_CHECK)
                   uart_data <= data_reg[7:0] ;
              else
                   uart_data <= uart_data  ;
         end
         else
         uart_data <= uart_data  ;
 
 rx_done

     always@(posedge sys_clk )
          if(!rst_n)
             rx_done <= 0 ;
          else if ( rx_flag == 1 )begin
               if ( cnt_bit == 10 && cnt == MID/2 - 1 )
                    rx_done <= 1 ;
               else
                    rx_done <= 0 ;
          end
          else
          rx_done <= 0 ;
        
 
 
//做测试用的 
// wire          tx_done     ;          
// wire          tx_data     ;         
// uart_tx uart_tx_u1(
//                       .    sys_clk   (sys_clk )    ,
//                       .    rst_n     (rst_n   )    ,
//                       .    ram_out   (uart_data )    , //uart_data(douta)
//                       .    tx_start  (rx_done)    , //rx_done
//                       .    tx_done   (tx_done )     ,
//                       .    tx_data   (tx_data )
//    );         
          

    
    
endmodule

发送端模块:

`timescale 1ns / 1ps
module uart_tx(
   input                 sys_clk   ,
   input                 rst_n     ,
   input     [7:0]       ram_out   , //uart_data(douta)
   input                 tx_start  , //rx_done
   output    reg         tx_done    ,
   output    reg         tx_data 
    );
    parameter             SYSCLK = 50_000_000  ;
    parameter             Baud   = 115200      ;
    parameter             COUNT  = SYSCLK/Baud ;
    parameter             MID    = COUNT/2     ;
    
    //start_flag
    reg               tx_reg1    ;
    reg               tx_reg2    ;
    wire              start_flag ;
    
    always@(posedge sys_clk )
         if(!rst_n)begin
            tx_reg1 <= 0 ;
            tx_reg2 <= 0 ;
         end
         else
             begin
                  tx_reg1 <= tx_start ;
                  tx_reg2 <= tx_reg1  ;
             end
     assign  start_flag = tx_reg1 & ~tx_reg2  ;
     
     ///tx_flag
     reg                   tx_flag  ;
     reg[9:0]              cnt      ;
     reg[4:0]              cnt_bit  ;
     
     always@(posedge sys_clk )
          if(!rst_n)     
             tx_flag <= 0 ;
          else if ( start_flag == 1 )
             tx_flag <= 1 ;
          else if ( cnt_bit == 10 && cnt == COUNT -1 )
//          else if ( cnt_bit == 10 && cnt == MID -1 )
             tx_flag <= 0 ;
          else
             tx_flag <= tx_flag ;
     
     cnt
     always@(posedge sys_clk )
          if(!rst_n)
             cnt <= 0 ;
          else if ( tx_flag == 1 )begin
               if ( cnt == COUNT - 1 )
                    cnt <= 0 ;
               else
                    cnt <= cnt +1 ;
          end
          else
          cnt <= 0 ;
  
  //cnt_bit
     always@(posedge sys_clk )
          if(!rst_n)
             cnt_bit <= 0 ;
          else if ( tx_flag == 1 )begin
               if ( cnt == COUNT - 1 )begin
                   if ( cnt_bit == 10 )
                        cnt_bit <= 0 ;
                   else
                        cnt_bit <= cnt_bit +1 ;
               end
               else
               cnt_bit <= cnt_bit  ;
          end
          else
          cnt_bit <= 0 ;
  
  ///tx_data
     parameter            MODE_CHECK = 0 ;
     always@( posedge sys_clk )
          if(!rst_n)
             tx_data <= 1 ;
          else if ( tx_flag == 1 )begin
               if ( cnt_bit > 0 && cnt_bit < 9 )
                    tx_data <= ram_out[cnt_bit -1]  ;
               else if ( cnt_bit == 0 )
                    tx_data <= 0 ;
               else if ( cnt_bit == 9 ) 
                    tx_data <= ( MODE_CHECK == 0 )? ^ram_out :~^ram_out ;
               else if ( cnt_bit == 10 )
                    tx_data <= 1 ;
               else
                    tx_data <= tx_data  ;
          end
          else
          tx_data <= 1 ;
 
   //tx_done 
     always@(posedge sys_clk )
          if(!rst_n)
             tx_done <= 0 ;
          else if ( tx_flag == 1 )begin
               if ( cnt_bit == 10 && cnt == COUNT - 1 )
//               if ( cnt_bit == 10 && cnt == MID/2 - 1 )
                     tx_done <= 1 ;
               else
                     tx_done <= 0 ;
          end
          else
          tx_done <= 0 ;
     

    
endmodule

RAM模块:

`timescale 1ns / 1ps
module private_ram_ctrl(
     input                 sys_clk     ,
     input                 rst_n       ,
     input                 key_flag    ,
     input    [7:0]        uart_data   ,
     input                 rx_done     ,
     input                 tx_done     ,
     output   reg[7:0]     ram_out     ,     
     output   reg          tx_start       
    );
    reg              wea       ;
    reg[3:0]         addra     ;
    reg[7:0]         dina      ;
    wire[7:0]        douta     ;
    
    //状态机
    localparam             IDLE    =  3'd0  ;
    localparam             WR_D    =  3'd1  ;
    localparam             WAIT    =  3'd2  ;
    localparam             TX_FIR  =  3'd3  ;
    localparam             TX_D    =  3'd4  ;
    
    reg[2:0]               cur_state     ;
    reg[2:0]               next_state    ;
    
    reg[7:0]               wr_len         ;
    reg[7:0]               wr_cnt         ;

    
    always@(posedge sys_clk )
         if(!rst_n)
            cur_state <= IDLE  ;
         else 
            cur_state <= next_state ;
            
    
    always@(*)
         case(cur_state)
             IDLE     : 
                       begin
                            if (rx_done)//指令数据的接收完成信号
                                next_state = WR_D ;
                            else
                                next_state = cur_state ;
                       end
             WR_D     :
                       begin
                            if( wr_len == wr_cnt )
                               next_state = WAIT  ;
                            else
                               next_state = cur_state ;
                       end
             WAIT     :
                       begin
                            if( key_flag )
                               next_state = TX_FIR  ;
                            else
                               next_state = cur_state ;
                       end
             TX_FIR   :
                       begin
                             next_state = TX_D  ;
                       end
             TX_D     :
                       begin
                            if ( wr_len == wr_cnt )
                                next_state = IDLE ;
                            else
                                next_state = cur_state  ;
                       end
         default:;
         endcase
      
      always@(posedge sys_clk )
           if(!rst_n)begin
              wr_len <= 0 ;
              wr_cnt <= 0 ;
              wea    <= 0 ;
              addra  <= 4'hf ;利用溢出功能   15
              dina   <= 0 ;
              tx_start <= 0 ;
              ram_out <= 0 ; ///ram_out <= douta
           end
           else
               case(cur_state)
                    IDLE  : 
                           begin
                                wr_len <= 0 ;   
                                wr_cnt <= 0 ;   
                                wea    <= 0 ;  
                                dina   <= 0 ; 
                                addra  <= 4'hf ;
                                tx_start <= 0 ;
                                if(rx_done)
                                   wr_len <= uart_data ;
                                else
                                   wr_len <= wr_len  ;
                           end  
                    WR_D  :
                           begin
                                 tx_start <= 0 ;
                                if ( rx_done )begin
                                    addra <= addra +1 ;
                                    wea <= 1 ;
                                    wr_cnt <= wr_cnt +1 ;
                                    dina <= uart_data ;
                                end
                                else
                                    wea <= 0 ;//其他的不用写会自动保持
                           end
                    WAIT  :
                           begin
                                tx_start <= 0 ;
                                addra <= 0 ;//保证发送数据的时候是从0开始发的
                                dina  <= 0 ;
                                wr_cnt <= 0 ;
                           end
                    TX_FIR:  //只待一个时钟周期
                           begin
                                tx_start <= 1 ;
                                addra <= addra + 1 ; //addra从0开始加
                                wr_cnt <= wr_cnt +1 ;
                                ram_out <= douta  ;
                           end
                    TX_D  :
                           begin
                                if(tx_done)begin
                                   tx_start <= 1 ;
                                   addra <= addra +1 ;
                                   wr_cnt <= wr_cnt +1; 
                                   ram_out <= douta  ;
                                end
                                else
                                   tx_start <= 0 ;
                           end
               default:;
               endcase
      
      
           
    
      single_ram your_instance_name (
  .clka(sys_clk),    // input wire clka
  .wea(wea),      // input wire [0 : 0] wea
  .addra(addra),  // input wire [3 : 0] addra
  .dina(dina),    // input wire [7 : 0] dina
  .douta(douta)  // output wire [7 : 0] douta
);
endmodule

顶层模块:

`timescale 1ns / 1ps
module TOP(
   input                sys_clk ,
   input                rst_n   ,
   input                key     ,
   input                rx_data ,
   output               tx_data 
    );
   ///key_debounce
   wire              key_flag  ;
   key_debounce  key_debounce_u1(
                            .   sys_clk   (sys_clk )    ,
                            .   rst_n     (rst_n   )    ,
                            .   key       (key     )    ,
                            .   key_flag  (key_flag)     
    );
   
   //private_ram_ctrl
   wire[7:0]           uart_data   ;
   wire                rx_done     ;
   wire                tx_done     ;
   wire[7:0]           ram_out     ;  
   wire                tx_start    ;
   private_ram_ctrl private_ram_ctrl_u1(
                             .    sys_clk   (sys_clk  )  ,
                             .    rst_n     (rst_n    )  ,
                             .    key_flag  (key_flag )  ,
                             .    uart_data (uart_data)  ,
                             .    rx_done   (rx_done  )  ,
                             .    tx_done   (tx_done  )  ,
                             
                             .    tx_start (tx_start)   ,
                             .    ram_out   (ram_out  )       

    );
  
  /uart_rx
  uart_rx uart_rx_u2(
                             .    sys_clk   (sys_clk  )  , 
                             .    rst_n     (rst_n    )  , 
                             .    rx_data   (rx_data  )  , 
                             
                             .    uart_data (uart_data)  , 
                             .    rx_done   (rx_done  )  
      ); 
  
  uart_tx

  uart_tx  uart_tx_u1(
                             .    sys_clk  (sys_clk ), //sys_clk  ,
                             .    rst_n    (rst_n   ), //rst_n    ,
                             .    ram_out  (ram_out ), //ram_out  , //uart_data(douta)
                             .    tx_start (tx_start), //tx_start , //rx_done
                             .    tx_done  (tx_done ), //tx_done   ,
                             .    tx_data  (tx_data ) //tx_data 
    );

    
endmodule

五、仿真结果

仿真uart_rx模块:

`timescale 1ns / 1ps
module test_uart_rx( );

   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;
   parameter               MID    = COUNT/2    ;
   
   initial
          begin
               sys_clk = 0 ;
               rst_n   = 0 ;
               #10
               rst_n   = 1 ;
          end
   always  #1  sys_clk = ~sys_clk ;
   
   initial
          begin
               uart_out ( 8'hCC );
               uart_out ( 8'hC8 );
               uart_out ( 8'h18 );
               uart_out ( 8'h78 );
               uart_out ( 8'h66 );
               uart_out ( 8'h1E );
               uart_out ( 8'hCC );
               uart_out ( 8'h9F );
               uart_out ( 8'h66 );
               uart_out ( 8'h9F );
               uart_out ( 8'h33 );
               uart_out ( 8'h1E );
               uart_out ( 8'hCC );
               uart_out ( 8'h9F );
               uart_out ( 8'h18 );
               uart_out ( 8'h33 );
               uart_out ( 8'hCC );
          end
   
   
   
   //任务函数
   task            uart_out  ;
       input    [8:0]    DATA   ;
       begin
            rx_data = 1 ; ///空闲位初始
            #20
            rx_data = 0 ;
            #(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 = 0        ;
            #(COUNT*2)    rx_data = 1        ;
            #(COUNT*2)                       ;
       end
   endtask
   

uart_rx  uart_rx_u1(
                  .       sys_clk   (sys_clk  ) ,
                  .       rst_n     (rst_n    ) ,
                  .       rx_data   (rx_data  ) ,
                  .       uart_data (uart_data) ,
                  .       rx_done   (rx_done  )
    );
endmodule

仿真TOP模块:

`timescale 1ns / 1ps
module test_TOP( );

   reg                sys_clk    ;
   reg                rst_n      ;
   reg                key        ;
   reg                rx_data    ;
   wire               tx_data    ;
   
      
      parameter               SYSCLK = 50_000_000 ;
      parameter               Baud   = 115200     ;
      parameter               COUNT  = SYSCLK/Baud;
      parameter               MID    = COUNT/2    ;
      
      initial
             begin
                  sys_clk = 0 ;
                  rst_n   = 0 ;
                  key     = 1 ;
                  #10
                  rst_n   = 1 ;
                  #200000//ns   200us
                  key     = 0 ;
//                  #200000
//                  key     = 1 ;
//                  #200000
//                  key     = 0 ;
//                  #200000
//                  key     = 1 ;
                  
             end
      always  #1  sys_clk = ~sys_clk ;
      
      initial
             begin
//                  uart_out ( 8'hf  );//0f   0000_1111
//                  uart_out ( 8'h0f );
//                  uart_out ( 8'hff );
                  uart_out ( 8'h0f  );
                  uart_out ( 8'h33  );
//                  uart_out ( 8'hff );//1111_1111
                  uart_out ( 8'h18 );//0001_1000
                  uart_out ( 8'h78 );
                  uart_out ( 8'h66 );
                  uart_out ( 8'h1E );
                  uart_out ( 8'hCC );
                  uart_out ( 8'h9F );
                  uart_out ( 8'h66 );
                  uart_out ( 8'h9F );
                  uart_out ( 8'h33 );
                  uart_out ( 8'h1E );
                  uart_out ( 8'hCC );
                  uart_out ( 8'h9F );
                  uart_out ( 8'h18 );
                  uart_out ( 8'h33 );

             end
 
 
 
      //任务函数
      task            uart_out  ;
          input    [8:0]    DATA   ;
          begin
               rx_data = 1 ; ///空闲位初始
               #20
               rx_data = 0 ;
               #(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 = 0        ;
               #(COUNT*2)    rx_data = 1        ;
               #(COUNT*2)                       ;
          end
      endtask
 
 


TOP  TOP_u1(
               .   sys_clk (sys_clk)  ,
               .   rst_n   (rst_n  )  ,
               .   key     (key    )  ,
               .   rx_data (rx_data)  ,
               .   tx_data (tx_data)  
    );




endmodule

这里记录一些小小的问题:

(1)

仿真的复位信号一定不要和数据的关键信号(使能/开始)重复。

这个是正常没重复的:

这个是由于复位拉高的时间过长造成重复了的:

(2)

因此我们可以做出如下的修改:

现在就正常了

  • 13
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值