UART

 1、UART简介

  通用异步收发传输器(Universal Asynchronous Receiver/Transmitter,UART)是一种异步收发传输器,其在数据发送时将并行数据转换成串行数据来传输,在数据接收时将接收到的串行数据转换成并行数据,可以实现全双工传输和接收。它包括了RS232、RS422 和RS485 等接口标准规范和总线标准规范。换句话说,UART 是异步串行通信的总称。而RS232、RS422 和RS485 等,是对应各种异步串行通信口的接口标准和总线标准,它们规定了通信口的电气特性、传输速率、连接特性和接口的机械特性等内容。

  RS232、RS485在串口通信中,主要区别是电平的不同,其中UART通常使用TTL电平,下面介绍这几个存在的差异:  

  TTL全名是晶体管-晶体管逻辑集成电路(Transistor-Transistor Logic) 

  • 逻辑“1”:VCC=3.3V或5V;
  • 逻辑“0”:VCC=0V;

  RS232

  • 逻辑“1”: -3V~-13V;
  • 逻辑“0”: +3V~+13V;

例如,对于传输数据0x55 ,即二进制的 1010101,RS232和TTL的区别如下:

  RS485是差分信号进行串行传输:

  • 逻辑1以两线间的电压差为 +(2~6)v 表示;
  • 逻辑0以两线间的电压差为 -(2~6)v 表示;

在工业通信中,使用RS485比较多,因为RS485是差分信号,可以抑制共模干扰,因此在恶劣的环境中拥有很好的抗干扰性,比较稳定

2、连接示意图

  在UART的设计中,既可以发送,也可以接收数据(全双工)。但是在实际的设计中,常常只做其中一部分,要么做收部分,要么做发部分。如下图所示,只有收部分。

  在设计中也可以做一个全双工的测试(回环测试,后面将采用这个方式验证UART的功能)。

 

3、数据包

  UART数据包的格式(或称为“帧”),当没有数据传输时总线上保持高电平“1”,有数据传输时,拉低表示起始位,接着8个数据位,然后校验位,最后拉高表示停止位,并且进入空闲状态,等待下一次的数据传输。

起始位:起始信号一般由一个逻辑‘0’的数据位表示。

数据位:在起始位后,紧接着的是传输数据的主体内容,即有效数据。通常有效数据的长度7和8位长。

校验位:在有效数据之后,有一个可选的数据校验位。由于数据通信很容易受到外界干扰,导致数据传输出现偏差,因此,可以在传输过程中加上数据校验位来解决这个问题。校验方法有奇校验(odd),偶校验(even),0校验(space),1校验(mark)以及无校验(noparity)。

停止位:停止信号可由1、1.5或2个逻辑‘1’的数据位表示。

  上图为B站UP主的时序图。他的FPGA时钟频率为50MHz,串口通信波特率: 115,200 bit/s。那么可以计算出每一个bit传输需要时钟周期数: 50000,000/115,200≈434        0.5个bit 传输需要时钟周期数434/2 =217

他这里设计了一个0.5bit是因为,他把每位数据分为两份,原本10bit的数据也就是20份0.5bit。这样处理可以实现在接收方采样时,在最中间采样,保证数据的准准确性。

  图中红色数字3、5、7等,即表示数据的中间位置,3表示half_bit_period,也就是217*3,当计数到217*3时,就可以将RX的一位串行数据存储到data[0]。以此类推,可以实现8位数据的并行存储。

 

4、波特率

  由于UART是异步通讯,通讯过程中没有时钟信号线,因此通讯双方需要约定好波特率,即每个码元的长度,以便对信号进行解码。它表示每秒传输二进制数据的位数。常用的波特率有9600、19200、35400、57600以及115200等。例如当波特率为9600,表示每秒可以传输9600个bit位数据(也就是传输一个bit位数据需要(1/9600≈104us)长的时间)。

 

5、UART设计

本实例设计的UART特性:(来自:小鱼学IC)

 (1) 并没有支持奇偶检验,故没有奇偶校验位

 (2) 并不支持数据位宽可配,数据位位宽固定为8bit。

 (3) 支持输入时钟与波特率可配。

        原理图如下,分两个大模块,一个数据接收控制模块(Receive_Control),一个数据发送控制模块(Send_Control):

      

    

  接收控制模块与发送控制模块内部都有一个波特率时钟产生模块(BuadRate_set),用于将电路输入时钟(clk)进行分频产生波特率时钟,用于接收和发送数据控制。

       可以看到,BuadRate_set模块有一个enable控制信号,只有当enable信号为高时,BuadRate_set模块才工作这是为了降低功耗

  • 在发送控制模块里面,只有发送数据的时候才拉高其相应的enable
  • 在接收控制模块里面,只有检测到有数据发送进来的时候才拉高其相应的enable。    

code

 来源网址:UART(串口)收发模块设计- 02 (qq.com)

module BuadRate_set #(
  parameter CLK_Period=50000000,//the unit is Hz
  parameter Buad_Rate=9600 //the unit is bits/s
)(
   input      clk,
   input      rst_n,
   input      enable,
   output     Buad_clk
);

localparam DIV_PEREM=CLK_Period/Buad_Rate/2;
reg[15:0] cnt;

always @( posedge clk )
  if( !rst_n )
    cnt <= 16'b0000;
  else if( enable ) begin
    if( cnt != DIV_PEREM )
      cnt <= cnt+1'b1;      
    else      
      cnt <= 16'h0000;
  end
  else
    cnt <= 16'h0000;
reg DIV_clk;

always @( posedge clk )
  if( !rst_n || !enable )
    DIV_clk <= 1'b1;
  else if(cnt==DIV_PEREM)
    DIV_clk <= ~DIV_clk;

assign Buad_clk = DIV_clk;
    
endmodule
BuadRate_set
module Send_Control #(
  parameter CLK_Period=50000000,//the unit is Hz
  parameter Buad_Rate=9600 //the unit is bits/s
)(
  input        clk,
  input        rst_n,
  input        tx_en,
  input [7:0]  tx_data,
  output       tx_finish,
  output       uart_tx
);
localparam IDLE=2'b00;
localparam EN_TX=2'b10;
localparam END_BIT=2'b11;
wire Buad_clk;
wire Buad_en;
BuadRate_set #(
  .CLK_Period(CLK_Period),//the unit is Hz
  .Buad_Rate (Buad_Rate) //the unit is bits/s
)
BuadRate_set_inst(
   .clk     (clk     ),
   .rst_n   (rst_n   ),
   .enable  (Buad_en ),
   .Buad_clk(Buad_clk)
);

reg [8:0] data_to_send; 

reg [1:0] state;
reg [3:0] cnt;
always @( posedge clk )
  if( !rst_n )
    state <= IDLE;
  else
    case(state)
    IDLE:if( tx_en )
         state <= EN_TX;
    EN_TX: if( cnt=='d9 )
         state <= END_BIT;
    END_BIT: if( cnt=='d0 )
         state <= IDLE;
    default: state <= IDLE;
    endcase

assign Buad_en = (state == EN_TX || state == END_BIT);    

always @( posedge Buad_clk or negedge rst_n)
  if( !rst_n )
    cnt <= 4'b000;
  else begin
    if( cnt!=4'd9)
      cnt <= cnt + 1'b1;
    else 
      cnt <= 4'b0000;
  end     

always @( posedge Buad_clk or negedge rst_n )
  if( !rst_n )
    data_to_send <= 8'hff;
  else if( cnt == 'd0 )
    data_to_send <= {tx_data,1'b0}; 
  else
    data_to_send <= {1'b1,data_to_send[8:1]};

assign uart_tx = (Buad_en)?data_to_send[0]:1'b1;    
assign tx_finish = (state == IDLE)? 1'b1:1'b0;

endmodule  
Send_Control
module Receive_Control #(
  parameter CLK_Period=50000000,//the unit is Hz
  parameter Buad_Rate=9600 //the unit is bits/s
)(
  input            clk,    
  input            rst_n,

  input            uart_rx,
  output reg [7:0] rx_data,
  output            rx_finish,
  output           o_valid  
);

localparam IDLE=2'b00;
localparam GET_DATA=2'b01;
localparam END_BIT=2'b11;

wire Buad_clk;
wire rx_en;
BuadRate_set #(
  .CLK_Period(CLK_Period),//the unit is Hz
  .Buad_Rate (Buad_Rate) //the unit is bits/s
)
BuadRate_set_inst(
   .clk     (clk     ),
   .rst_n   (rst_n   ),
   .enable  (rx_en ),
   .Buad_clk(Buad_clk)
);

reg[5:0] get_start_bit;
always @( posedge clk )
  if( !rst_n )
    get_start_bit <= 6'b111111;
  else
    get_start_bit <= {get_start_bit[4:0],uart_rx};

reg start;

always @( posedge clk )
  if( !rst_n )
    start <= 1'b0;
  else if( state !=IDLE )
    start <= 1'b0;
  else if( get_start_bit==6'b111000 )
    start <= 1'b1;


reg [1:0] state;
reg [3:0] cnt;

always @( negedge Buad_clk or negedge rst_n )
  if( !rst_n )
    state <= IDLE;
  else
      case( state )
        IDLE: begin
            if( start )
              state <= GET_DATA;
          end
        GET_DATA: begin
                if( cnt=='d7 )
              state <= END_BIT;
        end
        END_BIT: begin
              state <= IDLE;
        end
        default: state <= IDLE;
      endcase

assign rx_en =( ~(start==1'b0 && state==IDLE) )? 1'b1:1'b0;

always @( negedge Buad_clk or negedge rst_n )
  if( !rst_n )
    rx_data <= 8'b0;
  else if( state == GET_DATA )
    rx_data <= {uart_rx,rx_data[7:1]};

always @( negedge Buad_clk )
  if( state!=GET_DATA )
    cnt <= 'd0;
  else 
    cnt <= cnt+1'b1;

assign rx_finish=(state==END_BIT);
reg finish_d;
always @( posedge clk or negedge rst_n )
  if( !rst_n )
    finish_d<=1'b0;
  else 
    finish_d<=rx_finish;

assign o_valid = rx_finish&(~finish_d);   

endmodule
Receive_Control
module UART #(
  parameter CLK_Period=50000000,//the unit is Hz
  parameter Buad_Rate=9600 //the unit is bits/s
)(
    input        clk,
    input        rst_n,

    input  [7:0] tx_data,
    input        tx_en,
    output       tx_finish,
    output       uart_tx,

    input        uart_rx,
    output [7:0] rx_data,
    output      rx_finish
);                                                


Send_Control #(
  .CLK_Period(CLK_Period),//the unit is Hz
  .Buad_Rate (Buad_Rate) //the unit is bits/s
)
send_control_inst (
  .clk     ( clk      ),
  .rst_n   ( rst_n    ),
  .tx_en   ( tx_en    ),
  .tx_data ( tx_data  ),
  .tx_finish ( tx_finish  ),
  .uart_tx ( uart_tx  )
);

Receive_Control #(
  .CLK_Period(CLK_Period),//the unit is Hz
  .Buad_Rate (Buad_Rate ) //the unit is bits/s
)
Receive_inst
(
  .clk    (clk    ),    
  .rst_n  (rst_n  ),
  .uart_rx(uart_rx),
  .rx_data(rx_data),
  .rx_finish(rx_finish),
  .o_valid(o_valid)  
);

endmodule
UART
 
//UART回环顶层
//作者:DOVI666
//时间:24/1/5
module uart(
    input  clk,
    input  rst_n,
    input  rx,
    output tx
);
    wire [7:0]data;
    wire rx_tx_en;

    parameter sysclk      = 50_000_000;             //系统时钟
    parameter baud        = 115200;                 //波特率
    parameter half_period = sysclk/baud/2;          //半周期计数.整周期计数为434,半周期为217

//***********uart_rx例化***********//
    uart_rx #(
        .sysclk(sysclk),     
        .baud(baud),       
        .half_period(half_period)
    )uart2_rx_inst(
        .clk(clk),
        .rst_n(rst_n),
        .data_in(rx),
        .data_out(data),
        .rx_finish(rx_tx_en)
    );
    
//***********uart_tx例化***********//
    uart_tx #(
        .sysclk(sysclk),     
        .baud(baud),       
        .half_period(half_period)
    )uart2_tx_inst(
        .clk(clk),
        .rst_n(rst_n),
        .data_in(data),
        .tx_en(rx_tx_en),
        .data_out(tx)
);
     
endmodule
我的UART
//UART接收模块
//作者:DOVI666
//时间:24/1/5
module uart2_rx(
    input            clk,
    input            rst_n,
    input            data_in,
    output reg [7:0] data_out,
    output           rx_finish
);

    reg       data_in1;
    reg       data_in2;                             //用作数据打两拍

    parameter sysclk      = 50_000_000;             //系统时钟
    parameter baud        = 115200;                 //波特率
    parameter half_period = sysclk/baud/2;          //半周期计数.整周期计数为434,半周期为217
                                                    //整段数据1+8+1=10bit,则可分为20个半周期
    wire      start;
    reg [12:0]baud_cnt;                             //波特计数,最大4340
    reg       rx_flag;                              //开始接收串行数据标志位
 
 //************打两拍,用于判断输入数据是否进入起始位***************//
    always@(posedge clk or negedge rst_n)begin      
        if(!rst_n)begin
            data_in1 <= 1'b0;
            data_in2 <= 1'b0;
        end
        else begin
            data_in1 <= data_in;
            data_in2 <= data_in1;
        end
    end
    
    assign start = (~data_in)? (data_in2 ? 1'b1:1'b0) : 1'b0;   //起始位标志,判断打两拍前后数据是否一致,in=0,in2=1
                                                                //不一致表示下降沿到来,开始起始位
 
//*******数据正式传输flag标志************************//
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            rx_flag <= 1'b0;
        else if(start)
            rx_flag <= 1'b1;
        else if((baud_cnt == 20*half_period) && (data_in ==1'b1))
            rx_flag <= 1'b0;
        else
            rx_flag <= rx_flag;
    end
 
//************波特率计数***************************//
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            baud_cnt <= 13'b0;
         else if(rx_flag)                         
            baud_cnt <= (baud_cnt < (20*half_period))?            //只要小于20倍半周期,就会加1
                        (baud_cnt+1'b1):
                        (baud_cnt <= 13'b0);                      //大于20倍就置零,表示10bit数据的结束
         else
            baud_cnt <= 13'b0;
    end
    
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            data_out <= 8'b0;
        else if(rx_flag) begin
            case(baud_cnt)                                         //根据时序图编写
                3 *half_period : data_out[0] <= data_in;
                5 *half_period : data_out[1] <= data_in;
                7 *half_period : data_out[2] <= data_in;
                9 *half_period : data_out[3] <= data_in;
                11*half_period : data_out[4] <= data_in;
                13*half_period : data_out[5] <= data_in;
                15*half_period : data_out[6] <= data_in;
                17*half_period : data_out[7] <= data_in;
                default        : data_out    <= data_out;
            endcase
        end
        else 
            data_out <= data_out;
    end
    
    assign rx_finish = (baud_cnt == 20*half_period);    //只要波特率记满,就表示一次数据传输完毕
                                                        //这里没有写(data_in == 1'b1),是因为若一直没传数据,那就一直为空闲状态
                                                        //所以就没有产生一次数据传输完毕的标志

endmodule
我的UART_RX
//UART发送模块
//作者:DOVI666
//时间:24/1/5
module uart2_tx(
    input       clk,
    input       rst_n,
    input [7:0] data_in,
    input       tx_en,
    output reg  data_out
    //output      tx_finish
);

    parameter sysclk      = 50_000_000;               //系统时钟
    parameter baud        = 115200;                   //波特率
    parameter half_period = sysclk/baud/2;            //半周期计数.整周期计数为434,半周期为217
                                                      //整段数据1+8+1=10bit,则可分为20个半周期 
    
    reg  [13:0]baud_cnt;
    reg        tx_flag;
    reg [7:0]data_temp;
    
    
//*************暂存接收到的数据***********************//
    always@(posedge clk or negedge rst_n)begin       //因为rx部分只会又一个周期时间拉高rx_finish
        if(!rst_n)                                   //过了这个周期,会拉低,若不及时存储收到的数据
            data_temp <= 8'b0;                       //新数据会刷新寄存器,导致数据出错
        else if(tx_en)
            data_temp <= data_in;
        else
            data_temp <= data_temp;
    end
                                                      
    
//************波特率计数***************************//
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            baud_cnt <= 13'b0;
         else if(tx_flag)                         
            baud_cnt <= (baud_cnt < (20*half_period))?   //只要小于20倍半周期,就会加1
                        (baud_cnt+1'b1):
                        (baud_cnt <= 13'b0);             //大于20倍就置零,表示10bit数据的结束
         else
            baud_cnt <= 13'b0;
    end

    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            tx_flag <= 1'b0;
        else if(tx_en)
            tx_flag <= 1'b1;
        else if(baud_cnt == 20*half_period)
            tx_flag <= 1'b0;
        else
            tx_flag <= tx_flag;
    end
    
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            data_out <= 1'b1;
        else if(tx_flag)begin
            case(baud_cnt)                            //根据时序图编写
                0 *half_period : data_out <= 1'b0;
                2 *half_period : data_out <= data_temp[0];
                4 *half_period : data_out <= data_temp[1];
                6 *half_period : data_out <= data_temp[2];
                8 *half_period : data_out <= data_temp[3];
                10*half_period : data_out <= data_temp[4];
                12*half_period : data_out <= data_temp[5];
                14*half_period : data_out <= data_temp[6];
                16*half_period : data_out <= data_temp[7];
                18*half_period : data_out <= 1'b1;
                default        : data_out <= data_out;
            endcase
        end
        else
            data_out <= data_out;
    end

//    assign tx_finish = (baud_cnt == 20*half_period);    //只要波特率记满,就表示一次数据传输完毕

endmodule
我的UART_TX

 

 6、上板验证

  这里设计了一个实测设计(回环设计)(UART_TEST),功能如下:

串口助手(上位机)发什么就能收回什么

       上电复位后,通过串口向上位机发送数据8'h21,然后只要收到上位机发送过来的数据,就将其返回给上位机。(8‘h21对应ASCⅡ码为 “ ! ” )

 

module UART_TEST(
  input     clk,
  input     rst_n,

  input     uart_rx,
  output    uart_tx
);

wire rx_finish;
wire tx_finish;
wire [7:0] rx_data;
reg [7:0] tx_data;

always @( posedge clk )
  if( !rst_n )
    tx_data <= 8'h21;
  else if( rx_finish )
    tx_data <= rx_data;
    
reg tx_en;
reg tx_cnt;
always @( posedge clk or negedge rst_n )
  if( !rst_n ) begin
    tx_en<=1'b0;
    tx_cnt <=1'b0;
    end
  else if( !tx_cnt ) begin
    tx_en<=1'b1;//rx_finish;
    tx_cnt <= 1'b1;
  end
  else
    tx_en<=rx_finish;

UART #(
  .CLK_Period(50000000),//the unit is Hz
  .Buad_Rate(9600) //the unit is bits/s
)
UART_INST
(
    .clk       ( clk       ),
    .rst_n     ( rst_n     ),
                          
    .tx_data   ( tx_data   ),
    .tx_en     ( tx_en     ),
    .tx_finish ( tx_finish ),
    .uart_tx   ( uart_tx   ),
                          
    .uart_rx   ( uart_rx   ),
    .rx_data   ( rx_data   ),
    .rx_finish ( rx_finish )
); 
endmodule
UART_TEST

  

  这里使用了友善串口调试助手,选择正确端口,调整号对应的串口参数,点击开始即可连接串口。

  需要注意的是,开发板上的串口连接使用的是USB,需要现在出售的很多电脑、笔记本都没有串口,所以开发板都提供了usb2uart这个接口。既可以供也可以当串口使用,对于ax301这个开发板,使用的驱动可以从这里下载:

https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers?tab=downloads

 由图可知,本设计成功。

 7、UART——FIFO——数码管

  系统框图:

 

  功能:在电脑中,通过串口调试助手,发送数据到FPGA,FPGA中uart_rx模块接收数据,并存入fifo中缓存,通过数码管显示当前发送的数据(0123456789ABCDEF)。uart_rx模块是上文写的模块。fifo模块是在quartus软件中调用的fifo模块,seg数码管显示模块内部有1kHZ分频。

  以上是RTL视图。下方展示数码管模块显示代码与顶层设计代码(源自:咸鱼IC),

seg
//======================================================================
// --- 名称 : seg_display
// --- 作者 : xianyu_FPGA
// --- 日期 : 2018-11-10
// --- 描述 : 数码管动态显示模块,改自小梅哥FPGA
//======================================================================

module seg
//---------------------<端口声明>---------------------------------------
(
input                   clk                 , //时钟,50Mhz
input                   rst_n               , //复位,低电平有效
input                   en                  , //数码管显示使能
input      [ 7:0]       data                , //输入数据
output     [ 5:0]       seg_sel             , //数码管位选
output reg [ 7:0]       seg_data              //数码管段选,即内容显示
);
//---------------------<信号定义>---------------------------------------
reg  [14:0]             cnt                 ;
wire                    add_cnt             ;
wire                    end_cnt             ;
reg                     clk_1k              ;
reg  [ 5:0]             seg_sel_r           ;
reg  [ 3:0]             data_tmp            ;

//----------------------------------------------------------------------
//--   1k分频,扫描一个数目管时间为1ms
//----------------------------------------------------------------------

//计数
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        cnt <= 0;
    else if(add_cnt)begin
        if(end_cnt)
            cnt <= 0;
        else
            cnt <= cnt + 1'b1;
    end
    else
        cnt <= cnt;
end

assign add_cnt = en;    //en为1才允许计数
assign end_cnt = add_cnt && cnt==25000-1;

//分频
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        clk_1k <= 0;
    else if(end_cnt)
        clk_1k <= ~clk_1k;
    else
        clk_1k <= clk_1k;
end

//----------------------------------------------------------------------
//--   数码管扫描,8位循环扫描,频率为1k
//----------------------------------------------------------------------
always @(posedge clk_1k or negedge rst_n)begin
    if(!rst_n)
        seg_sel_r <= 6'b11_1110;
    else if(seg_sel==6'b01_1111)
        seg_sel_r <= 6'b11_1110;
    else
        seg_sel_r <= (seg_sel << 1) + 1'b1;
end

//----------------------------------------------------------------------
//--   位选,不同计数对应不同位选编码,也对应分割的不同数据
//----------------------------------------------------------------------
always @(*)begin
    case(seg_sel_r)
        8'b11_1110: data_tmp = data[ 3: 0] ; // 位1
        8'b11_1101: data_tmp = data[ 7: 4] ; // 位2
        8'b11_1011: data_tmp = data[ 3: 0] ; // 位3
        8'b11_0111: data_tmp = data[ 7: 4] ; // 位4
        8'b10_1111: data_tmp = data[ 3: 0] ; // 位5
        8'b01_1111: data_tmp = data[ 7: 4] ; // 位6
        default:    data_tmp = 4'b0000     ;
    endcase
end

assign seg_sel = en ? seg_sel_r : 6'b11_1111; // 位选使能

//----------------------------------------------------------------------
//--   段选,将不同分割数据进行段选编码
//----------------------------------------------------------------------
always @(*)begin
    case(data_tmp)
        4'h0:   seg_data = 8'b1100_0000;
        4'h1:   seg_data = 8'b1111_1001;
        4'h2:   seg_data = 8'b1010_0100;
        4'h3:   seg_data = 8'b1011_0000;
        4'h4:   seg_data = 8'b1001_1001;
        4'h5:   seg_data = 8'b1001_0010;
        4'h6:   seg_data = 8'b1000_0010;
        4'h7:   seg_data = 8'b1111_1000;
        4'h8:   seg_data = 8'b1000_0000;
        4'h9:   seg_data = 8'b1001_0000;
        4'ha:   seg_data = 8'b1000_1000;
        4'hb:   seg_data = 8'b1000_0011;
        4'hc:   seg_data = 8'b1100_0110;
        4'hd:   seg_data = 8'b1010_0001;
        4'he:   seg_data = 8'b1000_0110;
        4'hf:   seg_data = 8'b1011_1111;
        default:seg_data = 8'b1111_1111;
    endcase
end

endmodule

module uart_fifo_seg(
    input clk,
    input rst_n,
    input data_in,
    output [5:0]sel,
    output [7:0]seg
);

    wire [7:0]data_out;
    wire wrreq;
    wire [7:0]hex_data;
    wire a=1;
    

    
    seg seg_inst(
    .clk(clk), //时钟,50Mhz
    .rst_n(rst_n), //复位,低电平有效
    .en(a), //数码管显示使能
    .data(hex_data), //输入数据
    .seg_sel(sel), //数码管位选
    .seg_data(seg)//数码管段选,即内容显示
    );

    uart_rx uart_rx_inst(
    .clk(clk),
    .rst_n(rst_n),
    .data_in(data_in),
    .data_out(data_out),
    .rx_finish(wrreq)
    );

    fifo fifo_inst (
    .aclr ( ~rst_n ),     //这里的fifo是高电平清零,所以rst_n需要取反
    .clock (clk),
    .data (data_out),
    .rdreq (a),
    .wrreq (wrreq),
    .q (hex_data)
    );

endmodule
uart_fifo_seg

 

 

参考:

博客园:咸鱼IC

微信公众号:小鱼学IC

B站:UID:491502261

 

posted @ 2024-01-02 17:39  DOVI666  阅读(154)  评论(0)    收藏  举报