在lab04中决定对其代码进行好好的复盘,这几天也将uart的传输原理搞的七七八八。
在此记录,积极输出是为了更多的输入。
UART 原理 principle
-
UART:universal asynachronous receiver/transmitter,通用异步收发传输器
-
其在数据发送时将并行数据转换为串行数据来传输,在数据接收时将串行数据转换为并行数据来接受,实现全双工传输和接收。
-
包括了RS232,RS449,RS423,RS422,RS485等接口标准规范和总线标准规范。换句话说,UART是通用异步串行通信的总称,而RS232等是对应各种异步串行通信口的借口标准和总线标准,他们规定了通信口的电气特性、传输速率、连接特性和接口的机械特性等内容。
-
UART 通信在使用前需要做多项设置,最常见的设置包括数据位数、波特率大小、奇偶校验类型和停止位数。
按照一个完整的字节包括一位起始位、8位数据位、一位停止位即总共十位数据来算,要想完整的实现这十位数据的发送,就需要11个波特率时钟脉冲。
第1个脉冲标记一次传输的起始,第11个脉冲标记一次传输的结束。
UART模块 module
uart_tx 发送
- 波特率时钟生成(系统时钟计数值= 1/(bps*sys_clk_period) -1)
- 数据输出模块
- 通过对波特率时钟进行计数,来确定数据发送的循环状态
- 传输结束产生一个byte传送结束的信号
- 对输入数据进行寄存(打两拍来同步数据)
- 数据传输状态控制
-根据bps_cnt传输共10位bit数
module uart_byte_tx(
Clk, //50M时钟输入
Rst_n, //模块复位
data_byte, //待传输8bit数据
send_en, //发送使能
baud_set, //波特率设置
Rs232_Tx, //Rs232输出信号
Tx_Done, //一次发送数据完成标志
uart_state //发送数据状态
);
input Clk;
input Rst_n;
input [7:0]data_byte;
input send_en;
input [2:0]baud_set;
output reg Rs232_Tx;
output reg Tx_Done;
output reg uart_state;
reg bps_clk; //波特率时钟
reg [15:0]div_cnt;//分频计数
reg [15:0]bps_DR;//分频计数最大值
reg [3:0]bps_cnt;//波特率时钟计数器
reg [7:0]r_data_byte;
localparam START_BIT = 1'b0;
localparam STOP_BIT = 1'b1;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
uart_state <= 1'b0;
else if(send_en)
uart_state <= 1'b1;
else if(Tx_Done)
uart_state <= 1'b0;
else
uart_state <= uart_state;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
r_data_byte <= 8'd0;
else if(send_en)
r_data_byte <= data_byte;
else
r_data_byte <= r_data_byte;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
bps_DR <= 16'd5207;
else begin
case(baud_set)
0:bps_DR <= 16'd5207;
1:bps_DR <= 16'd2603;
2:bps_DR <= 16'd1301;
3:bps_DR <= 16'd867;
4:bps_DR <= 16'd433;
default:bps_DR <= 16'd5207;
endcase
end
//counter
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
div_cnt <= 16'd0;
else if(uart_state)begin
if(div_cnt == bps_DR)
div_cnt <= 16'd0;
else
div_cnt <= div_cnt + 1'b1;
end
else
div_cnt <= 16'd0;
// bps_clk gen
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
bps_clk <= 1'b0;
else if(div_cnt == 16'd1)
bps_clk <= 1'b1;
else
bps_clk <= 1'b0;
//bps counter
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
bps_cnt <= 4'd0;
else if(Tx_Done)
bps_cnt <= 4'd0;
else if(bps_clk)
bps_cnt <= bps_cnt + 1'b1;
else
bps_cnt <= bps_cnt;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
Tx_Done <= 1'b0;
else if(bps_cnt == 4'd11)
Tx_Done <= 1'b1;
else
Tx_Done <= 1'b0;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
Rs232_Tx <= 1'b1;
else begin
case(bps_cnt)
0:Rs232_Tx <= 1'b1;
1:Rs232_Tx <= START_BIT;
2:Rs232_Tx <= r_data_byte[0];
3:Rs232_Tx <= r_data_byte[1];
4:Rs232_Tx <= r_data_byte[2];
5:Rs232_Tx <= r_data_byte[3];
6:Rs232_Tx <= r_data_byte[4];
7:Rs232_Tx <= r_data_byte[5];
8:Rs232_Tx <= r_data_byte[6];
9:Rs232_Tx <= r_data_byte[7];
10:Rs232_Tx <= STOP_BIT;
default:Rs232_Tx <= 1'b1;
endcase
end
endmodule
uart_rx 接收
- 串行输入信号同步设计
- 同步寄存器(消除亚稳态)
- 数据寄存器(为了定义下降沿)
- 采样时钟生成
- 实际采样频率是波特率的16倍
- 系统时钟计数值=1/(bpssys_clk_period16) -1
- 采样数据接收模块设计
- 数据状态判定模块设计
【注】:全文参考小梅哥FPGA自学笔记3.10/3.11