赞
踩
目录
UART的全称是通用异步收发器(Universal Asynchronous Receiver/Transmitter)
UART是一个通用的接口协议,被广泛的应用在各类MCU和SOC产品上。“不需要额外的时钟线进行数据的同步传输”,只要信号拉低,就可开始传送数据。UART 只需要两条信号线:RXD 和 TXD(一个数据的发送方和一个数据的接收方 ),其中 RXD 是 UART 的接收端,TXD 是 UART 的发送端,接收与发送是全双工形式。
它可以和各种标准串行接口,如 RS 232 和 RS 485 等进行全双工异步通信, 具有传输距离远、成本低、可靠性高等优点。一般 UART 由专用芯片如: 8250, 16450 来实现,但专用芯片引脚都较多,内含许多辅助功能,在实际使用时往往只需要用到 UART 的基本功能,使用专用芯片会造成资源浪费和成本提高。
UART的一帧由四部分组成起始位(1bit),数据位(6\7\8bit),校验位(1bit),停止位(1\1.5\2bit),如下图所示,
uart 是将传输数据的每个字符一位接一位地传输。 其中每一位(Bit)的意义如下:
空闲位:高电平,表明当前无传输事务。
起始位:一位低电平信号,标志着数据传输的开始。
数据位:紧接着起始位之后。数据位的个数可以是 6、7、8 等,构 成一个字符。通常采用 ASCII 码。从最低位开始传送,依靠时钟定位。
奇偶校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或 奇数(奇校验),以此来校验数据传送的正确性。
停止位:一个字符数据的结束标志。可以是 1 位、1.5 位、2 位的高电平。
由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通 信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束, 并且提供计算机校正时钟同步的机会。停止位的位数越多,不同时钟同步的容 忍程度越大,但是数据传输率同时也越慢。
因为UART没有控制线,要让接收方知道什么时候开始接收数据,需要一些手段,UART数据的传输中,只有一根线,所以在发送数据之前,先发一位逻辑“0”作为数据发送的起始标志,接收方在空闲时,当检测到有一个低电平,则开始接逐位接收数据。
因为通信两个机器之间不可避免的存在时钟偏移,为了消除数据交互之间时钟偏移对数据传输产生的影响,所以在每一次数据发送结束后,要发送一位逻辑“1”作为数据发送的结束标志,接收方在空闲时,当检测到有一个高电平,则结束接收一次数据。
默认无传输数据时,为高电平
当信号拉低,传输线上的电平拉低,意味着开始进行数据传输
紧接着起始位的是数据位,它可以是5、6、7或8位。
UART的“校验位”紧挨着“数据位”,采用奇偶校验方式,根据设置,校验位可以存在也可以不存在。
UART将停止位作为停止标志,是在数据位(没有校验位)和校验位(有校验位)之后发送1~2位的逻辑“1”高电平。当发送完停止位之后,UART总线进入空闲。
因为UART是一种低速总线,每多发一位都占用不少的时间(由传输波特率决定),所以可以根据传输数据的特点,采用不同位宽以节约数据传输的时间。
波特率等于每秒钟传输的数据位数。
常用的波特率有:9600、19200、38400、57600、115200,本工程所用到的是115200。
计算传输1bit需要的时间如下表:假如我们的全局时钟频率为100MHz,波特率设置为9600,那么意味着每秒该UART传输协议可以传输9600bits的数据。传输1比特需时间约为:10^9(ns)/9600=104166(ns)。
uart 的设计分为两个部分,一部分为发送模块,另一部分为接收模块。程 序设计主要通过状态机实现,系统框架图如下:
全局参数
- parameter CHECK_BIT = "None" , //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
- parameter BPS = 115200 , //系统波特率
- parameter CLK = 50_000_000 , //系统时钟频率
- parameter DATA_BIT = 8 , //数据位(6、7、8)
- parameter STOP_BIT = 1 //停止位
IDLE:空闲状态,无数据传输,输出高电平,当tx_data_vld信号到来时跳转到START;
START:起始位,无数据传输,输出低电平为 ,无条件跳转至DATA;
DATA:数据位,进行数据传输,先发送低比特,根据数据输出高低电平,假如有校验位,跳到CHECK,假如数据传输不设校验位,跳转到STOP;
CHECK:奇偶校验位,
STOP:停止位,高电平,共 1 位。 发送模块在上一状态向下一状态切换时,改变电平
- /**************************************功能介绍***********************************
- Date : 2023年9月18日21:37:53
- Author : linxiaoxiao.
- Version :
- Description: uart串口发送模块
- *********************************************************************************/
- //例化模版
- // tx_uart #(
- // .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
- // .BPS ( 115200 ), //系统波特率
- // .CLK ( 50_000_000 ), //系统时钟频率
- // .DATA_BIT ( 8 ), //数据位(6、7、8)
- // .STOP_BIT ( 1 ) //停止位
- // )tx_uart_inst(
- // /* input */.clk (),
- // /* input */.rst_n (),
- // /* input */.tx_data_vld (),
- // /* input [DATA_BIT - 1:0] */.tx_data (),
-
- // /* output */.tx_ready (),
- // /* output reg */.tx ()
- // );
-
- //---------<模块及端口声名>------------------------------------------------------
- module tx_uart#(
- parameter CHECK_BIT = "None" , //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
- parameter BPS = 115200 , //系统波特率
- parameter CLK = 50_000_000 , //系统时钟频率
- parameter DATA_BIT = 8 , //数据位(6、7、8)
- parameter STOP_BIT = 1 //停止位
- )(
- input clk ,
- input rst_n ,
- input tx_data_vld ,
- input [DATA_BIT - 1:0] tx_data ,
-
- output tx_ready ,
- output reg tx
- );
- //---------<参数定义>---------------------------------------------------------
-
- //波特计数最大值
- localparam BPS_MAX = CLK/BPS;
- //状态机参数定义
- localparam IDLE = 0 ,//
- START = 1 ,//
- DATA = 2 ,//
- CHECK = 3 ,
- STOP = 4 ;//
-
- //---------<内部信号定义>-----------------------------------------------------
-
- reg [2:0] state ;//现态
-
- //状态转移条件
- wire idle2start ;
- wire start2data ;
- wire data2check ;
- wire data2stop ;
- wire check2stop ;
- wire stop2idle ;
-
- reg [25:0] bps_cnt ;
- wire add_bps_cnt ,
- end_bps_cnt ;
- reg [3:0] bit_cnt ,
- BIT_MAX ;
- wire add_bit_cnt ,
- end_bit_cnt ;
-
- reg [DATA_BIT - 1:0] tx_data_r ;
- wire check_vld ;//校验位使能
-
- /****************************************************************
- 数据校验
- ****************************************************************/
-
- //奇校验缩位同或
- /* assign check_vld = ~^tx_data_r; */
-
- //偶校验缩位异或
- /* assign check_vld = ^tx_data_r; */
- assign check_vld = (CHECK_BIT == "Odd")?~^tx_data_r:^tx_data_r;
-
- /****************************************************************
- 输入数据寄存
- ****************************************************************/
- always @(posedge clk or negedge rst_n)
- if(!rst_n)
- tx_data_r <= 'd0;
- else if(tx_data_vld)
- tx_data_r <= tx_data;
- /****************************************************************
- fsm
- ****************************************************************/
- // 时序逻辑描述状态转移
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- state <= IDLE;
- end
- else case(state)
- IDLE : if(idle2start) state <= START;
- START : if(start2data) state <= DATA ;
- DATA : if(data2check) state <= CHECK;
- else if(data2stop ) state <= STOP ;
- CHECK : if(check2stop) state <= STOP ;
- STOP : if(stop2idle ) state <= IDLE ;
- default : state <= IDLE ;
- endcase
- end
-
- assign idle2start = state == IDLE && tx_data_vld;
- assign start2data = state == START && end_bit_cnt;
- assign data2check = state == DATA && end_bit_cnt && CHECK_BIT != "None";
- assign data2stop = state == DATA && end_bit_cnt && CHECK_BIT == "None";
- assign check2stop = state == CHECK && end_bit_cnt;
- assign stop2idle = state == STOP && end_bit_cnt;
-
- /****************************************************************
- bps_cnt
- ****************************************************************/
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- bps_cnt <= 'd0;
- end
- else if(add_bps_cnt)begin
- if(end_bps_cnt)begin
- bps_cnt <= 'd0;
- end
- else begin
- bps_cnt <= bps_cnt + 1'b1;
- end
- end
- end
-
- assign add_bps_cnt = state != IDLE;
- assign end_bps_cnt = add_bps_cnt && bps_cnt == BPS_MAX - 1;
-
- /****************************************************************
- bit_cnt
- ****************************************************************/
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- bit_cnt <= 'd0;
- end
- else if(add_bit_cnt)begin
- if(end_bit_cnt)begin
- bit_cnt <= 'd0;
- end
- else begin
- bit_cnt <= bit_cnt + 1'b1;
- end
- end
- end
-
- assign add_bit_cnt = end_bps_cnt;
- assign end_bit_cnt = add_bit_cnt && bit_cnt == BIT_MAX - 1;
- //计数器复用
- always @(*)begin
- case (state)
- START : BIT_MAX = 1;
- DATA : BIT_MAX = DATA_BIT;
- CHECK : BIT_MAX = 1;
- STOP : BIT_MAX = STOP_BIT;
- default: BIT_MAX = 1;
- endcase
- end
-
- /****************************************************************
- tx时序
- ****************************************************************/
- always @(*)begin
- case (state)
- IDLE : tx = 1;
- START : tx = 0;
- DATA : if(tx_data_r[bit_cnt]) tx= 1;
- else tx = 0;
- CHECK : tx = check_vld;
- STOP : tx = 1;
- default : tx = 1;
- endcase
- end
-
- assign tx_ready = state == IDLE;
-
- endmodule
- `timescale 1ns/1ns
-
- module tx_tb();
-
- //激励信号定义
- reg tb_clk ;
- reg tb_rst_n ;
- reg [7:0] tx_data ;
- reg tx_data_vld ;
-
- //输出信号定义
- wire tx ;
-
-
- //时钟周期参数定义
- parameter CLOCK_CYCLE = 20;
-
- //模块例化
- tx_uart #(
- .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
- .BPS ( 115200 ), //系统波特率
- .CLK ( 50_000_000 ), //系统时钟频率
- .DATA_BIT ( 8 ), //数据位(6、7、8)
- .STOP_BIT ( 1 ) //停止位
- )tx_uart_inst(
- /* input */.clk (tb_clk ),
- /* input */.rst_n (tb_rst_n ),
- /* input */.tx_data_vld (tx_data_vld ),
- /* input [DATA_BIT - 1:0] */.tx_data (tx_data ),
- /* output */.tx_ready (tx_ready ),
- /* output reg */.tx (tx )
- );
-
- //产生时钟
- initial tb_clk = 1'b0;
- always #(CLOCK_CYCLE/2) tb_clk = ~tb_clk;
-
- //复位
- initial begin
- tb_rst_n = 1'b1;
- #(CLOCK_CYCLE*2);
- tb_rst_n = 1'b0;
- #(CLOCK_CYCLE*20);
- tb_rst_n = 1'b1;
- end
- integer i;
- //描述输入
- initial begin
-
- #(CLOCK_CYCLE*200);
- #1;
- tx_data = 0;
- tx_data_vld = 0;
- #(CLOCK_CYCLE*4);
- for ( i= 0;i<10 ;i=i+1 ) begin
- #(CLOCK_CYCLE*20);
- tx_data_vld = 1;
-
- tx_data = {$random}%256;
- #20;
- tx_data_vld = 0;
- wait(tx_uart_inst.stop2idle == 1);
- end
-
- #100800;
- $stop;
- end
- endmodule
模拟多次数据传输:
放大:
这里引入一个按键消抖模块作为接收使能,检验代码如下:
- /**************************************功能介绍***********************************
- Date :
- Author : linxiaoxiao.
- Version :
- Description: 测试tx模块
- *********************************************************************************/
-
- //---------<模块及端口声名>------------------------------------------------------
- module tx_text(
- input clk ,
- input rst_n ,
- input key_in ,
-
- output tx
- );
-
- //---------<内部信号定义>-----------------------------------------------------
-
- wire key_down;
-
- //模块例化
- tx_uart #(
- .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
- .BPS ( 115200 ), //系统波特率
- .CLK ( 50_000_000 ), //系统时钟频率
- .DATA_BIT ( 8 ), //数据位(6、7、8)
- .STOP_BIT ( 1 ) //停止位
- )tx_uart_inst(
- /* input */.clk ( clk ),
- /* input */.rst_n ( rst_n ),
- /* input */.tx_data_vld ( key_down ),
- /* input [DATA_BIT - 1:0] */.tx_data ( 8'hac ),
-
- /* output */.tx_ready ( tx_ready ),
- /* output reg */.tx ( tx )
- );
-
-
- fsm_key_filter #( .WIDTH(1)) fsm_key_filter_inst (
- /* input */.clk ( clk ),
- /* input */.rst_n ( rst_n ),
- /* input [WIDTH-1:0] */.key_in ( key_in ),
- /* output reg [WIDTH-1:0]*/.key_down ( key_down )
- );
-
-
- endmodule
配置引脚
- #引脚参数导入脚本
- #时钟、复位
- set_location_assignment PIN_E1 -to clk
- set_location_assignment PIN_E15 -to rst_n
-
- #UART
- #set_location_assignment PIN_M2 -to uart_rx
- set_location_assignment PIN_G1 -to tx
串口窗口 可设置奇偶校验:
IDLE:空闲状态,无数据传输,输出高电平,当tx_data_vld信号到来时跳转到START;
START:起始位,无数据传输,输出低电平为 ,延时结束后至DATA;
DATA:数据位,进行数据传输,先发送低比特,根据数据输出高低电平,假如有校验位,跳到CHECK,假如数据传输不设校验位,跳转到STOP;
CHECK:奇偶校验位
STOP:停止位,高电平,共 1 位。 发送模块在上一状态向下一状态切换时,改变电平
- /**************************************功能介绍***********************************
- Date : 2023年9月18日22:37:53
- Author : linxiaoxiao.
- Version :
- Description: uart串口接收模块
- *********************************************************************************/
- //例化模版
- // rx_uart #(
- // .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
- // .BPS ( 115200 ), //系统波特率
- // .CLK ( 50_000_000 ), //系统时钟频率
- // .DATA_BIT ( 8 ), //数据位(6、7、8)
- // .STOP_BIT ( 1 ) //停止位
- // )rx_uart_inst(
- // /* input */ .clk (),
- // /* input */ .rst_n (),
- // /* input reg */ .rx (),
- // /* output */ .rx_data_vld (),
- // /* output [DATA_BIT - 1:0] */ .rx_data (),
- // /* output */ .rx_ready ()
- // // );
-
- //---------<模块及端口声名>------------------------------------------------------
- module rx_uart#(
- parameter CHECK_BIT = "None" , //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
- parameter BPS = 115200 , //系统波特率
- parameter CLK = 50_000_000 , //系统时钟频率
- parameter DATA_BIT = 8 , //数据位(6、7、8)
- parameter STOP_BIT = 1 //停止位
- )(
- input clk ,
- input rst_n ,
- input rx ,
- output rx_data_vld ,
- output [DATA_BIT - 1:0] rx_data ,
- output rx_ready
-
- );
- //---------<参数定义>---------------------------------------------------------
-
- //波特计数最大值
- localparam BPS_MAX = CLK/BPS;
- //状态机参数定义
- localparam IDLE = 0 ,//空闲
- START = 1 ,//起始位
- DATA = 2 ,//数据位
- CHECK = 3 ,//奇偶校验位
- STOP = 4 ;//停止位
-
- //---------<内部信号定义>-----------------------------------------------------
-
- reg [2:0] state ;//现态
-
- //状态转移条件
- wire idle2start ;
- wire start2data ;
- wire data2check ;
- wire data2stop ;
- wire check2stop ;
- wire stop2idle ;
-
- reg [25:0] bps_cnt ;
- wire add_bps_cnt ,
- end_bps_cnt ;
- reg [3:0] bit_cnt ,
- BIT_MAX ;
- wire add_bit_cnt ,
- end_bit_cnt ;
-
- reg [DATA_BIT - 1:0] temp_data ;//输入数据零时缓存
-
- reg check_reg ;//校验寄存
- wire check_vld ;//校验位使能
-
- reg rx_r0 ,//输入数据同步寄存
- rx_r1 ;
- wire flag_n ;//下降沿监测 确定rx采样时序
-
- /****************************************************************
- 输入数据寄存(同步打拍)
- ****************************************************************/
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- rx_r0 <= 0;
- rx_r1 <= 0;
- end
- else begin
- rx_r0 <= rx;
- rx_r1 <= rx_r0;
- end
- end
- //下降沿标志
- assign flag_n = !rx_r0 && rx_r1;
- /****************************************************************
- 数据接收逻辑
- ****************************************************************/
- always @(posedge clk or negedge rst_n)
- if(!rst_n)
- temp_data <= 'd0;
- else if(state == DATA && bps_cnt == BPS_MAX >> 1)
- temp_data[bit_cnt] <= rx_r0;
- /****************************************************************
- 接收数据校验
- ****************************************************************/
- always @(posedge clk or negedge rst_n)
- if(!rst_n)
- check_reg <= 'd0;
- else if(state == CHECK && bps_cnt == BPS_MAX >> 1)
- check_reg <= rx_r0;
- //校验位选择
- assign check_vld = (CHECK_BIT == "Odd")?~^temp_data : ^temp_data;
-
- /****************************************************************
- fsm
- ****************************************************************/
- // 时序逻辑描述状态转移
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- state <= IDLE;
- end
- else case(state)
- IDLE : if(idle2start) state <= START;
- START : if(start2data) state <= DATA ;
- DATA : if(data2check) state <= CHECK;
- else if(data2stop ) state <= STOP ;
- CHECK : if(check2stop) state <= STOP ;
- STOP : if(stop2idle ) state <= IDLE ;
- default : state <= IDLE ;
- endcase
- end
-
- assign idle2start = state == IDLE && flag_n ;
- assign start2data = state == START && end_bit_cnt;
- assign data2check = state == DATA && end_bit_cnt && CHECK_BIT != "None";
- assign data2stop = state == DATA && end_bit_cnt && CHECK_BIT == "None";
- assign check2stop = state == CHECK && end_bit_cnt;
- assign stop2idle = state == STOP && end_bit_cnt;
-
- /****************************************************************
- bps_cnt
- ****************************************************************/
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- bps_cnt <= 'd0;
- end
- else if(add_bps_cnt)begin
- if(end_bps_cnt)begin
- bps_cnt <= 'd0;
- end
- else begin
- bps_cnt <= bps_cnt + 1'b1;
- end
- end
- end
-
- assign add_bps_cnt = state != IDLE;
- assign end_bps_cnt = add_bps_cnt && bps_cnt == BPS_MAX - 1;
- /****************************************************************
- bit_cnt
- ****************************************************************/
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- bit_cnt <= 'd0;
- end
- else if(add_bit_cnt)begin
- if(end_bit_cnt)begin
- bit_cnt <= 'd0;
- end
- else begin
- bit_cnt <= bit_cnt + 1'b1;
- end
- end
- end
-
- assign add_bit_cnt = end_bps_cnt;
- assign end_bit_cnt = add_bit_cnt && bit_cnt == BIT_MAX - 1;
- //计数器复用
- always @(*)begin
- case (state)
- START : BIT_MAX = 1;
- DATA : BIT_MAX = DATA_BIT;
- CHECK : BIT_MAX = 1;
- STOP : BIT_MAX = STOP_BIT;
- default: BIT_MAX = 1;
- endcase
- end
-
- /****************************************************************
- 输出逻辑
- ****************************************************************/
-
- assign rx_ready = state == IDLE;
- assign rx_data_vld = (CHECK_BIT == "None")? stop2idle
- : (stop2idle && (check_vld == check_reg))? 1
- : 0;
-
- assign rx_data =(state == STOP && bit_cnt == STOP_BIT - 1) ? temp_data : 'b0 ;
-
- endmodule
两种模拟输入方式,都在下面体现了:
- `timescale 1ns/1ns
-
- module rx_tb ();
-
- //激励信号定义
- reg clk ;
- reg rst_n ;
- reg /* tx_data_vld , */rx_din;
- /* reg [7:0] tx_data ; */
- /* wire tx ; */
-
- //输出信号定义
- wire /* tx_ready , */rx_data_vld ;
-
-
-
-
- //时钟周期参数定义
- parameter CLOCK_CYCLE = 20;
-
-
- //模块例化
- // tx_uart #(
- // .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
- // .BPS ( 115200 ), //系统波特率
- // .CLK ( 50_000_000 ), //系统时钟频率
- // .DATA_BIT ( 8 ), //数据位(6、7、8)
- // .STOP_BIT ( 1 ) //停止位
- // )tx_uart_inst(
- // /* input */.clk (clk ),
- // /* input */.rst_n (rst_n ),
- // /* input */.tx_data_vld (tx_data_vld ),
- // /* input [DATA_BIT - 1:0] */.tx_data (tx_data ),
- // /* output */.tx_ready (tx_ready ),
- // /* output reg */.tx (tx )
- // );
-
-
- rx_uart #(
- .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
- .BPS ( 115200 ), //系统波特率
- .CLK ( 50_000_000 ), //系统时钟频率
- .DATA_BIT ( 8 ), //数据位(6、7、8)
- .STOP_BIT ( 1 ) //停止位
- )rx_uart_inst(
- /* input */ .clk ( clk ),
- /* input */ .rst_n ( rst_n ),
- /* input reg */ .rx ( rx_din ),
- /* output */ .rx_data_vld ( rx_data_vld ),
- /* output [DATA_BIT - 1:0] */ .rx_data ( rx_data ),
- /* output */ .rx_ready ( rx_ready )
- );
-
-
- //产生时钟
- initial clk = 1'b0;
- always #(CLOCK_CYCLE/2) clk = ~clk;
- //产生激励
- initial begin
- rst_n = 1'b1;
- #(CLOCK_CYCLE*2);
- rst_n = 1'b0;
- #(CLOCK_CYCLE*20);
- rst_n = 1'b1;
- end
-
- initial begin
- repeat(5)begin
- rx_din = 1'b1;
- #(20*100)
- rx_din = 1'b0;
- #(434*20)
- repeat(8)begin
- rx_din = {$random};
- #(434*20);
- end
- rx_din = 1'b1;
- wait(rx_data_vld == 1);
- end
- #10000;
- $stop;
- // tx_data = 0;
- // tx_data_vld = 0;
- // #(CLOCK_CYCLE*6);
-
- // tx_data_vld = 1;
- // repeat(8) begin
- // tx_data = {$random};#20;
- // tx_data_vld = 0;
- // #200;
- // tx_data_vld = 1;
- // wait(tx_ready == 1);
- // #20;
- // end
- // #20000000;
- // $stop;
- end
- endmodule
代码:
- /**************************************功能介绍***********************************
- Date :
- Author : linxiaoxiao.
- Version :
- Description: 串口回环(未加fifo)
- *********************************************************************************/
- //---------<模块及端口声名>------------------------------------------------------
- module top(
- input clk ,
- input rst_n ,
- input rx ,
-
- output tx
- );
-
- //---------<内部信号定义>-----------------------------------------------------
-
- wire [7:0] rx_data ;
- wire tx_ready ;
- wire rx_data_vld;
-
- //模块例化
- tx_uart #(
- .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
- .BPS ( 115200 ), //系统波特率
- .CLK ( 50_000_000 ), //系统时钟频率
- .DATA_BIT ( 8 ), //数据位(6、7、8)
- .STOP_BIT ( 1 ) //停止位
- )tx_uart_inst(
- /* input */.clk ( clk ),
- /* input */.rst_n ( rst_n ),
- /* input */.tx_data_vld ( rx_data_vld && tx_ready ),
- /* input [DATA_BIT - 1:0] */.tx_data ( rx_data ),
-
- /* output */.tx_ready ( tx_ready ),
- /* output reg */.tx ( tx )
- );
-
- rx_uart #(
- .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
- .BPS ( 115200 ), //系统波特率
- .CLK ( 50_000_000 ), //系统时钟频率
- .DATA_BIT ( 8 ), //数据位(6、7、8)
- .STOP_BIT ( 1 ) //停止位
- )rx_uart_inst(
- /* input */ .clk ( clk ),
- /* input */ .rst_n ( rst_n ),
- /* input reg */ .rx ( rx ),
- /* output */ .rx_data_vld ( rx_data_vld ),
- /* output [DATA_BIT - 1:0] */ .rx_data ( rx_data ),
- /* output */ .rx_ready ( rx_ready )
- );
-
- endmodule
在串口通信中,采用缓冲器FIFO的主要意义是解决数据传输中的**时序差异**问题,并提供数据的缓冲和流控能力。具体而言,它有以下几个作用:
1. 时序匹配:串口通信中发送方和接收方的时钟频率可能存在差异,使用FIFO可以将数据以一定的速率存储在缓冲区中,从而实现发送方和接收方之间的时序匹配,避免数据的丢失和错误。
2. 数据缓冲:在数据传输中,当发送方产生数据的速率快于接收方处理数据的速率时,FIFO可以暂时存储多出来的数据,保证数据不会丢失。
3. 流控控制:当接收方处理能力不足以处理发送方的数据时,FIFO可以用于流控,即发送方通过监测FIFO的状态来控制数据的发送速率,从而避免数据的丢失。
4. 缓存传输:一些应用场景中,需要在某个特定时刻对数据进行处理,而不是即时处理。FIFO可以将接收到的数据缓存在缓冲区中,待到特定时刻再进行处理。
总之,**FPGA串口数据缓冲器FIFO在数据传输中起到了时序匹配、数据缓冲、流控控制和缓存传输的重要作用,提高了数据传输的可靠性和灵活性。**
- /**************************************功能介绍***********************************
- Date : 2023年9月21日21:48:59
- Author : linxiaoxiao.
- Version :
- Description: uart_ctrl控制模块——fifo
- *********************************************************************************/
- //---------<模块及端口声名>------------------------------------------------------
- module uart_ctrl(
- input clk ,
- input rst_n ,
-
- input [7:0] rx_data ,
- input rx_data_vld ,
- input tx_ready ,
- output [7:0] tx_data ,
- output tx_data_vld
- );
- //---------<内部信号定义>-----------------------------------------------------
-
- wire fifo_empty ;
- wire fifo_full ;
-
- fifo fifo_inst (
- .aclr ( ~rst_n ),
- .clock ( clk ),
- .data ( rx_data ),
- .rdreq ( ~fifo_empty && tx_ready ),
- .wrreq ( rx_data_vld && ~fifo_full ),
- .empty ( fifo_empty ),
- .full ( fifo_full ),
- .q ( tx_data ),
- .usedw ( )
- );
-
- assign tx_data_vld = tx_ready && ~fifo_empty ;
-
- endmodule
- /**************************************功能介绍***********************************
- Date :
- Author : linxiaoxiao.
- Version :
- Description:
- *********************************************************************************/
-
- //---------<模块及端口声名>------------------------------------------------------
- module top(
- input clk ,
- input rst_n ,
- input rx ,
- output tx
- );
- //---------<内部信号定义>-----------------------------------------------------
-
- wire [7:0] tx_data , rx_data ;
- wire tx_ready , rx_ready ;
- wire tx_data_vld,rx_data_vld;
-
- //模块例化
- tx_uart #(
- .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
- .BPS ( 115200 ), //系统波特率
- .CLK ( 50_000_000 ), //系统时钟频率
- .DATA_BIT ( 8 ), //数据位(6、7、8)
- .STOP_BIT ( 1 ) //停止位
- )tx_uart_inst(
- /* input */.clk ( clk ),
- /* input */.rst_n ( rst_n ),
- /* input */.tx_data_vld ( tx_data_vld ),
- /* input [DATA_BIT - 1:0] */.tx_data ( tx_data ),
-
- /* output */.tx_ready ( tx_ready ),
- /* output reg */.tx ( tx )
- );
-
- uart_ctrl uart_ctrl_inst(
- /* input */.clk ( clk ),
- /* input */.rst_n ( rst_n ),
- /* input [7:0] */.rx_data ( rx_data ),
- /* input */.rx_data_vld ( rx_data_vld ),
- /* input */.tx_ready ( tx_ready ),
- /* output [7:0] */.tx_data ( tx_data ),
- /* output */.tx_data_vld ( tx_data_vld )
- );
-
- rx_uart #(
- .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
- .BPS ( 115200 ), //系统波特率
- .CLK ( 50_000_000 ), //系统时钟频率
- .DATA_BIT ( 8 ), //数据位(6、7、8)
- .STOP_BIT ( 1 ) //停止位
- )rx_uart_inst(
- /* input */ .clk ( clk ),
- /* input */ .rst_n ( rst_n ),
- /* input reg */ .rx ( rx ),
- /* output */ .rx_data_vld ( rx_data_vld ),
- /* output [DATA_BIT - 1:0] */ .rx_data ( rx_data ),
- /* output */ .rx_ready ( rx_ready )
- );
- endmodule
8.2.1 仿真文件
- `timescale 1ns/1ns
-
- module tb_top ();
-
- //激励信号定义
- reg clk ;
- reg rst_n ;
- reg rx_din ;
-
- //时钟周期参数定义
- parameter CLOCK_CYCLE = 20;
-
-
- top top_inst(
- /* input */.clk ( clk ),
- /* input */.rst_n ( rst_n ),
- /* input */.rx ( rx_din ),
- /* output */.tx ( tx )
- );
-
- //产生时钟
- initial clk = 1'b0;
- always #(CLOCK_CYCLE/2) clk = ~clk;
- //产生激励
- initial begin
- rst_n = 1'b1;
- #(CLOCK_CYCLE*2);
- rst_n = 1'b0;
- #(CLOCK_CYCLE*20);
- rst_n = 1'b1;
- end
-
- initial begin
- repeat(5)begin
- rx_din = 1'b1;
- #(20*100)
- rx_din = 1'b0;
- #(434*20)
- repeat(8)begin
- rx_din = {$random};
- #(434*20);
- end
- rx_din = 1'b1;
- wait(top_inst.rx_uart_inst.rx_data_vld == 1);
- end
- #10000;
- $stop;
- end
- endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。