UART异步串口协议
- 1 UART
- 1.1 数据格式
- 1.2 波特率
- 2 UART的发送和接收模块
- 2.1 uart发送模块
- 2.2 uart的接收模块
【博客首发于微信公众号《 漫谈芯片与编程》】
本篇文章介绍常用的芯片外围低速协议:UART;
1 UART
UART是异步串行传输协议,即在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换到并行数据;
UART串口协议只需要两根信号线来实现即可;一根用于发送,一根用于接收;
数据流:数据以并行形式从数据总线传输到传输UART。在发送UART从数据总线获取并行数据后,它会添加一个起始位、一个奇偶校验位和一个停止位,从而创建数据包。接下来,数据包在Tx引脚上逐位串行输出。接收UART在其Rx引脚上逐位读取数据包。然后,接收的UART将数据转换回并行形式,并删除起始位、奇偶校验位和停止位。最后,接收UART将数据包并行传输到接收端的数据总线:
1.1 数据格式
UART传输的数据格式:通常以一个起始位、若干数据位、一个可选的奇偶校验位和一个或多个停止位组成。
- 起始位:标志一帧数据的开始;
- 停止位:标志一帧数据的结束;
- 数据位:标志一帧数据中的有效数据;可选5~9位,一般选择8位;
- 校验位:标志一帧数据中的奇偶校验;
- 停止位:标志一帧数据中的停止;
1.2 波特率
波特率:表示每秒传输二进制数据的位数,单位是bps;常见波特率:9600,19200,38400,57600,115200;
2 UART的发送和接收模块
2.1 uart发送模块
//==========================================================
//--Author : colonel
//--Date : 11-05
//--Module : uart_send
//--Function: uart is diviede into uart_send,uart_reciver
//==========================================================
module uart_send(
//==========================< 端口 >=========================input clk,input rst_n,input tx_en,input [8 -1:0] tx_din,output reg uart_txd
);
//==========================< 参数 >=========================
localparam BAUD_RATE = 9600;
localparam CLK_FREQ = 50000000;
localparam BAUD_PERIOD = CLK_FREQ / BAUD_RATE;//==========================< 信号 >=========================
reg tx_en_sync0;
reg tx_en_sync1;//=========================================================
//-- tx_en_sync0/1
//=========================================================
always @(posedge clk or rst_n) beginif (!rst_n) begintx_en_sync0 <= 1'b0;tx_en_sync1 <= 1'b0;end else begintx_en_sync0 <= tx_en;tx_en_sync1 <= tx_en_sync0;end
endwire start_flag = tx_en_sync0 && !tx_en_sync1; //pos pulse//==========================< 信号 >=========================
reg [16 -1:0] bps_cnt;
reg [4 -1:0] tx_cnt;//=========================================================
//-- bps_cnt, tx_cnt:
//=========================================================
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginbps_cnt <= 'b0;end else beginif (bps_cnt < BAUD_PERIOD -1) beginbps_cnt <= bps_cnt + 1'b1;end else beginbps_cnt <= 'b0;endend
endalways @(posedge clk or negedge rst_n) beginif (!rst_n) begintx_cnt <= 'b0;end else beginif (bps_cnt==BAUD_PERIOD-1) begintx_cnt <= tx_cnt + 1'b1;end else if(start_flag)begintx_cnt <= 1'b0;end else begintx_cnt <= tx_cnt;endend
end//==========================< 信号 >=========================
reg tx_flag;
reg [8 -1:0] tx_data; //floped for uart_din//=========================================================
//-- tx_flag,tx_data
//=========================================================
always @(posedge clk or negedge rst_n) beginif (!rst_n) begintx_data <= 'd0;end else beginif (start_flag) begintx_data <= tx_din;end else if (tx_cnt==4'd9 &&(bps_cnt==BAUD_PERIOD/2)) begintx_data <= 0;end else begintx_data <= tx_data;endend
endalways @(posedge clk or negedge rst_n) beginif (!rst_n) begintx_flag <= 1'b0;end else beginif (start_flag) begintx_flag <= 1'b1;end else if(tx_cnt==4'd9) begintx_flag <= 1'b0;end else begintx_flag <= tx_flag;endend
end//=========================================================
//-- uart_txd
//=========================================================always @(posedge clk or negedge rst_n) beginif (!rst_n) beginuart_txd <= 1'b1;end else beginif (tx_flag) begincase (tx_cnt)4'd0: uart_txd <= 1'b0; 4'd1: uart_txd <= tx_data[0]; 4'd2: uart_txd <= tx_data[1]; 4'd3: uart_txd <= tx_data[2]; 4'd4: uart_txd <= tx_data[3]; 4'd5: uart_txd <= tx_data[4]; 4'd6: uart_txd <= tx_data[5]; 4'd7: uart_txd <= tx_data[6]; 4'd8: uart_txd <= tx_data[7]; 4'd9: uart_txd <= 1'b1; default: uart_txd <= 1'b1;endcaseend else beginuart_txd <= 1'b1;endend
endendmodule
2.2 uart的接收模块
//==========================================================
//--Author : colonel
//--Date : 11-05
//--Module : uart_reci
//--Function: uart is diviede into uart_send,uart_reciver
//==========================================================
module uart_reciver (
//==========================< 端口 >=========================input clk,input rst_n,input uart_rxd,output [8 -1:0] uart_txd,output rx_done
);
//==========================< 参数 >=========================
localparam BAUD_RATE = 9600;
localparam CLK_FREQ = 50000000;
localparam BAUD_PERIOD = CLK_FREQ / BAUD_RATE;//==========================< 信号 >=========================
reg uart_rxd_r1;
reg uart_rxd_r2;//=========================================================
//-- uart_rxd_r1/2
//=========================================================
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginuart_rxd_r1 <= 1'b0;uart_rxd_r2 <= 1'b0;end else beginuart_rxd_r1 <= uart_rxd;uart_rxd_r2 <= uart_rxd_r1;end
endwire start_flag_neg = uart_rxd_r2 && !uart_rxd_r1;//==========================< 信号 >=========================
reg [16 -1:0] bps_cnt;
reg [4 -1:0] rx_cnt;//=========================================================
//-- bps_cnt, rx_cnt:
//=========================================================
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginbps_cnt <= 'b0;end else beginif (bps_cnt < BAUD_PERIOD -1) beginbps_cnt <= bps_cnt + 1'b1;end else beginbps_cnt <= 'b0;endend
endalways @(posedge clk or negedge rst_n) beginif (!rst_n) beginrx_cnt <= 'b0;end else beginif (bps_cnt==BAUD_PERIOD-1) beginrx_cnt <= rx_cnt + 1'b1;end else if(start_flag_neg) beginrx_cnt <= 1'b0;end else beginrx_cnt <= rx_cnt;endend
end//==========================< 信号 >=========================
reg rx_flag;//=========================================================
//-- rx_flag
//=========================================================
always @(posedge clk or rst_n) beginif (!rst_n) beginrx_flag <= 1'b0;end else beginif (start_flag_neg) beginrx_flag <= 1'b1;end else if (rx_cnt==4'd9 && (bps_cnt==BAUD_PERIOD/2)) beginrx_flag <= 1'b0;end else beginrx_flag <= rx_flag;endend
end//==========================< 信号 >=========================
reg [8 -1:0] uart_txd_r;
//=========================================================
//-- uart_txd_r
//=========================================================
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginuart_txd_r <= 8'b0;end else beginif (rx_flag && bps_cnt==BAUD_PERIOD/2) begincase (rx_cnt)4'd1: uart_txd_r[0] <= uart_rxd_r1;4'd2: uart_txd_r[1] <= uart_rxd_r1;4'd3: uart_txd_r[2] <= uart_rxd_r1;4'd4: uart_txd_r[3] <= uart_rxd_r1;4'd5: uart_txd_r[4] <= uart_rxd_r1;4'd6: uart_txd_r[5] <= uart_rxd_r1;4'd7: uart_txd_r[6] <= uart_rxd_r1;4'd8: uart_txd_r[7] <= uart_rxd_r1;default: ; endcaseend else beginuart_txd_r <= uart_txd_r;endend
endendmodule
以上是uart的发送和接收模块,从这里可以看出核心是维护cnt;
【REF】
1.https://www.cnblogs.com/liujinggang/p/9535366.html
2.https://blog.csdn.net/m0_61298445/article/details/125073150