一.uart簡(jiǎn)介
- UART(universal asynchronous receiver-transmitter)是一種采用異步串行通信方式的通用異步收發(fā)傳輸器。
- 定義如上,那么出現(xiàn)問(wèn)題了,什么叫異步串行通信?請(qǐng)關(guān)注下文原理。
二.原理
1.同步通信&&異步通信
1.1同步通信
- 發(fā)送方發(fā)送出數(shù)據(jù)后,等接收方響應(yīng)后才發(fā)送下一個(gè)數(shù)據(jù)
1.2異步通信
- 發(fā)送方發(fā)出數(shù)據(jù)后,不等接收方發(fā)回相應(yīng),接著發(fā)送下一個(gè)數(shù)據(jù)
2.并行通信&&串行通信
2.1并行通信
- 并行通信是指數(shù)據(jù)各個(gè)位用多條數(shù)據(jù)線同時(shí)進(jìn)行傳輸
2.2串行通信
- 串行通信是將數(shù)據(jù)分成一位一位的形式在一條線上逐個(gè)傳輸
3.全雙工&&半雙工
3.1全雙工
- 雙方都可以發(fā)送接收數(shù)據(jù),并可以同時(shí)進(jìn)行
3.2半雙工
- 雙方都可以發(fā)送接收數(shù)據(jù),但是同一時(shí)刻只能一方發(fā)送,一方接收
4.協(xié)議層
4.1數(shù)據(jù)格式
- 解析上圖可以看出:空閑位處于高電平,起始位為0(拉低);數(shù)據(jù)位可以是6-8bit,注意是低位先發(fā);暫時(shí)不考慮校驗(yàn)位,停止位為1(拉高)。
4.2傳輸速率
- 串口通信的速率用波特率表示,它表示每秒傳輸二進(jìn)制數(shù)據(jù)的位數(shù),單位是bit/s(位/秒),簡(jiǎn)稱bps。常用的波特率有9600、19200、38400、57600、115200等。本文中設(shè)計(jì)用的115200的波特率==>傳輸1bit需要計(jì)數(shù)50_000_000/115200 = 434次
二.初步設(shè)計(jì)
1.模塊圖
2.tx設(shè)計(jì)
- tx將8bit的數(shù)據(jù)轉(zhuǎn)換為1bit數(shù)據(jù)輸出
3.rx設(shè)計(jì)
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-820228.html
- rx將1bit的數(shù)據(jù)轉(zhuǎn)換為8bit數(shù)據(jù)輸出
- 這里由于加入stop狀態(tài)后面會(huì)導(dǎo)致?tīng)顟B(tài)跳崩了,于是我不要stop狀態(tài)了
4.加入FIFO
- FIFO配置上,數(shù)據(jù)寬度選8bit,數(shù)據(jù)深度選32bit,其他配置可參考前文https://blog.csdn.net/weixin_67803687/article/details/132248964?spm=1001.2014.3001.5501中的單時(shí)鐘前顯模式
三.代碼
1.uart_tx
/**************************************功能介紹***********************************
Date : 2023年8月16日17:07:11
Author : Alegg xy.
Version : 2.0
Description: FPGA向上位機(jī)發(fā)送數(shù)據(jù)【8bit變1bit(波形)】
*********************************************************************************/
//---------<模塊及端口聲名>------------------------------------------------------
module uart_tx(
input clk ,
input rst_n ,
input [7:0] tx_data ,
input tx_data_vld,
output ready ,
output reg tx
);
//---------<參數(shù)定義>---------------------------------------------------------
parameter MAX_1bit = 9'd434;//1bit要計(jì)434次
//狀態(tài)機(jī)參數(shù)定義
localparam IDLE = 'b0001,//空閑狀態(tài)
START = 'b0010,//起始位
DATA = 'b0100,//數(shù)據(jù)位
STOP = 'b1000;//停止位
//---------<內(nèi)部信號(hào)定義>-----------------------------------------------------
reg [3:0] cstate ;//現(xiàn)態(tài)
reg [3:0] nstate ;//次態(tài)
wire IDLE_START;
wire START_DATA;
wire DATA_CHECK;
wire CHECK_STOP;
wire STOP_IDLE;
reg [8:0] cnt_baud ;//波特計(jì)數(shù)器,波特率115200
wire add_cnt_baud ;
wire end_cnt_baud ;
reg [2:0] cnt_bit ;//bit計(jì)數(shù)器,起始位1bit,數(shù)據(jù)位8bit,結(jié)束位1bit
wire add_cnt_bit ;
wire end_cnt_bit ;
reg [3:0] bit_max;//bit最大值,復(fù)用需要考察每個(gè)狀態(tài)的bit值
reg [7:0] tx_data_r;
//計(jì)434次
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_baud <= 'd0;
end
else if(add_cnt_baud)begin
if(end_cnt_baud)begin
cnt_baud <= 'd0;
end
else begin
cnt_baud <= cnt_baud + 1'd1;
end
end
end
assign add_cnt_baud = cstate != IDLE;
assign end_cnt_baud = add_cnt_baud && cnt_baud == MAX_1bit - 1'd1;
//bit計(jì)數(shù)器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_bit <= 'd0;
end
else if(add_cnt_bit)begin
if(end_cnt_bit)begin
cnt_bit <= 'd0;
end
else begin
cnt_bit <= cnt_bit + 1'd1;
end
end
end
assign add_cnt_bit = end_cnt_baud;
assign end_cnt_bit = add_cnt_bit && cnt_bit == bit_max -1'd1;
//計(jì)數(shù)器復(fù)用
always @(*)begin
case (cstate)
IDLE :bit_max = 'd0;
START:bit_max = 'd1;//起始位1bit
DATA :bit_max = 'd8;//數(shù)據(jù)位8bit
STOP :bit_max = 'd1;//結(jié)束位1bit
default: bit_max = 'd0;
endcase
end
assign IDLE_START = (cstate == IDLE) && tx_data_vld;//考察到開(kāi)始傳輸信號(hào)
assign START_DATA = (cstate == START) && end_cnt_bit;//計(jì)1bit數(shù)據(jù)
assign DATA_STOP = (cstate == DATA) && end_cnt_bit;
assign STOP_IDLE = (cstate == STOP) && end_cnt_bit;//計(jì)1bit數(shù)據(jù)
//第一段:時(shí)序邏輯描述狀態(tài)轉(zhuǎn)移
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cstate <= IDLE;
end
else begin
cstate <= nstate;
end
end
//第二段:組合邏輯描述狀態(tài)轉(zhuǎn)移規(guī)律和狀態(tài)轉(zhuǎn)移條件
always @(*) begin
case(cstate)
IDLE :begin
if (IDLE_START) begin
nstate = START;
end
else begin
nstate = cstate;
end
end
START :begin
if (START_DATA) begin
nstate = DATA;
end
else begin
nstate = cstate;
end
end
DATA :begin
if (DATA_STOP) begin
nstate = STOP;
end
else begin
nstate = cstate;
end
end
STOP :begin
if (STOP_IDLE) begin
nstate = IDLE;
end
else begin
nstate = cstate;
end
end
default : nstate = cstate;
endcase
end
//寄存一拍
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
tx_data_r <= 'd0;
end
else if (tx_data_vld) begin
tx_data_r <= tx_data;
end
else begin
tx_data_r <= tx_data_r;
end
end
//第三段:描述輸出,時(shí)序邏輯或組合邏輯皆可
always @(*)begin
case (cstate)
IDLE : tx = 1'b1;
START: tx = 1'b0;//起始位為0
DATA : tx = tx_data_r[cnt_bit];
STOP : tx = 1'b1;//結(jié)束位為1
default: tx = 1'b1;
endcase
end
assign ready = cstate == IDLE;//當(dāng)狀態(tài)為IDLE時(shí),表示tx端可以接收數(shù)據(jù)
endmodule
2.uart_rx
/**************************************功能介紹***********************************
Date : 2023年8月16日18:25:03
Author : Alegg xy.
Version : 1.0
Description: FPGA收上位機(jī)發(fā)來(lái)的數(shù)據(jù)【1bit(波形)變8bit】
*********************************************************************************/
//---------<模塊及端口聲名>------------------------------------------------------
module uart_rx(
input clk ,
input rst_n ,
input rx ,
output rx_data_vld,
output reg [7:0] rx_data
);
//---------<參數(shù)定義>---------------------------------------------------------
parameter MAX_1bit = 9'd434;//1bit要計(jì)434次
//狀態(tài)機(jī)參數(shù)定義
localparam IDLE = 'b001,//空閑狀態(tài)
START = 'b010,//起始位
DATA = 'b100;//數(shù)據(jù)位
//---------<內(nèi)部信號(hào)定義>-----------------------------------------------------
reg [2:0] cstate ;//現(xiàn)態(tài)
reg [2:0] nstate ;//次態(tài)
wire IDLE_START;
wire START_DATA;
wire DATA_IDLE;
reg [8:0] cnt_baud ;//波特計(jì)數(shù)器,波特率115200
wire add_cnt_baud ;
wire end_cnt_baud ;
reg [2:0] cnt_bit ;//bit計(jì)數(shù)器,起始位1bit,數(shù)據(jù)位8bit,結(jié)束位1bit
wire add_cnt_bit ;
wire end_cnt_bit ;
reg [3:0] bit_max;//bit最大值,復(fù)用需要考察每個(gè)狀態(tài)的bit值
//計(jì)434次
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_baud <= 'd0;
end
else if(add_cnt_baud)begin
if(end_cnt_baud)begin
cnt_baud <= 'd0;
end
else begin
cnt_baud <= cnt_baud + 1'd1;
end
end
end
assign add_cnt_baud = cstate != IDLE;
assign end_cnt_baud = add_cnt_baud && cnt_baud == MAX_1bit - 1'd1;
//bit計(jì)數(shù)器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_bit <= 'd0;
end
else if(add_cnt_bit)begin
if(end_cnt_bit)begin
cnt_bit <= 'd0;
end
else begin
cnt_bit <= cnt_bit + 1'd1;
end
end
end
assign add_cnt_bit = end_cnt_baud;
assign end_cnt_bit = add_cnt_bit && cnt_bit == bit_max -1'd1;
//計(jì)數(shù)器復(fù)用
always @(*)begin
case (cstate)
IDLE :bit_max = 'd0;
START:bit_max = 'd1;//起始位1bit
DATA :bit_max = 'd8;//數(shù)據(jù)位8bit
default: bit_max = 'd0;
endcase
end
assign IDLE_START = (cstate == IDLE) && rx == 0;//識(shí)別到起始位0
assign START_DATA = (cstate == START) && end_cnt_bit;//計(jì)1bit數(shù)據(jù)
assign DATA_IDLE = (cstate == DATA) && end_cnt_bit;//計(jì)8bit數(shù)據(jù)
//第一段:時(shí)序邏輯描述狀態(tài)轉(zhuǎn)移
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cstate <= IDLE;
end
else begin
cstate <= nstate;
end
end
//第二段:組合邏輯描述狀態(tài)轉(zhuǎn)移規(guī)律和狀態(tài)轉(zhuǎn)移條件
always @(*) begin
case(cstate)
IDLE :begin
if (IDLE_START) begin
nstate = START;
end
else begin
nstate = cstate;
end
end
START :begin
if (START_DATA) begin
nstate = DATA;
end
else begin
nstate = cstate;
end
end
DATA :begin
if (DATA_IDLE) begin
nstate = IDLE;
end
else begin
nstate = cstate;
end
end
default : nstate = IDLE;
endcase
end
//第三段:描述輸出,時(shí)序邏輯或組合邏輯皆可
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rx_data <= 0;
end
else if (cstate == DATA && cnt_baud == MAX_1bit >> 1) begin//電平中間值采樣,邊沿采樣容易出錯(cuò)
rx_data[cnt_bit] <= rx;
end
else begin
rx_data <= rx_data;
end
end
assign rx_data_vld = DATA_IDLE;//開(kāi)始傳輸數(shù)據(jù)信號(hào)為計(jì)滿數(shù)據(jù)位
endmodule
3.ctrl(FIFO)
/**************************************功能介紹***********************************
Date : 2023年8月16日18:43:33
Author : Alegg xy.
Version : 1.0
Description: 調(diào)用FIFO
*********************************************************************************/
//---------<模塊及端口聲名>------------------------------------------------------
module ctrl(
input clk ,
input rst_n ,
input [7:0] rx_data ,
input rx_data_vld,
input ready ,
output tx_data_vld,
output [7:0] tx_data
);
//---------<參數(shù)定義>---------------------------------------------------------
wire fifo_rdempty;//FIFO讀空信號(hào)
wire fifo_wrfull;//FIFO寫(xiě)滿信號(hào)
//---------<內(nèi)部信號(hào)定義>-----------------------------------------------------
fifo fifo_inst (
.aclr ( ~rst_n ),
.data ( rx_data ),
.rdclk ( clk ),
.rdreq ( ready && ~fifo_rdempty ),
.wrclk ( clk ),
.wrreq ( rx_data_vld && ~fifo_wrfull ),
.q ( tx_data ),
.rdempty ( fifo_rdempty ),
.wrfull ( fifo_wrfulll )
);
assign tx_data_vld = ready && ~fifo_rdempty;
endmodule
4.top
/**************************************功能介紹***********************************
Date : 2023年8月16日18:51:42
Author : Alegg xy.
Version : 1.0
Description: 頂層模塊
*********************************************************************************/
//---------<模塊及端口聲名>------------------------------------------------------
module top(
input clk ,
input rst_n ,
input rx ,
output tx
);
//---------<參數(shù)定義>---------------------------------------------------------
wire [7:0] tx_data;
wire tx_data_vld;
wire [7:0] rx_data;
wire rx_data_vld;
wire ready;
//---------<內(nèi)部信號(hào)定義>-----------------------------------------------------
uart_tx u_uart_tx(
.clk (clk),
.rst_n (rst_n),
.tx_data (tx_data),
.tx_data_vld(tx_data_vld),
.ready (ready),
.tx (tx)
);
uart_rx u_uart_rx(
.clk (clk),
.rst_n (rst_n),
.rx (rx),
.rx_data_vld(rx_data_vld),
.rx_data (rx_data)
);
ctrl u_ctrl(
.clk (clk),
.rst_n (rst_n),
.rx_data (rx_data),
.rx_data_vld(rx_data_vld),
.ready (ready),
.tx_data_vld(tx_data_vld),
.tx_data (tx_data)
);
endmodule
四.效果
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-820228.html
到了這里,關(guān)于uart串口環(huán)回(加FIFO)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!