FIFO

     FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。

    FIFO多用于:1、不同时钟之间的数据传输;2、不同跨度的接口;

   

//程序实现的功能:串口从FIFO中读出数据,然后发送给上位机(串口调试助手)
 
 module fifo_uart
     (
       clk,
       rst_n,
       rs232_tx
     
     
     );

input   clk;
input   rst_n;
output  rs232_tx;
wire[7:0]wrf_data;      //数据写入缓存FIFO输入数据总线;
wire wrf_wrreq;     //数据写入缓存FIFO输入数据请求信号,高电平有效;
wire fifo232_rdreq;    //FIFO读请求信号,高电平有效;
wire fifo_empty;       //FIFO空请求信号,高电平有效;
wire[7:0] tx_data;     //串口要发送的数据;
wire tx_start ;         //串口发送标志位;

assign tx_start=~fifo_empty;

datagene    datagene          //数据产生模块;
          (
            .clk(clk) ,
            .rst_n(rst_n),
            .wrf_data(wrf_data),
            .wrf_wrreq(wrf_wrreq)
          
          );  


fifo_232    fifo_232_inst      //例化FIFO模块
         (
          .clock ( clk ),
          .data ( wrf_data ),
          .rdreq ( fifo232_rdreq ),
          .wrreq ( wrf_wrreq ),
          .empty ( fifo_empty ),
          .q ( tx_data )
         );
           

uart    uart               //串口通信模块
        (
          .clk(clk),
          .rst_n(rst_n),
          .tx_start(tx_start),
          .tx_data(tx_data),
          .fifo232_rdreq(fifo232_rdreq),
          .rs232_tx(rs232_tx) 
               
        );
        
 endmodule 
       
                  
module datagene          //数据产生模块;
       (
         clk,
         rst_n,
         wrf_wrreq,
         wrf_data
             
       );

input       clk;
input       rst_n;
output      wrf_wrreq;    //数据写入缓存FIFO输入数据请求信号,高电平有效;
output[7:0] wrf_data;

reg[24:0] cntwr;

always @ (posedge clk or negedge rst_n)
  begin
       if(!rst_n)
         cntwr<=25'd0;
       else 
         cntwr<=cntwr+1'b1;  

  end  

assign wrf_wrreq=(cntwr>=25'h1fffff0)&&(cntwr<=25'h1ffffff);

reg[7:0] wrf_data_r;
always @ (posedge clk or negedge rst_n)
  begin
       if(!rst_n)
         wrf_data_r<=8'd0;
       else if((cntwr>=25'h1fffff0)&&(cntwr<=25'h1ffffff)) 
         wrf_data_r<=wrf_data_r+1'b1; 
  end

assign wrf_data=wrf_data_r;

endmodule  
       


module uart                   //串口通信顶层模块;
      (
        clk,
        rst_n,
        tx_start,
        tx_data,
        fifo232_rdreq,
        rs232_tx
      );

input      clk;    
input      rst_n;
input      tx_start;       //串口发送标志位;
input[7:0] tx_data;        //串口待发送数据;
output     fifo232_rdreq;  //FIFO读请求信号,高电平有效;
output     rs232_tx;       //rs232发送给PC机的数据;

wire bps_start;     //波特率计数器启动信号;
wire clk_bps;       //发送数据标志位;

speed_select   speed_select             //模特率产生模块;
             (
               .clk(clk),
               .rst_n(rst_n),
               .bps_start(bps_start),
               .clk_bps(clk_bps)
             
             
             );


uart_tx     uart_tx                  //串口发送模块;
            (
              .clk(clk),
              .rst_n(rst_n),
              .clk_bps(clk_bps),
              .tx_start(tx_start),
              .tx_data(tx_data),
              .bps_start(bps_start),
              .fifo232_rdreq(fifo232_rdreq),
              .rs232_tx(rs232_tx)
            
             
            
            );
             
endmodule             
      

module speed_select
         (
           clk,
           rst_n,
           bps_start,
           clk_bps
                 
         );

input  clk;
input  rst_n;
input  bps_start;           //
output clk_bps;

parameter  BPS=5207;       //波特率为9600bps,传一位数据所需要计的数;
parameter  BPS_2=2603;     //波特率为9600bps,一位数据传需到中间位置时,所需记得数;

reg [12:0] cnt;
always @ (posedge clk or negedge rst_n)
  begin
       if(!rst_n)
          cnt<=13'd0;
        else if(!bps_start||cnt==BPS)
          cnt<=13'd0;
        else
          cnt<=cnt+1'b1;     
  end

reg clk_bps_r;
always @ (posedge clk or negedge rst_n)
  begin
       if(!rst_n)
          clk_bps_r<=1'b0;
        else if(cnt==BPS_2)        //一位数据传需到中间位置是,最稳定,所以可以开始采样;
          clk_bps_r<=1'b1;
        else
          clk_bps_r<=1'b0;  
  end 
   
assign  clk_bps=clk_bps_r;


endmodule
         

module uart_tx
     (
      clk,
      rst_n,
      clk_bps,
      tx_start,
      tx_data,
      bps_start,
      fifo232_rdreq,
      rs232_tx
        
     ); 

input       clk;        //系统时钟;
input       rst_n;      //复位信号,低电平有效;
input       tx_start;   //串口发送标志位;
input       clk_bps;    //发送数据标志位;
input[7:0]  tx_data;    //串口待发送数据
output      bps_start;  //波特率计数器启动信号;
output      fifo232_rdreq;
output      rs232_tx;    

reg tx_en;      //数据发送能信号;
reg[3:0] num;

always @ (posedge clk or negedge rst_n)
  begin
       if(!rst_n)
         tx_en<=1'b0;
       else if(num==4'd11)      //数据发送完成;
         tx_en<=1'b0;  
       else if(tx_start)  //进入发送数据状态
         tx_en<=1'b1;
       
  end
assign  bps_start=tx_en;

reg tx_enr0;
always @ (posedge clk or negedge rst_n)
  begin
        if(!rst_n)
          tx_enr0<=1'b0;
        else 
          tx_enr0<=tx_en;  
  end 
  
reg tx_enr1;
always @ (posedge clk or negedge rst_n)
  begin
        if(!rst_n)
          tx_enr1<=1'b0;
        else 
          tx_enr1<=tx_enr0;  
  end   

assign fifo232_rdreq=(~tx_enr1)&tx_enr0;    //上升沿检测;  当tx_en由0变为1时,fifo232_rdreq置高一个周期;

reg rs232_tx_r;
always @ (posedge clk or negedge rst_n)
  begin
       if(!rst_n)
         begin
          num<=4'd0;
          rs232_tx_r<=1'b1;
         end  
       else if(tx_en)
           begin
             if(clk_bps)
               begin
                   num<=num+1'b1;
                   case(num)
                     4'd0 :  rs232_tx_r<=1'b0;  //发送起始位
                     4'd1 :  rs232_tx_r<=tx_data[0];
                     4'd2 :  rs232_tx_r<=tx_data[1];   
                     4'd3 :  rs232_tx_r<=tx_data[2];
                     4'd4 :  rs232_tx_r<=tx_data[3];
                     4'd5 :  rs232_tx_r<=tx_data[4];
                     4'd6 :  rs232_tx_r<=tx_data[5];
                     4'd7 :  rs232_tx_r<=tx_data[6];
                     4'd8 :  rs232_tx_r<=tx_data[7];
                     4'd9 :  rs232_tx_r<=1'b1;   //结束位;
                     default :  rs232_tx_r<=1'b1;
                   endcase  
               end
              else if(num==4'd11)
                 num<=4'd0; 
           end   
  end

assign rs232_tx=rs232_tx_r;

endmodule  
  

 程序RTL视图

FIFO

程序现象:

FIFO

只要FIFO中有数据,串口接口就会将数据发送给上位机(串口调试助手)。

转载于:https://www.cnblogs.com/tphust/archive/2012/09/04/2670649.html